class AgentConfigurationBuilder(object): def __init__(self, clients, RR2=None): self.clients = clients self.RR2 = RR2 if self.RR2 is None: log.warn("Creating new RR2") self.RR2 = EnhancedResourceRegistryClient(self.clients.resource_registry) if not isinstance(self.RR2, EnhancedResourceRegistryClient): raise AssertionError("Type of self.RR2 is %s not %s" % (type(self.RR2), type(EnhancedResourceRegistryClient))) self.agent_instance_obj = None self.associated_objects = None self.last_id = None self.will_launch = False self.generated_config = False def _predicates_to_cache(self): return [PRED.hasOutputProduct, #PRED.hasStream, #PRED.hasStreamDefinition, PRED.hasAgentInstance, PRED.hasAgentDefinition, PRED.hasDataset, PRED.hasDevice, #PRED.hasParameterContext, ] def _resources_to_cache(self): return [#RT.StreamDefinition, #RT.ParameterDictionary, #RT.ParameterContext, ] def _update_cached_predicates(self): # cache some predicates for in-memory lookups preds = self._predicates_to_cache() log.debug("updating cached predicates: %s" % preds) time_caching_start = get_ion_ts() for pred in preds: log.debug(" - %s", pred) self.RR2.cache_predicate(pred) time_caching_stop = get_ion_ts() total_time = int(time_caching_stop) - int(time_caching_start) log.info("Cached %s predicates in %s seconds", len(preds), total_time / 1000.0) def _update_cached_resources(self): # cache some resources for in-memory lookups rsrcs = self._resources_to_cache() log.debug("updating cached resources: %s" % rsrcs) time_caching_start = get_ion_ts() for r in rsrcs: log.debug(" - %s", r) self.RR2.cache_resources(r) time_caching_stop = get_ion_ts() total_time = int(time_caching_stop) - int(time_caching_start) log.info("Cached %s resource types in %s seconds", len(rsrcs), total_time / 1000.0) def _clear_caches(self): log.warn("Clearing caches") for r in self._resources_to_cache(): self.RR2.clear_cached_resource(r) for p in self._predicates_to_cache(): self.RR2.clear_cached_predicate(p) def _lookup_means(self): """ return a dict indicating how various related resources will be looked up The dict is keyed on association type: PRED.hasAgentInstance -> device type PRED.hasModel -> model type PRED.hasAgentDefinition -> agent type """ raise NotImplementedError("Extender of class must implement this") def _augment_dict(self, title, basedict, newitems): for k, v in newitems.iteritems(): if k in basedict: prev_v = basedict[k] # just warn if the new value is different if v != prev_v: log.warn("Overwriting %s[%s] of '%s' with '%s'", title, k, prev_v, v) else: log.debug("Overwriting %s[%s] with same value already assigned '%s'", title, k, v) basedict[k] = v def _check_associations(self): assert self.agent_instance_obj assert self.associated_objects lookup_means = self._lookup_means() assert lookup_means # make sure we've picked up the associations we expect def check_keys(somekeys): for k in somekeys: assert k in lookup_means assert lookup_means[k] in self.associated_objects #check_keys([PRED.hasAgentInstance, PRED.hasModel, PRED.hasAgentDefinition]) check_keys([PRED.hasAgentInstance, PRED.hasAgentDefinition]) assert RT.ProcessDefinition in self.associated_objects def set_agent_instance_object(self, agent_instance_obj): """ Set the agent instance object that we'll be interacting with it may be necessary to set this several times, such as if external operations update the object """ assert agent_instance_obj._id if self.last_id != agent_instance_obj._id: self.associated_objects = None self.agent_instance_obj = agent_instance_obj self.last_id = agent_instance_obj._id self.generated_config = False def prepare(self, will_launch=True): """ Prepare (validate) an agent for launch, fetching all associated resources @param will_launch - whether the running status should be checked -- set false if just generating config """ assert self.agent_instance_obj if will_launch: #if there is an agent pid then assume that a drive is already started if self.agent_instance_obj.agent_process_id: raise BadRequest("Agent Instance already running for this device pid: %s" % str(self.agent_instance_obj.agent_process_id)) # fetch caches just in time if any([not self.RR2.has_cached_prediate(x) for x in self._predicates_to_cache()]): self._update_cached_predicates() if any([not self.RR2.has_cached_resource(x) for x in self._resources_to_cache()]): self._update_cached_resources() # validate the associations, then pick things up self._collect_agent_instance_associations() self.will_launch = will_launch return self.generate_config() def _generate_org_governance_name(self): log.debug("_generate_org_governance_name for %s", self.agent_instance_obj.name) log.debug("retrieve the Org governance name to which this agent instance belongs") try: org_obj = self.RR2.find_subject(RT.Org, PRED.hasResource, self.agent_instance_obj._id, id_only=False) return org_obj.org_governance_name except NotFound: return '' except: raise def _generate_device_type(self): log.debug("_generate_device_type for %s", self.agent_instance_obj.name) return type(self._get_device()).__name__ def _generate_driver_config(self): log.debug("_generate_driver_config for %s", self.agent_instance_obj.name) # get default config driver_config = self.agent_instance_obj.driver_config agent_obj = self._get_agent() # Create driver config. add_driver_config = { 'workdir' : tempfile.gettempdir(), 'dvr_mod' : agent_obj.driver_module, 'dvr_cls' : agent_obj.driver_class } self._augment_dict("Agent driver_config", driver_config, add_driver_config) return driver_config def _get_param_dict_by_name(self, name): dict_obj = self.RR2.find_resources_by_name(RT.ParameterDictionary, name)[0] parameter_contexts = \ self.RR2.find_parameter_contexts_of_parameter_dictionary_using_has_parameter_context(dict_obj._id) return DatasetManagementService.build_parameter_dictionary(dict_obj, parameter_contexts) def _generate_stream_config(self): log.debug("_generate_stream_config for %s", self.agent_instance_obj.name) dsm = self.clients.dataset_management psm = self.clients.pubsub_management agent_obj = self._get_agent() device_obj = self._get_device() streams_dict = {} for stream_cfg in agent_obj.stream_configurations: #create a stream def for each param dict to match against the existing data products param_dict_id = dsm.read_parameter_dictionary_by_name(stream_cfg.parameter_dictionary_name, id_only=True) stream_def_id = psm.create_stream_definition(parameter_dictionary_id=param_dict_id) streams_dict[stream_cfg.stream_name] = {'param_dict_name':stream_cfg.parameter_dictionary_name, 'stream_def_id':stream_def_id, 'records_per_granule': stream_cfg.records_per_granule, 'granule_publish_rate':stream_cfg.granule_publish_rate, 'alarms' :stream_cfg.alarms } #retrieve the output products device_id = device_obj._id data_product_objs = self.RR2.find_data_products_of_instrument_device_using_has_output_product(device_id) out_streams = {} for d in data_product_objs: product_id = d._id stream_id = self.RR2.find_stream_id_of_data_product_using_has_stream(product_id) out_streams[stream_id] = d.name stream_config = {} log.debug("Creating a stream config for each stream (dataproduct) assoc with this agent/device") for product_stream_id in out_streams.keys(): #get the streamroute object from pubsub by passing the stream_id stream_def_id = self.RR2.find_stream_definition_id_of_stream_using_has_stream_definition(product_stream_id) #match the streamdefs/apram dict for this model with the data products attached to this device to know which tag to use for model_stream_name, stream_info_dict in streams_dict.items(): # read objects from cache to be compared if psm.compare_stream_definition(stream_def_id, stream_info_dict.get('stream_def_id')): #model_param_dict = self.RR2.find_resources_by_name(RT.ParameterDictionary, # stream_info_dict.get('param_dict_name'))[0] #model_param_dict = self._get_param_dict_by_name(stream_info_dict.get('param_dict_name')) #stream_route = self.RR2.read(product_stream_id).stream_route model_param_dict = DatasetManagementService.get_parameter_dictionary_by_name(stream_info_dict.get('param_dict_name')) stream_route = psm.read_stream_route(stream_id=product_stream_id) log.info("stream_config[%s] matches product '%s'", model_stream_name, out_streams[product_stream_id]) if model_stream_name in stream_config: log.warn("Overwiting stream_config[%s]", model_stream_name) stream_config[model_stream_name] = {'routing_key' : stream_route.routing_key, 'stream_id' : product_stream_id, 'stream_definition_ref' : stream_def_id, 'exchange_point' : stream_route.exchange_point, 'parameter_dictionary' : model_param_dict.dump(), 'records_per_granule' : stream_info_dict.get('records_per_granule'), 'granule_publish_rate' : stream_info_dict.get('granule_publish_rate'), 'alarms' : stream_info_dict.get('alarms') } log.debug("Stream config generated") log.trace("generate_stream_config: %s", str(stream_config) ) return stream_config def _generate_agent_config(self): log.debug("_generate_agent_config for %s", self.agent_instance_obj.name) # should override this return {} def _generate_alerts_config(self): log.debug("_generate_alerts_config for %s", self.agent_instance_obj.name) # should override this return self.agent_instance_obj.alerts def _generate_startup_config(self): log.debug("_generate_startup_config for %s", self.agent_instance_obj.name) # should override this return {} def _generate_children(self): log.debug("_generate_children for %s", self.agent_instance_obj.name) # should override this return {} def _generate_skeleton_config_block(self): log.info("Generating skeleton config block for %s", self.agent_instance_obj.name) # should override this agent_config = self.agent_instance_obj.agent_config # Create agent_ config. agent_config['instance_name'] = self.agent_instance_obj.name agent_config['org_governance_name'] = self._generate_org_governance_name() agent_config['device_type'] = self._generate_device_type() agent_config['driver_config'] = self._generate_driver_config() agent_config['stream_config'] = self._generate_stream_config() agent_config['agent'] = self._generate_agent_config() agent_config['aparam_alert_config'] = self._generate_alerts_config() agent_config['startup_config'] = self._generate_startup_config() agent_config['children'] = self._generate_children() log.info("DONE generating skeleton config block for %s", self.agent_instance_obj.name) return agent_config def _summarize_children(self, config_dict): ret = dict([(v['instance_name'], self._summarize_children(v)) for k, v in config_dict["children"].iteritems()]) #agent_config['agent']['resource_id'] return ret def generate_config(self): """ create the generic parts of the configuration including resource_id, egg_uri, and org """ if self.generated_config: log.warn("Generating config again for the same Instance object (%s)", self.agent_instance_obj.name) self._check_associations() agent_config = self._generate_skeleton_config_block() device_obj = self._get_device() agent_obj = self._get_agent() log.debug("complement agent_config with resource_id") if 'agent' not in agent_config: agent_config['agent'] = {'resource_id': device_obj._id} elif 'resource_id' not in agent_config.get('agent'): agent_config['agent']['resource_id'] = device_obj._id log.debug("add egg URI if available") if agent_obj.driver_uri: agent_config['driver_config']['process_type'] = (DriverProcessType.EGG,) agent_config['driver_config']['dvr_egg'] = agent_obj.driver_uri else: agent_config['driver_config']['process_type'] = (DriverProcessType.PYTHON_MODULE,) if log.isEnabledFor(logging.INFO): tree = self._summarize_children(agent_config) log.info("Children of %s are %s", self.agent_instance_obj.name, tree) self.generated_config = True return agent_config def record_launch_parameters(self, agent_config, process_id): """ record process id of the launch """ log.debug("add the process id and update the resource") self.agent_instance_obj.agent_config = agent_config self.agent_instance_obj.agent_process_id = process_id self.RR2.update(self.agent_instance_obj) log.debug('completed agent start') return process_id def _collect_agent_instance_associations(self): """ Collect related resources to this agent instance Returns a dict of objects necessary to start this instance, keyed on the values of self._lookup_means() PRED.hasAgentInstance -> device_obj PRED.hasModel -> model_obj PRED.hasAgentDefinition -> agent_obj RT.ProcessDefinition -> process_def_obj """ assert self.agent_instance_obj lookup_means = self._lookup_means() assert lookup_means assert PRED.hasAgentInstance in lookup_means assert PRED.hasModel in lookup_means assert PRED.hasAgentDefinition in lookup_means #assert PRED.hasProcessDefinition in lookup_means lu = lookup_means ret = {} log.debug("retrieve the associated device") device_obj = self.RR2.find_subject(subject_type=lu[PRED.hasAgentInstance], predicate=PRED.hasAgentInstance, object=self.agent_instance_obj._id) ret[lu[PRED.hasAgentInstance]]= device_obj device_id = device_obj._id log.debug("%s '%s' connected to %s '%s' (L4-CI-SA-RQ-363)", lu[PRED.hasAgentInstance], str(device_id), type(self.agent_instance_obj).__name__, str(self.agent_instance_obj._id)) # log.debug("retrieve the model associated with the device") # model_obj = self.RR2.find_object(subject=device_id, # predicate=PRED.hasModel, # object_type=lu[PRED.hasModel]) # # ret[lu[PRED.hasModel]] = model_obj # model_id = model_obj #retrive the stream info for this model #todo: add stream info to the platofrom model create # streams_dict = platform_models_objs[0].custom_attributes['streams'] # if not streams_dict: # raise BadRequest("Device model does not contain stream configuation used in launching the agent. Model: '%s", str(platform_models_objs[0]) ) #TODO: get the agent from the instance not from the model!!!!!!! log.debug("retrieve the agent associated with the model") agent_obj = self.RR2.find_object(subject=self.agent_instance_obj._id, predicate=PRED.hasAgentDefinition, object_type=lu[PRED.hasAgentDefinition]) ret[lu[PRED.hasAgentDefinition]] = agent_obj agent_id = agent_obj._id if not agent_obj.stream_configurations: raise BadRequest("Agent '%s' does not contain stream configuration used in launching" % str(agent_obj) ) log.debug("retrieve the process definition associated with this agent") process_def_obj = self.RR2.find_object(subject=agent_id, predicate=PRED.hasProcessDefinition, object_type=RT.ProcessDefinition) ret[RT.ProcessDefinition] = process_def_obj #retrieve the output products data_product_ids = self.RR2.find_objects(device_id, PRED.hasOutputProduct, RT.DataProduct, id_only=True) if not data_product_ids: raise NotFound("No output Data Products attached to this Device " + str(device_id)) #retrieve the streams assoc with each defined output product for product_id in data_product_ids: self.RR2.find_stream_id_of_data_product_using_has_stream(product_id) # check one stream per product self.RR2.find_dataset_id_of_data_product_using_has_dataset(product_id) # check one dataset per product self.associated_objects = ret def _get_device(self): self._check_associations() return self.associated_objects[self._lookup_means()[PRED.hasAgentInstance]] # def _get_model(self): # self._check_associations() # return self.associated_objects[self._lookup_means()[PRED.hasModel]] def _get_agent(self): self._check_associations() return self.associated_objects[self._lookup_means()[PRED.hasAgentDefinition]] def _get_process_definition(self): self._check_associations() return self.associated_objects[RT.ProcessDefinition]
def freeze(): if isinstance(resource_registry_client, EnhancedResourceRegistryClient): RR2 = resource_registry_client else: RR2 = EnhancedResourceRegistryClient(resource_registry_client) for p in predicate_list: if not RR2.has_cached_prediate(p): RR2.cache_predicate(p) def get_related_resources_partial_fn(predicate_dictionary, resource_whitelist): """ This function generates a resource crawler from 2 data structures representing desired crawl behavior The predicate dictionary is keyed on a predicate type, whose value is a 2-tuple of booleans the first boolean is whether to crawl subject-object, the second boolean for object-subject For example: dict([(PRED.hasModel, (False, True)]) would generate a crawler that could find platforms or instruments with a given model The resource whitelist is a list of resource types that will be crawled. The return value of this function is a function that accepts a resource id and returns a list of associations related (based on crawl behavior) """ log.trace("get_related_resources_partial_fn predicate_dict=%s rsrc_whitelist=%s", predicate_dictionary, resource_whitelist) # assertions on data types assert type({}) == type(predicate_dictionary) for v in predicate_dictionary.values(): assert type((True, True)) == type(v) assert type([]) == type(resource_whitelist) for rt in resource_whitelist: RR2.cache_resources(rt) def lookup_fn(resource_id): """ return a dict of related resources as dictated by the pred dict and whitelist - the key is the next resource id to crawl - the value is the entire association """ retval = {} sto_match = lambda assn: assn.s == resource_id and assn.ot in resource_whitelist ots_match = lambda assn: assn.o == resource_id and assn.st in resource_whitelist for p, (search_sto, search_ots) in predicate_dictionary.iteritems(): if search_sto: for a in RR2.filter_cached_associations(p, sto_match): log.trace("lookup_fn matched %s object", a.ot) retval[a.o] = a if search_ots: for a in RR2.filter_cached_associations(p, ots_match): log.trace("lookup_fn matched %s subject", a.st) retval[a.s] = a return retval def get_related_resources_h(accum, input_resource_id, recursion_limit): """ This is a recursive helper function that does the work of crawling for related resources The accum is a tuple: (set of associations that are deemed "Related", set of "seen" resources) The input resource id is the current resource being crawled The recursion limit decrements with each recursive call, ending at 0. So -1 for infinity. The return value is a list of associations """ if 0 == recursion_limit: return accum if -1000 > recursion_limit: log.warn("Terminating related resource recursion, hit -1000") return accum acc, seen = accum matches = lookup_fn(input_resource_id) log.trace("get_related_resources_h got matches %s", [dict((k, "%s %s %s" % (a.st, a.p, a.ot)) for k, a in matches.iteritems())]) unseen = set(matches.keys()) - seen seen.add(input_resource_id) acc = acc | set(matches.values()) #if log.isEnabledFor(logging.TRACE): # summary = {} # for a in acc: # label = "%s %s %s" % (a.st, a.p, a.ot) # if not label in summary: summary[label] = 0 # summary[label] += 1 # log.trace("acc2 is now %s", ["%s x%d" % (k, v) for k, v in summary.iteritems()]) def looper(acc2, input_rsrc_id): return get_related_resources_h(acc2, input_rsrc_id, recursion_limit - 1) h_ret = reduce(looper, unseen, (acc, seen)) #h_ret = reduce(looper, unseen, (acc, seen)) #(h_ret_acc, h_ret_seen) = h_ret #log.trace("h_ret is %s", ["%s %s %s" % (a.st, a.p, a.ot) for a in h_ret_acc]) return h_ret def get_related_resources_fn(input_resource_id, recursion_limit=1024): """ This is the function that finds related resources. input_resource_id and recursion_limit are self explanatory The return value is a list of associations. """ retval, _ = get_related_resources_h((set([]), set([])), input_resource_id, recursion_limit) log.trace("final_ret is %s", ["%s %s %s" % (a.st, a.p, a.ot) for a in retval]) return list(retval) return get_related_resources_fn # retval of get_related_resources_partial_fn return get_related_resources_partial_fn # retval of freeze()
class TestEnhancedResourceRegistryClient(PyonTestCase): def setUp(self): self.rr = Mock() self.RR2 = EnhancedResourceRegistryClient(self.rr) def sample_resource(self): return any_old(RT.InstrumentDevice) def test_init(self): pass def test_create(self): """ test resource creation in normal case """ # get objects good_sample_resource = self.sample_resource() #configure Mock self.rr.create.return_value = ('111', 'bla') self.rr.find_resources.return_value = ([], []) sample_resource_id = self.RR2.create(good_sample_resource, RT.InstrumentDevice) self.rr.create.assert_called_once_with(good_sample_resource) self.assertEqual(sample_resource_id, '111') def test_create_bad_wrongtype(self): """ test resource creation failure for wrong type """ # get objects bad_sample_resource = any_old(RT.PlatformDevice) delattr(bad_sample_resource, "name") #configure Mock self.rr.create.return_value = ('111', 'bla') self.rr.find_resources.return_value = ([], []) self.assertRaises(BadRequest, self.RR2.create, bad_sample_resource, RT.InstrumentDevice) def test_create_bad_noname(self): """ test resource creation failure for no name """ # get objects bad_sample_resource = self.sample_resource() delattr(bad_sample_resource, "name") #configure Mock self.rr.create.return_value = ('111', 'bla') self.rr.find_resources.return_value = ([], []) self.assertRaises(BadRequest, self.RR2.create, bad_sample_resource, RT.InstrumentDevice) # def test_create_bad_dupname(self): # """ # test resource creation failure for duplicate name # """ # # get objects # # bad_sample_resource = self.sample_resource() # #really, the resource doesn't matter; it's the retval from find that matters # # #configure Mock # self.rr.create.return_value = ('111', 'bla') # self.rr.find_resources.return_value = ([0], [0]) # # self.assertRaises(BadRequest, self.RR2.create, bad_sample_resource, RT.InstrumentDevice) # def test_read(self): """ test resource read (passthru) """ # get objects myret = self.sample_resource() #configure Mock self.rr.read.return_value = myret response = self.RR2.read("111", RT.InstrumentDevice) self.rr.read.assert_called_once_with("111") self.assertEqual(response, myret) #self.assertDictEqual(response.__dict__, # self.sample_resource().__dict__) def test_read_bad_wrongtype(self): """ test resource read (passthru) """ # get objects myret = self.sample_resource() #configure Mock self.rr.read.return_value = myret self.assertRaises(BadRequest, self.RR2.read, "111", RT.PlatformDevice) self.rr.read.assert_called_once_with("111") def test_update(self): """ test resource update in normal case """ # get objects good_sample_resource = self.sample_resource() setattr(good_sample_resource, "_id", "111") #configure Mock self.rr.update.return_value = ('111', 'bla') self.rr.find_resources.return_value = ([], []) self.RR2.update(good_sample_resource, RT.InstrumentDevice) self.rr.update.assert_called_once_with(good_sample_resource) def test_update_bad_wrongtype(self): """ test update failure due to duplicate name """ # get objects bad_sample_resource = self.sample_resource() self.assertRaises(BadRequest, self.RR2.update, bad_sample_resource, RT.PlatformDevice) # # def test_update_bad_dupname(self): # """ # test update failure due to duplicate name # """ # # get objects # # bad_sample_resource = self.sample_resource() # setattr(bad_sample_resource, "_id", "111") # # self.rr.find_resources.return_value = ([0], [0]) # self.assertRaises(BadRequest, self.RR2.update, bad_sample_resource, RT.InstrumentDevice) def test_update_bad_noid(self): """ test update failure due to duplicate name """ # get objects bad_sample_resource = self.sample_resource() self.rr.find_resources.return_value = ([0], [0]) self.assertRaises(BadRequest, self.RR2.update, bad_sample_resource, RT.InstrumentDevice) def test_retire(self): """ test retire """ # get objects myret = self.sample_resource() #configure Mock self.rr.read.return_value = myret self.rr.delete.return_value = None self.rr.retire.return_value = None try: self.RR2.retire("111", RT.InstrumentDevice) except TypeError as te: # for logic tests that run into mock trouble if "'Mock' object is not iterable" != te.message: raise te else: raise SkipTest("Must test this with INT test") except Exception as e: raise e #self.rr.read.assert_called_with("111", "") self.rr.retire.assert_called_once_with("111") def test_retire_bad_wrongtype(self): """ test resource read (passthru) """ # get objects myret = self.sample_resource() #configure Mock self.rr.read.return_value = myret self.assertRaises(BadRequest, self.RR2.retire, "111", RT.PlatformDevice) self.rr.read.assert_called_once_with("111") def test_pluck_delete(self): """ test delete """ # get objects myret = self.sample_resource() #configure Mock self.rr.read.return_value = myret self.rr.delete.return_value = None self.rr.find_resources.return_value = None self.rr.find_objects.return_value = (["2"], ["2"]) self.rr.find_subjects.return_value = (["3"], ["3"]) self.RR2.pluck_delete("111", RT.InstrumentDevice) self.rr.delete.assert_called_once_with("111") def test_advance_lcs(self): """ call RR when the transition ISN'T retire """ self.RR2.advance_lcs("111", LCE.PLAN) self.rr.execute_lifecycle_transition.assert_called_once_with(resource_id="111", transition_event=LCE.PLAN) self.RR2.advance_lcs("222", LCE.RETIRE) self.rr.retire.assert_called_once_with("222") def test_delete_association(self): self.rr.get_association.return_value = "111" self.RR2.delete_association("a", "b", "c") self.rr.delete_association.assert_called_once_with("111") def test_delete_all_object_associations(self): self.rr.find_associations.return_value = ["111"] self.RR2.delete_object_associations("x") self.rr.delete_association.assert_called_once_with("111") def test_delete_all_subject_associations(self): self.rr.find_associations.return_value = ["111"] self.RR2.delete_subject_associations("x") self.rr.delete_association.assert_called_once_with("111") def test_pluck(self): self.rr.find_subjects.return_value = (["111"], ["aaa"]) self.rr.find_objects.return_value = (["222"], ["bbb"]) self.RR2.pluck("x") #self.rr.delete_association.assert_called_with("bbb") self.rr.delete_association.assert_called_with("aaa") self.assertEqual(self.rr.delete_association.call_count, 2) def test_find_objects_using_id(self): self.tbase_find_objects("x_id") def test_find_objects_using_ionobj(self): obj = any_old(RT.InstrumentDevice) setattr(obj, "_id", "foo_id") self.tbase_find_objects(obj) def test_find_objects_using_junk(self): self.tbase_find_objects(1) def tbase_find_objects(self, sample_obj): """ test all 8 flavors of find objects: return IonObjects/ids, return single/multiple, use predicate/no-predicate """ def rst(): self.rr.find_objects.reset_mock() self.rr.find_objects.return_value = ([], []) self.assertEqual(0, self.rr.find_subjects.call_count) def rst1(): self.rr.find_objects.reset_mock() self.rr.find_objects.return_value = (["x"], ["x"]) self.assertEqual(0, self.rr.find_subjects.call_count) def rst2(): self.rr.find_objects.reset_mock() self.rr.find_objects.return_value = (["x", "y"], ["z", "k"]) self.assertEqual(0, self.rr.find_subjects.call_count) x = sample_obj xx = x if hasattr(x, "_id"): xx = x._id # find none rst() self.RR2.find_instrument_models_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) rst() self.assertRaises(NotFound, self.RR2.find_instrument_model_of_instrument_device_using_has_model, x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) rst() self.RR2.find_instrument_model_ids_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) rst() self.assertRaises(NotFound, self.RR2.find_instrument_model_id_of_instrument_device_using_has_model, x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) # find one rst1() self.RR2.find_instrument_models_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) rst1() self.RR2.find_instrument_model_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) rst1() self.RR2.find_instrument_model_ids_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) rst1() self.RR2.find_instrument_model_id_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) # find multiples rst2() self.RR2.find_instrument_models_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) rst2() self.assertRaises(Inconsistent, self.RR2.find_instrument_model_of_instrument_device_using_has_model, x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) rst2() self.RR2.find_instrument_model_ids_of_instrument_device_using_has_model(x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) rst2() self.assertRaises(Inconsistent, self.RR2.find_instrument_model_id_of_instrument_device_using_has_model, x) self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) # # find using # rst2() # self.RR2.find_instrument_models_of_instrument_device_using_has_model(x) # self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) # # rst2() # self.assertRaises(Inconsistent, self.RR2.find_instrument_model_of_instrument_device_using_has_model, x) # self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=False) # # rst2() # self.RR2.find_instrument_model_ids_of_instrument_device_using_has_model(x) # self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) # # rst2() # self.assertRaises(Inconsistent, self.RR2.find_instrument_model_id_of_instrument_device_using_has_model, x) # self.rr.find_objects.assert_called_once_with(subject=xx, predicate=PRED.hasModel, object_type=RT.InstrumentModel, id_only=True) def test_find_subjects_using_id(self): self.tbase_find_subjects("x_id") def test_find_subjects_using_ionobj(self): obj = any_old(RT.InstrumentDevice) setattr(obj, "_id", "foo_id") self.tbase_find_subjects(obj) def test_find_subjects_using_junk(self): self.tbase_find_subjects(1) def tbase_find_subjects(self, sample_obj): """ test all 8 flavors of find subjects: return IonObjects/ids, return single/multiple, use predicate/no-predicate """ def rst(): self.rr.find_subjects.reset_mock() self.rr.find_subjects.return_value = ([], []) self.assertEqual(0, self.rr.find_objects.call_count) def rst1(): self.rr.find_subjects.reset_mock() self.rr.find_subjects.return_value = (["x"], ["x"]) self.assertEqual(0, self.rr.find_objects.call_count) def rst2(): self.rr.find_subjects.reset_mock() self.rr.find_subjects.return_value = (["x", "y"], ["z", "k"]) self.assertEqual(0, self.rr.find_objects.call_count) x = sample_obj xx = x if hasattr(x, "_id"): xx = x._id # find none rst() self.RR2.find_instrument_devices_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) rst() self.assertRaises(NotFound, self.RR2.find_instrument_device_by_instrument_model_using_has_model, x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) rst() self.RR2.find_instrument_device_ids_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) rst() self.assertRaises(NotFound, self.RR2.find_instrument_device_id_by_instrument_model_using_has_model, x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) # find 1 rst1() self.RR2.find_instrument_devices_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) rst1() self.RR2.find_instrument_device_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) rst1() self.RR2.find_instrument_device_ids_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) rst1() self.RR2.find_instrument_device_id_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) # find multiple rst2() self.RR2.find_instrument_devices_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) rst2() self.assertRaises(Inconsistent, self.RR2.find_instrument_device_by_instrument_model_using_has_model, x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) rst2() self.RR2.find_instrument_device_ids_by_instrument_model_using_has_model(x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) rst2() self.assertRaises(Inconsistent, self.RR2.find_instrument_device_id_by_instrument_model_using_has_model, x) self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) # # # find using # rst2() # self.RR2.find_instrument_devices_by_instrument_model_using_has_model(x) # self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) # # rst2() # self.assertRaises(Inconsistent, self.RR2.find_instrument_device_by_instrument_model_using_has_model, x) # self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=False) # # rst2() # self.RR2.find_instrument_device_ids_by_instrument_model_using_has_model(x) # self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) # # rst2() # self.assertRaises(Inconsistent, self.RR2.find_instrument_device_id_by_instrument_model_using_has_model, x) # self.rr.find_subjects.assert_called_once_with(object=xx, predicate=PRED.hasModel, subject_type=RT.InstrumentDevice, id_only=True) def test_assign_unassign(self): """ test all flavors of assign and unassign: with/without predicates """ x = "x_id" y = "y_id" self.RR2.assign_instrument_model_to_instrument_device_with_has_model(y, x) self.rr.create_association.assert_called_once_with(x, PRED.hasModel, y) self.rr.get_association.return_value = "zzz" self.RR2.unassign_instrument_model_from_instrument_device_with_has_model(y, x) self.rr.delete_association.assert_called_once_with("zzz") self.rr.create_association.reset_mock() self.RR2.assign_data_product_to_data_process_with_has_output_product(y, x) self.rr.create_association.assert_called_once_with(x, PRED.hasOutputProduct, y) self.rr.delete_association.reset_mock() self.rr.get_association.reset_mock() self.rr.get_association.return_value = "aaa" self.RR2.unassign_data_product_from_data_process_with_has_output_product(y, x) self.rr.delete_association.assert_called_once_with("aaa") def test_assign_single_object(self): x = "x_id" y = "y_id" def rst(): self.rr.find_objects.reset_mock() self.rr.get_association.reset_mock() rst() self.rr.find_objects.return_value = ([], []) self.RR2.assign_one_instrument_model_to_instrument_device_with_has_model(y, x) self.rr.create_association.assert_called_once_with(x, PRED.hasModel, y) rst() self.rr.find_objects.return_value = (["a", "b"], ["c", "d"]) self.assertRaises(Inconsistent, self.RR2.assign_one_instrument_model_to_instrument_device_with_has_model, y, x) rst() self.rr.find_objects.return_value = (["a"], ["b"]) self.rr.get_association.return_value = "yay" self.RR2.assign_one_instrument_model_to_instrument_device_with_has_model(y, x) rst() self.rr.find_objects.return_value = (["a"], ["b"]) self.rr.get_association.side_effect = NotFound("") self.assertRaises(BadRequest, self.RR2.assign_one_instrument_model_to_instrument_device_with_has_model, y, x) def test_assign_single_subject(self): x = "x_id" y = "y_id" def rst(): self.rr.find_subjects.reset_mock() self.rr.get_association.reset_mock() rst() self.rr.find_subjects.return_value = ([], []) self.RR2.assign_instrument_device_to_one_instrument_site_with_has_device(y, x) self.rr.create_association.assert_called_once_with(x, PRED.hasDevice, y) rst() self.rr.find_subjects.return_value = (["a", "b"], ["c", "d"]) self.assertRaises(Inconsistent, self.RR2.assign_instrument_device_to_one_instrument_site_with_has_device, y, x) rst() self.rr.find_subjects.return_value = (["a"], ["b"]) self.rr.get_association.return_value = "yay" self.RR2.assign_instrument_device_to_one_instrument_site_with_has_device(y, x) rst() self.rr.find_subjects.return_value = (["a"], ["b"]) self.rr.get_association.side_effect = NotFound("") self.assertRaises(BadRequest, self.RR2.assign_instrument_device_to_one_instrument_site_with_has_device, y, x) def test_bad_dynamics(self): x = "x_id" self.RR2.assign_foo_to_bar(x) self.rr.assign_foo_to_bar.assert_called_once_with(x) self.assertRaises(BadRequest, getattr, self.RR2, "find_instrument_model_of_instrument_device_using_has_site") self.assertRaises(BadRequest, getattr, self.RR2, "find_instrument_model_of_instrument_device_using_has_banana") #self.assertRaises(BadRequest, getattr, self.RR2, "find_data_product_of_data_process") self.RR2.find_sensor_model_by_data_product(x) self.rr.find_sensor_model_by_data_product.assert_called_once_with(x) def test_cached_predicate_search(self): d = "d_id" m = "m_id" x = "x_id" good_assn = DotDict(s=d, st=RT.InstrumentDevice, p=PRED.hasModel, o=m, ot=RT.InstrumentModel) bad_assn = DotDict(s=d, st=RT.PlatformDevice, p=PRED.hasModel, o=m, ot=RT.PlatformModel) self.rr.find_associations.return_value = [good_assn, bad_assn] self.RR2.cache_predicate(PRED.hasModel) self.assertTrue(self.RR2.has_cached_prediate(PRED.hasModel)) self.rr.find_associations.assert_called_once_with(predicate=PRED.hasModel, id_only=False) # object searches that should return 0, 0, 1 results results = self.RR2.find_objects(x, PRED.hasModel, RT.InstrumentModel, True) self.assertEqual([], results) results = self.RR2.find_instrument_model_ids_of_instrument_device_using_has_model(x) self.assertEqual([], results) results = self.RR2.find_instrument_model_ids_of_instrument_device_using_has_model(d) self.assertEqual([m], results) self.assertEqual(0, self.rr.find_objects.call_count) # subject searches that should return 0, 0, 1 results results = self.RR2.find_subjects(RT.InstrumentDevice, PRED.hasModel, x, True) self.assertEqual([], results) results = self.RR2.find_instrument_device_ids_by_instrument_model_using_has_model(x) self.assertEqual([], results) results = self.RR2.find_instrument_device_ids_by_instrument_model_using_has_model(m) self.assertEqual([d], results) self.assertEqual(0, self.rr.find_subjects.call_count)