Implement per-test timeout guard

Timeout value can be specified by test in suite.conf:

config:
  suite:
    <suite_name>:
      <test_name>:
        timeout: 2 # 2 seconds timeout

Change-Id: I522f51f77f8be64ebfdb5d5e07ba92baf82d7706
diff --git a/src/osmo_gsm_tester/core/suite.py b/src/osmo_gsm_tester/core/suite.py
index 9b9062d..938471c 100644
--- a/src/osmo_gsm_tester/core/suite.py
+++ b/src/osmo_gsm_tester/core/suite.py
@@ -44,6 +44,8 @@
         self.suite_dir = suite_dir
         self.conf = None
         self._schema = None
+        self.test_basenames = []
+        self.load_test_basenames()
         self.read_conf()
 
     def read_conf(self):
@@ -54,13 +56,16 @@
                                              SuiteDefinition.CONF_FILENAME))
         # Drop schema part since it's dynamically defining content, makes no sense to validate it.
         self._schema = self.conf.pop('schema', {})
+        # Add per-test 'timeout' attribute:
+        d = {t.rstrip('.py'):{'timeout': schema.DURATION} for t in self.test_basenames}
+        schema.combine(self._schema, d)
+        # Convert config file format to proper schema format and register it:
         sdef = schema.config_to_schema_def(self._schema, "%s." % self._suite_name)
         schema.register_config_schema('suite', sdef)
+        # Finally validate the file:
         schema.validate(self.conf, schema.get_all_schema())
-        self.load_test_basenames()
 
     def load_test_basenames(self):
-        self.test_basenames = []
         for basename in sorted(os.listdir(self.suite_dir)):
             if not basename.endswith('.py'):
                 continue