1
2
3 """
4 Testing infrastructure - generates and executes tests
5
6 Computer Systems Architecture Course
7 Assignment 1
8 March 2016
9 """
10 import getopt
11 import os
12 import pickle
13 import random
14 import subprocess
15 import sys
16 from threading import Timer
17
18 from supervisor import Supervisor
19 from test import TestCase, TestParams
20
21
22 START_TEST_MSG = "**************** Start %10s *****************"
23 END_TEST_MSG = "***************** End %10s ******************"
24 TEST_ERRORS_MSG = "Errors in iteration %d of %d:"
25 TEST_FINISHED_MSG = "%-10s finished.................%d%% completed"
26 TIMEOUT_MSG = "%-10s timeout..................%d%% completed"
29 """
30 Runs the test.
31 """
33 """
34 Constructor.
35 @type output_filename: String
36 @param output_filename: the file in which the tester logs results
37 """
38 self.output_filename = output_filename
39
40 self.passed_tests = 0
41
42 self.rand_gen = random.Random()
43 self.rand_gen.seed(0)
44
45 - def run_test(self, testcase, num_iterations=1):
46 """
47 Performs a testcase generated from a given file or randomly.
48 To better check for synchronization errors the testcase is run several
49 times, as given by the 'num_iterations' parameter.
50 @type testcase: TestCase
51 @param testcase: the testcase to run
52 @type num_iterations: Integer
53 @param num_iterations: number of time to run the test
54 """
55 print START_TEST_MSG % testcase.name
56
57 self.passed_tests = 0
58
59 testcase.num_iterations = num_iterations
60 for i in range(num_iterations):
61 print TEST_ERRORS_MSG % (i + 1, num_iterations)
62 testcase.crt_iteration = i + 1
63 if self.start_test(testcase) == 0:
64 self.passed_tests += 1
65 print "No errors"
66
67 print END_TEST_MSG % testcase.name
68
69 out_file = open(self.output_filename, "a")
70
71 msg = TEST_FINISHED_MSG % (testcase.name, 100.0 * self.passed_tests / num_iterations)
72
73 out_file.write(msg + "\n")
74 out_file.close()
75
76 @staticmethod
77 - def timer_fn(iteration, num_iterations):
78 """
79 Timer function, it's executed in case of timeout when running a testcase
80 @type iteration: integer
81 @param iteration: the current iteration of the given testcase
82 @type num_iterations: integer
83 @param num_iterations: the total number of iterations for the given testcase
84 """
85 print >> sys.stderr, "timeout"
86
87 os.abort()
88
90 """
91 Starts a child process that will run the test case.
92
93 @type test: TestCase
94 @param test: an object containing all the information necessary for
95 running the test case
96 """
97 path = os.path.dirname(sys.argv[0])
98 path = "." if path == "" else path
99 command = "python %s/tester.py" % path
100 test = pickle.dumps(test)
101 process = subprocess.Popen(command, stdin=subprocess.PIPE, shell=True)
102 process.communicate(test)
103
104 return process.returncode
105
108 print "Usage: python %s [OPTIONS]"%argv[0]
109 print "options:"
110 print "\t-t, --test\tspecial test to run"
111 print "\t-f, --testfile\ttest file, if not specified run a pickled test from stdin"
112 print "\t-o, --out\t\toutput file"
113 print "\t-i, --iterations\t\tthe number of times the test is run (iterations), defaults to 2"
114 print "\t-h, --help\t\tprint this help screen"
115
118 try:
119 opts, _ = getopt.getopt(sys.argv[1:], "h:t:f:o:i:",
120 ["help", "--test", "testfile=", "out=", "iterations="])
121
122 except getopt.GetoptError, err:
123 print str(err)
124 usage(sys.argv)
125 sys.exit(2)
126
127 test_name = None
128 test_file = ""
129 iterations = 2
130 output_file = "tester.out"
131
132 for opt, arg in opts:
133 if opt in ("-h", "--help"):
134 usage(sys.argv)
135 sys.exit(0)
136 elif opt in ("-t", "--test"):
137 test_name = arg
138 elif opt in ("-f", "--testfile"):
139 test_file = arg
140 elif opt in ("-o", "--out"):
141 output_file = arg
142 elif opt in ("-i", "--iterations"):
143 try:
144 iterations = int(arg)
145 except TypeError, err:
146 print str(err)
147 sys.exit(2)
148 else:
149 assert False, "unhandled option"
150
151 if test_name == "test0":
152 tester = Tester(output_file)
153 test = TestCase.create_simple_test_case()
154 tester.run_test(test, iterations)
155 elif test_name == "test9":
156 tester = Tester(output_file)
157 test = TestCase.create_sharing1_test_case()
158 tester.run_test(test, iterations)
159 elif test_name == "test10":
160 tester = Tester(output_file)
161 test = TestCase.create_sharing2_test_case()
162 tester.run_test(test, iterations)
163 elif test_file:
164 tester = Tester(output_file)
165 test_params = TestParams.load_test(test_file)
166 test = TestCase.create_test_case(test_params, tester.rand_gen)
167 tester.run_test(test, iterations)
168
169 else:
170 test = pickle.loads("".join(sys.stdin.readlines()))
171
172 watchdog = Timer(interval=test.timeout,
173 function=Tester.timer_fn,
174 args=(test.crt_iteration, test.num_iterations))
175
176 watchdog.start()
177
178 supervisor = Supervisor(test)
179 supervisor.register_banned_thread(watchdog)
180 supervisor.register_banned_thread()
181 return_code = supervisor.run_testcase()
182
183 watchdog.cancel()
184
185 sys.stdout.flush()
186 sys.stderr.flush()
187 sys.exit(return_code)
188
189
190 if __name__ == "__main__":
191 main()
192