Browse Source

Fix test for powerwindow

Yentl Van Tendeloo 4 years ago
parent
commit
ff99517f64
5 changed files with 188 additions and 30 deletions
  1. 106 0
      integration/log_output.py
  2. 39 0
      integration/log_output.xml
  3. 11 11
      integration/test_powerwindow.py
  4. 6 1
      models/bfs.alc
  5. 26 18
      wrappers/modelverse.py

+ 106 - 0
integration/log_output.py

@@ -0,0 +1,106 @@
+"""
+Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
+
+Date:   Mon Aug 28 10:53:51 2017
+
+Model author: Yentl Van Tendeloo
+Model name:   Logging
+Model description:
+For testing: append all input to a log until finished
+"""
+
+from sccd.runtime.statecharts_core import *
+
+# package "Logging"
+
+class Logging(RuntimeClassBase):
+    def __init__(self, controller, log):
+        RuntimeClassBase.__init__(self, controller)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        Logging.user_defined_constructor(self, log)
+    
+    def user_defined_constructor(self, log):
+        self.log = log
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /init
+        self.states["/init"] = State(1, "/init", self)
+        self.states["/init"].setEnter(self._init_enter)
+        self.states["/init"].setExit(self._init_exit)
+        
+        # state /finished
+        self.states["/finished"] = State(2, "/finished", self)
+        
+        # add children
+        self.states[""].addChild(self.states["/init"])
+        self.states[""].addChild(self.states["/finished"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/init"]
+        
+        # transition /init
+        _init_0 = Transition(self, self.states["/init"], [self.states["/init"]])
+        _init_0.setAction(self._init_0_exec)
+        _init_0.setTrigger(Event("input", "inp"))
+        self.states["/init"].addTransition(_init_0)
+        _init_1 = Transition(self, self.states["/init"], [self.states["/init"]])
+        _init_1.setTrigger(Event("_0after"))
+        self.states["/init"].addTransition(_init_1)
+        _init_2 = Transition(self, self.states["/init"], [self.states["/finished"]])
+        _init_2.setTrigger(Event("terminate", "inp"))
+        self.states["/init"].addTransition(_init_2)
+    
+    def _init_enter(self):
+        self.addTimer(0, 0.1)
+    
+    def _init_exit(self):
+        self.removeTimer(0)
+    
+    def _init_0_exec(self, parameters):
+        value = parameters[0]
+        self.log.append(value)
+        print("Got value: " + str(value))
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/init"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class ObjectManager(ObjectManagerBase):
+    def __init__(self, controller):
+        ObjectManagerBase.__init__(self, controller)
+    
+    def instantiate(self, class_name, construct_params):
+        if class_name == "Logging":
+            instance = Logging(self.controller, construct_params[0])
+            instance.associations = {}
+        else:
+            raise Exception("Cannot instantiate class " + class_name)
+        return instance
+
+class Controller(ThreadsControllerBase):
+    def __init__(self, log, keep_running = None, behind_schedule_callback = None):
+        if keep_running == None: keep_running = True
+        if behind_schedule_callback == None: behind_schedule_callback = None
+        ThreadsControllerBase.__init__(self, ObjectManager(self), keep_running, behind_schedule_callback)
+        self.addInputPort("inp")
+        self.addOutputPort("outp")
+        self.object_manager.createInstance("Logging", [log])

+ 39 - 0
integration/log_output.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<diagram author="Yentl Van Tendeloo" name="Logging">
+    <description>
+        For testing: append all input to a log until finished
+    </description>
+
+    <inport name="inp"/>
+    <outport name="outp"/>
+
+    <class name="Logging" default="true">
+        <constructor>
+            <parameter name="log"/>
+            <body>
+                self.log = log
+            </body>
+        </constructor>
+        <scxml initial="init">
+            <state id="init">
+                <transition event="input" port="inp" target=".">
+                    <parameter name="value"/>
+                    <script>
+                        self.log.append(value)
+                        print("Got value: " + str(value))
+                    </script>
+                </transition>
+
+                <transition after="0.1" target="."/>
+
+                <transition event="terminate" port="inp" target="../finished"/>
+            </state>
+
+            <state id="finished">
+                <script>
+                    print("FINISHED")
+                </script>
+            </state>
+        </scxml>
+    </class>
+</diagram>

+ 11 - 11
integration/test_powerwindow.py

@@ -176,10 +176,12 @@ class TestPowerWindow(unittest.TestCase):
         cb_query = get_function("models/query_model.mvc")
         cb_arch = get_function("models/architecture_model.mvc")
 
-        self.error_path = None
-
-        def got_path(path):
-            self.error_path = path
+        import log_output
+        error_path = []
+        ctrl = log_output.Controller(error_path, keep_running=False)
+        thrd = threading.Thread(target=ctrl.start)
+        thrd.daemon = True
+        thrd.start()
 
         callbacks = {
                 "models/revise_req": cb_req,
@@ -188,17 +190,15 @@ class TestPowerWindow(unittest.TestCase):
                 "models/revise_control": cb_ctrl,
                 "models/revise_query": cb_query,
                 "models/revise_architecture": cb_arch,
-                "models/bfs": got_path,
+                "models/bfs": (ctrl, "inp", "outp"),
             }
 
-        try:
-            process_execute("models/pm_powerwindow", "pm_", callbacks)
-        except:
-            import traceback
-            print(traceback.format_exc())
+        process_execute("models/pm_powerwindow", "pm_", callbacks)
+
+        thrd.join()
 
         if called != 11:
             print(called)
             raise Exception("Not executed sufficiently:" + str(called))
 
-        assert self.error_path != None
+        assert len(error_path) == 10

+ 6 - 1
models/bfs.alc

@@ -36,7 +36,12 @@ Boolean function bfs(model : Element):
 			// Found an error path!
 			log("Found error path!")
 			log(list_to_string(path))
-			output(list_to_string(path))
+			
+			Integer i
+			i = 0
+			while (i < list_len(path)):
+				output(list_read(path, i))
+				i = i + 1
 			break!
 
 		options = allOutgoingAssociationInstances(model, state, "ReachabilityGraph/Transition")

+ 26 - 18
wrappers/modelverse.py

@@ -387,9 +387,8 @@ def process_execute(process_name, prefix, callbacks=None):
 
     INPUT("process_execute", None, [process_name, prefix])
 
-    #TODO this is all pseudo-code
+    operation = OUTPUT()
     while 1:
-        operation = OUTPUT()
         print("Operation: " + str(operation))
         if isinstance(operation, (list, tuple)):
             t, name, context = operation
@@ -398,26 +397,35 @@ def process_execute(process_name, prefix, callbacks=None):
                 if name in callbacks:
                     callbacks[name](context)
                 INPUT("exit", context, [])
+                operation = OUTPUT()
             elif t == "SC":
                 if name in callbacks:
                     statechart = callbacks[name]
-                    while 1:
-                        empty = True
-
-                        # Fetch output from the MV
-                        response = responses.fetch(0)
-                        if response is not None:
-                            print("Got response from MV: " + str(response))
-                            if response.name == "data_output":
-                                # Got output of MV, so forward to SCCD
+                else:
+                    statechart = None
+
+                while 1:
+                    empty = True
+
+                    # Fetch output from the MV
+                    response = responses.fetch(0)
+                    if response is not None:
+                        print("Got response from MV: " + str(response))
+                        if response.name == "data_output":
+                            # Got output of MV, so forward to SCCD
+                            if statechart:
                                 statechart[0].addInput(Event("input", statechart[1], response.parameters))
-                            elif response.name == "result":
-                                # Finished execution, so continue and return result
+                        elif response.name == "result":
+                            # Finished execution, so continue and return result
+                            if statechart:
                                 statechart[0].addInput(Event("terminate", statechart[1], []))
-                                return response.parameters[1]
-                            empty = False
+                            # Break from the most inner loop
+                            operation = response.parameters[1]
+                            break
+                        empty = False
 
-                        # Fetch output from the SC
+                    # Fetch output from the SC
+                    if statechart:
                         response = sc_ports[name].fetch(0)
                         if response is not None:
                             print("Got response from SC: " + str(response))
@@ -425,8 +433,8 @@ def process_execute(process_name, prefix, callbacks=None):
                                 controller.addInput(Event("data_input", "action_in", [response.parameters, context]))
                             empty = False
 
-                        if empty:
-                            time.sleep(0.01)
+                    if empty:
+                        time.sleep(0.01)
         else:
             if operation == "Finished":
                 # Finished execution of the process, so exit