def test_calling_resource_fails(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) with pytest.raises(TypeError): resource()
def test_repr(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) name = discovery_document.get("name") version = discovery_document.get("version") base_url = discovery_document.get("baseUrl") assert name in str(api) and version in str(api) and base_url in str(api)
def test_resources_getattr_fails_on_unknown_resource(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) nonexistent_resource = 'I_MUST_NEVER_EXIST_ANYWHEREEEEEEEE' with pytest.raises(AttributeError) as e: getattr(api, nonexistent_resource)
def test_str_resource(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) assert discovery_document['rootUrl'] in str(resource) assert 'resource' in str(resource)
def test_repr(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) name = discovery_document.get('name') version = discovery_document.get('version') base_url = discovery_document.get('baseUrl') assert name in str(api) and version in str(api) and base_url in str(api)
def test_getattr(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get("resources").items(): resource_object = getattr(api, resource_name) assert isinstance(resource_object, Resource) assert resource_name == resource_object.name
async def list_notes(): async with Aiogoogle(service_account_creds=creds) as aiogoogle: async with aiohttp.ClientSession() as session: async with session.get(DISCOVERY_DOC_URL) as resp: disc_doc = await resp.json() keep = GoogleAPI(disc_doc) res = await aiogoogle.as_service_account(keep.notes.list()) pprint(res)
def test_len(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) methods_len = len(discovery_document.get( 'methods')) if discovery_document.get('methods') else 0 resources_len = len(discovery_document.get( 'resources')) if discovery_document.get('resources') else 0 assert len(api) == methods_len + resources_len
def test_resource_construction(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) for nested_resource_name in resource.resources_available: nested_resource = getattr(resource, nested_resource_name) assert isinstance(nested_resource, Resource)
def test_len(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) assert isinstance(len(method), int)
def test_str_resource_has_the_word_resource_in_it(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get("resources").items(): resource = getattr(api, resource_name) assert discovery_document["rootUrl"] in str(resource) assert "resource" in str(resource)
def test_stack_parameters(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) for param_name in STACK_QUERY_PARAMETERS: assert param_name in resource._global_parameters assert resource._global_parameters[ param_name] == STACK_QUERY_PARAMETER_DEFAULT_VALUE
def test_user_authorized_for_method(open_discovery_document): discovery_document = open_discovery_document('youtube', 'v3') youtube = GoogleAPI(discovery_document=discovery_document) aiogoogle = Aiogoogle() assert aiogoogle.oauth2.authorized_for_method( method=youtube.videos.list, user_creds={ 'scopes': [ "https://www.googleapis.com/auth/youtube", "https://www.googleapis.com/auth/youtube.force-ssl", "https://www.googleapis.com/auth/youtube.readonly", "https://www.googleapis.com/auth/youtubepartner" ] } ) is True assert aiogoogle.oauth2.authorized_for_method( method=youtube.videos.list, user_creds={ 'scopes': [ #"https://www.googleapis.com/auth/youtube", "https://www.googleapis.com/auth/youtube.force-ssl", "https://www.googleapis.com/auth/youtube.readonly", "https://www.googleapis.com/auth/youtubepartner" ] } ) is False assert aiogoogle.oauth2.authorized_for_method( method=youtube.videos.list, user_creds={ 'scopes': [ "https://www.googleapis.com/auth/youtube", "https://www.googleapis.com/auth/youtube.force-ssl", "https://www.googleapis.com/auth/youtube.readonly", "https://www.googleapis.com/auth/youtubepartner", "useless_scope" ] } ) is True assert aiogoogle.oauth2.authorized_for_method( method=youtube.videos.list, user_creds={ 'scopes': [] } ) is False with pytest.raises(TypeError) as e: aiogoogle.oauth2.authorized_for_method( method=youtube.videos.list, user_creds={ 'scopes': None } ) assert str(e) == 'Scopes should be an instance of list, set or tuple'
def test_query_parameters(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) for parameter_name in method.query_parameters: parameter = method.parameters[parameter_name] assert parameter.get('location') == 'query'
def test_stack_parameters(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) for stack_param_name in STACK_QUERY_PARAMETERS: assert stack_param_name in method.optional_parameters assert stack_param_name in method.parameters
def test_parameters_not_colliding_with_google_api__call__( open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) google_api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(google_api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) params = method.parameters for param_name, _ in params.items(): assert param_name not in RESERVED_KEYWORDS
def test_parameters(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) for parameter_name, _ in method.parameters.items(): assert (parameter_name in discovery_document.get('parameters') or parameter_name in discovery_document['resources'] [resource_name]['methods'][method_name]['parameters'])
def test_resource_returns_available_methods(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get("resources", {}).items(): resource = getattr(api, resource_name) if resource.methods_available: # Assert that it returns methods not resources for available_method_name in resource.methods_available: available_method = resource._get_method(available_method_name) assert isinstance(available_method, Method)
def test_resources_and_methods_dont_share_name(open_discovery_document, name, version): ''' Asserts no resources and methods that are on the same level share the same name. If a name was being shared, Aiogoogle will give precedence to the resource, rendering the method inaccessible ''' def assert_no_similarity(resource): for resource_name in resource.resources_available: assert resource_name not in resource.methods_available assert_no_similarity(getattr(resource, resource_name)) assert_no_similarity(GoogleAPI(open_discovery_document(name, version)))
def test_resource_returns_nested_resource(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources', {}).items(): resource = getattr(api, resource_name) if resource.resources_available: # Assert that it returns resources not methods for nested_resource_name in resource.resources_available: nested_resource = getattr(resource, nested_resource_name) assert isinstance(nested_resource, Resource)
def test_properties_only_in_objects_not_any_other_type(open_discovery_document, name, version): ''' Disc doc sanity check. Checks if objects are the only google-jsonschema type that has a an attribute call "Properties" ''' discovery_document = open_discovery_document(name, version) google_api = GoogleAPI(discovery_document=discovery_document) if google_api.discovery_document.get('schemas'): for _, v in google_api.discovery_document['schemas'].items(): if v['type'] != 'object': assert not v.get('properties')
def test_parameters_exist_in_discovery_document(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get("resources").items(): resource = getattr(api, resource_name) for method_name in resource.methods_available: method = resource._get_method(method_name) for parameter_name, _ in method.parameters.items(): assert (parameter_name in discovery_document.get("parameters") or parameter_name in discovery_document["resources"] [resource_name]["methods"][method_name]["parameters"])
def test_len(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) methods_len = ( len(discovery_document.get("methods")) if discovery_document.get("methods") else 0 ) resources_len = ( len(discovery_document.get("resources")) if discovery_document.get("resources") else 0 ) assert len(api) == methods_len + resources_len
def test_resource_constructor(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource_object = getattr(api, resource_name) assert isinstance(resource_object, Resource) assert resource_name == resource_object.name assert resource_object._resource_specs == discovery_document[ 'resources'][resource_name] assert resource_object._global_parameters == discovery_document.get( 'parameters') assert resource_object._schemas == discovery_document.get('schemas') ## assert api['schemas'] is resource_object._schemas assert api['parameters'] is resource_object._global_parameters
def test_parameters_not_included_twice(open_discovery_document, name, version): ''' I was curious whether global parameters might have identical names with Method.parameters. Fails if similarities found ''' discovery_document = open_discovery_document(name, version) google_api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(google_api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) local_params = method['parameters'] or {} for parameter_name, _ in local_params.items(): assert parameter_name not in method._global_parameters
def test_parameters_are_not_objects(open_discovery_document, name, version): ''' I was curious whether global parameters might have identical names with Method.parameters. Fails if similarities found ''' discovery_document = open_discovery_document(name, version) google_api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(google_api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) if method.parameters: for _, v in method.parameters.items(): assert v.get('type') != 'object' assert not v.get('properties')
def test_method_construction(open_discovery_document, name, version): discovery_document = open_discovery_document(name, version) api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) # Assert a resource has the returned method assert method.name in discovery_document['resources'][ resource_name]['methods'] # Assert specs belong to the created method assert method._method_specs == discovery_document['resources'][ resource_name]['methods'][method_name] # Assert global parameters were passed correctly assert method._global_parameters == discovery_document.get( 'parameters') # Assert schemas where passed correctly assert method._schemas == discovery_document.get('schemas')
def test_parameters_not_colliding_with_google_api__call__fails( open_discovery_document, name, version): ''' asserts previous test catches collisions if any''' COLLIDING_RESERVED_KEYWORDS = ['alt', 'part'] class CollisionError(Exception): pass def check_collision(param_name): if param_name in COLLIDING_RESERVED_KEYWORDS: raise CollisionError() discovery_document = open_discovery_document(name, version) google_api = GoogleAPI(discovery_document=discovery_document) for resource_name, _ in discovery_document.get('resources').items(): resource = getattr(google_api, resource_name) for method_name in resource.methods_available: method = getattr(resource, method_name) params = method.parameters with pytest.raises(CollisionError): for param_name, _ in params.items(): check_collision(param_name)
def test_schemas_consistency(open_discovery_document, name, version): ''' Tests the following: 1. every schema has a type 2. If an schema of type object doesn't have properties, then it must have additionalProperties 3. addiotionalProperties should only contain a single schema 4. All schemas should be objects (dicts) 5. Tests all patterns in all schemas compile without errors Errors: 1. 1 test fails because a schema that is of type: "object" neither has properties nor additionalProperties: - Youtube-v3, schemas, TokenPagination 2. 2 schemas/properties doesn't have a type: 1) pagespeedonline-v5 Category groups = { 'additional_properties': { .... 'properties': 'description': { 'description': 'An optional human readable description of the category group.', 'type': 'string' }, 'title': { 'description': 'The title of the category group.', 'type': 'string' } } } } 2) discovery-v1: RestDescription: { id: "RestDescription", type: "object", properties: { auth: { type: "object", description: "Authentication information.", properties: { oauth2: { type: "object", description: "OAuth 2.0 authentication information.", properties: { scopes: { type: "object", description: "Available OAuth 2.0 scopes.", additionalProperties: { type: "object", description: "The scope value.", properties: { description: { type: "string", Indentation is wrong here description: "Description of scope." Indentation is wrong here } } } } } } } } 3. The following is a less major inconsistency and has been commented out from the test below: Some additionalProperties return a string instead of a schema or bool Those additional properties will be ignored by default: https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.4: 5.4. additionalProperties This attribute defines a schema for all properties that are not explicitly defined in an object type definition. If specified, the value MUST be a schema or a boolean. If false is provided, no additional properties are allowed beyond the properties defined in the schema. The default value is an empty schema which allows any value for additional properties. I know that Google's version of jsonschema3 isn't supposed to be 100% compliant but the errors above make it really hard to perform the simplest of validation ''' # Avoid infinite recursion e.g. # https://www.googleapis.com/discovery/v1/apis/bigquery/v2/rest / schemas / QueryParameterType schema schemas_checked = [] def resolve(schema, schemas): ''' Resolves schema if resolvable ''' if '$ref' in schema: schema = schemas[schema['$ref']] return schema def methods_gen(resource): ''' Generates all methods available in a given resource/googleAPI ''' for method in resource.methods_available: yield getattr(resource, method) for n_resource in resource.resources_available: yield from methods_gen(getattr(resource, n_resource)) def validate(schema_name, schema, schemas): schema = resolve(schema, schemas) assert 'type' in schema if schema['type'] == 'object': if 'properties' not in schema: #################################################################################### # Remove the following **line** for a proper test. This is just silencing the error if schema_name not in ['TokenPagination', 'tokenPagination']: #################################################################################### assert 'additionalProperties' in schema else: for name, prop in schema['properties'].items(): if name not in schemas_checked: schemas_checked.append(name) validate(name, prop, schemas) if schema.get('additionalProperties'): schema = schema['additionalProperties'] if isinstance(schema, dict): if 'properties' not in schema: # correct if schema not in schemas_checked: schemas_checked.append(schema) validate('additionalProperties', schema, schemas) # # If many additionalProperties, (it should only be one schema for all the additional props), iterate over them (Causes two more errors) # else: # for k,v in schema.items(): # # Might cause an infinite loop # validate(k, v, schemas) #elif isinstance(prop, bool): # pass #else: # #raise TypeError( # # f'The following additionalProperty should be either a schema or bool not "{prop}"') # pass # #for _ in range(100000): # # print(prop) else: # all schemas/subschemas should eventually reach this point for testing if schema.get('pattern'): re.compile(schema['pattern']) disc_doc = open_discovery_document(name, version) schemas = disc_doc['schemas'] assert isinstance(schemas, dict) # Validate methods gapi = GoogleAPI(disc_doc) for method in methods_gen(gapi): for name, param in method.parameters.items(): validate(name, param, schemas) # Validate schemas for name, schema in disc_doc['schemas'].items(): if name not in schemas_checked: validate(name, schema, schemas)
def wrapped(name, version): disc_doc = open_discovery_document(name, version) return GoogleAPI(discovery_document=disc_doc)