Parcourir la source

Fixed error message propagation from sub-threads during activity execution

Yentl Van Tendeloo il y a 7 ans
Parent
commit
cb1e5b81d6

+ 24 - 37
bootstrap/core_algorithm.alc

@@ -427,12 +427,6 @@ Void function model_overwrite(model : Element, model_id : String, metamodel_id :
 
 	return!
 
-Boolean function check_conformance(model_id : String):
-	// TODO check if it actually conforms, considering that instanceOf link
-	//    --> in-depth check
-
-	return True!
-
 Element function merge_models(models_dict : Element, operation_name : String):
 	core = import_node(core_model_location)
 	// 0) Find operation signature
@@ -454,7 +448,6 @@ Element function merge_models(models_dict : Element, operation_name : String):
 	Element trace_links
 
 	// 1) Find merged metamodel
-
 	trace_links = allOutgoingAssociationInstances(core, operation_id, "tracability")
 	merged_metamodel_id = ""
 	while (set_len(trace_links) > 0):
@@ -463,7 +456,6 @@ Element function merge_models(models_dict : Element, operation_name : String):
 			merged_metamodel_id = readAssociationDestination(core, trace_link_id)
 
 	// 2) Merge source models
-
 	if (merged_metamodel_id != ""):
 		Element model_tuples
 		Element keys
@@ -512,6 +504,12 @@ Element function split_model(model : Element, metamodels_dict : Element):
 
 	return model_split(model, model_tuples, read_root())!
 
+Boolean function check_conformance(model_id : String):
+	// TODO check if it actually conforms, considering that instanceOf link
+	//    --> in-depth check
+
+	return True!
+
 Element function get_model(model_name : String, metamodel_name : String):
 	core = import_node(core_model_location)
 	return get_full_model(get_entry_id(model_name), get_entry_id(metamodel_name))!
@@ -620,15 +618,13 @@ Element function execute_operation(operation_id : String, input_models : Element
 				cmd_model_add(input_metamodels[key], input_models[key], "")
 			mm = get_full_model(get_entry_id(input_models[key]), get_entry_id(input_metamodels[key]))
 			if (element_eq(mm, read_root())):
-				output("Signature mismatch in operation for tag " + key)
-				return read_root()!
+				return "Signature mismatch in operation for tag: " + key!
 			set_add_node(model_tuples, create_tuple(key, mm))
 
 		Element merged_metamodel
 		merged_metamodel = get_full_model(merged_metamodel_id, get_entry_id("formalisms/SimpleClassDiagrams"))
 		if (element_eq(merged_metamodel, read_root())):
-			output("Type cannot be typed as formalisms/SimpleClassDiagrams: 'merged'")
-			return read_root()!
+			return "Type cannot be typed as formalisms/SimpleClassDiagrams: 'merged'"!
 
 		merged_model = model_join(model_tuples, merged_metamodel, tracability_model)
 	else:
@@ -637,14 +633,12 @@ Element function execute_operation(operation_id : String, input_models : Element
 			Element m
 			m = get_full_model(get_entry_id(input_models[set_pop(dict_keys(input_models))]), get_entry_id(input_metamodels[set_pop(dict_keys(input_metamodels))]))
 			if (element_eq(m, read_root())):
-				output("Signature mismatch in operation for tag " + cast_value(set_pop(dict_keys(input_models))))
-				return read_root()!
+				return "Signature mismatch in operation for tag: " + cast_value(set_pop(dict_keys(input_models)))!
 			merged_model = model_copy(m)
 		elif (bool_and(dict_len(input_models) == 0, dict_len(output_metamodels) == 0)):
 			merged_model = read_root()
 		else:
-			output("Could not resolve intermediate merged metamodel")
-			return read_root()!
+			return "Could not resolve intermediate merged metamodel"!
 
 	// 3) Transform
 
@@ -659,11 +653,11 @@ Element function execute_operation(operation_id : String, input_models : Element
 		Element operation
 		operation = get_full_model(operation_id, ramified_metamodel_id)
 		if (element_eq(operation, read_root())):
-			output("Operation could not be typed by specified RAMified metamodel!")
-			return read_root()!
+			return "Operation could not be typed by specified RAMified metamodel!"!
 		result = transform(merged_model, operation)
 	elif (exact_type == "ManualOperation"):
 		output("Please perform manual operation " + cast_value(full_name(operation_id)))
+		log("Performing manual")
 		if (element_neq(merged_model, read_root())):
 			String model_name
 			model_name = ""
@@ -683,13 +677,11 @@ Element function execute_operation(operation_id : String, input_models : Element
 		Element al
 		al = get_full_model(operation_id, get_entry_id("formalisms/ActionLanguage"))
 		if (element_eq(al, read_root())):
-			output("Action Language operation not typed by ActionLanguage metamodel!")
-			return read_root()!
+			return "Action Language operation not typed by ActionLanguage metamodel!"!
 		func = get_func_AL_model(al)
 		result = func(merged_model)
 	else:
-		output("Unknown type of operation: " + exact_type)
-		return read_root()!
+		return "Unknown type of operation: " + exact_type!
 
 	// 4) Split in different models depending on type
 
@@ -706,8 +698,7 @@ Element function execute_operation(operation_id : String, input_models : Element
 			Element mm
 			mm = get_full_model(get_entry_id(output_metamodels[key]), get_entry_id("formalisms/SimpleClassDiagrams"))
 			if (element_eq(mm, read_root())):
-				output("Type cannot be typed as formalisms/SimpleClassDiagrams: " + key)
-				return read_root()!
+				return "Type cannot be typed as formalisms/SimpleClassDiagrams: " + key!
 			set_add_node(model_tuples, create_tuple(key, mm))
 
 		result = model_split(merged_model, model_tuples, tracability)
@@ -722,7 +713,7 @@ Element function execute_operation(operation_id : String, input_models : Element
 
 		return result!
 	else:
-		return read_root()!
+		return "Failure"!
 
 Boolean function enact_action(pm : Element, element : String, mapping : Element):
 	Boolean result
@@ -797,7 +788,7 @@ Boolean function enact_action(pm : Element, element : String, mapping : Element)
 
 	log(string_join("Finished: ", read_attribute(pm, element, "name")))
 
-	if (element_eq(result, read_root())):
+	if (is_physical_string(result)):
 		// Something went wrong!
 		output("Failure")
 		return False!
@@ -1382,7 +1373,7 @@ Boolean function do_spawn_modify(model_name : String, write : Boolean):
 	input()
 	return False!
 
-Boolean function do_spawn_activity(transformation_id : String, tracability_name : String, inputs : Element, outputs : Element, output_map : Element):
+String function do_spawn_activity(transformation_id : String, tracability_name : String, inputs : Element, outputs : Element, output_map : Element):
 	Element lst
 	Element returnvalue
 	String taskname
@@ -1403,7 +1394,7 @@ Boolean function do_spawn_activity(transformation_id : String, tracability_name
 		sleep(0.1)
 
 	output("Finished task: " + taskname)
-	return cast_boolean(set_pop(returnvalue))!
+	return set_pop(returnvalue)!
 
 Void function spawn_activity(returnvalue : Element, transformation_id : String, tracability_name : String, inputs : Element, outputs : Element, output_map : Element):
 	Element result
@@ -1438,10 +1429,10 @@ Void function spawn_activity(returnvalue : Element, transformation_id : String,
 		model_overwrite(tracability_model, get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
 
 	// Now write out the models again
-	if (element_eq(result, read_root())):
+	if (is_physical_string(result)):
 		// Something went wrong!
-		set_add(returnvalue, False)
-		output("Failure")
+		set_add(returnvalue, result)
+		output("Nothing to modify")
 	else:
 		keys = dict_keys(outputs)
 		while (set_len(keys) > 0):
@@ -1453,8 +1444,7 @@ Void function spawn_activity(returnvalue : Element, transformation_id : String,
 			else:
 				model_overwrite(result[key], get_entry_id(outputs[key]), get_entry_id(output_map[key]))
 
-		set_add(returnvalue, True)
-		output("Success")
+		set_add(returnvalue, "Success")
 
 	while (other_has_output(get_taskname())):
 		sleep(1)
@@ -1533,10 +1523,7 @@ String function cmd_transformation_execute(transformation_name : String, source_
 							else:
 								return "Write permission denied to: " + target_model_name!
 
-				if (do_spawn_activity(transformation_id, tracability_name, inputs, outputs, output_map)):
-					return "Success"!
-				else:
-					return "Failure"!
+				return do_spawn_activity(transformation_id, tracability_name, inputs, outputs, output_map)!
 			else:
 				return "Execute permission denied to: " + transformation_name!
 		else:

+ 47 - 1
unit/test_all.py

@@ -4210,10 +4210,56 @@ class TestModelverse(unittest.TestCase):
         transformation_add_MANUAL({}, {}, "users/user/test/c")
 
         def operation(model):
-            print("Executing")
+            assert model is None
 
+        # Now execute
         transformation_execute_MANUAL("users/user/test/c", {}, {}, operation)
 
+        # Now do the same, but with a model
+        transformation_add_MANUAL({"MODEL_A": "users/user/test/A"}, {"MODEL_B": "users/user/test/B"}, "users/user/test/d")
+
+        def operation(model):
+            assert model is not None
+            assert [{"__id": "MODEL_A/__0", "__type": "MODEL_A/A", "name": None}] == element_list_nice(model)
+            instantiate(model, "MODEL_B/B")
+
+        transformation_execute_MANUAL("users/user/test/d", {"MODEL_A": "users/user/test/a"}, {"MODEL_B": "users/user/test/e"}, operation)
+        lst = element_list_nice("users/user/test/e")
+        assert len(lst) == 1
+        assert lst[0]["__type"] == "B"
+        assert lst[0]["name"] == None
+        assert lst[0]["__id"].startswith("__")
+
+        # Execute activity with non-existing model (input)
+        try:
+            transformation_execute_MANUAL("users/user/test/d", {"MODEL_A": "dfadf"}, {"MODEL_B": "users/user/test/f"}, lambda i: i)
+            self.fail()
+        except UnknownModel:
+            assert "f" not in model_list("users/user/test")
+
+        # Execute non-existing activity
+        try:
+            transformation_execute_MANUAL("adfadf", {}, {"MODEL_B": "users/user/test/abc"}, lambda i: i)
+            self.fail()
+        except UnknownModel:
+            assert "abc" not in model_list("users/user/test")
+
+        # Execute activity with non-conforming input models
+        try:
+            transformation_execute_MANUAL("users/user/test/d", {"MODEL_A": "users/user/test/b"}, {"MODEL_B": "users/user/test/f"}, lambda i: i)
+            self.fail()
+        except SignatureMismatch:
+            assert "f" not in model_list("users/user/test")
+
+        # Execute activity with non-conforming output models that already exist
+        try:
+            transformation_execute_MANUAL("users/user/test/d", {"MODEL_A": "users/user/test/b"}, {"MODEL_B": "users/user/test/c"}, lambda i: i)
+            self.fail()
+        except SignatureMismatch:
+            assert element_list_nice("users/user/test/c") > 0
+
+        # Execute activity with colliding models
+
     """
     def test_op_model_render(self):
     def test_op_transformation_execute_MT(self):

+ 16 - 4
wrappers/classes/modelverse.xml

@@ -1602,10 +1602,16 @@
                         </raise>
                     </transition>
 
+                    <transition cond="self.expect_response_partial('Signature mismatch in operation for tag: ', pop=False)" target="../wait_for_action/history">
+                        <raise event="exception">
+                            <parameter expr="'SignatureMismatch'"/>
+                            <parameter expr="self.responses.pop(0)"/>
+                        </raise>
+                    </transition>
+
                     <transition cond="self.expect_response_partial('', pop=False)" target="../wait_for_action/history">
                         <script>
                             print("Unknown Error: " + self.responses[0])
-                            pass
                         </script>
                         <raise event="exception">
                             <parameter expr="'UnknownError'"/>
@@ -1687,13 +1693,19 @@
                                 </transition>
 
                                 <transition cond="self.inputs" target="../../../history">
-                                    <script>
-                                        self.inputs.pop(0)
-                                    </script>
                                     <raise event="request">
                                         <parameter expr="0"/>
                                     </raise>
                                 </transition>
+
+                                <!--
+                                <transition cond="self.expect_response_partial('', pop=False)" target=".">
+                                    <script>
+                                        print("ERROR: " + str(self.responses))
+                                        self.responses.pop(0)
+                                    </script>
+                                </transition>
+                                -->
                             </state>
                         </state>
                     </state>

+ 10 - 0
wrappers/modelverse.py

@@ -152,25 +152,32 @@ def __run_new_modelverse_activity(address, username, password, taskname, pipe, c
     controller.username = username
     controller.password = password
     t = OUTPUT()
+    print("Got t: " + str(t))
 
     if t == "OP":
         model = OUTPUT()
+        print("Model: " + str(model))
         if callback is not None:
+            print("INVOKE")
             __invoke(callback, model)
+            print("DONE")
         controller.addInput(Event("data_input", "action_in", [None]))
         time.sleep(2)
+        print("FINISH")
     elif t == "SC":
         while 1:
             empty = True
 
             # Fetch output from the MV
             response = responses.fetch(0)
+            print("Got response: " + str(response))
             if response is not None:
                 if response.name == "data_output":
                     # Got output of MV, so forward to SCCD
                     if pipe is not None:
                         pipe.send(("input", response.parameters))
                 elif response.name == "result":
+                    print("Got result: " + str(response))
                     # Finished execution, so continue and return result
                     if pipe is not None:
                         pipe.send(("terminate", []))
@@ -217,6 +224,7 @@ def _process_SC(statechart, port_sc, taskname):
             empty = False
 
         response = port_sc.fetch(0)
+        print("Got response in process: " + str(response))
         if response is not None:
             p2c_pipe.send(response)
             empty = False
@@ -241,6 +249,7 @@ def OUTPUT():
         if response.name == "result":
             return response.parameters[1]
         elif response.name == "exception":
+            print("Got exception event: " + str(response))
             try:
                 raise eval(response.parameters[1])(*response.parameters[2:])
             except NameError:
@@ -378,6 +387,7 @@ def __transformation_execute(operation_name, input_models_dict, output_models_di
     taskname = OUTPUT()
     if statechart is not None:
         threading.Thread(target=_process_SC, args=[statechart, port_sc, taskname]).start()
+    print("Waiting for output...")
     return OUTPUT()
 
 def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):

+ 12 - 3
wrappers/modelverse_SCCD.py

@@ -1903,6 +1903,11 @@ class Modelverse(RuntimeClassBase):
         _initialized_behaviour_operations_32.setTrigger(None)
         _initialized_behaviour_operations_32.setGuard(self._initialized_behaviour_operations_32_guard)
         self.states["/initialized/behaviour/operations"].addTransition(_initialized_behaviour_operations_32)
+        _initialized_behaviour_operations_33 = Transition(self, self.states["/initialized/behaviour/operations"], [self.states["/initialized/behaviour/wait_for_action/history"]])
+        _initialized_behaviour_operations_33.setAction(self._initialized_behaviour_operations_33_exec)
+        _initialized_behaviour_operations_33.setTrigger(None)
+        _initialized_behaviour_operations_33.setGuard(self._initialized_behaviour_operations_33_guard)
+        self.states["/initialized/behaviour/operations"].addTransition(_initialized_behaviour_operations_33)
         
         # transition /initialized/behaviour/operations/store_on_scripted/transformation_add
         _initialized_behaviour_operations_store_on_scripted_transformation_add_0 = Transition(self, self.states["/initialized/behaviour/operations/store_on_scripted/transformation_add"], [self.states["/initialized/behaviour/wait_for_action/megamodelling"]])
@@ -2480,11 +2485,16 @@ class Modelverse(RuntimeClassBase):
         return self.expect_response_partial('Conformance hierarchy unknown for: ', pop=False)
     
     def _initialized_behaviour_operations_32_exec(self, parameters):
+        self.raiseInternalEvent(Event("exception", None, ['SignatureMismatch', self.responses.pop(0)]))
+    
+    def _initialized_behaviour_operations_32_guard(self, parameters):
+        return self.expect_response_partial('Signature mismatch in operation for tag: ', pop=False)
+    
+    def _initialized_behaviour_operations_33_exec(self, parameters):
         print("Unknown Error: " + self.responses[0])
-        pass
         self.raiseInternalEvent(Event("exception", None, ['UnknownError', 'Error: %s' % self.responses.pop(0)]))
     
-    def _initialized_behaviour_operations_32_guard(self, parameters):
+    def _initialized_behaviour_operations_33_guard(self, parameters):
         return self.expect_response_partial('', pop=False)
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_0_exec(self, parameters):
@@ -3344,7 +3354,6 @@ class Modelverse(RuntimeClassBase):
         return self.expect_response_partial('Nothing to modify', pop=True)
     
     def _initialized_behaviour_wait_for_action_activity_OP_forwarding_3_exec(self, parameters):
-        self.inputs.pop(0)
         self.raiseInternalEvent(Event("request", None, [0]))
     
     def _initialized_behaviour_wait_for_action_activity_OP_forwarding_3_guard(self, parameters):