def test_custom_template_directory(): # Create a generator. opts = options.Options.build('python-gapic-templates=/templates/') g = generator.Generator(opts) # Assert that the Jinja loader will pull from the correct location. assert g._env.loader.searchpath == ['/templates/']
def test_get_filenames_with_namespace(): g = generator.Generator(api_schema=make_api(naming=make_naming( name='Spam', namespace=('Ham', 'Bacon'), version='v2', ), )) template_name = '$namespace/$name_$version/foo.py.j2' assert g._get_filenames(template_name) == ('ham/bacon/spam_v2/foo.py', )
def test_constructor(): # Create a generator. g = generator.Generator(api_schema=make_api()) assert isinstance(g._api, api.API) # Assert we have a Jinja environment also, with the expected filters. # This is internal implementation baseball, but this is the best place # to establish this and templates will depend on it. assert isinstance(g._env, jinja2.Environment) assert 'snake_case' in g._env.filters assert 'wrap' in g._env.filters
def test_get_filenames_with_namespace_init(): g = generator.Generator(api_schema=make_api(naming=make_naming( namespace=('Foo', 'Bar', 'Baz'), name='Spam', version='v2', ))) template_name = '$namespace/__init__.py.j2' assert g._get_filenames(template_name) == ( 'foo/__init__.py', 'foo/bar/__init__.py', 'foo/bar/baz/__init__.py', )
def test_get_filenames_with_service(): g = generator.Generator(api_schema=make_api(naming=make_naming( namespace=(), name='Spam', version='v2'), )) template_name = '$name/$service/foo.py.j2' assert g._get_filenames( template_name, context={ 'service': wrappers.Service( methods=[], service_pb=descriptor_pb2.ServiceDescriptorProto(name='Eggs'), ), }) == ('spam/eggs/foo.py', )
def test_generate_autogen_samples(mock_generate_sample, mock_generate_specs): opts = Options.build("autogen-snippets") g = generator.Generator(opts) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( naming=naming.NewNaming(name="Mollusc", version="v6")) actual_response = g.get_response(api_schema, opts=opts) # Just check that generate_sample_specs was called # Correctness of the spec is tested in samplegen unit tests mock_generate_specs.assert_called_once_with(api_schema, opts=opts)
def test_render_templates_additional_context(): g = generator.Generator(api_schema=make_api()) # Determine the templates to be rendered. templates = ('foo.j2',) with mock.patch.object(jinja2.Environment, 'get_template') as get_template: get_template.return_value = jinja2.Template('A {{ thing }}!') # Render the templates. files = g._render_templates(templates, additional_context={ 'thing': 'bird', }) # Test that we get back the expected content for each template. assert len(files) == 1 assert files[0].name == 'foo' assert files[0].content == 'A bird!\n'
def test_get_response(): # Create a generator with mock data. # # We want to ensure that templates are rendered for each service, # which we prove by sending two services. file_pb2 = descriptor_pb2.FileDescriptorProto( name='bacon.proto', package='foo.bar.v1', service=[ descriptor_pb2.ServiceDescriptorProto(name='SpamService'), descriptor_pb2.ServiceDescriptorProto(name='EggsService') ], ) api_schema = make_api(make_proto(file_pb2)) g = generator.Generator(api_schema=api_schema) # Mock all the rendering methods. with mock.patch.object(g, '_render_templates') as _render_templates: _render_templates.return_value = [ plugin_pb2.CodeGeneratorResponse.File( name='template_file', content='This was a template.', ), ] # Okay, now run the `get_response` method. response = g.get_response() # First and foremost, we care that we got a valid response # object back (albeit not so much what is in it). assert isinstance(response, plugin_pb2.CodeGeneratorResponse) # Next, determine that the general API templates and service # templates were both called; the method should be called # once per service plus one for the API as a whole. assert _render_templates.call_count == len(file_pb2.service) + 1 # The service templates should have been called with the # filename transformation and the additional `service` variable. for call in _render_templates.mock_calls: _, args, kwargs = call if args[0] != g._env.loader.service_templates: continue service = kwargs['additional_context']['service'] assert isinstance(service, wrappers.Service)
def test_render_templates(): g = generator.Generator(api_schema=make_api()) # Determine the templates to be rendered. templates = ('foo.j2', 'bar.j2') with mock.patch.object(jinja2.Environment, 'get_template') as get_template: get_template.side_effect = lambda t: jinja2.Template( f'Hello, I am `{t}`.', ) # Render the templates. files = g._render_templates(templates) # Test that we get back the expected content for each template. assert len(files) == 2 assert files[0].name == 'foo' assert files[1].name == 'bar' assert files[0].content == 'Hello, I am `foo.j2`.\n' assert files[1].content == 'Hello, I am `bar.j2`.\n'
def test_samplegen_config_to_output_files(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner fs.create_file('samples.yaml', contents=dedent(''' --- type: com.google.api.codegen.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming - region_tag: clam_sample rpc: get_clam ''')) mock_generate_sample g = generator.Generator(options.Options.build('samples=samples.yaml', )) api_schema = make_api(naming=naming.Naming(name='Mollusc', version='v6')) actual_response = g.get_response(api_schema) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/clam_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/Mollusc.v6.python.21120601.131313.manifest.yaml", content=dedent("""\ --- type: manifest/samples schema_version: 3 python: &python environment: python bin: python3 base_path: samples invocation: '{bin} {path} @args' samples: - <<: *python sample: squid_sample path: '{base_path}/squid_sample.py' region_tag: humboldt_tag - <<: *python sample: clam_sample path: '{base_path}/clam_sample.py' region_tag: clam_sample """), ) ]) assert actual_response == expected_response
def make_generator(opts_str: str = '') -> generator.Generator: return generator.Generator(options.Options.build(opts_str))
def test_samplegen_id_disambiguation(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner # Note: The first two samples will have the same nominal ID, the first by # explicit naming and the second by falling back to the region_tag. # The third has no id of any kind, so the generator is required to make a # unique ID for it. fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming # Note that this region tag collides with the id of the previous sample. - region_tag: squid_sample rpc: get_squid_streaming # No id or region tag. - rpc: get_squid_streaming """), ) g = generator.Generator(Options.build("samples=samples.yaml")) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( naming=naming.NewNaming(name="Mollusc", version="v6")) actual_response = g.get_response(api_schema, opts=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample_91a465c6.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample_55051b38.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/157884ee.py", content="\n", ), # TODO(busunkim): Re-enable manifest generation once metadata # format has been formalized. # https://docs.google.com/document/d/1ghBam8vMj3xdoe4xfXhzVcOAIwrkbTpkMLgKc9RPD9k/edit#heading=h.sakzausv6hue # CodeGeneratorResponse.File( # name="samples/generated_samples/mollusc.v6.python.21120601.131313.manifest.yaml", # content=dedent( # """\ # --- # type: manifest/samples # schema_version: 3 # python: &python # environment: python # bin: python3 # base_path: samples # invocation: '{bin} {path} @args' # samples: # - <<: *python # sample: squid_sample_91a465c6 # path: '{base_path}/squid_sample_91a465c6.py' # region_tag: humboldt_tag # - <<: *python # sample: squid_sample_55051b38 # path: '{base_path}/squid_sample_55051b38.py' # region_tag: squid_sample # - <<: *python # sample: 157884ee # path: '{base_path}/157884ee.py' # """ # ), # ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
def test_samplegen_config_to_output_files( mock_gmtime, mock_generate_sample, fs, ): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming - region_tag: clam_sample rpc: get_clam """), ) g = generator.Generator(Options.build("samples=samples.yaml", )) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( naming=naming.NewNaming(name="Mollusc", version="v6")) actual_response = g.get_response(api_schema, opts=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/generated_samples/clam_sample.py", content="\n", ), # TODO(busunkim): Re-enable manifest generation once metadata # format has been formalized. # https://docs.google.com/document/d/1ghBam8vMj3xdoe4xfXhzVcOAIwrkbTpkMLgKc9RPD9k/edit#heading=h.sakzausv6hue # CodeGeneratorResponse.File( # name="samples/generated_samples/mollusc.v6.python.21120601.131313.manifest.yaml", # content=dedent( # """\ # --- # type: manifest/samples # schema_version: 3 # python: &python # environment: python # bin: python3 # base_path: samples # invocation: '{bin} {path} @args' # samples: # - <<: *python # sample: squid_sample # path: '{base_path}/squid_sample.py' # region_tag: humboldt_tag # - <<: *python # sample: clam_sample # path: '{base_path}/clam_sample.py' # region_tag: clam_sample # """ # ), # ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
def test_custom_template_directory(): # Create a generator. g = generator.Generator(api_schema=make_api(), templates='/templates/') # Assert that the Jinja loader will pull from the correct location. assert g._env.loader.searchpath == ['/templates/']
def test_samplegen_id_disambiguation(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner # Note: The first two samples will have the same nominal ID, the first by # explicit naming and the second by falling back to the region_tag. # The third has no id of any kind, so the generator is required to make a # unique ID for it. fs.create_file('samples.yaml', contents=dedent(''' --- type: com.google.api.codegen.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming # Note that this region tag collides with the id of the previous sample. - region_tag: squid_sample rpc: get_squid_streaming # No id or region tag. - rpc: get_squid_streaming ''')) g = generator.Generator(options.Options.build('samples=samples.yaml')) api_schema = make_api(naming=naming.Naming(name='Mollusc', version='v6')) actual_response = g.get_response(api_schema) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample_91a465c6.py", content="\n", ), CodeGeneratorResponse.File( name="samples/squid_sample_c8014108.py", content="\n", ), CodeGeneratorResponse.File( name="samples/157884ee.py", content="\n", ), CodeGeneratorResponse.File( name="samples/Mollusc.v6.python.21120601.131313.manifest.yaml", content=dedent("""\ --- type: manifest/samples schema_version: 3 python: &python environment: python bin: python3 base_path: samples invocation: '{bin} {path} @args' samples: - <<: *python sample: squid_sample_91a465c6 path: '{base_path}/squid_sample_91a465c6.py' region_tag: humboldt_tag - <<: *python sample: squid_sample_c8014108 path: '{base_path}/squid_sample_c8014108.py' region_tag: squid_sample - <<: *python sample: 157884ee path: '{base_path}/157884ee.py' """)), ]) assert actual_response == expected_response
def test_samplegen_config_to_output_files(mock_gmtime, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag service: Mollusc.v1.Mollusc rpc: GetSquidStreaming - region_tag: clam_sample service: Mollusc.v1.Mollusc rpc: GetClam """), ) g = generator.Generator(Options.build("samples=samples.yaml", )) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = DummyApiSchema( services={ "Mollusc": DummyService( name="Mollusc", methods={ # For this test the generator only cares about the dictionary keys "GetSquidStreaming": DummyMethod(), "GetClam": DummyMethod(), }, ) }, naming=DummyNaming( name="mollusc", version="v1", warehouse_package_name="mollusc-cephalopod-teuthida-", versioned_module_name="teuthida_v1", module_namespace="mollusc.cephalopod", proto_package="google.mollusca"), ) with mock.patch("gapic.samplegen.samplegen.generate_sample", side_effect=mock_generate_sample): actual_response = g.get_response( api_schema, opts=Options.build("autogen-snippets=False")) expected_snippet_index_json = { "clientLibrary": { "apis": [{ "id": "google.mollusca", "version": "v1" }], "language": "PYTHON", "name": "mollusc-cephalopod-teuthida-" }, "snippets": [{ "clientMethod": { "method": { "service": { "shortName": "Mollusc" }, "shortName": "GetSquidStreaming" } }, "file": "squid_sample.py", "segments": [{ "type": "FULL" }, { "type": "SHORT" }, { "type": "CLIENT_INITIALIZATION" }, { "type": "REQUEST_INITIALIZATION" }, { "type": "REQUEST_EXECUTION" }, { "type": "RESPONSE_HANDLING" }], "title": "squid_sample.py" }, { "clientMethod": { "method": { "service": { "shortName": "Mollusc" }, "shortName": "GetClam" } }, "file": "clam_sample.py", "segments": [{ "type": "FULL" }, { "type": "SHORT" }, { "type": "CLIENT_INITIALIZATION" }, { "type": "REQUEST_INITIALIZATION" }, { "type": "REQUEST_EXECUTION" }, { "type": "RESPONSE_HANDLING" }], "title": "clam_sample.py" }] } assert actual_response.supported_features == CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL assert len(actual_response.file) == 3 assert actual_response.file[0] == CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample.py", content="\n", ) assert actual_response.file[1] == CodeGeneratorResponse.File( name="samples/generated_samples/clam_sample.py", content="\n", ) assert actual_response.file[ 2].name == "samples/generated_samples/snippet_metadata_mollusc_v1.json" assert json.loads( actual_response.file[2].content) == expected_snippet_index_json
def test_get_filenames(): g = generator.Generator(api_schema=make_api(naming=make_naming( namespace=(), name='Spam', version='v2'), )) template_name = '$namespace/$name_$version/foo.py.j2' assert g._get_filenames(template_name) == ('spam_v2/foo.py', )
def test_samplegen_id_disambiguation(mock_gmtime, mock_generate_sample, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner # Note: The first two samples will have the same nominal ID, the first by # explicit naming and the second by falling back to the region_tag. # The third has no id of any kind, so the generator is required to make a # unique ID for it. fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming # Note that this region tag collides with the id of the previous sample. - region_tag: squid_sample rpc: get_squid_streaming # No id or region tag. - rpc: get_squid_streaming """), ) g = generator.Generator(Options.build("samples=samples.yaml")) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( naming=naming.NewNaming(name="Mollusc", version="v6")) actual_response = g.get_response(api_schema, opts=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample_91a465c6.py", content="\n", ), CodeGeneratorResponse.File( name="samples/squid_sample_55051b38.py", content="\n", ), CodeGeneratorResponse.File( name="samples/157884ee.py", content="\n", ), CodeGeneratorResponse.File( name="samples/mollusc.v6.python.21120601.131313.manifest.yaml", content=dedent("""\ --- type: manifest/samples schema_version: 3 python: &python environment: python bin: python3 base_path: samples invocation: '{bin} {path} @args' samples: - <<: *python sample: squid_sample_91a465c6 path: '{base_path}/squid_sample_91a465c6.py' region_tag: humboldt_tag - <<: *python sample: squid_sample_55051b38 path: '{base_path}/squid_sample_55051b38.py' region_tag: squid_sample - <<: *python sample: 157884ee path: '{base_path}/157884ee.py' """), ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
def test_samplegen_config_to_output_files( mock_gmtime, mock_generate_sample, fs, ): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid_streaming - region_tag: clam_sample rpc: get_clam """), ) g = generator.Generator(Options.build("samples=samples.yaml", )) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = make_api( naming=naming.NewNaming(name="Mollusc", version="v6")) actual_response = g.get_response(api_schema, opts=Options.build("")) expected_response = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/clam_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/mollusc.v6.python.21120601.131313.manifest.yaml", content=dedent("""\ --- type: manifest/samples schema_version: 3 python: &python environment: python bin: python3 base_path: samples invocation: '{bin} {path} @args' samples: - <<: *python sample: squid_sample path: '{base_path}/squid_sample.py' region_tag: humboldt_tag - <<: *python sample: clam_sample path: '{base_path}/clam_sample.py' region_tag: clam_sample """), ), ]) expected_response.supported_features |= ( CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL) assert actual_response == expected_response
def test_samplegen_id_disambiguation(mock_gmtime, fs): # These time values are nothing special, # they just need to be deterministic. returner = mock.MagicMock() returner.tm_year = 2112 returner.tm_mon = 6 returner.tm_mday = 1 returner.tm_hour = 13 returner.tm_min = 13 returner.tm_sec = 13 mock_gmtime.return_value = returner # Note: The first two samples will have the same nominal ID, the first by # explicit naming and the second by falling back to the region_tag. # The third has no id of any kind, so the generator is required to make a # unique ID for it. fs.create_file( "samples.yaml", contents=dedent(""" --- type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: GetSquidStreaming service: Mollusc.v1.Mollusc # Note that this region tag collides with the id of the previous sample. - region_tag: squid_sample rpc: GetSquidStreaming service: Mollusc.v1.Mollusc # No id or region tag. - rpc: GetSquidStreaming service: Mollusc.v1.Mollusc """), ) g = generator.Generator(Options.build("samples=samples.yaml")) # Need to have the sample template visible to the generator. g._env.loader = jinja2.DictLoader({"sample.py.j2": ""}) api_schema = DummyApiSchema( services={ "Mollusc": DummyService( name="Mollusc", methods={ # The generator only cares about the dictionary keys "GetSquidStreaming": DummyMethod(), "GetClam": DummyMethod(), }, ) }, naming=DummyNaming( name="mollusc", version="v1", warehouse_package_name="mollusc-cephalopod-teuthida-", versioned_module_name="teuthida_v1", module_namespace="mollusc.cephalopod", proto_package="google.mollusca"), ) with mock.patch("gapic.samplegen.samplegen.generate_sample", side_effect=mock_generate_sample): actual_response = g.get_response( api_schema, opts=Options.build("autogen-snippets=False")) expected_snippet_metadata_json = { "clientLibrary": { "apis": [{ "id": "google.mollusca", "version": "v1" }], "language": "PYTHON", "name": "mollusc-cephalopod-teuthida-" }, "snippets": [{ "clientMethod": { "method": { "service": { "shortName": "Mollusc" }, "shortName": "GetSquidStreaming" } }, "file": "squid_sample_1cfd0b3d.py", "segments": [{ "type": "FULL" }, { "type": "SHORT" }, { "type": "CLIENT_INITIALIZATION" }, { "type": "REQUEST_INITIALIZATION" }, { "type": "REQUEST_EXECUTION" }, { "type": "RESPONSE_HANDLING" }], "title": "squid_sample_1cfd0b3d.py" }, { "clientMethod": { "method": { "service": { "shortName": "Mollusc" }, "shortName": "GetSquidStreaming" } }, "file": "squid_sample_cf4d4fa4.py", "segments": [{ "type": "FULL" }, { "type": "SHORT" }, { "type": "CLIENT_INITIALIZATION" }, { "type": "REQUEST_INITIALIZATION" }, { "type": "REQUEST_EXECUTION" }, { "type": "RESPONSE_HANDLING" }], "title": "squid_sample_cf4d4fa4.py" }, { "clientMethod": { "method": { "service": { "shortName": "Mollusc" }, "shortName": "GetSquidStreaming" } }, "file": "7384949e.py", "segments": [{ "type": "FULL" }, { "type": "SHORT" }, { "type": "CLIENT_INITIALIZATION" }, { "type": "REQUEST_INITIALIZATION" }, { "type": "REQUEST_EXECUTION" }, { "type": "RESPONSE_HANDLING" }], "title": "7384949e.py" }] } assert actual_response.supported_features == CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL assert len(actual_response.file) == 4 assert actual_response.file[0] == CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample_1cfd0b3d.py", content="\n", ) assert actual_response.file[1] == CodeGeneratorResponse.File( name="samples/generated_samples/squid_sample_cf4d4fa4.py", content="\n", ) assert actual_response.file[2] == CodeGeneratorResponse.File( name="samples/generated_samples/7384949e.py", content="\n", ) print(actual_response.file[3].content) assert actual_response.file[ 3].name == "samples/generated_samples/snippet_metadata_mollusc_v1.json" assert json.loads( actual_response.file[3].content) == expected_snippet_metadata_json