def make_naming(**kwargs) -> naming.Naming: kwargs.setdefault('name', 'Hatstand') kwargs.setdefault('namespace', ('Google', 'Cloud')) kwargs.setdefault('version', 'v1') kwargs.setdefault('product_name', 'Hatstand') kwargs.setdefault('product_url', 'https://cloud.google.com/hatstand/') return naming.Naming(**kwargs)
def test_generator_duplicate_samples(fs): config_fpath = "samples.yaml" fs.create_file(config_fpath, contents=dedent(''' # Note: the samples are duplicates. type: com.google.api.codegen.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample region_tag: humboldt_tag rpc: get_squid - id: squid_sample region_tag: humboldt_tag rpc: get_squid ''')) generator = make_generator('samples=samples.yaml') generator._env.loader = jinja2.DictLoader({'sample.py.j2': ''}) api_schema = make_api(naming=naming.Naming(name='Mollusc', version='v6')) with pytest.raises(types.DuplicateSample): generator.get_response(api_schema=api_schema)
def make_naming(**kwargs) -> naming.Naming: kwargs.setdefault('name', 'Hatstand') kwargs.setdefault('namespace', ('Google', 'Cloud')) kwargs.setdefault('version', 'v1') kwargs.setdefault('product_name', 'Hatstand') return naming.Naming(**kwargs)
def test_address_subpackage_empty(): addr = metadata.Address( package=('foo', 'bar', 'baz', 'v1'), api_naming=naming.Naming(proto_package='foo.bar.baz.v1'), ) assert addr.subpackage == ()
def test_address_subpackage_no_version(): addr = metadata.Address( package=('foo', 'bar', 'baz', 'spam', 'eggs'), api_naming=naming.Naming(proto_package='foo.bar.baz'), ) assert addr.subpackage == ('spam', 'eggs')
def test_generate_sample_basic(): # Note: the sample integration tests are needfully large # and difficult to eyeball parse. They are intended to be integration tests # that catch errors in behavior that is emergent from combining smaller features # or in features that are sufficiently small and trivial that it doesn't make sense # to have standalone tests. input_type = DummyMessage( type="REQUEST TYPE", fields={ "classify_request": DummyField(message=DummyMessage( type="CLASSIFY TYPE", fields={ "video": DummyField(message=DummyMessage(type="VIDEO TYPE"), ), "location_annotation": DummyField(message=DummyMessage(type="LOCATION TYPE"), ) }, )) }) api_naming = naming.Naming(name="MolluscClient", namespace=("molluscs", "v1")) service = wrappers.Service( service_pb=namedtuple('service_pb', ['name'])('MolluscClient'), methods={ "Classify": DummyMethod(input=input_type, output=message_factory("$resp.taxonomy")) }) schema = DummyApiSchema( services={"animalia.mollusca.v1.Mollusc": service}, naming=api_naming, ) sample = { "service": "animalia.mollusca.v1.Mollusc", "rpc": "Classify", "id": "mollusc_classify_sync", "description": "Determine the full taxonomy of input mollusc", "request": [{ "field": "classify_request.video", "value": "'path/to/mollusc/video.mkv'", "input_parameter": "video", "value_is_file": True }, { "field": "classify_request.location_annotation", "value": "'New Zealand'", "input_parameter": "location" }], "response": [{ "print": ["Mollusc is a %s", "$resp.taxonomy"] }] } sample_str = samplegen.generate_sample( sample, schema, env.get_template('examples/sample.py.j2')) sample_id = ("mollusc_classify_sync") expected_str = '''# TODO: add a copyright # TODO: add a license # # DO NOT EDIT! This is a generated sample ("request", "%s") # # To install the latest published package dependency, execute the following: # pip3 install molluscs-v1-molluscclient # [START %s] from google import auth from google.auth import credentials from molluscs.v1.molluscclient.services.mollusc_client import MolluscClient def sample_classify(video, location): """Determine the full taxonomy of input mollusc""" client = MolluscClient( credentials=credentials.AnonymousCredentials(), transport="grpc", ) classify_request = {} # video = 'path/to/mollusc/video.mkv' with open(video, "rb") as f: classify_request["video"] = f.read() # location = 'New Zealand' classify_request["location_annotation"] = location response = client.classify(classify_request) print("Mollusc is a {}".format(response.taxonomy)) # [END %s] def main(): import argparse parser = argparse.ArgumentParser() parser.add_argument("--video", type=str, default='path/to/mollusc/video.mkv') parser.add_argument("--location", type=str, default='New Zealand') args = parser.parse_args() sample_classify(args.video, args.location) if __name__ == "__main__": main() ''' % (sample_id, sample_id, sample_id) assert sample_str == expected_str
def test_dont_generate_in_code_samples(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 config_fpath = "samples.yaml" fs.create_file(config_fpath, contents=dedent(''' type: com.google.api.codegen.samplegen.v1p2.SampleConfigProto schema_version: 1.2.0 samples: - id: squid_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - standalone - incode/SQUID - id: clam_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - incode/CLAM - id: whelk_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc sample_type: - standalone - id: octopus_sample rpc: IdentifyMollusc service: Mollusc.v1.Mollusc ''')) generator = make_generator(f'samples={config_fpath}') generator._env.loader = jinja2.DictLoader({'sample.py.j2': ''}) api_schema = make_api( make_proto( descriptor_pb2.FileDescriptorProto( name='mollusc.proto', package='Mollusc.v1', service=[ descriptor_pb2.ServiceDescriptorProto(name='Mollusc') ], ), ), naming=naming.Naming(name='Mollusc', version='v6'), ) # Note that we do NOT expect a clam sample. # There are four tests going on: # 1) Just an explicit standalone sample type. # 2) Multiple sample types, one of which is standalone. # 3) Explicit sample types but NO standalone sample type. # 4) Implicit standalone sample type. expected = CodeGeneratorResponse(file=[ CodeGeneratorResponse.File( name="samples/squid_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/whelk_sample.py", content="\n", ), CodeGeneratorResponse.File( name="samples/octopus_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\' - <<: *python sample: whelk_sample path: \'{base_path}/whelk_sample.py\' - <<: *python sample: octopus_sample path: \'{base_path}/octopus_sample.py\' """)) ]) actual = generator.get_response(api_schema=api_schema, opts=options.Options.build('')) assert actual == expected
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.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.Naming(name='Mollusc', version='v6')) actual_response = g.get_response(api_schema, opts=options.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' """)), ]) 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.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.Naming(name='Mollusc', version='v6')) actual_response = g.get_response(api_schema, opts=options.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 """), ) ]) assert actual_response == expected_response
def test_generate_sample_basic(): # Note: the sample integration tests are needfully large # and difficult to eyeball parse. They are intended to be integration tests # that catch errors in behavior that is emergent from combining smaller features # or in features that are sufficiently small and trivial that it doesn't make sense # to have standalone tests. input_type = DummyMessage( type="REQUEST TYPE", fields={ "classify_target": DummyField( message=DummyMessage( type="CLASSIFY TYPE", fields={ "video": DummyField( message=DummyMessage(type="VIDEO TYPE"), ), "location_annotation": DummyField( message=DummyMessage(type="LOCATION TYPE"), ) }, ) ) } ) api_naming = naming.Naming( name="MolluscClient", namespace=("molluscs", "v1")) service = wrappers.Service( service_pb=namedtuple('service_pb', ['name'])('MolluscService'), methods={ "Classify": DummyMethod( input=input_type, output=message_factory("$resp.taxonomy"), flattened_fields={ "classify_target": DummyField(name="classify_target") } ) } ) schema = DummyApiSchema( services={"animalia.mollusca.v1.Mollusc": service}, naming=api_naming, ) sample = {"service": "animalia.mollusca.v1.Mollusc", "rpc": "Classify", "id": "mollusc_classify_sync", "description": "Determine the full taxonomy of input mollusc", "request": [ {"field": "classify_target.video", "value": "path/to/mollusc/video.mkv", "input_parameter": "video", "value_is_file": True}, {"field": "classify_target.location_annotation", "value": "New Zealand", "input_parameter": "location"} ], "response": [{"print": ['Mollusc is a "%s"', "$resp.taxonomy"]}]} sample_str = samplegen.generate_sample( sample, schema, env.get_template('examples/sample.py.j2') ) sample_id = ("mollusc_classify_sync") expected_str = '''# -*- coding: utf-8 -*- # Copyright (C) 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # DO NOT EDIT! This is a generated sample ("request", "%s") # # To install the latest published package dependency, execute the following: # pip3 install molluscs-v1-molluscclient # [START %s] from google import auth from google.auth import credentials from molluscs.v1.molluscclient.services.mollusc_service import MolluscServiceClient def sample_classify(video, location): """Determine the full taxonomy of input mollusc""" client = MolluscServiceClient( credentials=credentials.AnonymousCredentials(), transport="grpc", ) classify_target = {} # video = "path/to/mollusc/video.mkv" with open(video, "rb") as f: classify_target["video"] = f.read() # location = "New Zealand" classify_target["location_annotation"] = location response = client.classify(classify_target=classify_target) print("Mollusc is a \\"{}\\"".format(response.taxonomy)) # [END %s] def main(): import argparse parser = argparse.ArgumentParser() parser.add_argument("--video", type=str, default="path/to/mollusc/video.mkv") parser.add_argument("--location", type=str, default="New Zealand") args = parser.parse_args() sample_classify(args.video, args.location) if __name__ == "__main__": main() ''' % (sample_id, sample_id, sample_id) assert sample_str == expected_str