1 #!/usr/bin/env ./Shell.py
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2006 The Trustees of Princeton University
8 # $Id: Test.py,v 1.10 2006/10/16 21:57:28 mlhuang Exp $
11 from pprint import pprint
12 from string import letters, digits, punctuation
17 from random import Random
20 def randfloat(min = 0.0, max = 1.0):
21 return float(min) + (random.random() * (float(max) - float(min)))
23 def randint(min = 0, max = 1):
24 return int(randfloat(min, max + 1))
26 # See "2.2 Characters" in the XML specification:
28 # #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
30 # [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF]
32 low_xml_chars = map(unichr, [0x9, 0xA, 0xD])
33 low_xml_chars += map(unichr, xrange(0x20, 0x7F - 1))
34 low_xml_chars += map(unichr, xrange(0x84 + 1, 0x86 - 1))
35 low_xml_chars += map(unichr, xrange(0x9F + 1, 0xFF))
36 valid_xml_chars = list(low_xml_chars)
37 valid_xml_chars += map(unichr, xrange(0xFF + 1, 0xD7FF))
38 valid_xml_chars += map(unichr, xrange(0xE000, 0xFDD0 - 1))
39 valid_xml_chars += map(unichr, xrange(0xFDDF + 1, 0xFFFD))
41 def randstr(length, pool = valid_xml_chars, encoding = "utf-8"):
42 sample = random.sample(pool, min(length, len(pool)))
45 bytes = len(s.encode(encoding))
49 sample += random.sample(pool, min(length - bytes, len(pool)))
50 random.shuffle(sample)
56 # 1. Each part begins and ends with a letter or number.
57 # 2. Each part except the last can contain letters, numbers, or hyphens.
58 # 3. Each part is between 1 and 64 characters, including the trailing dot.
59 # 4. At least two parts.
60 # 5. Last part can only contain between 2 and 6 letters.
61 hostname = 'a' + randstr(61, letters + digits + '-') + '1.' + \
62 'b' + randstr(61, letters + digits + '-') + '2.' + \
63 'c' + randstr(5, letters)
66 def unicmp(a, b, encoding = "utf-8"):
68 When connected directly to the DB, values are returned as raw
69 8-bit strings that may need to be decoded (as UTF-8 by default) in
70 order to compare them against expected Python Unicode strings.
73 is8bit = re.compile("[\x80-\xff]").search
74 if isinstance(a, str) and is8bit(a):
75 a = unicode(a, encoding)
76 if isinstance(b, str) and is8bit(b):
77 b = unicode(b, encoding)
80 admin = {'AuthMethod': "capability",
81 'Username': config.PLC_API_MAINTENANCE_USER,
82 'AuthString': config.PLC_API_MAINTENANCE_PASSWORD,
85 user = {'AuthMethod': "password",
88 pi = {'AuthMethod': "password",
91 tech = {'AuthMethod': "password",
98 abbreviated_name = randstr(50)
99 login_base = randstr(20, letters).lower()
100 latitude = int(randfloat(-90.0, 90.0) * 1000) / 1000.0
101 longitude = int(randfloat(-180.0, 180.0) * 1000) / 1000.0
104 print "AddSite(%s)" % login_base,
105 site_id = AddSite(admin, name, abbreviated_name, login_base,
106 {'latitude': latitude, 'longitude': longitude})
108 # Should return a unique site_id
109 assert site_id not in site_ids
110 site_ids.append(site_id)
114 print "GetSites(%d)" % site_id,
115 site = GetSites(admin, [site_id])[0]
116 for key in 'name', 'abbreviated_name', 'login_base', 'latitude', 'longitude', 'site_id':
117 assert unicmp(site[key], locals()[key])
122 abbreviated_name = randstr(50)
123 latitude = int(randfloat(-90.0, 90.0) * 1000) / 1000.0
124 longitude = int(randfloat(-180.0, 180.0) * 1000) / 1000.0
126 print "UpdateSite(%s)" % login_base,
127 UpdateSite(admin, site_id, {'name': name, 'abbreviated_name': abbreviated_name,
128 'latitude': latitude, 'longitude': longitude,
129 'max_slices': max_slices})
130 site = GetSites(admin, [site_id])[0]
131 for key in 'name', 'abbreviated_name', 'latitude', 'longitude', 'max_slices':
132 assert unicmp(site[key], locals()[key])
136 sites = GetSites(admin, site_ids)
137 assert set(site_ids) == set([site['site_id'] for site in sites])
141 roles = GetRoles(admin)
142 role_ids = [role['role_id'] for role in roles]
143 roles = [role['name'] for role in roles]
144 roles = dict(zip(roles, role_ids))
149 for auth in user, pi, tech:
150 first_name = randstr(128)
151 last_name = randstr(128)
152 # 119 + 1 + 64 + 64 + 6 = 254
153 email = (randstr(119, letters + digits) + "@" + randhostname()).lower()
155 # Accounts are disabled by default
158 auth['Username'] = email
159 auth['AuthString'] = randstr(254)
162 print "AddPerson(%s)" % email,
163 person_id = AddPerson(admin, first_name, last_name,
164 {'email': email, 'bio': bio,
165 'password': auth['AuthString']})
167 # Should return a unique person_id
168 assert person_id not in person_ids
169 person_ids.append(person_id)
170 print "=>", person_id
173 print "GetPersons(%d)" % person_id,
174 person = GetPersons(admin, [person_id])[0]
175 for key in 'first_name', 'last_name', 'email', 'bio', 'person_id', 'enabled':
176 assert unicmp(person[key], locals()[key])
180 first_name = randstr(128)
181 last_name = randstr(128)
183 print "UpdatePerson(%d)" % person_id,
184 UpdatePerson(admin, person_id, {'first_name': first_name,
185 'last_name': last_name,
189 # Check account again
190 person = GetPersons(admin, [person_id])[0]
191 for key in 'first_name', 'last_name', 'email', 'bio':
192 assert unicmp(person[key], locals()[key])
194 # Check that account is really disabled
196 assert not AuthCheck(auth)
201 role_id = roles[auth['Role']]
202 print "AddRoleToPerson(%d, %d)" % (role_id, person_id),
203 AddRoleToPerson(admin, role_id, person_id)
204 person = GetPersons(admin, [person_id])[0]
205 assert [role_id] == person['role_ids']
209 UpdatePerson(admin, person_id, {'enabled': True})
211 # Check authentication
212 print "AuthCheck(%s)" % auth['Username'],
213 assert AuthCheck(auth)
216 # Associate account with each site
217 for site_id in site_ids:
218 print "AddPersonToSite(%d, %d)" % (person_id, site_id),
219 AddPersonToSite(admin, person_id, site_id)
222 # Make sure it really did it
223 person = GetPersons(admin, [person_id])[0]
224 person_site_ids = person['site_ids']
225 assert set(site_ids) == set(person['site_ids'])
227 # First site should be the primary site
228 print "SetPersonPrimarySite(%d, %d)" % (person_id, person_site_ids[1]),
229 SetPersonPrimarySite(auth, person_id, person_site_ids[1])
230 person = GetPersons(admin, [person_id])[0]
231 assert person['site_ids'][0] == person_site_ids[1]
235 persons = GetPersons(admin, person_ids)
236 assert set(person_ids) == set([person['person_id'] for person in persons])
237 print "=>", person_ids
243 description = randstr(200)
246 print "AddNodeGroup",
247 nodegroup_id = AddNodeGroup(admin, name, {'description': description})
249 # Should return a unique nodegroup_id
250 assert nodegroup_id not in nodegroup_ids
251 nodegroup_ids.append(nodegroup_id)
252 print "=>", nodegroup_id
255 print "GetNodeGroups(%d)" % nodegroup_id,
256 nodegroup = GetNodeGroups(admin, [nodegroup_id])[0]
257 for key in 'name', 'description', 'nodegroup_id':
258 assert unicmp(nodegroup[key], locals()[key])
262 name = randstr(16, letters + ' ' + digits)
263 description = randstr(200)
264 print "UpdateNodeGroup",
265 UpdateNodeGroup(admin, nodegroup_id, {'name': name, 'description': description})
268 # Check node group again
269 nodegroup = GetNodeGroups(admin, [nodegroup_id])[0]
270 for key in 'name', 'description', 'nodegroup_id':
271 assert unicmp(nodegroup[key], locals()[key])
273 print "GetNodeGroups",
274 nodegroups = GetNodeGroups(admin, nodegroup_ids)
275 assert set(nodegroup_ids) == set([nodegroup['nodegroup_id'] for nodegroup in nodegroups])
276 print "=>", nodegroup_ids
280 for site_id in site_ids:
282 hostname = randhostname()
287 print "AddNode(%s)" % hostname,
288 node_id = AddNode(admin, site_id, hostname,
289 {'boot_state': boot_state, 'model': model})
291 # Should return a unique node_id
292 assert node_id not in node_ids
293 node_ids.append(node_id)
297 print "GetNodes(%d)" % node_id,
298 node = GetNodes(admin, [node_id])[0]
299 for key in 'hostname', 'boot_state', 'model', 'node_id':
300 assert unicmp(node[key], locals()[key])
304 hostname = randhostname()
306 print "UpdateNode(%d)" % node_id,
307 UpdateNode(admin, node_id, {'hostname': hostname, 'model': model})
311 node = GetNodes(admin, [node_id])[0]
312 for key in 'hostname', 'boot_state', 'model', 'node_id':
313 assert unicmp(node[key], locals()[key])
316 for nodegroup_id in nodegroup_ids:
317 print "AddNodeToNodeGroup(%d, %d)" % (nodegroup_id, node_id),
318 AddNodeToNodeGroup(admin, nodegroup_id, node_id)
322 nodes = GetNodes(admin, node_ids)
323 assert set(node_ids) == set([node['node_id'] for node in nodes])
326 print "GetNodeGroups",
327 nodegroups = GetNodeGroups(admin, nodegroup_ids)
328 for nodegroup in nodegroups:
329 assert set(nodegroup['node_ids']) == set(node_ids)
334 for node_id in node_ids:
335 ip = randint(0, 0xffffffff)
336 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
337 network = ip & netmask
338 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
339 gateway = randint(network + 1, broadcast - 1)
340 dns1 = randint(0, 0xffffffff)
341 bwlimit = randint(500000, 10000000)
343 for method in 'static', 'dhcp':
344 optional = {'bwlimit': bwlimit}
345 if method == 'static':
346 for key in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
347 optional[key] = socket.inet_ntoa(struct.pack('>L', locals()[key]))
350 print "AddNodeNetwork(%s)" % method,
351 nodenetwork_id = AddNodeNetwork(admin, node_id, method, 'ipv4', optional)
353 # Should return a unique nodenetwork_id
354 assert nodenetwork_id not in nodenetwork_ids
355 nodenetwork_ids.append(nodenetwork_id)
356 print "=>", nodenetwork_id
359 print "GetNodeNetworks(%d)" % nodenetwork_id,
360 nodenetwork = GetNodeNetworks(admin, [nodenetwork_id])[0]
361 if method == 'static':
362 for key in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
363 address = struct.unpack('>L', socket.inet_aton(nodenetwork[key]))[0]
364 assert address == locals()[key]
367 # Update node network
368 optional = {'bwlimit': bwlimit}
369 if nodenetwork['method'] == 'static':
370 for key in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
371 optional[key] = socket.inet_ntoa(struct.pack('>L', locals()[key]))
373 print "UpdateNodeNetwork(%d)" % nodenetwork_id,
374 UpdateNodeNetwork(admin, nodenetwork['nodenetwork_id'], optional)
377 # Check node network again
378 nodenetwork = GetNodeNetworks(admin, [nodenetwork_id])[0]
379 if nodenetwork['method'] == 'static':
380 for key in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
381 address = struct.unpack('>L', socket.inet_aton(nodenetwork[key]))[0]
382 assert address == locals()[key]
384 print "GetNodeNetworks",
385 nodenetworks = GetNodeNetworks(admin, nodenetwork_ids)
386 assert set(nodenetwork_ids) == set([nodenetwork['nodenetwork_id'] for nodenetwork in nodenetworks])
387 print "=>", nodenetwork_ids
389 # Add slice attribute types
390 attribute_type_ids = []
393 description = randstr(254)
394 min_role_id = random.sample(roles.values(), 1)[0]
396 # Add slice attribute type
397 print "AddSliceAttributeType",
398 attribute_type_id = AddSliceAttributeType(admin, name,
399 {'description': description,
400 'min_role_id': min_role_id})
402 # Should return a unique attribute_type_id
403 assert attribute_type_id not in attribute_type_ids
404 attribute_type_ids.append(attribute_type_id)
405 print "=>", attribute_type_id
407 # Check slice attribute type
408 print "GetSliceAttributeTypes(%d)" % attribute_type_id,
409 attribute_type = GetSliceAttributeTypes(admin, [attribute_type_id])[0]
410 for key in 'name', 'min_role_id', 'description':
411 assert unicmp(attribute_type[key], locals()[key])
414 # Update slice attribute type
415 name = "attribute_" + randstr(10, letters + '_')
416 description = randstr(254)
417 min_role_id = random.sample(roles.values(), 1)[0]
418 print "UpdateSliceAttributeType(%d)" % attribute_type_id,
419 UpdateSliceAttributeType(admin, attribute_type_id,
421 'description': description,
422 'min_role_id': min_role_id})
423 attribute_type = GetSliceAttributeTypes(admin, [attribute_type_id])[0]
424 for key in 'name', 'min_role_id', 'description':
425 assert unicmp(attribute_type[key], locals()[key])
428 # Add slices and slice attributes
430 slice_attribute_ids = []
433 name = site['login_base'] + "_" + randstr(11, letters).lower()
434 url = "http://" + randhostname() + "/"
435 description = randstr(2048)
438 print "AddSlice(%s)" % name,
439 slice_id = AddSlice(admin, name, {'url': url, 'description': description})
441 # Should return a unique slice_id
442 assert slice_id not in slice_ids
443 slice_ids.append(slice_id)
447 print "GetSlices(%d)" % slice_id,
448 slice = GetSlices(admin, [slice_id])[0]
449 for key in 'name', 'url', 'description', 'slice_id':
450 assert unicmp(slice[key], locals()[key])
454 url = "http://" + randhostname() + "/"
455 description = randstr(2048)
456 print "UpdateSlice(%d)" % slice_id,
457 UpdateSlice(admin, slice_id, {'url': url, 'description': description})
458 slice = GetSlices(admin, [slice_id])[0]
459 for key in 'name', 'url', 'description', 'slice_id':
460 assert unicmp(slice[key], locals()[key])
463 # Add slice to all nodes
464 print "AddSliceToNodes(%d, %s)" % (slice_id, str(node_ids)),
465 AddSliceToNodes(admin, name, node_ids)
466 slice = GetSlices(admin, [slice_id])[0]
467 assert set(node_ids) == set(slice['node_ids'])
471 for person_id in person_ids:
472 print "AddPersonToSlice(%d, %d)" % (person_id, slice_id),
473 AddPersonToSlice(admin, person_id, slice_id)
475 slice = GetSlices(admin, [slice_id])[0]
476 assert set(person_ids) == set(slice['person_ids'])
478 # Set slice/sliver attributes
479 for attribute_type_id in attribute_type_ids:
480 value = randstr(16, letters + '_' + digits)
481 # Make it a sliver attribute with 50% probability
482 node_id = random.sample(node_ids + [None] * len(node_ids), 1)[0]
484 # Add slice attribute
485 print "AddSliceAttribute(%d, %d)" % (slice_id, attribute_type_id),
487 slice_attribute_id = AddSliceAttribute(admin, slice_id, attribute_type_id, value)
489 slice_attribute_id = AddSliceAttribute(admin, slice_id, attribute_type_id, value, node_id)
491 # Should return a unique slice_attribute_id
492 assert slice_attribute_id not in slice_attribute_ids
493 slice_attribute_ids.append(slice_attribute_id)
494 print "=>", slice_attribute_id
496 # Check slice attribute
497 print "GetSliceAttributes(%d)" % slice_attribute_id,
498 slice_attribute = GetSliceAttributes(admin, [slice_attribute_id])[0]
499 for key in 'attribute_type_id', 'slice_id', 'node_id', 'slice_attribute_id', 'value':
500 assert unicmp(slice_attribute[key], locals()[key])
503 # Update slice attribute
504 url = "http://" + randhostname() + "/"
505 description = randstr(2048)
506 print "UpdateSliceAttribute(%d)" % slice_attribute_id,
507 UpdateSliceAttribute(admin, slice_attribute_id, value)
508 slice_attribute = GetSliceAttributes(admin, [slice_attribute_id])[0]
509 for key in 'attribute_type_id', 'slice_id', 'node_id', 'slice_attribute_id', 'value':
510 assert unicmp(slice_attribute[key], locals()[key])
514 for slice_id in slice_ids:
515 # Delete slice attributes
516 slice = GetSlices(admin, [slice_id])[0]
517 for slice_attribute_id in slice['slice_attribute_ids']:
518 print "DeleteSliceAttribute(%d, %d)" % (slice_id, slice_attribute_id),
519 DeleteSliceAttribute(admin, slice_attribute_id)
521 slice = GetSlices(admin, [slice_id])[0]
522 assert not slice['slice_attribute_ids']
524 # Delete users from slice
525 for person_id in person_ids:
526 print "DeletePersonFromSlice(%d, %d)" % (person_id, slice_id),
527 DeletePersonFromSlice(admin, person_id, slice_id)
529 slice = GetSlices(admin, [slice_id])[0]
530 assert not slice['person_ids']
532 # Delete nodes from slice
533 print "DeleteSliceFromNodes(%d, %s)" % (slice_id, node_ids),
534 DeleteSliceFromNodes(admin, slice_id, node_ids)
536 slice = GetSlices(admin, [slice_id])[0]
537 assert not slice['node_ids']
540 print "DeleteSlice(%d)" % slice_id,
541 DeleteSlice(admin, slice_id)
542 assert not GetSlices(admin, [slice_id])
544 # Make sure it really deleted it
545 slices = GetSlices(admin, slice_ids)
546 assert slice_id not in [slice['slice_id'] for slice in slices]
550 assert not GetSlices(admin, slice_ids)
553 # Delete slice attribute types
554 for attribute_type_id in attribute_type_ids:
555 # Delete slice attribute type
556 print "DeleteSliceAttributeType(%d)" % attribute_type_id,
557 DeleteSliceAttributeType(admin, attribute_type_id)
558 assert not GetSliceAttributeTypes(admin, [attribute_type_id])
560 # Make sure it really deleted it
561 attribute_types = GetSliceAttributeTypes(admin, attribute_type_ids)
562 assert attribute_type_id not in [attribute_type['attribute_type_id'] for attribute_type in attribute_types]
565 print "GetSliceAttributeTypes",
566 assert not GetSliceAttributeTypes(admin, attribute_type_ids)
569 # Delete node networks
570 for nodenetwork_id in nodenetwork_ids:
571 print "DeleteNodeNetwork(%d)" % nodenetwork_id,
572 DeleteNodeNetwork(admin, nodenetwork_id)
575 print "GetNodeNetworks",
576 assert not GetNodeNetworks(admin, nodenetwork_ids)
580 for node_id in node_ids:
581 # Remove from node groups
582 for nodegroup_id in nodegroup_ids:
583 print "DeleteNodeFromNodeGroup(%d, %d)" % (nodegroup_id, node_id),
584 DeleteNodeFromNodeGroup(admin, nodegroup_id, node_id)
586 node = GetNodes(admin, [node_id])[0]
587 assert not node['nodegroup_ids']
590 print "DeleteNode(%d)" % node_id,
591 DeleteNode(admin, node_id)
592 assert not GetNodes(admin, [node_id])
594 # Make sure it really deleted it
595 nodes = GetNodes(admin, node_ids)
596 assert node_id not in [node['node_id'] for node in nodes]
600 assert not GetNodes(admin, node_ids)
603 nodegroups = GetNodeGroups(admin, nodegroup_ids)
604 for nodegroup in nodegroups:
605 assert not set(node_ids).intersection(nodegroup['node_ids'])
608 for person_id in person_ids:
609 # Remove from each site
610 for site_id in site_ids:
611 print "DeletePersonFromSite(%d, %d)" % (person_id, site_id),
612 DeletePersonFromSite(admin, person_id, site_id)
614 person = GetPersons(admin, [person_id])[0]
615 assert not person['site_ids']
618 person = GetPersons(admin, [person_id])[0]
619 for role_id in person['role_ids']:
620 print "DeleteRoleFromPerson(%d, %d)" % (role_id, person_id),
621 DeleteRoleFromPerson(admin, role_id, person_id)
623 person = GetPersons(admin, [person_id])[0]
624 assert not person['role_ids']
627 UpdatePerson(admin, person_id, {'enabled': False})
628 person = GetPersons(admin, [person_id])[0]
629 assert not person['enabled']
632 print "DeletePerson(%d)" % person_id,
633 DeletePerson(admin, person_id)
634 assert not GetPersons(admin, [person_id])
638 assert not GetPersons(admin, person_ids)
642 for nodegroup_id in nodegroup_ids:
643 print "DeleteNodeGroup(%d)" % nodegroup_id,
644 DeleteNodeGroup(admin, nodegroup_id)
645 assert not GetNodeGroups(admin, [nodegroup_id])
648 print "GetNodeGroups",
649 assert not GetNodeGroups(admin, nodegroup_ids)
653 for site_id in site_ids:
654 print "DeleteSite(%d)" % site_id,
655 DeleteSite(admin, site_id)
656 assert not GetSites(admin, [site_id])
660 assert not GetSites(admin, site_ids)