Add additional multi-layer complex squashing test

This commit is contained in:
Joseph Schorr 2018-09-12 15:26:57 -04:00
parent f252b0b16f
commit 7424a6d73a
3 changed files with 99 additions and 3 deletions

View file

@ -37,6 +37,45 @@ def sized_images():
] ]
@pytest.fixture(scope="session")
def multi_layer_images():
""" Returns complex images (with sizes) for push and pull testing. """
# Note: order is from base layer down to leaf.
layer1_bytes = layer_bytes_for_contents('layer 1 contents', mode='', other_files={
'file1': 'from-layer-1',
})
layer2_bytes = layer_bytes_for_contents('layer 2 contents', mode='', other_files={
'file2': 'from-layer-2',
})
layer3_bytes = layer_bytes_for_contents('layer 3 contents', mode='', other_files={
'file1': 'from-layer-3',
'file3': 'from-layer-3',
})
layer4_bytes = layer_bytes_for_contents('layer 4 contents', mode='', other_files={
'file3': 'from-layer-4',
})
layer5_bytes = layer_bytes_for_contents('layer 5 contents', mode='', other_files={
'file4': 'from-layer-5',
})
return [
Image(id='layer1', bytes=layer1_bytes, parent_id=None, size=len(layer1_bytes),
config={'internal_id': 'layer1'}),
Image(id='layer2', bytes=layer2_bytes, parent_id='layer1', size=len(layer2_bytes),
config={'internal_id': 'layer2'}),
Image(id='layer3', bytes=layer3_bytes, parent_id='layer2', size=len(layer3_bytes),
config={'internal_id': 'layer3'}),
Image(id='layer4', bytes=layer4_bytes, parent_id='layer3', size=len(layer4_bytes),
config={'internal_id': 'layer4'}),
Image(id='someid', bytes=layer5_bytes, parent_id='layer4', size=len(layer5_bytes),
config={'internal_id': 'layer5'}),
]
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def jwk(): def jwk():
return RSAKey(key=RSA.generate(2048)) return RSAKey(key=RSA.generate(2048))

View file

@ -14,8 +14,9 @@ PushResult = namedtuple('PushResult', ['checksums', 'manifests', 'headers'])
PullResult = namedtuple('PullResult', ['manifests', 'image_ids']) PullResult = namedtuple('PullResult', ['manifests', 'image_ids'])
def layer_bytes_for_contents(contents, mode='|gz'): def layer_bytes_for_contents(contents, mode='|gz', other_files=None):
layer_data = StringIO() layer_data = StringIO()
tar_file = tarfile.open(fileobj=layer_data, mode='w' + mode)
def add_file(name, contents): def add_file(name, contents):
tar_file_info = tarfile.TarInfo(name=name) tar_file_info = tarfile.TarInfo(name=name)
@ -23,12 +24,16 @@ def layer_bytes_for_contents(contents, mode='|gz'):
tar_file_info.size = len(contents) tar_file_info.size = len(contents)
tar_file_info.mtime = 1 tar_file_info.mtime = 1
tar_file = tarfile.open(fileobj=layer_data, mode='w' + mode)
tar_file.addfile(tar_file_info, StringIO(contents)) tar_file.addfile(tar_file_info, StringIO(contents))
tar_file.close()
add_file('contents', contents) add_file('contents', contents)
if other_files is not None:
for file_name, file_contents in other_files.iteritems():
add_file(file_name, file_contents)
tar_file.close()
layer_bytes = layer_data.getvalue() layer_bytes = layer_data.getvalue()
layer_data.close() layer_data.close()
return layer_bytes return layer_bytes

View file

@ -930,6 +930,58 @@ def test_squashed_image_disabled_user(pusher, sized_images, liveserver_session,
assert response.status_code == 403 assert response.status_code == 403
@pytest.mark.parametrize('use_estimates', [
False,
True,
])
def test_multilayer_squashed_images(use_estimates, pusher, multi_layer_images, liveserver_session,
liveserver, registry_server_executor, app_reloader):
""" Test: Pulling of multilayer, complex squashed images. """
credentials = ('devtable', 'password')
# Push an image to download.
pusher.push(liveserver_session, 'devtable', 'newrepo', 'latest', multi_layer_images,
credentials=credentials)
if use_estimates:
# Clear the uncompressed size stored for the images, to ensure that we estimate instead.
for image in multi_layer_images:
registry_server_executor.on(liveserver).clear_uncompressed_size(image.id)
# Pull the squashed version.
response = liveserver_session.get('/c1/squash/devtable/newrepo/latest', auth=credentials)
tar = tarfile.open(fileobj=StringIO(response.content))
# Verify the squashed image.
expected_image_id = 'cdc6d6c0d07d2cbacfc579e49ce0c256c5084b9b2b16c1b1b0c45f26a12a4ba5'
expected_names = ['repositories',
expected_image_id,
'%s/json' % expected_image_id,
'%s/VERSION' % expected_image_id,
'%s/layer.tar' % expected_image_id]
assert tar.getnames() == expected_names
# Verify the JSON image data.
json_data = (tar.extractfile(tar.getmember('%s/json' % expected_image_id)).read())
# Ensure the JSON loads and parses.
result = json.loads(json_data)
assert result['id'] == expected_image_id
assert result['config']['internal_id'] == 'layer5'
# Ensure that squashed layer tar can be opened.
tar = tarfile.open(fileobj=tar.extractfile(tar.getmember('%s/layer.tar' % expected_image_id)))
assert set(tar.getnames()) == {'contents', 'file1', 'file2', 'file3', 'file4'}
# Check the contents of various files.
assert tar.extractfile('contents').read() == 'layer 5 contents'
assert tar.extractfile('file1').read() == 'from-layer-3'
assert tar.extractfile('file2').read() == 'from-layer-2'
assert tar.extractfile('file3').read() == 'from-layer-4'
assert tar.extractfile('file4').read() == 'from-layer-5'
@pytest.mark.parametrize('use_estimates', [ @pytest.mark.parametrize('use_estimates', [
False, False,
True, True,