예제 #1
0
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/']
예제 #2
0
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', )
예제 #3
0
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
예제 #4
0
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',
    )
예제 #5
0
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'
예제 #8
0
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)
예제 #9
0
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
예제 #11
0
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
예제 #14
0
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
예제 #17
0
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', )
예제 #18
0
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
예제 #19
0
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