def test_has_related_image_envs(self, var, does_have): data = { 'kind': 'ClusterServiceVersion', 'spec': { 'install': { 'spec': { 'deployments': [{ 'spec': { 'template': { 'spec': { 'containers': [{ 'name': 'spam', 'image': 'eggs', 'env': [] }] } } } }] } } } } if var is not None: deployment = data['spec']['install']['spec']['deployments'][0] deployment['spec']['template']['spec']['containers'][0][ 'env'].append(var) csv = OperatorCSV('original.yaml', data) assert csv.has_related_image_envs() == does_have
def test_dump(self, tmpdir): path = tmpdir.join("original.yaml") csv = OperatorCSV(str(path), ORIGINAL.data) csv.dump() content = path.read() # Formatting does not necessarily have to match, at least check the data... assert yaml.load(content) == csv.data # ...and that the comment was preserved assert content.startswith('# A meaningful comment')
def test_valuefrom_references_not_allowed(self): data = ORIGINAL.data env_path = EGGS.path[:-1] env = chain_get(data, env_path) env["valueFrom"] = "somewhere" csv = OperatorCSV("original.yaml", data) with pytest.raises(RuntimeError) as exc_info: csv.get_pullspecs() assert '"valueFrom" references are not supported' in str( exc_info.value)
def test_wrong_kind(self): data = ORIGINAL.data del data["kind"] with pytest.raises(NotOperatorCSV) as exc_info: OperatorCSV("original.yaml", data) assert str(exc_info.value) == "Not a ClusterServiceVersion" data["kind"] = "ClusterResourceDefinition" with pytest.raises(NotOperatorCSV) as exc_info: OperatorCSV("original.yaml", data) assert str(exc_info.value) == "Not a ClusterServiceVersion"
def test_from_file(self, tmpdir): path = tmpdir.join("original.yaml") path.write(ORIGINAL.content) csv = OperatorCSV.from_file(str(path)) assert csv.path == str(path) assert csv.data == ORIGINAL.data
def test_replace_pullspecs_everywhere(self, caplog): csv = OperatorCSV("original.yaml", ORIGINAL.data) csv.replace_pullspecs_everywhere(self._replacement_pullspecs) assert csv.data == REPLACED_EVERYWHERE.data expected_logs = { "original.yaml - Replaced pullspec: {foo} -> {foo.replace}": 3, "original.yaml - Replaced pullspec: {bar} -> {bar.replace}": 3, "original.yaml - Replaced pullspec: {eggs} -> {eggs.replace}": 4, "original.yaml - Replaced pullspec: {spam} -> {spam.replace}": 3, "original.yaml - Replaced pullspec: {ham} -> {ham.replace}": 3, "original.yaml - Replaced pullspec: {jam} -> {jam.replace}": 3, "original.yaml - Replaced pullspec: {baz} -> {baz.replace}": 3, "original.yaml - Replaced pullspec: {p1} -> {p1.replace}": 3, "original.yaml - Replaced pullspec: {p2} -> {p2.replace}": 3, } for log, count in expected_logs.items(): assert caplog.text.count(log.format(**PULLSPECS)) == count
def test_replace_pullspecs(self, caplog): csv = OperatorCSV("original.yaml", ORIGINAL.data) csv.replace_pullspecs(self._replacement_pullspecs) assert csv.data == REPLACED.data expected_logs = [ "{file} - Replaced pullspec for relatedImage foo: {foo} -> {foo.replace}", "{file} - Replaced pullspec for relatedImage bar: {bar} -> {bar.replace}", "{file} - Replaced pullspec for RELATED_IMAGE_EGGS var: {eggs} -> {eggs.replace}", "{file} - Replaced pullspec for RELATED_IMAGE_P2 var: {p2} -> {p2.replace}", "{file} - Replaced pullspec for container spam: {spam} -> {spam.replace}", "{file} - Replaced pullspec for container ham: {ham} -> {ham.replace}", "{file} - Replaced pullspec for container jam: {jam} -> {jam.replace}", "{file} - Replaced pullspec for containerImage annotation: {baz} -> {baz.replace}", "{file} - Replaced pullspec for initContainer p1: {p1} -> {p1.replace}", ] for log in expected_logs: assert log.format(file="original.yaml", **PULLSPECS) in caplog.text
def test_get_pullspecs(self, caplog): csv = OperatorCSV("original.yaml", ORIGINAL.data) pullspecs = csv.get_pullspecs() assert pullspecs == self._original_pullspecs expected_logs = [ "original.yaml - Found pullspec for relatedImage foo: {foo}", "original.yaml - Found pullspec for relatedImage bar: {bar}", "original.yaml - Found pullspec for RELATED_IMAGE_EGGS var: {eggs}", "original.yaml - Found pullspec for RELATED_IMAGE_P2 var: {p2}", "original.yaml - Found pullspec for container spam: {spam}", "original.yaml - Found pullspec for container ham: {ham}", "original.yaml - Found pullspec for container jam: {jam}", "original.yaml - Found pullspec for containerImage annotation: {baz}", "original.yaml - Found pullspec for initContainer p1: {p1}", ] for log in expected_logs: assert log.format(**PULLSPECS) in caplog.text
def test_replace_only_some_pullspecs(self, caplog): replacement_pullspecs = self._replacement_pullspecs.copy() # Foo won't be replaced because replacement is identical replacement_pullspecs[FOO.value] = FOO.value # Bar won't be replaced because no replacement available del replacement_pullspecs[BAR.value] csv = OperatorCSV("original.yaml", ORIGINAL.data) csv.replace_pullspecs(replacement_pullspecs) assert FOO.find_in_data(csv.data) == FOO.value assert BAR.find_in_data(csv.data) == BAR.value foo_log = "original.yaml - Replaced pullspec for related image foo: {foo}" bar_log = "original.yaml - Replaced pullspec for related image bar: {bar}" assert foo_log.format(foo=FOO) not in caplog.text assert bar_log.format(bar=BAR) not in caplog.text
def test_set_related_images(self, caplog): data = ORIGINAL.data csv = OperatorCSV("original.yaml", data) csv.set_related_images() # the order is: # 1. existing relatedImages # 2. annotations # 3. containers # 4. initContainers # 5. container env vars # 6. initContainer env vars expected_related_images = [ CommentedMap([("name", name), ("image", pullspec.value.to_str())]) for name, pullspec in [ ("foo", FOO), ("bar", BAR), ("baz-annotation", BAZ), ("spam", SPAM), ("ham", HAM), ("jam", JAM), ("p1", P1), ("eggs", EGGS), ("p2", P2), ] ] assert csv.data["spec"]["relatedImages"] == expected_related_images expected_logs = [ "{path} - Set relatedImage foo (from relatedImage foo): {foo}", "{path} - Set relatedImage bar (from relatedImage bar): {bar}", "{path} - Set relatedImage baz-annotation (from containerImage annotation): {baz}", "{path} - Set relatedImage spam (from container spam): {spam}", "{path} - Set relatedImage ham (from container ham): {ham}", "{path} - Set relatedImage jam (from container jam): {jam}", "{path} - Set relatedImage p1 (from initContainer p1): {p1}", "{path} - Set relatedImage eggs (from RELATED_IMAGE_EGGS var): {eggs}", "{path} - Set relatedImage p2 (from RELATED_IMAGE_P2 var): {p2}", ] for log in expected_logs: assert log.format(path="original.yaml", **PULLSPECS) in caplog.text
def test_set_related_images_conflicts(self, related_images, containers, err_msg): data = { "kind": "ClusterServiceVersion", "spec": { "relatedImages": related_images, "install": { "spec": { "deployments": [{ "spec": { "template": { "spec": { "containers": containers } } } }] } } } } csv = OperatorCSV("original.yaml", data) if err_msg is not None: with pytest.raises(RuntimeError) as exc_info: csv.set_related_images() assert str(exc_info.value) == err_msg.format(path="original.yaml") else: csv.set_related_images() updated_counts = Counter( x['name'] for x in csv.data['spec']['relatedImages']) # check that there are no duplicates in .spec.relatedImages for name, count in updated_counts.items(): assert count == 1, 'Duplicate in relatedImages: {}'.format( name)
def test_get_pullspecs_some_locations(self, rel_images, rel_envs, containers, annotations, init_rel_envs, init_containers): data = ORIGINAL.data expected = {p.value for p in PULLSPECS.values()} if not rel_images: expected -= {FOO.value, BAR.value} del data["spec"]["relatedImages"] deployments = chain_get(data, ["spec", "install", "spec", "deployments"]) if not rel_envs: expected -= {EGGS.value} for d in deployments: for c in chain_get(d, ["spec", "template", "spec", "containers"]): c.pop("env", None) if not containers: expected -= {SPAM.value, HAM.value, JAM.value} for d in deployments: del d["spec"]["template"]["spec"]["containers"] if not annotations: expected -= {BAZ.value} del data["metadata"]["annotations"] if not init_rel_envs: expected -= {P2.value} for d in deployments: for c in chain_get( d, ["spec", "template", "spec", "initContainers"], default=[]): c.pop("env", None) if not init_containers: expected -= {P1.value} for d in deployments: d["spec"]["template"]["spec"].pop("initContainers", None) csv = OperatorCSV("x.yaml", data) assert csv.get_pullspecs() == expected
def test_has_related_images(self, pullspecs, does_have): data = {'kind': 'ClusterServiceVersion', 'spec': {}} if pullspecs is not None: data['spec']['relatedImages'] = pullspecs csv = OperatorCSV('original.yaml', data) assert csv.has_related_images() == does_have