def test_node_json_validation(self): node = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': 'http://example.com/1', 'type': 'Assertion', 'schema:location': { '@context': 'https://w3id.org/openbadges/extensions/geoCoordinatesExtension/context.json', 'type': ['Extension', 'extensions:GeoCoordinates'], 'description': 'That place in the woods where we built the fort', 'schema:geo': { 'schema:latitude': 44.580900, 'schema:longitude': -123.301815 } } } loader = CachableDocumentLoader(use_cache=True) loader.session.cache.remove_old_entries(datetime.datetime.utcnow()) loader.contexts = set() options = {'jsonld_options': {'documentLoader': loader}} set_up_context_mock() loader(OPENBADGES_CONTEXT_V2_URI) schema_url = list(GeoLocation.validation_schema)[0] responses.add(responses.GET, GeoLocation.context_url, status=200, json=GeoLocation.context_json) loader(GeoLocation.context_url) responses.add(responses.GET, schema_url, status=200, json=GeoLocation.validation_schema[schema_url]) loader.session.get(schema_url) state = INITIAL_STATE task = add_task(INTAKE_JSON, data=json.dumps(node), node_id=node['id']) result, message, actions = task_named(INTAKE_JSON)(state, task, **options) state = main_reducer(state, actions[0]) result, message, actions = task_named(actions[1]['name'])( state, actions[1], **options) # JSONLD_COMPACT_DATE state = main_reducer(state, actions[0]) # ADD_NODE task_meta = actions[1] # VALIDATE_EXTENSION_NODE result, message, actions = validate_extension_node(state, task_meta) self.assertTrue(result, "A valid expression of the extension should pass") self.assertIn('validated on node', message) self.assertEqual(len(actions), 0) del state['graph'][0]['schema:location']['schema:geo'][ 'schema:latitude'] result, message, actions = validate_extension_node(state, task_meta) self.assertFalse( result, "A required property not present should be detected by JSON-schema." )
def test_can_detect_v1_based_on_context(self): json_data = test_components['1_1_basic_assertion'] state = INITIAL_STATE task = add_task(INTAKE_JSON, data=json_data) result, message, actions = task_named(task['name'])(state, task) self.assertTrue(result) self.assertEqual(actions[2]['name'], UPGRADE_1_1_NODE) json_data = test_components['1_1_basic_badgeclass'] task['data'] = json_data result, message, actions = task_named(task['name'])(state, task) self.assertTrue(result) self.assertEqual(actions[2]['name'], UPGRADE_1_1_NODE) json_data = test_components['1_1_basic_issuer'] task['data'] = json_data result, message, actions = task_named(task['name'])(state, task) self.assertTrue(result) self.assertEqual(actions[2]['name'], UPGRADE_1_1_NODE) json_data = test_components['1_0_basic_issuer'] task['data'] = json_data result, message, actions = task_named(task['name'])(state, task) self.assertTrue(result) self.assertEqual(actions[1]['name'], UPGRADE_1_0_NODE)
def load_mocks(self): loader = CachableDocumentLoader(use_cache=True) loader.session.cache.remove_old_entries(datetime.datetime.utcnow()) loader.contexts = set() self.options = {'jsonld_options': {'documentLoader': loader}} set_up_context_mock() loader(OPENBADGES_CONTEXT_V2_URI) schema_url = list(ExampleExtension.validation_schema)[0] responses.add(responses.GET, ExampleExtension.context_url, status=200, json=ExampleExtension.context_json) loader(ExampleExtension.context_url) responses.add(responses.GET, schema_url, status=200, json=ExampleExtension.validation_schema[schema_url]) loader.session.get(schema_url) self.state = INITIAL_STATE task = add_task(INTAKE_JSON, data=json.dumps(self.first_node), node_id=self.first_node['id']) result, message, actions = task_named(INTAKE_JSON)(self.state, task, **self.options) self.state = main_reducer(self.state, actions[0]) result, message, actions = task_named(actions[1]['name'])( self.state, actions[1], **self.options) # JSONLD_COMPACT_DATE self.state = main_reducer(self.state, actions[0]) # ADD_NODE self.validation_task = actions[1] # VALIDATE_EXTENSION_NODE
def test_queue_validation_on_unknown_extension(self): set_up_context_mock() self.set_up_test_extension() first_node_json = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': 'http://example.org/assertion', 'extensions:exampleExtension': { '@context': self.extension_context_url, 'type': ['Extension', 'extensions:UnknownExtension'], 'unknownProperty': 'I\'m a property, short and sweet' }, 'evidence': 'http://example.org/evidence' } state = INITIAL_STATE task_meta = add_task( INTAKE_JSON, data=json.dumps(first_node_json), node_id=first_node_json['id']) result, message, actions = task_named(INTAKE_JSON)(state, task_meta) for action in actions: state = main_reducer(state, action) # Compact JSON result, message, actions = task_named(state['tasks'][0]['name'])(state, state['tasks'][0]) self.assertEqual(len(actions), 3) state = main_reducer(state, actions[0]) validation_action = actions[1] result, message, actions = validate_extension_node(state, validation_action) self.assertTrue(result)
def test_upgrade_1_1_badgeclass_with_multiple_alignments(self): setUpContextCache() data = json.loads(test_components['1_1_basic_badgeclass']) data['alignment'] = [{ 'name': 'Target 1 Name', 'description': 'Target 1 Description', 'url': 'http://example.org/target-1' }, { 'name': 'Target 2 Name', 'url': 'http://example.org/target-2' }] state = INITIAL_STATE task = add_task(INTAKE_JSON, node_id='https://example.org/robotics-badge.json', data=json.dumps(data)) result, message, actions = task_named(INTAKE_JSON)(state, task) for action in actions: state = main_reducer(state, action) for task in state.get('tasks'): result, message, actions = task_named(task['name'])(state, task) for action in actions: state = main_reducer(state, action) # Test alignment object upgrades self.assertEqual(len(state['graph'][0]['alignment']), 2) self.assertEqual(state['graph'][0]['alignment'][0]['targetUrl'], data['alignment'][0]['url'])
def test_extension_discovered_jsonld_compact(self): """ Ensure an extension node is properly discovered and that the task runs without error. """ node = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': 'http://example.com/1', 'type': 'Assertion', 'schema:location': { '@context': GeoLocation.context_url, 'type': ['Extension', 'extensions:GeoCoordinates'], 'description': 'That place in the woods where we built the fort', 'schema:geo': { 'schema:latitude': 44.580900, 'schema:longitude': -123.301815 } } } state = INITIAL_STATE set_up_context_mock() responses.add(responses.GET, GeoLocation.context_url, body=json.dumps(GeoLocation.context_json), status=200, content_type='application/ld+json') schema_url = 'https://w3id.org/openbadges/extensions/geoCoordinatesExtension/schema.json' responses.add(responses.GET, schema_url, body=json.dumps( GeoLocation.validation_schema[schema_url]), status=200, content_type='application/ld+json') compact_task = add_task(JSONLD_COMPACT_DATA, data=json.dumps(node), jsonld_options=jsonld_no_cache, context_urls=[GeoLocation.context_url]) result, message, actions = task_named(JSONLD_COMPACT_DATA)( state, compact_task) self.assertTrue(result, "JSON-LD Compact is successful.") self.assertIn(VALIDATE_EXTENSION_NODE, [i.get('name') for i in actions], "Validation task queued.") state = main_reducer(state, actions[0]) # ADD_NODE validate_task = [ i for i in actions if i.get('name') == VALIDATE_EXTENSION_NODE ][0] self.assertIsNotNone(validate_task['node_json']) result, message, actions = task_named(VALIDATE_EXTENSION_NODE)( state, validate_task) self.assertTrue(result, "Validation task is successful.")
def test_upgrade_1_1_issuer(self): setUpContextCache() data = json.loads(test_components['1_1_basic_issuer']) data['type'] = 'IssuerOrg' # Test alias that was accepted in v1.1 context json_data = json.dumps(data) state = INITIAL_STATE task = add_task(INTAKE_JSON, node_id='https://example.org/organization.json', data=json_data) result, message, actions = task_named(INTAKE_JSON)(state, task) for action in actions: state = main_reducer(state, action) for task in state.get('tasks'): result, message, actions = task_named(task['name'])(state, task) for action in actions: state = main_reducer(state, action) self.assertTrue(result) self.assertEqual(state['graph'][0]['type'], OBClasses.Issuer)
def test_upgrade_1_0_assertion(self): json_data = test_components['1_0_basic_assertion'] state = INITIAL_STATE task = add_task(INTAKE_JSON, node_id='http://a.com/instance', data=json_data) result, message, actions = task_named(INTAKE_JSON)(state, task) for action in actions: state = main_reducer(state, action) task = state.get('tasks')[0] result, message, actions = task_named(task['name'])(state, task) self.assertTrue(result) self.assertEqual(len(actions), 2) for action in actions: state = main_reducer(state, action) self.assertEqual(len(state.get('tasks')), 3) modified_data = json.loads(state.get('tasks')[1]['data']) self.assertEqual(modified_data['@context'], OPENBADGES_CONTEXT_V1_URI) self.assertEqual(modified_data['id'], modified_data['verify']['url']) self.assertEqual(modified_data['type'], OBClasses.Assertion)
def test_upgrade_1_1_badgeclass(self): setUpContextCache() json_data = test_components['1_1_basic_badgeclass'] state = INITIAL_STATE task = add_task(INTAKE_JSON, node_id='https://example.org/robotics-badge.json', data=json_data) result, message, actions = task_named(INTAKE_JSON)(state, task) for action in actions: state = main_reducer(state, action) for task in state.get('tasks'): result, message, actions = task_named(task['name'])(state, task) for action in actions: state = main_reducer(state, action) # Test criteria class upgrade state['graph'][0]['alignment'] = { 'url': 'http://somewhere.overtherainbow.net/wayuphigh', 'name': "Knowledge of children's songs" } result, message, actions = task_named(UPGRADE_1_1_NODE)(state, task) self.assertTrue(result) self.assertEqual(len(actions), 1)
def test_can_print_exception(self): state = INITIAL_STATE.copy() # Create a state that will trigger an exception state['graph'] = [AttributeError("Haha this isn't a dict!")] task = add_task(VALIDATE_PROPERTY, node_id='http://example.org/1', prop_name='turnips', prop_type=ValueTypes.TEXT) store = create_store(main_reducer, state) store.dispatch(task) call_task(task_named(VALIDATE_PROPERTY), store.get_state()['tasks'][0], store) state = store.get_state() self.assertEqual(len(state['tasks']), 1, 'There is one task in state.') task = state['tasks'][0] self.assertFalse(task['success']) self.assertIn('AttributeError:', task['result'], "assert an AttributeError is formatted as the message.")
def test_upgrade_1_1_assertion(self): setUpContextCache() json_data = test_components['1_1_basic_assertion'] state = INITIAL_STATE task = add_task( INTAKE_JSON, node_id='https://example.org/beths-robotics-badge.json', data=json_data) result, message, actions = task_named(INTAKE_JSON)(state, task) for action in actions: state = main_reducer(state, action) for task in state.get('tasks'): result, message, actions = task_named(task['name'])(state, task) for action in actions: state = main_reducer(state, action) result, message, actions = task_named(UPGRADE_1_1_NODE)(state, task) self.assertTrue(result) self.assertEqual(len(actions), 0) # Test timestamp upgrading state['graph'][0]['issuedOn'] = 1500423730 result, message, actions = task_named(UPGRADE_1_1_NODE)(state, task) self.assertTrue(result) self.assertEqual(len(actions), 1) self.assertEqual(actions[0]['data']['issuedOn'], '2017-07-19T00:22:10+00:00') self.assertEqual(len(actions[0]['data'].keys()), 1, "There is a patch made of one prop") state['graph'][0]['issuedOn'] = '1500423730.5' result, message, actions = task_named(UPGRADE_1_1_NODE)(state, task) self.assertTrue(result) self.assertEqual(len(actions), 1) state = main_reducer(state, actions[0]) state['graph'][0]['issuedOn'] = '2016-05-15' result, message, actions = task_named(UPGRADE_1_1_NODE)(state, task) self.assertTrue(result) self.assertEqual(len(actions), 1) state = main_reducer(state, actions[0])
def test_queue_validation_on_unknown_extension(self): set_up_context_mock() extension_schema = { "$schema": "http://json-schema.org/draft-04/schema#", "title": "1.1 Open Badge Example Extension for testing: Unknown Extension", "description": "An extension that allows you to add a single string unknownProperty to an extension object for unknown reasons.", "type": "object", "properties": { "unknownProperty": { "type": "string" } }, "required": ["unknownProperty"] } extension_schema_url = 'http://example.org/unkownSchema' extension_context = { '@context': { "obi": "https://w3id.org/openbadges#", "extensions": "https://w3id.org/openbadges/extensions#", 'unknownProperty': 'http://schema.org/unknownProperty' }, "obi:validation": [ { "obi:validatesType": "extensions:UnknownExtension", "obi:validationSchema": extension_schema_url } ] } extension_context_url = 'http://example.org/unknownExtensionContext' first_node_json = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': 'http://example.org/assertion', 'extensions:exampleExtension': { '@context': extension_context_url, 'type': ['Extension', 'extensions:UnknownExtension'], 'unknownProperty': 'I\'m a property, short and sweet' }, 'evidence': 'http://example.org/evidence' } responses.add( responses.GET, extension_context_url, json=extension_context ) responses.add( responses.GET, extension_schema_url, json=extension_schema ) state = INITIAL_STATE task_meta = add_task( INTAKE_JSON, data=json.dumps(first_node_json), node_id=first_node_json['id']) result, message, actions = task_named(INTAKE_JSON)(state, task_meta) for action in actions: state = main_reducer(state, action) # Compact JSON result, message, actions = task_named(state['tasks'][0]['name'])(state, state['tasks'][0]) self.assertEqual(len(actions), 3) state = main_reducer(state, actions[0]) validation_action = actions[1] result, message, actions = validate_extension_node(state, validation_action) self.assertTrue(result)
def test_validate_badgeclass_image_formats(self): session = CachedSession(backend='memory', expire_after=100000) loader = CachableDocumentLoader(use_cache=True, session=session) options = { 'jsonld_options': {'documentLoader': loader} } image_url = 'http://example.org/awesomebadge.png' badgeclass = { 'id': 'http://example.org/badgeclass', 'name': 'Awesome badge', 'image': image_url } state = {'graph': [badgeclass]} with open(os.path.join(os.path.dirname(__file__), 'testfiles', 'public_domain_heart.png'), 'rb') as f: responses.add(responses.GET, badgeclass['image'], body=f.read(), content_type='image/png') response = session.get(badgeclass['image']) self.assertEqual(response.status_code, 200) task_meta = add_task( VALIDATE_EXPECTED_NODE_CLASS, node_id=badgeclass['id'], expected_class=OBClasses.BadgeClass) result, message, actions = task_named(VALIDATE_EXPECTED_NODE_CLASS)(state, task_meta, **options) self.assertTrue(result) image_task = [a for a in actions if a.get('prop_name') == 'image'][0] class_image_validation_task = [a for a in actions if a.get('name') == IMAGE_VALIDATION][0] result, message, actions = task_named(image_task['name'])(state, image_task, **options) self.assertTrue(result) self.assertEqual(len(actions), 0) result, message, actions = task_named(class_image_validation_task['name'])( state, class_image_validation_task, **options) self.assertTrue(result) self.assertEqual(len(actions), 1) # self.assertEqual(actions[0]['name'], STORE_ORIGINAL_RESOURCE) # Case 2: Embedded image document badgeclass['image'] = { 'id': 'http://example.org/awesomebadge.png', 'author': 'http://someoneelse.org/1', 'caption': 'A hexagon with attitude' } # Validate BadgeClass, queuing the image node validation task result, message, actions = task_named(image_task['name'])(state, image_task, **options) self.assertTrue(result) self.assertEqual(len(actions), 1, "Image node validation task queued") # Run image node task discovery next_task = actions[0] result, message, actions = task_named(next_task['name'])(state, next_task, **options) self.assertTrue(result) # Run validation task for the Image node next_task = [a for a in actions if a.get('name') == IMAGE_VALIDATION][0] result, message, actions = task_named(next_task['name'])(state, next_task, **options) self.assertTrue(result) # Store image data next_task = actions[0] self.assertEqual(next_task['type'], STORE_ORIGINAL_RESOURCE) new_state = input_reducer({}, next_task) self.assertTrue(new_state['original_json'][image_url].startswith('data:'), "Data is stored in the expected spot.")