From da26b0987d3b6a009be2c04d7f59e2cf0b4c01c3 Mon Sep 17 00:00:00 2001
From: Mikael Salson <mikael.salson@univ-lille1.fr>
Date: Tue, 12 Feb 2019 17:36:21 +0100
Subject: [PATCH 1/3] should.py: Add parameter to set timeout

It will be easier to test the timeout if we can customize it.
---
 src/should.py | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/should.py b/src/should.py
index 9613a55..eefb28b 100755
--- a/src/should.py
+++ b/src/should.py
@@ -222,6 +222,7 @@ for p in (parser, options):
     p.add_argument('--extra', metavar='ARG', default='', help='extra argument after the first word of each command (or replacing %s)' % VAR_EXTRA)
     p.add_argument('--mod', metavar='MODIFIERS', action='append', help='global ' + parser_mod.help)
     p.add_argument('--var', metavar='NAME=value', action='append', help='variable definition (then use $NAME in .should files)')
+    p.add_argument('--timeout', type=int, default = TIMEOUT, help = 'Delay (in seconds) after which the task is stopped (default: %(default)d)')
 
 parser.add_argument('--shuffle', action='store_true', help='shuffle the tests')
 
@@ -631,7 +632,7 @@ class TestSuite():
     ok - Exit code is 0
     '''
 
-    def __init__(self, modifiers = '', cd = None, name = ''):
+    def __init__(self, modifiers = '', cd = None, name = '', timeout = TIMEOUT):
         self.name = name
         self.requires = True
         self.requires_cmd = None
@@ -650,6 +651,7 @@ class TestSuite():
         self.use_launcher = True
         self.expected_exit_code = 0
         self.elapsed_time = None
+        self.timeout = timeout
 
     def load(self, should_lines):
         name = ''
@@ -785,11 +787,11 @@ class TestSuite():
                              close_fds=True)
 
         try:
-            self.exit_code = p.wait(TIMEOUT)
+            self.exit_code = p.wait(self.timeout)
             self.tests.append(ExternalTestCase('Exit code is %d' % self.expected_exit_code, self.exit_code == self.expected_exit_code, str(self.exit_code)))
         except subprocess.TimeoutExpired:
             self.exit_code = None
-            self.tests.append(ExternalTestCase('Exit code is %d' % self.expected_exit_code, SKIP, 'timeout after %s seconds' % TIMEOUT))
+            self.tests.append(ExternalTestCase('Exit code is %d' % self.expected_exit_code, SKIP, 'timeout after %s seconds' % self.timeout))
 
         f_stdout.seek(0)
         f_stderr.seek(0)
@@ -886,13 +888,14 @@ class TestSuite():
 
 class FileSet():
 
-    def __init__(self, files, modifiers = ''):
+    def __init__(self, files, modifiers = '', timeout = TIMEOUT):
         self.files = files
         self.sets = []
         self.modifiers = modifiers
         self.status = None
         self.stats = Stats('file')
         self.stats_tests = Stats('test')
+        self.timeout = timeout
 
     def __len__(self):
         return len(self.files)
@@ -905,7 +908,7 @@ class FileSet():
             if verbose > 0:
                 print(f)
             cd_f = os.path.dirname(f) if cd_same else cd
-            s = TestSuite(self.modifiers, cd_f, name = f)
+            s = TestSuite(self.modifiers, cd_f, name = f, timeout = self.timeout)
             self.sets.append(s)
             s.load(open(f))
 
@@ -1023,7 +1026,7 @@ if __name__ == '__main__':
         print("Shuffling test files")
         random.shuffle(args.file)
 
-    fs = FileSet(args.file, modifiers=''.join(args.mod if args.mod else []))
+    fs = FileSet(args.file, timeout = args.timeout, modifiers=''.join(args.mod if args.mod else []))
     status = fs.test(variables = variables, cd = args.cd, cd_same = args.cd_same, output = args.output, verbose = args.verbose)
 
     if len(fs) > 1:
-- 
GitLab


From 0d121a19950c6ea90d958d4aaa8506aa63751fc9 Mon Sep 17 00:00:00 2001
From: Mikael Salson <mikael.salson@univ-lille1.fr>
Date: Tue, 12 Feb 2019 17:43:42 +0100
Subject: [PATCH 2/3] demo: Test for #25

---
 demo/kill-on-timeout.should | 14 ++++++++++++++
 demo/tests/timeout.should   |  6 ++++++
 2 files changed, 20 insertions(+)
 create mode 100644 demo/kill-on-timeout.should
 create mode 100644 demo/tests/timeout.should

diff --git a/demo/kill-on-timeout.should b/demo/kill-on-timeout.should
new file mode 100644
index 0000000..7688c32
--- /dev/null
+++ b/demo/kill-on-timeout.should
@@ -0,0 +1,14 @@
+# when task takes too many time it should be killed by should.py
+
+./should --timeout 1 demo/tests/timeout.should
+# Check that the script is not running anymore
+ps awux | grep  'seq 1 10.*sleep' | grep -v grep || echo "not found"
+
+$ The task must time out
+1: timeout after
+
+$ The elapsed time must be close to the timeout
+r1:^1.[0-9]+s
+
+$ The task must not run anymore
+1:not found
diff --git a/demo/tests/timeout.should b/demo/tests/timeout.should
new file mode 100644
index 0000000..d7276cf
--- /dev/null
+++ b/demo/tests/timeout.should
@@ -0,0 +1,6 @@
+
+for i in `seq 1 10`; do sleep .5s; done
+echo $i
+
+$ The variable should reach its final value
+1:10
-- 
GitLab


From 09a701c86f6f975e12525bd4fca871f46b352cfe Mon Sep 17 00:00:00 2001
From: Mikael Salson <mikael.salson@univ-lille1.fr>
Date: Tue, 12 Feb 2019 17:43:59 +0100
Subject: [PATCH 3/3] should.py: Kill process on timeout

Fix #25
---
 src/should.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/should.py b/src/should.py
index eefb28b..864ed9a 100755
--- a/src/should.py
+++ b/src/should.py
@@ -792,6 +792,7 @@ class TestSuite():
         except subprocess.TimeoutExpired:
             self.exit_code = None
             self.tests.append(ExternalTestCase('Exit code is %d' % self.expected_exit_code, SKIP, 'timeout after %s seconds' % self.timeout))
+            p.kill()
 
         f_stdout.seek(0)
         f_stderr.seek(0)
-- 
GitLab