Packing support for blob data
=============================

Set up:

    >>> from ZODB.serialize import referencesf
    >>> from ZODB.blob import Blob
    >>> from ZODB import utils
    >>> from ZODB.DB import DB
    >>> import transaction

A helper method to assure a unique timestamp across multiple platforms:

    >>> from ZODB.tests.testblob import new_time

UNDOING
=======

We need a database with an undoing blob supporting storage:

    >>> blob_storage = create_storage()
    >>> database = DB(blob_storage)

Create our root object:

    >>> connection1 = database.open()
    >>> root = connection1.root()

Put some revisions of a blob object in our database and on the filesystem:

    >>> import os
    >>> tids = []
    >>> times = []
    >>> nothing = transaction.begin()
    >>> times.append(new_time())
    >>> blob = Blob()
    >>> with blob.open('w') as file:
    ...     _ = file.write(b'this is blob data 0')
    >>> root['blob'] = blob
    >>> transaction.commit()
    >>> tids.append(blob._p_serial)

    >>> nothing = transaction.begin()
    >>> times.append(new_time())
    >>> with root['blob'].open('w') as file:
    ...     _ = file.write(b'this is blob data 1')
    >>> transaction.commit()
    >>> tids.append(blob._p_serial)

    >>> nothing = transaction.begin()
    >>> times.append(new_time())
    >>> with root['blob'].open('w') as file:
    ...     _ = file.write(b'this is blob data 2')
    >>> transaction.commit()
    >>> tids.append(blob._p_serial)

    >>> nothing = transaction.begin()
    >>> times.append(new_time())
    >>> with root['blob'].open('w') as file:
    ...     _ = file.write(b'this is blob data 3')
    >>> transaction.commit()
    >>> tids.append(blob._p_serial)

    >>> nothing = transaction.begin()
    >>> times.append(new_time())
    >>> with root['blob'].open('w') as file:
    ...     _ = file.write(b'this is blob data 4')
    >>> transaction.commit()
    >>> tids.append(blob._p_serial)

    >>> oid = root['blob']._p_oid
    >>> fns = [ blob_storage.fshelper.getBlobFilename(oid, x) for x in tids ]
    >>> [ os.path.exists(x) for x in fns ] # no pack
    [True, True, True, True, True]

Do a pack to the slightly before the first revision was written:

    >>> packtime = times[0]
    >>> blob_storage.pack(packtime, referencesf)
    >>> [ os.path.exists(x) for x in fns ]
    [True, True, True, True, True]

Do a pack to the slightly before the second revision was written:

    >>> packtime = times[1]
    >>> blob_storage.pack(packtime, referencesf)
    >>> [ os.path.exists(x) for x in fns ]
    [True, True, True, True, True]

Do a pack to the slightly before the third revision was written:

    >>> packtime = times[2]
    >>> blob_storage.pack(packtime, referencesf)
    >>> [ os.path.exists(x) for x in fns ]
    [False, True, True, True, True]

Do a pack to the slightly before the fourth revision was written:

    >>> packtime = times[3]
    >>> blob_storage.pack(packtime, referencesf)
    >>> [ os.path.exists(x) for x in fns ]
    [False, False, True, True, True]

Do a pack to the slightly before the fifth revision was written:

    >>> packtime = times[4]
    >>> blob_storage.pack(packtime, referencesf)
    >>> [ os.path.exists(x) for x in fns ]
    [False, False, False, True, True]

Do a pack to now:

    >>> packtime = new_time()
    >>> blob_storage.pack(packtime, referencesf)
    >>> [ os.path.exists(x) for x in fns ]
    [False, False, False, False, True]

Delete the object and do a pack, it should get rid of the most current
revision as well as the entire directory:

    >>> nothing = transaction.begin()
    >>> del root['blob']
    >>> transaction.commit()
    >>> packtime = new_time()
    >>> blob_storage.pack(packtime, referencesf)
    >>> [ os.path.exists(x) for x in fns ]
    [False, False, False, False, False]
    >>> os.path.exists(os.path.split(fns[0])[0])
    False

Clean up our blob directory and database:

    >>> database.close()
