Home | History | Annotate | Download | only in Util
      1 # -*-coding:utf-8 -*
      2 
      3 # Copyright (c) 2011-2015, Intel Corporation
      4 # All rights reserved.
      5 #
      6 # Redistribution and use in source and binary forms, with or without modification,
      7 # are permitted provided that the following conditions are met:
      8 #
      9 # 1. Redistributions of source code must retain the above copyright notice, this
     10 # list of conditions and the following disclaimer.
     11 #
     12 # 2. Redistributions in binary form must reproduce the above copyright notice,
     13 # this list of conditions and the following disclaimer in the documentation and/or
     14 # other materials provided with the distribution.
     15 #
     16 # 3. Neither the name of the copyright holder nor the names of its contributors
     17 # may be used to endorse or promote products derived from this software without
     18 # specific prior written permission.
     19 #
     20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     21 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     22 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     23 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     24 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     27 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 import os
     32 import subprocess
     33 import unittest
     34 import time
     35 import socket
     36 
     37 class RemoteCli(object):
     38 
     39     def setRemoteProcess(self, remoteProcess):
     40         self.remoteProcess = remoteProcess
     41 
     42     def sendCmd(self, cmd, *args, **kwargs):
     43         """ Execute a remote-process command and assert its result.
     44             @param[in] cmd, *args the command to execute and its arguments
     45             @param[in] expectSuccess If True, assert that the command will succeed
     46                                      If False, assert that the command will succeed
     47                                      If None, do not assert result
     48                                      Default to True
     49             @return (command stdout, None) None is return for legacy reason
     50         """
     51         expectSuccess=kwargs.get("expectSuccess", True)
     52 
     53         assert self.remoteProcess.poll() == None, "Can not send command to Test platform as it has died. Return code: %s" % self.remoteProcess.returncode
     54 
     55         sys_cmd = self.platform_command + [cmd]
     56         if args is not None:
     57             sys_cmd += args
     58         print "CMD  : %s" % sys_cmd
     59 
     60         try:
     61             p = subprocess.Popen(sys_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     62         except Exception as (errno, strerror):
     63             return None, strerror
     64         out, err = p.communicate()
     65         out = out.rstrip('\r\n')
     66 
     67         if (expectSuccess != None):
     68             assert (p.returncode == 0) == expectSuccess, "Unexpected command result:\nexpectedSuccess=%s\nCMD=%s\nreturncode=%s\nstdout=%s\nstderr=%s" % (expectSuccess, sys_cmd, p.returncode, out, err)
     69 
     70         return out, None
     71 
     72 class Pfw(RemoteCli):
     73     platform_command = ["remote-process", "localhost", "5000"]
     74 
     75 class Hal(RemoteCli):
     76     # Arbitrary choosen port, try to avoid conflicting with IANA registered ports
     77     testPlatformPort = 18444
     78     platform_command = ["remote-process", "localhost", str(testPlatformPort)]
     79 
     80     def __init__(self, pfw):
     81         self.pfw = pfw
     82 
     83     # Starts the HAL exe
     84     def startHal(self):
     85         cmd= ["test-platform", os.environ["PFW_TEST_CONFIGURATION"], str(self.testPlatformPort)]
     86         self.setRemoteProcess(subprocess.Popen(cmd))
     87         # Wait for the test-platform listening socket
     88         while socket.socket().connect_ex(("localhost", self.testPlatformPort)) != 0:
     89             assert self.remoteProcess.poll() == None, "Test platform has failed to start. Return code: %s" % self.remoteProcess.returncode
     90             time.sleep(0.01)
     91 
     92     # Send command "stop" to the HAL
     93     def stopHal(self):
     94         try:
     95             self.sendCmd("exit")
     96         except Exception as exitEx:
     97             # Kill test-platform as cooperative exit failed
     98             try:
     99                 self.remoteProcess.terminate()
    100             except Exception as killEx:
    101                 raise Exception("Fail to terminate after a exit request failed", exitEx, killEx)
    102             raise
    103         else:
    104             # exit request accepted, wait for server to stop
    105             returncode = self.remoteProcess.wait()
    106             assert returncode == 0, "test-platform did not stop succesfully: %s" % returncode
    107 
    108     def createInclusiveCriterion(self, name, nb):
    109         self.sendCmd("createInclusiveSelectionCriterion", name, nb)
    110 
    111     def createExclusiveCriterion(self, name, nb):
    112         self.sendCmd("createExclusiveSelectionCriterion", name, nb)
    113 
    114     # Starts the Pfw
    115     def start(self):
    116         self.sendCmd("setSchemaUri", os.environ["PFW_SCHEMAS"])
    117         self.sendCmd("setValidateSchemasOnStart", "true")
    118         self.sendCmd("start")
    119         self.pfw.setRemoteProcess(self.remoteProcess)
    120 
    121 # A PfwTestCase gather tests performed on one instance of the PFW.
    122 class PfwTestCase(unittest.TestCase):
    123 
    124     pfw = Pfw()
    125     hal = Hal(pfw)
    126 
    127     @classmethod
    128     def setUpClass(cls):
    129         cls.startHal()
    130 
    131     @classmethod
    132     def tearDownClass(cls):
    133         cls.stopHal()
    134 
    135     @classmethod
    136     def startHal(cls):
    137         # set up the Hal & pfw
    138         cls.hal.startHal()
    139         try:
    140             # create criterions
    141             cls.hal.createInclusiveCriterion("Crit_0", "2")
    142             cls.hal.createExclusiveCriterion("Crit_1", "2")
    143             # start the Pfw
    144             cls.hal.start()
    145         except Exception as startE:
    146             # Leave the hal stopped in case of start failure
    147             try:
    148                 cls.stopHal()
    149             except Exception as stopE:
    150                 raise Exception("Fail to stop after a failed start: ", startE, stopE)
    151             raise
    152 
    153     @classmethod
    154     def stopHal(cls):
    155         cls.hal.stopHal()
    156