Module test
[hide private]
[frames] | no frames]

Source Code for Module test

  1  """ 
  2  Utilities for loading input files and generating and representing test cases. 
  3   
  4  Computer Systems Architecture Course 
  5  Assignment 1 
  6  March 2016 
  7  """ 
  8   
  9  import os 
 10  import re 
 11  from collections import namedtuple 
 12   
 13  # TestCase parameters, the same string as in the test* file format 
 14  TESTCASE_NAME = "name" 
 15  NUM_DEVICES = "num_nodes" 
 16  NUM_LOCATIONS = "num_locations" 
 17  NUM_SCRIPTS = "num_scripts" 
 18  DURATION = "duration" 
 19  TIMEOUT_PERIOD = "timeout" 
 20  SCRIPTS_DELAY = "scripts_delay" 
 21  SCRIPT_SLEEP = "script_sleep" 
 22  PARALLEL_SCRIPT = "parallel_script" 
 23  OVERLAP = "overlap" 
 24  GEN_SEED = "gen_seed" 
 25  RUN_SEED = "run_seed" 
 26  EXTRA_DURATION = "extra_duration" 
 27  SCRIPT_ASSIGNMENT = "script_assignment" 
 28  SCRIPT_ASSIGNMENT_RANDOM = "RANDOM" 
 29  SCRIPT_ASSIGNMENT_ALL = "ALL" 
 30  SCRIPT_ASSIGNMENT_SINGLE = "SINGLE" 
 31   
 32  Location = namedtuple("Location", ['id', 'sensor_data']) 
 33  Encounter = namedtuple("Encounter", ['time_point', 'devices']) 
 34  DeviceTestData = namedtuple("DeviceTestData", ['id', 'locations', 'encounters']) 
 35  ScriptTestData = namedtuple("ScriptTestData", ['time_point', 'device', 'location']) 
36 37 38 -class TestCase(object):
39 """ 40 Class representing a test case: various parameters and lists of devices and scripts. 41 """ 42
43 - def __init__(self):
44 45 self.name = None 46 self.num_locations = None 47 self.duration = None 48 self.scripts = None 49 self.devices = None 50 self.script_delay = None 51 self.script_sleep = None 52 self.parallel_script = None 53 self.timeout = None 54 self.num_iterations = None 55 self.crt_iteration = None
56 57 @staticmethod
59 """ 60 Creates a basic test case without using parameters provided in a test file. 61 62 @rtype: TestCase 63 @return: a TestCase object 64 """ 65 test_case = TestCase() 66 test_case.name = "Test 0" 67 test_case.script_delay = (0.5, 0.5) 68 test_case.parallel_script = False 69 test_case.duration = 1 70 test_case.extra_duration = 0 71 test_case.timeout = 4 72 test_case.num_locations = 2 73 dev0_loc0 = Location(id=0, sensor_data=42.0) 74 dev1_loc1 = Location(id=1, sensor_data=64.0) 75 dev0 = DeviceTestData(id=0, locations=[dev0_loc0], encounters=[]) 76 dev1 = DeviceTestData(id=1, locations=[dev1_loc1], encounters=[]) 77 test_case.devices = [dev0, dev1] 78 dev0_script0 = ScriptTestData(time_point=0, device=0, location=0) 79 dev1_script0 = ScriptTestData(time_point=0, device=1, location=1) 80 test_case.scripts = [dev0_script0, dev1_script0] 81 return test_case
82 83 @staticmethod
85 """ 86 Creates a stress test for shared data synchronization. 87 88 @rtype: TestCase 89 @return: a TestCase object 90 """ 91 test_case = TestCase() 92 test_case.name = "Test 9" 93 test_case.script_delay = (0.01, 0.01) 94 test_case.script_sleep = (0.01, 0.01) 95 test_case.parallel_script = True 96 test_case.duration = 3 97 test_case.extra_duration = 0 98 test_case.timeout = 7 99 test_case.num_locations = 2 100 locations = [Location(id=0, sensor_data=64.0) for i in range(98)] 101 locations.append(Location(id=0, sensor_data=100.0)) 102 locations.append(Location(id=0, sensor_data=42.0)) 103 test_case.devices = [DeviceTestData(id=i, locations=[locations[i]], encounters=[Encounter(time_point=1, devices=[99]), Encounter(time_point=2, devices=[98])]) for i in range(100)] 104 test_case.scripts = [ScriptTestData(time_point=0, device=i, location=0) for i in range(99)] 105 106 return test_case
107 108 @staticmethod
110 """ 111 Creates a stress test for shared data synchronization. 112 113 @rtype: TestCase 114 @return: a TestCase object 115 """ 116 test_case = TestCase() 117 test_case.name = "Test 10" 118 test_case.script_delay = (0, 0) 119 test_case.script_sleep = (0.05, 0.05) 120 test_case.parallel_script = False 121 test_case.duration = 3 122 test_case.extra_duration = 0 123 test_case.timeout = 12 124 test_case.num_locations = 2 125 locations = [Location(id=0, sensor_data=56.0) for i in range(58)] 126 locations.append(Location(id=0, sensor_data=73.0)) 127 locations.append(Location(id=0, sensor_data=50.0)) 128 test_case.devices = [DeviceTestData(id=i, locations=[locations[i]], encounters=[Encounter(time_point=1, devices=[59]), Encounter(time_point=2, devices=[58])]) for i in range(60)] 129 test_case.scripts = [ScriptTestData(time_point=0, device=i, location=0) for i in range(59)] 130 131 return test_case
132 133 @staticmethod
134 - def create_test_case(params, rand_gen):
135 """ 136 Creates a test case using the provided parameters. 137 @type params: TestParams 138 @param params: a TestCase specification 139 @type rand_gen: Random 140 @param rand_gen: a random generator used for creating the test case's components 141 @return: a TestCase object 142 """ 143 test_case = TestCase() 144 test_case.name = params.name 145 test_case.num_locations = params.num_locations 146 test_case.duration = params.duration 147 test_case.script_delay = params.script_delay 148 test_case.script_sleep = params.script_sleep 149 test_case.parallel_script = params.parallel_script 150 test_case.timeout = params.timeout 151 test_case.run_seed = params.run_seed 152 test_case.extra_duration = params.extra_duration 153 154 if params.gen_seed is not None: 155 rand_gen = random.Random(params.gen_seed) 156 157 test_case.generate_test_data(params, rand_gen) 158 159 return test_case
160
161 - def generate_test_data(self, params, rand_gen):
162 """ 163 Creates the elements of a test case: lists of devices, locations, encounters, scripts 164 @type params: TestParams 165 @param params: the test for which the elements are generated 166 @type rand_gen: Random 167 @param rand_gen: a random generator 168 """ 169 170 """ Create devices """ 171 172 # each location i has a list of indexes of devices 173 # i-th elem in locations corresponds to the i-th elem in devices_for_location 174 devices_for_locations = [None] * self.num_locations 175 176 if params.overlap == 1: # one location per device 177 178 # aka device i has location j 179 location_for_each_device = rand_gen.sample(xrange(self.num_locations), 180 params.num_devices) 181 182 location_for_each_device_as_list = [[Location(location_for_each_device[i], 183 rand_gen.randint(30, 100))] 184 for i in range(params.num_devices)] 185 self.devices = [DeviceTestData(i, location_for_each_device_as_list[i], []) 186 for i in range(params.num_devices)] 187 188 # aka location j has device j 189 for device_id in range(len(location_for_each_device)): 190 devices_for_locations[location_for_each_device[device_id]] = [device_id] 191 192 else: 193 self.devices = [DeviceTestData(i, [], []) for i in range(params.num_devices)] 194 195 # assign visited locations to devices 196 197 for i in range(self.num_locations): 198 num_devices = rand_gen.randint(1, params.overlap) 199 devices_for_locations[i] = rand_gen.sample(xrange(params.num_devices), num_devices) 200 201 for device in self.devices: 202 for i in range(len(devices_for_locations)): 203 if device.id in devices_for_locations[i]: 204 device.locations.append(Location(i, rand_gen.randint(30, 100))) 205 206 """ Create Scripts """ 207 208 if params.script_assignment == SCRIPT_ASSIGNMENT_SINGLE: 209 # all scripts use the same location (picked randomly) 210 location = rand_gen.randint(1, self.num_locations-1) 211 212 self.scripts = [ScriptTestData(rand_gen.randint(0, self.duration-1), 213 rand_gen.randint(0, params.num_devices-1), 214 location) for _ in range(params.num_scripts)] 215 216 if params.script_assignment == SCRIPT_ASSIGNMENT_RANDOM: 217 # scripts use a random location 218 self.scripts = [ScriptTestData(rand_gen.randint(0, self.duration-1), 219 rand_gen.randint(0, params.num_devices-1), 220 rand_gen.randint(0, self.num_locations-1)) 221 for _ in range(params.num_scripts)] 222 223 if params.script_assignment == SCRIPT_ASSIGNMENT_ALL: 224 # each script uses a different location 225 script_locations = rand_gen.sample(xrange(self.num_locations), params.num_scripts) 226 self.scripts = [ScriptTestData(rand_gen.randint(0, self.duration-1), 227 rand_gen.randint(0, params.num_devices-1), 228 script_locations[i]) 229 for i in range(params.num_scripts)] 230 231 self.scripts = sorted(self.scripts, key=lambda s: s.time_point) 232 233 """ Create encounters """ 234 235 for script in self.scripts: 236 loc = script.location 237 time = script.time_point 238 device = script.device 239 240 location_devices = devices_for_locations[loc] 241 encounters = [] 242 num_encouters = rand_gen.randint(1, self.duration+self.extra_duration-time) 243 244 set_of_unique_devices = set() 245 for i in range(num_encouters): 246 247 encountered_devices = rand_gen.sample(location_devices, 248 rand_gen.randint(1, len(location_devices)/2+1)) 249 set_of_unique_devices |= set(encountered_devices) 250 251 encounters.append(Encounter(time+i, encountered_devices)) 252 253 for dev in location_devices: 254 if dev not in set_of_unique_devices: 255 encounters[rand_gen.randint(0, len(encounters)-1)].devices.append(dev) 256 257 for d in self.devices: 258 if d.id == device: 259 d.encounters.extend(encounters) 260 break
261
262 # print "Locations: ", 263 # for loc in range(len(devices_for_locations)): 264 # print "%d:%s " % (loc, str(devices_for_locations[loc])), 265 # print 266 # 267 # for script in self.scripts: 268 # print script 269 # 270 # for encounter in sorted([e for dev in self.devices for e in dev.encounters], key=lambda e : e.time_point): 271 # print encounter, [d.id for d in self.devices if encounter in d.encounters] 272 # 273 # for dev in self.devices: 274 # print "DeviceTestData(id=", dev.id 275 # print "\tlocations=" 276 # for loc in dev.locations: 277 # print "\t\t", loc 278 # print "\tencounters=" 279 # for enc in dev.encounters: 280 # print "\t\t", enc 281 282 283 284 -class TestParams(object):
285 """ 286 Class representing the parameters of a test case, as specified in test input files. 287 """ 288
289 - def __init__(self, name="TestCase", num_devices=0, num_locations=0, num_scripts=0, 290 script_delay=None, script_sleep=None, parallel_script=False, timeout=0, duration=1, 291 overlap=1, gen_seed = None, run_seed = None, extra_duration = 0, script_assignment="RANDOM"):
292 self.name = name 293 self.num_devices = num_devices 294 self.num_locations = num_locations 295 self.num_scripts = num_scripts 296 self.script_delay = script_delay 297 self.script_sleep = script_sleep 298 self.parallel_script = parallel_script 299 self.timeout = timeout 300 self.duration = duration 301 self.overlap = overlap 302 self.gen_seed = gen_seed 303 self.run_seed = run_seed 304 self.extra_duration = extra_duration 305 self.script_assignment = script_assignment
306 307 @staticmethod
308 - def load_test(filename):
309 """ 310 Loads the test description from a file with the following format: 311 312 param_name1 = value 313 param_name2 = value 314 [...] 315 316 Blank lines or lines starting with # (comments) are ignored 317 318 Parameter names are defined in this class. Parameters can be 319 declared in any order in the file. 320 321 @type filename: str 322 @param filename: the test file 323 @return: a TestCase object 324 """ 325 params_names = [NUM_DEVICES, TESTCASE_NAME, NUM_LOCATIONS, NUM_SCRIPTS, 326 DURATION, TIMEOUT_PERIOD, SCRIPTS_DELAY, 327 PARALLEL_SCRIPT, OVERLAP, SCRIPT_ASSIGNMENT, SCRIPT_SLEEP, GEN_SEED, RUN_SEED, EXTRA_DURATION] 328 329 test_params = dict.fromkeys(params_names, 0) 330 331 test_name, num_devices, num_locations, num_scripts = None, None, None, None 332 timeout, scripts_delay, duration, overlap, script_assignment = None, None, None, None, None 333 parallel_script, script_sleep, gen_seed, run_seed, extra_duration = None, None, None, None, 0 334 335 try: 336 with open(filename, "r") as test_file: 337 for line in test_file: 338 line = line.strip() 339 if len(line) == 0 or line.startswith('#'): 340 continue 341 342 parts = [i.strip() for i in re.split("=", line)] 343 if len(parts) != 2: 344 raise StandardError("Wrong test file format") 345 346 if parts[0] not in test_params: 347 raise StandardError("Wrong parameter name: %s" % parts[0]) 348 349 elif parts[0] == TESTCASE_NAME: 350 test_name = parts[1] 351 elif parts[0] == NUM_DEVICES: 352 num_devices = int(parts[1]) 353 elif parts[0] == NUM_LOCATIONS: 354 num_locations = int(parts[1]) 355 elif parts[0] == NUM_SCRIPTS: 356 num_scripts = int(parts[1]) 357 elif parts[0] == SCRIPT_SLEEP: 358 if len(parts[1].split(",")) != 2: 359 raise StandardError("Wrong format for specifying output" 360 + "script sleep : %s" % parts[1]) 361 script_sleep = (float(parts[1].split(",")[0].strip()), 362 float(parts[1].split(",")[1].strip())) 363 elif parts[0] == PARALLEL_SCRIPT: 364 parallel_script = bool(parts[1]) 365 elif parts[0] == SCRIPTS_DELAY: 366 if len(parts[1].split(",")) != 2: 367 raise StandardError("Wrong format for specifying output" 368 + "scripts delay : %s" % parts[1]) 369 script_delay = (float(parts[1].split(",")[0].strip()), 370 float(parts[1].split(",")[1].strip())) 371 elif parts[0] == DURATION: 372 duration = int(parts[1]) 373 elif parts[0] == TIMEOUT_PERIOD: 374 timeout = int(parts[1]) 375 elif parts[0] == OVERLAP: 376 overlap = int(parts[1]) 377 elif parts[0] == GEN_SEED: 378 gen_seed = int(parts[1]) 379 elif parts[0] == RUN_SEED: 380 run_seed = int(parts[1]) 381 elif parts[0] == EXTRA_DURATION: 382 extra_duration = int(parts[1]) 383 elif parts[0] == SCRIPT_ASSIGNMENT: 384 if parts[1] not in [SCRIPT_ASSIGNMENT_ALL, SCRIPT_ASSIGNMENT_RANDOM, 385 SCRIPT_ASSIGNMENT_SINGLE]: 386 raise StandardError("Wrong script assignment type %s"%parts[1]) 387 script_assignment = parts[1] 388 389 # some basic validation 390 if script_assignment == SCRIPT_ASSIGNMENT_ALL and num_scripts > num_locations: 391 raise StandardError("Too many scripts (%d) for the given locations (%d)" 392 % (num_scripts, num_locations)) 393 if overlap > num_devices: 394 raise StandardError("Too many devices for the overlap parameter %d" % overlap) 395 if overlap == 1 and num_locations != num_devices: 396 raise StandardError("When overlap is %d, the number of locations must be equal\ 397 to the number of devices" % overlap) 398 399 except StandardError, err: 400 print err 401 os.abort() 402 403 return (TestParams(name=test_name, 404 num_devices=num_devices, 405 num_locations=num_locations, 406 num_scripts=num_scripts, 407 script_delay=script_delay, 408 script_sleep=script_sleep, 409 parallel_script=parallel_script, 410 timeout=timeout, 411 duration=duration, 412 overlap=overlap, 413 gen_seed=gen_seed, 414 run_seed=run_seed, 415 extra_duration=extra_duration, 416 script_assignment=script_assignment))
417
418 - def __str__(self):
419 # TODO this is missing some fields 420 return "{} devices\n{} locations\n{} scripts\n{}s timeout\n{}s duration\n" \ 421 "{}s min script delay\n{}s max script delay\n" \ 422 "max {} device per location\n{} script assignment".format(self.num_devices, 423 self.num_locations, 424 self.num_scripts, 425 self.timeout, 426 self.duration, 427 self.script_delay[0], 428 self.script_delay[1], 429 self.overlap, 430 self.script_assignment)
431 432 if __name__ == "__main__": 433 params = TestParams.load_test("../tests/test1") 434 print params 435 import random 436 TestCase.create_test_case(params, random.Random()) 437