def test_search_pagination(query, authed_username, initialized_db): # Create some public repos. repo1 = create_repository('devtable', 'somenewrepo', None, repo_kind='image', visibility='public') repo2 = create_repository('devtable', 'somenewrepo2', None, repo_kind='image', visibility='public') repo3 = create_repository('devtable', 'somenewrepo3', None, repo_kind='image', visibility='public') repositories = get_filtered_matching_repositories( query, filter_username=authed_username) assert len(repositories) > 3 next_repos = get_filtered_matching_repositories( query, filter_username=authed_username, offset=1) assert repositories[0].id != next_repos[0].id assert repositories[1].id == next_repos[0].id
def test_delete_namespace_via_marker(initialized_db): def create_transaction(db): return db.transaction() # Create a user and then mark it for deletion. user = create_user_noverify("foobar", "*****@*****.**", email_required=False) # Add some repositories. create_repository("foobar", "somerepo", user) create_repository("foobar", "anotherrepo", user) # Mark the user for deletion. queue = WorkQueue("testgcnamespace", create_transaction) marker_id = mark_namespace_for_deletion(user, [], queue) # Delete the user. with check_transitive_modifications(): delete_namespace_via_marker(marker_id, []) # Ensure the user was actually deleted. with pytest.raises(User.DoesNotExist): User.get(id=user.id) with pytest.raises(DeletedNamespace.DoesNotExist): DeletedNamespace.get(id=marker_id)
def test_duplicate_repository_different_kinds(initialized_db): # Create an image repo. assert create_repository("devtable", "somenewrepo", None, repo_kind="image") # Try to create an app repo with the same name, which should fail. assert not create_repository( "devtable", "somenewrepo", None, repo_kind="application")
def test_duplicate_repository_different_kinds(initialized_db): # Create an image repo. create_repository('devtable', 'somenewrepo', None, repo_kind='image') # Try to create an app repo with the same name, which should fail. with pytest.raises(IntegrityError): create_repository('devtable', 'somenewrepo', None, repo_kind='application')
def test_lookup_manifest_child_tag(initialized_db): repository = create_repository("devtable", "newrepo", None) manifest, manifest_impl = create_manifest_for_testing(repository) # Mark the hidden tag as dead. hidden_tag = Tag.get(manifest=manifest, hidden=True) hidden_tag.lifetime_end_ms = hidden_tag.lifetime_start_ms hidden_tag.save() # Ensure the manifest cannot currently be looked up, as it is not pointed to by an alive tag. assert lookup_manifest(repository, manifest.digest) is None assert lookup_manifest(repository, manifest.digest, allow_dead=True) is not None # Populate a manifest list. list_builder = DockerSchema2ManifestListBuilder() list_builder.add_manifest(manifest_impl, "amd64", "linux") manifest_list = list_builder.build() # Write the manifest list, which should also write the manifests themselves. created_tuple = get_or_create_manifest(repository, manifest_list, storage) assert created_tuple is not None # Since the manifests are not yet referenced by a tag, they cannot be found. assert lookup_manifest(repository, manifest.digest) is None assert lookup_manifest(repository, manifest_list.digest) is None # Unless we ask for "dead" manifests. assert lookup_manifest(repository, manifest.digest, allow_dead=True) is not None assert lookup_manifest(repository, manifest_list.digest, allow_dead=True) is not None
def test_change_tag_expiration(expiration_offset, expected_offset, initialized_db): repository = create_repository('devtable', 'somenewrepo', None) image1 = find_create_or_link_image('foobarimage1', repository, None, {}, 'local_us') manifest = Manifest.get() footag = create_or_update_tag_for_repo(repository, 'foo', image1.docker_image_id, oci_manifest=manifest) expiration_date = None if expiration_offset is not None: expiration_date = datetime.utcnow() + convert_to_timedelta(expiration_offset) assert change_tag_expiration(footag, expiration_date) # Lookup the tag again. footag_updated = get_active_tag('devtable', 'somenewrepo', 'foo') oci_tag = _get_oci_tag(footag_updated) if expected_offset is None: assert footag_updated.lifetime_end_ts is None assert oci_tag.lifetime_end_ms is None else: start_date = datetime.utcfromtimestamp(footag_updated.lifetime_start_ts) end_date = datetime.utcfromtimestamp(footag_updated.lifetime_end_ts) expected_end_date = start_date + convert_to_timedelta(expected_offset) assert (expected_end_date - end_date).total_seconds() < 5 # variance in test assert oci_tag.lifetime_end_ms == (footag_updated.lifetime_end_ts * 1000)
def test_create_reversion_tag(initialized_db): repository = create_repository('devtable', 'somenewrepo', None) manifest = Manifest.get() image1 = find_create_or_link_image('foobarimage1', repository, None, {}, 'local_us') footag = create_or_update_tag_for_repo(repository, 'foo', image1.docker_image_id, oci_manifest=manifest, reversion=True) assert footag.reversion oci_tag = _get_oci_tag(footag) assert oci_tag.name == footag.name assert not oci_tag.hidden assert oci_tag.reversion == footag.reversion
def lookup_repository(self, namespace_name, repo_name, kind_filter=None, raise_on_error=False, manifest_ref=None): """ Looks up and returns a reference to the repository with the given namespace and name, or None if none. If the repository does not exist and the given manifest_ref exists upstream, creates the repository. """ repo = get_repository(namespace_name, repo_name) exists = repo is not None if exists: return RepositoryReference.for_repo_obj( repo, namespace_name, repo_name, repo.namespace_user.stripe_id is None if repo else None, state=repo.state if repo is not None else None, ) # we only create a repository for images that exist upstream, and if # we're not given a manifest reference then we can't check whether the # image exists upstream or not, so we refuse to create the repo. if manifest_ref is None: return None try: self._proxy.manifest_exists(manifest_ref, ACCEPTED_MEDIA_TYPES) except UpstreamRegistryError as e: if raise_on_error: raise RepositoryDoesNotExist(str(e)) return None repo = create_repository(namespace_name, repo_name, self._user) return RepositoryReference.for_repo_obj( repo, namespace_name, repo_name, repo.namespace_user.stripe_id is None if repo else None, state=repo.state if repo is not None else None, )
def test_update_repository_score(bucket_sums, expected_score, initialized_db): # Create a new repository. repo = create_repository('devtable', 'somenewrepo', None, repo_kind='image') # Delete the RAC created in create_repository. RepositoryActionCount.delete().where( RepositoryActionCount.repository == repo).execute() # Add RAC rows for each of the buckets. for index, bucket in enumerate(SEARCH_BUCKETS): for day in range(0, bucket.days): RepositoryActionCount.create( repository=repo, count=(bucket_sums[index] / bucket.days * 1.0), date=date.today() - bucket.delta + timedelta(days=day)) assert update_repository_score(repo) assert RepositorySearchScore.get(repository=repo).score == expected_score
def test_create_manifest_cannot_load_config_blob(initialized_db): repository = create_repository("devtable", "newrepo", None) layer_json = json.dumps({ "config": {}, "rootfs": { "type": "layers", "diff_ids": [] }, "history": [ { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, ], }) # Add a blob containing the config. _, config_digest = _populate_blob(layer_json) # Add a blob of random data. random_data = "hello world" _, random_digest = _populate_blob(random_data) remote_digest = sha256_digest(b"something") builder = DockerSchema2ManifestBuilder() builder.set_config_digest(config_digest, len(layer_json.encode("utf-8"))) builder.add_layer(random_digest, len(random_data.encode("utf-8"))) manifest = builder.build() broken_retriever = BrokenRetriever() # Write the manifest. with pytest.raises(CreateManifestException): get_or_create_manifest(repository, manifest, storage, retriever=broken_retriever, raise_on_error=True)
def test_is_empty(initialized_db): create_repository("devtable", "somenewrepo", None, repo_kind="image") assert is_empty("devtable", "somenewrepo") assert not is_empty("devtable", "simple")
def test_get_or_create_manifest_with_remote_layers(initialized_db): repository = create_repository("devtable", "newrepo", None) layer_json = json.dumps({ "config": {}, "rootfs": { "type": "layers", "diff_ids": [] }, "history": [ { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, ], }) # Add a blob containing the config. _, config_digest = _populate_blob(layer_json) # Add a blob of random data. random_data = "hello world" _, random_digest = _populate_blob(random_data) remote_digest = sha256_digest(b"something") builder = DockerSchema2ManifestBuilder() builder.set_config_digest(config_digest, len(layer_json.encode("utf-8"))) builder.add_layer(remote_digest, 1234, urls=["http://hello/world"]) builder.add_layer(random_digest, len(random_data.encode("utf-8"))) manifest = builder.build() assert remote_digest in manifest.blob_digests assert remote_digest not in manifest.local_blob_digests assert manifest.has_remote_layer assert not manifest.has_legacy_image assert manifest.get_schema1_manifest("foo", "bar", "baz", None) is None # Write the manifest. created_tuple = get_or_create_manifest(repository, manifest, storage) assert created_tuple is not None created_manifest = created_tuple.manifest assert created_manifest assert created_manifest.media_type.name == manifest.media_type assert created_manifest.digest == manifest.digest assert created_manifest.config_media_type == manifest.config_media_type assert created_manifest.layers_compressed_size == manifest.layers_compressed_size # Verify the legacy image. legacy_image = get_legacy_image_for_manifest(created_manifest) assert legacy_image is None # Verify the linked blobs. blob_digests = { mb.blob.content_checksum for mb in ManifestBlob.select().where( ManifestBlob.manifest == created_manifest) } assert random_digest in blob_digests assert config_digest in blob_digests assert remote_digest not in blob_digests
def test_is_empty(initialized_db): create_repository('devtable', 'somenewrepo', None, repo_kind='image') assert is_empty('devtable', 'somenewrepo') assert not is_empty('devtable', 'simple')
def _create_repo(orgname, reponame, user): r = create_repository(orgname, reponame, user) assert r is not None repo_ref = registry_model.lookup_repository(orgname, reponame) assert repo_ref is not None return repo_ref
def test_get_or_create_manifest(schema_version, initialized_db): repository = create_repository("devtable", "newrepo", None) expected_labels = { "Foo": "Bar", "Baz": "Meh", } layer_json = json.dumps({ "id": "somelegacyid", "config": { "Labels": expected_labels, }, "rootfs": { "type": "layers", "diff_ids": [] }, "history": [ { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, ], }) # Create a legacy image. find_create_or_link_image("somelegacyid", repository, "devtable", {}, "local_us") # Add a blob containing the config. _, config_digest = _populate_blob(layer_json) # Add a blob of random data. random_data = "hello world" _, random_digest = _populate_blob(random_data) # Build the manifest. if schema_version == 1: builder = DockerSchema1ManifestBuilder("devtable", "simple", "anothertag") builder.add_layer(random_digest, layer_json) sample_manifest_instance = builder.build(docker_v2_signing_key) elif schema_version == 2: builder = DockerSchema2ManifestBuilder() builder.set_config_digest(config_digest, len(layer_json.encode("utf-8"))) builder.add_layer(random_digest, len(random_data.encode("utf-8"))) sample_manifest_instance = builder.build() assert sample_manifest_instance.layers_compressed_size is not None # Create a new manifest. created_manifest = get_or_create_manifest(repository, sample_manifest_instance, storage) created = created_manifest.manifest newly_created = created_manifest.newly_created assert newly_created assert created is not None assert created.media_type.name == sample_manifest_instance.media_type assert created.digest == sample_manifest_instance.digest assert created.manifest_bytes == sample_manifest_instance.bytes.as_encoded_str( ) assert created_manifest.labels_to_apply == expected_labels assert created.config_media_type == sample_manifest_instance.config_media_type assert created.layers_compressed_size == sample_manifest_instance.layers_compressed_size # Lookup the manifest and verify. found = lookup_manifest(repository, created.digest, allow_dead=True) assert found.digest == created.digest assert found.config_media_type == created.config_media_type assert found.layers_compressed_size == created.layers_compressed_size # Verify it has a temporary tag pointing to it. assert Tag.get(manifest=created, hidden=True).lifetime_end_ms # Verify the linked blobs. blob_digests = [ mb.blob.content_checksum for mb in ManifestBlob.select().where(ManifestBlob.manifest == created) ] assert random_digest in blob_digests if schema_version == 2: assert config_digest in blob_digests # Retrieve it again and ensure it is the same manifest. created_manifest2 = get_or_create_manifest(repository, sample_manifest_instance, storage) created2 = created_manifest2.manifest newly_created2 = created_manifest2.newly_created assert not newly_created2 assert created2 == created # Ensure it again has a temporary tag. assert Tag.get(manifest=created2, hidden=True).lifetime_end_ms # Ensure the labels were added. labels = list(list_manifest_labels(created)) assert len(labels) == 2 labels_dict = {label.key: label.value for label in labels} assert labels_dict == expected_labels
def test_get_or_create_manifest_list_duplicate_child_manifest(initialized_db): repository = create_repository("devtable", "newrepo", None) expected_labels = { "Foo": "Bar", "Baz": "Meh", } layer_json = json.dumps({ "id": "somelegacyid", "config": { "Labels": expected_labels, }, "rootfs": { "type": "layers", "diff_ids": [] }, "history": [ { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, ], }) # Create a legacy image. find_create_or_link_image("somelegacyid", repository, "devtable", {}, "local_us") # Add a blob containing the config. _, config_digest = _populate_blob(layer_json) # Add a blob of random data. random_data = "hello world" _, random_digest = _populate_blob(random_data) # Build the manifest. v2_builder = DockerSchema2ManifestBuilder() v2_builder.set_config_digest(config_digest, len(layer_json.encode("utf-8"))) v2_builder.add_layer(random_digest, len(random_data.encode("utf-8"))) v2_manifest = v2_builder.build() # Write the manifest. v2_created = get_or_create_manifest(repository, v2_manifest, storage) assert v2_created assert v2_created.manifest.digest == v2_manifest.digest # Build the manifest list, with the child manifest repeated. list_builder = DockerSchema2ManifestListBuilder() list_builder.add_manifest(v2_manifest, "amd64", "linux") list_builder.add_manifest(v2_manifest, "amd32", "linux") manifest_list = list_builder.build() # Write the manifest list, which should also write the manifests themselves. created_tuple = get_or_create_manifest(repository, manifest_list, storage) assert created_tuple is not None created_list = created_tuple.manifest assert created_list assert created_list.media_type.name == manifest_list.media_type assert created_list.digest == manifest_list.digest # Ensure the child manifest links exist. child_manifests = { cm.child_manifest.digest: cm.child_manifest for cm in ManifestChild.select().where( ManifestChild.manifest == created_list) } assert len(child_manifests) == 1 assert v2_manifest.digest in child_manifests assert child_manifests[ v2_manifest.digest].media_type.name == v2_manifest.media_type # Try to create again and ensure we get back the same manifest list. created2_tuple = get_or_create_manifest(repository, manifest_list, storage) assert created2_tuple is not None assert created2_tuple.manifest == created_list
def test_get_or_create_manifest_list(initialized_db): repository = create_repository('devtable', 'newrepo', None) expected_labels = { 'Foo': 'Bar', 'Baz': 'Meh', } layer_json = json.dumps({ 'id': 'somelegacyid', 'config': { 'Labels': expected_labels, }, "rootfs": { "type": "layers", "diff_ids": [] }, "history": [ { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, ], }) # Create a legacy image. find_create_or_link_image('somelegacyid', repository, 'devtable', {}, 'local_us') # Add a blob containing the config. _, config_digest = _populate_blob(layer_json) # Add a blob of random data. random_data = 'hello world' _, random_digest = _populate_blob(random_data) # Build the manifests. v1_builder = DockerSchema1ManifestBuilder('devtable', 'simple', 'anothertag') v1_builder.add_layer(random_digest, layer_json) v1_manifest = v1_builder.build(docker_v2_signing_key).unsigned() v2_builder = DockerSchema2ManifestBuilder() v2_builder.set_config_digest(config_digest, len(layer_json)) v2_builder.add_layer(random_digest, len(random_data)) v2_manifest = v2_builder.build() # Write the manifests. v1_created = get_or_create_manifest(repository, v1_manifest, storage) assert v1_created assert v1_created.manifest.digest == v1_manifest.digest v2_created = get_or_create_manifest(repository, v2_manifest, storage) assert v2_created assert v2_created.manifest.digest == v2_manifest.digest # Build the manifest list. list_builder = DockerSchema2ManifestListBuilder() list_builder.add_manifest(v1_manifest, 'amd64', 'linux') list_builder.add_manifest(v2_manifest, 'amd32', 'linux') manifest_list = list_builder.build() # Write the manifest list, which should also write the manifests themselves. created_tuple = get_or_create_manifest(repository, manifest_list, storage) assert created_tuple is not None created_list = created_tuple.manifest assert created_list assert created_list.media_type.name == manifest_list.media_type assert created_list.digest == manifest_list.digest # Ensure the child manifest links exist. child_manifests = { cm.child_manifest.digest: cm.child_manifest for cm in ManifestChild.select().where( ManifestChild.manifest == created_list) } assert len(child_manifests) == 2 assert v1_manifest.digest in child_manifests assert v2_manifest.digest in child_manifests assert child_manifests[ v1_manifest.digest].media_type.name == v1_manifest.media_type assert child_manifests[ v2_manifest.digest].media_type.name == v2_manifest.media_type
def test_list_active_tags(initialized_db): # Create a new repository. repository = create_repository('devtable', 'somenewrepo', None) manifest = Manifest.get() # Create some images. image1 = find_create_or_link_image('foobarimage1', repository, None, {}, 'local_us') image2 = find_create_or_link_image('foobarimage2', repository, None, {}, 'local_us') # Make sure its tags list is empty. assert_tags(repository) # Add some new tags. footag = create_or_update_tag_for_repo(repository, 'foo', image1.docker_image_id, oci_manifest=manifest) bartag = create_or_update_tag_for_repo(repository, 'bar', image1.docker_image_id, oci_manifest=manifest) # Since timestamps are stored on a second-granularity, we need to make the tags "start" # before "now", so when we recreate them below, they don't conflict. footag.lifetime_start_ts -= 5 footag.save() bartag.lifetime_start_ts -= 5 bartag.save() footag_oci = _get_oci_tag(footag) footag_oci.lifetime_start_ms -= 5000 footag_oci.save() bartag_oci = _get_oci_tag(bartag) bartag_oci.lifetime_start_ms -= 5000 bartag_oci.save() # Make sure they are returned. assert_tags(repository, 'foo', 'bar') # Set the expirations to be explicitly empty. set_tag_end_ts(footag, None) set_tag_end_ts(bartag, None) # Make sure they are returned. assert_tags(repository, 'foo', 'bar') # Mark as a tag as expiring in the far future, and make sure it is still returned. set_tag_end_ts(footag, footag.lifetime_start_ts + 10000000) # Make sure they are returned. assert_tags(repository, 'foo', 'bar') # Delete a tag and make sure it isn't returned. footag = delete_tag('devtable', 'somenewrepo', 'foo') set_tag_end_ts(footag, footag.lifetime_end_ts - 4) assert_tags(repository, 'bar') # Add a new foo again. footag = create_or_update_tag_for_repo(repository, 'foo', image1.docker_image_id, oci_manifest=manifest) footag.lifetime_start_ts -= 3 footag.save() footag_oci = _get_oci_tag(footag) footag_oci.lifetime_start_ms -= 3000 footag_oci.save() assert_tags(repository, 'foo', 'bar') # Mark as a tag as expiring in the far future, and make sure it is still returned. set_tag_end_ts(footag, footag.lifetime_start_ts + 10000000) # Make sure they are returned. assert_tags(repository, 'foo', 'bar') # "Move" foo by updating it and make sure we don't get duplicates. create_or_update_tag_for_repo(repository, 'foo', image2.docker_image_id, oci_manifest=manifest) assert_tags(repository, 'foo', 'bar')
def test_retriever(initialized_db): repository = create_repository("devtable", "newrepo", None) layer_json = json.dumps({ "config": {}, "rootfs": { "type": "layers", "diff_ids": [] }, "history": [ { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, ], }) # Add a blob containing the config. _, config_digest = _populate_blob(layer_json) # Add a blob of random data. random_data = "hello world" _, random_digest = _populate_blob(random_data) # Add another blob of random data. other_random_data = "hi place" _, other_random_digest = _populate_blob(other_random_data) remote_digest = sha256_digest(b"something") builder = DockerSchema2ManifestBuilder() builder.set_config_digest(config_digest, len(layer_json.encode("utf-8"))) builder.add_layer(other_random_digest, len(other_random_data.encode("utf-8"))) builder.add_layer(random_digest, len(random_data.encode("utf-8"))) manifest = builder.build() assert config_digest in manifest.blob_digests assert random_digest in manifest.blob_digests assert other_random_digest in manifest.blob_digests assert config_digest in manifest.local_blob_digests assert random_digest in manifest.local_blob_digests assert other_random_digest in manifest.local_blob_digests # Write the manifest. created_tuple = get_or_create_manifest(repository, manifest, storage) assert created_tuple is not None created_manifest = created_tuple.manifest assert created_manifest assert created_manifest.media_type.name == manifest.media_type assert created_manifest.digest == manifest.digest # Verify the linked blobs. blob_digests = { mb.blob.content_checksum for mb in ManifestBlob.select().where( ManifestBlob.manifest == created_manifest) } assert random_digest in blob_digests assert other_random_digest in blob_digests assert config_digest in blob_digests # Delete any Image rows linking to the blobs from temp tags. for blob_digest in blob_digests: storage_row = ImageStorage.get(content_checksum=blob_digest) for image in list(Image.select().where(Image.storage == storage_row)): all_temp = all([ rt.hidden for rt in RepositoryTag.select().where( RepositoryTag.image == image) ]) if all_temp: RepositoryTag.delete().where( RepositoryTag.image == image).execute() image.delete_instance(recursive=True) # Verify the blobs in the retriever. retriever = RepositoryContentRetriever(repository, storage) assert (retriever.get_manifest_bytes_with_digest( created_manifest.digest) == manifest.bytes.as_encoded_str()) for blob_digest in blob_digests: assert retriever.get_blob_bytes_with_digest(blob_digest) is not None
def test_get_most_recent_tag_empty_repo(initialized_db): empty_repo = create_repository("devtable", "empty", None) with assert_query_count(1): assert get_most_recent_tag(empty_repo) is None
def test_get_or_create_manifest(schema_version, initialized_db): repository = create_repository('devtable', 'newrepo', None) expected_labels = { 'Foo': 'Bar', 'Baz': 'Meh', } layer_json = json.dumps({ 'id': 'somelegacyid', 'config': { 'Labels': expected_labels, }, "rootfs": { "type": "layers", "diff_ids": [] }, "history": [ { "created": "2018-04-03T18:37:09.284840891Z", "created_by": "do something", }, ], }) # Create a legacy image. find_create_or_link_image('somelegacyid', repository, 'devtable', {}, 'local_us') # Add a blob containing the config. _, config_digest = _populate_blob(layer_json) # Add a blob of random data. random_data = 'hello world' _, random_digest = _populate_blob(random_data) # Build the manifest. if schema_version == 1: builder = DockerSchema1ManifestBuilder('devtable', 'simple', 'anothertag') builder.add_layer(random_digest, layer_json) sample_manifest_instance = builder.build(docker_v2_signing_key) elif schema_version == 2: builder = DockerSchema2ManifestBuilder() builder.set_config_digest(config_digest, len(layer_json)) builder.add_layer(random_digest, len(random_data)) sample_manifest_instance = builder.build() # Create a new manifest. created_manifest = get_or_create_manifest(repository, sample_manifest_instance, storage) created = created_manifest.manifest newly_created = created_manifest.newly_created assert newly_created assert created is not None assert created.media_type.name == sample_manifest_instance.media_type assert created.digest == sample_manifest_instance.digest assert created.manifest_bytes == sample_manifest_instance.bytes.as_encoded_str( ) assert created_manifest.labels_to_apply == expected_labels # Verify it has a temporary tag pointing to it. assert Tag.get(manifest=created, hidden=True).lifetime_end_ms # Verify the legacy image. legacy_image = get_legacy_image_for_manifest(created) assert legacy_image is not None assert legacy_image.storage.content_checksum == random_digest # Verify the linked blobs. blob_digests = [ mb.blob.content_checksum for mb in ManifestBlob.select().where(ManifestBlob.manifest == created) ] assert random_digest in blob_digests if schema_version == 2: assert config_digest in blob_digests # Retrieve it again and ensure it is the same manifest. created_manifest2 = get_or_create_manifest(repository, sample_manifest_instance, storage) created2 = created_manifest2.manifest newly_created2 = created_manifest2.newly_created assert not newly_created2 assert created2 == created # Ensure it again has a temporary tag. assert Tag.get(manifest=created2, hidden=True).lifetime_end_ms # Ensure the labels were added. labels = list(list_manifest_labels(created)) assert len(labels) == 2 labels_dict = {label.key: label.value for label in labels} assert labels_dict == expected_labels