3 # Test script utility class
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2006 The Trustees of Princeton University
8 # $Id: Test.py,v 1.19 2007/01/09 16:23:47 mlhuang Exp $
11 from pprint import pprint
12 from string import letters, digits, punctuation
13 from traceback import print_exc
14 from optparse import OptionParser
21 from PLC.Shell import Shell
23 from random import Random
26 def randfloat(min = 0.0, max = 1.0):
27 return float(min) + (random.random() * (float(max) - float(min)))
29 def randint(min = 0, max = 1):
30 return int(randfloat(min, max + 1))
32 # See "2.2 Characters" in the XML specification:
34 # #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
36 # [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF]
39 ascii_xml_chars = map(unichr, [0x9, 0xA])
40 # xmlrpclib uses xml.parsers.expat, which always converts either '\r'
41 # (#xD) or '\n' (#xA) to '\n'. So avoid using '\r', too, if this is
43 if xmlrpclib.loads(xmlrpclib.dumps(('\r',)))[0][0] == '\r':
44 ascii_xml_chars.append('\r')
45 ascii_xml_chars += map(unichr, xrange(0x20, 0x7F - 1))
46 low_xml_chars = list(ascii_xml_chars)
47 low_xml_chars += map(unichr, xrange(0x84 + 1, 0x86 - 1))
48 low_xml_chars += map(unichr, xrange(0x9F + 1, 0xFF))
49 valid_xml_chars = list(low_xml_chars)
50 valid_xml_chars += map(unichr, xrange(0xFF + 1, 0xD7FF))
51 valid_xml_chars += map(unichr, xrange(0xE000, 0xFDD0 - 1))
52 valid_xml_chars += map(unichr, xrange(0xFDDF + 1, 0xFFFD))
54 def randstr(length, pool = valid_xml_chars, encoding = "utf-8"):
55 sample = random.sample(pool, min(length, len(pool)))
58 bytes = len(s.encode(encoding))
62 sample += random.sample(pool, min(length - bytes, len(pool)))
63 random.shuffle(sample)
69 # 1. Each part begins and ends with a letter or number.
70 # 2. Each part except the last can contain letters, numbers, or hyphens.
71 # 3. Each part is between 1 and 64 characters, including the trailing dot.
72 # 4. At least two parts.
73 # 5. Last part can only contain between 2 and 6 letters.
74 hostname = 'a' + randstr(61, letters + digits + '-') + '1.' + \
75 'b' + randstr(61, letters + digits + '-') + '2.' + \
76 'c' + randstr(5, letters)
81 for i in range(randint(1, 10)):
82 parts.append(randstr(randint(1, 30), ascii_xml_chars))
83 return u'/'.join(parts)[0:length]
86 return (randstr(100, letters + digits) + "@" + randhostname()).lower()
88 def randkey(bits = 2048):
89 ssh_key_types = ["ssh-dss", "ssh-rsa"]
90 key_type = random.sample(ssh_key_types, 1)[0]
91 return ' '.join([key_type,
92 base64.b64encode(''.join(randstr(bits / 8).encode("utf-8"))),
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 def random_address_type():
107 'description': randstr(254),
110 def random_address():
112 'line1': randstr(254),
113 'line2': randstr(254),
114 'line3': randstr(254),
115 'city': randstr(254),
116 'state': randstr(254),
117 'postalcode': randstr(64),
118 'country': randstr(128),
123 'first_name': randstr(128),
124 'last_name': randstr(128),
125 'email': randemail(),
127 # Accounts are disabled by default
129 'password': randstr(254),
132 def random_key(key_types):
134 'key_type': random.sample(key_types, 1)[0],
138 def random_nodegroup():
141 'description': randstr(200),
144 def random_node(boot_states):
146 'hostname': randhostname(),
147 'boot_state': random.sample(boot_states, 1)[0],
148 'model': randstr(255),
149 'version': randstr(64),
152 def random_nodenetwork(method, type):
153 nodenetwork_fields = {
156 'bwlimit': randint(500000, 10000000),
160 ip = randint(0, 0xffffffff)
161 netmask = (0xffffffff << randint(2, 31)) & 0xffffffff
162 network = ip & netmask
163 broadcast = ((ip & netmask) | ~netmask) & 0xffffffff
164 gateway = randint(network + 1, broadcast - 1)
165 dns1 = randint(0, 0xffffffff)
167 for field in 'ip', 'netmask', 'network', 'broadcast', 'gateway', 'dns1':
168 nodenetwork_fields[field] = socket.inet_ntoa(struct.pack('>L', locals()[field]))
170 return nodenetwork_fields
174 'hostname': randhostname(),
175 'ip': socket.inet_ntoa(struct.pack('>L', randint(0, 0xffffffff))),
176 'protocol': randstr(16),
177 'username': randstr(254),
178 'password': randstr(254),
179 'notes': randstr(254),
180 'model': randstr(32),
183 def random_conf_file():
185 'enabled': bool(randint()),
186 'source': randpath(255),
187 'dest': randpath(255),
188 'file_permissions': "%#o" % randint(0, 512),
189 'file_owner': randstr(32, letters + '_' + digits),
190 'file_group': randstr(32, letters + '_' + digits),
191 'preinstall_cmd': randpath(100),
192 'postinstall_cmd': randpath(100),
193 'error_cmd': randpath(100),
194 'ignore_cmd_errors': bool(randint()),
195 'always_update': bool(randint()),
198 def random_attribute_type(role_ids):
200 'name': randstr(100),
201 'description': randstr(254),
202 'min_role_id': random.sample(role_ids, 1)[0],
205 def random_slice(login_base):
207 'name': login_base + "_" + randstr(11, letters).lower(),
208 'url': "http://" + randhostname() + "/",
209 'description': randstr(2048),
216 'addresses_per_site': 1,
217 'persons_per_site': 1,
218 'keys_per_person': 1,
221 'nodenetworks_per_node': 1,
224 'attribute_types': 1,
225 'slices_per_site': 1,
226 'attributes_per_slice': 1,
232 'addresses_per_site': 2,
233 'persons_per_site': 10,
234 'keys_per_person': 2,
237 'nodenetworks_per_node': 1,
240 'attribute_types': 10,
241 'slices_per_site': 10,
242 'attributes_per_slice': 2,
245 def __init__(self, api, check = True, verbose = True):
248 self.verbose = verbose
251 self.address_type_ids = []
252 self.address_ids = []
255 self.nodegroup_ids = []
257 self.nodenetwork_ids = []
259 self.conf_file_ids = []
260 self.attribute_type_ids = []
262 self.slice_attribute_ids = []
264 def Run(self, **kwds):
266 Run a complete database and API consistency test. Populates
267 the database with a set of random entities, updates them, then
268 deletes them. Examples:
270 test.Run() # Defaults
271 test.Run(**Test.default) # Defaults
272 test.Run(**Test.tiny) # Tiny set
273 test.Run(sites = 123, slices_per_site = 4) # Defaults with overrides
282 def Add(self, **kwds):
284 Populate the database with a set of random entities. Examples:
286 test.populate() # Defaults
287 test.populate(Test.tiny) # Tiny set
288 test.populate(sites = 123, slices_per_site = 4) # Defaults with overrides
291 params = self.default.copy()
294 self.AddSites(params['sites'])
295 self.AddAddressTypes(params['address_types'])
296 self.AddAddresses(params['addresses_per_site'])
297 self.AddPersons(params['persons_per_site'])
298 self.AddKeys(params['keys_per_person'])
299 self.AddNodeGroups(params['nodegroups'])
300 self.AddNodes(params['nodes_per_site'])
301 self.AddNodeNetworks(params['nodenetworks_per_node'])
302 self.AddPCUs(params['pcus_per_site'])
303 self.AddConfFiles(params['conf_files'])
304 self.AddSliceAttributeTypes(params['attribute_types'])
305 self.AddSlices(params['slices_per_site'])
306 self.AddSliceAttributes(params['attributes_per_slice'])
310 self.UpdateAddressTypes()
311 self.UpdateAddresses()
314 self.UpdateNodeGroups()
316 self.UpdateNodeNetworks()
318 self.UpdateConfFiles()
319 self.UpdateSliceAttributeTypes()
321 self.UpdateSliceAttributes()
324 self.DeleteSliceAttributes()
326 self.DeleteSliceAttributeTypes()
328 self.DeleteConfFiles()
330 self.DeleteNodeNetworks()
333 self.DeleteNodeGroups()
334 self.DeleteAddresses()
335 self.DeleteAddressTypes()
338 def AddSites(self, n = 10):
340 Add a number of random sites.
345 site_fields = random_site()
346 site_id = self.api.AddSite(site_fields)
348 # Should return a unique site_id
349 assert site_id not in self.site_ids
350 self.site_ids.append(site_id)
352 # Enable slice creation
353 site_fields['max_slices'] = randint(1, 10)
354 self.api.UpdateSite(site_id, site_fields)
358 site = self.api.GetSites([site_id])[0]
359 for field in site_fields:
360 assert site[field] == site_fields[field]
363 print "Added site", site_id
365 def UpdateSites(self):
367 Make random changes to any sites we may have added.
370 for site_id in self.site_ids:
372 site_fields = random_site()
373 # Do not change login_base
374 del site_fields['login_base']
375 self.api.UpdateSite(site_id, site_fields)
379 site = self.api.GetSites([site_id])[0]
380 for field in site_fields:
381 assert site[field] == site_fields[field]
384 print "Updated site", site_id
386 def DeleteSites(self):
388 Delete any random sites we may have added.
391 for site_id in self.site_ids:
392 self.api.DeleteSite(site_id)
395 assert not self.api.GetSites([site_id])
398 print "Deleted site", site_id
401 assert not self.api.GetSites(self.site_ids)
405 def AddAddressTypes(self, n = 2):
407 Add a number of random address types.
411 address_type_fields = random_address_type()
412 address_type_id = self.api.AddAddressType(address_type_fields)
414 # Should return a unique address_type_id
415 assert address_type_id not in self.address_type_ids
416 self.address_type_ids.append(address_type_id)
420 address_type = self.api.GetAddressTypes([address_type_id])[0]
421 for field in address_type_fields:
422 assert address_type[field] == address_type_fields[field]
425 print "Added address type", address_type_id
427 def UpdateAddressTypes(self):
429 Make random changes to any address types we may have added.
432 for address_type_id in self.address_type_ids:
433 # Update address_type
434 address_type_fields = random_address_type()
435 self.api.UpdateAddressType(address_type_id, address_type_fields)
439 address_type = self.api.GetAddressTypes([address_type_id])[0]
440 for field in address_type_fields:
441 assert address_type[field] == address_type_fields[field]
444 print "Updated address_type", address_type_id
446 def DeleteAddressTypes(self):
448 Delete any random address types we may have added.
451 for address_type_id in self.address_type_ids:
452 self.api.DeleteAddressType(address_type_id)
455 assert not self.api.GetAddressTypes([address_type_id])
458 print "Deleted address type", address_type_id
461 assert not self.api.GetAddressTypes(self.address_type_ids)
463 self.address_type_ids = []
465 def AddAddresses(self, per_site = 2):
467 Add a number of random addresses to each site.
470 for site_id in self.site_ids:
471 for i in range(per_site):
472 address_fields = random_address()
473 address_id = self.api.AddSiteAddress(site_id, address_fields)
475 # Should return a unique address_id
476 assert address_id not in self.address_ids
477 self.address_ids.append(address_id)
479 # Add random address type
480 if self.address_type_ids:
481 for address_type_id in random.sample(self.address_type_ids, 1):
482 self.api.AddAddressTypeToAddress(address_type_id, address_id)
486 address = self.api.GetAddresses([address_id])[0]
487 for field in address_fields:
488 assert address[field] == address_fields[field]
491 print "Added address", address_id, "to site", site_id
493 def UpdateAddresses(self):
495 Make random changes to any addresses we may have added.
498 for address_id in self.address_ids:
500 address_fields = random_address()
501 self.api.UpdateAddress(address_id, address_fields)
505 address = self.api.GetAddresses([address_id])[0]
506 for field in address_fields:
507 assert address[field] == address_fields[field]
510 print "Updated address", address_id
512 def DeleteAddresses(self):
514 Delete any random addresses we may have added.
517 for address_id in self.address_ids:
518 # Remove address types
519 address = self.api.GetAddresses([address_id])[0]
520 for address_type_id in address['address_type_ids']:
521 self.api.DeleteAddressTypeFromAddress(address_type_id, address_id)
524 address = self.api.GetAddresses([address_id])[0]
525 assert not address['address_type_ids']
527 self.api.DeleteAddress(address_id)
530 assert not self.api.GetAddresses([address_id])
533 print "Deleted address", address_id
536 assert not self.api.GetAddresses(self.address_ids)
538 self.address_ids = []
540 def AddPersons(self, per_site = 10):
542 Add a number of random users to each site.
545 for site_id in self.site_ids:
546 for i in range(per_site):
548 person_fields = random_person()
549 person_id = self.api.AddPerson(person_fields)
551 # Should return a unique person_id
552 assert person_id not in self.person_ids
553 self.person_ids.append(person_id)
557 person = self.api.GetPersons([person_id])[0]
558 for field in person_fields:
559 if field != 'password':
560 assert person[field] == person_fields[field]
562 auth = {'AuthMethod': "password",
563 'Username': person_fields['email'],
564 'AuthString': person_fields['password']}
567 # Check that user is disabled
569 assert not self.api.AuthCheck(auth)
573 # Add random set of roles
574 role_ids = random.sample([20, 30, 40], randint(1, 3))
575 for role_id in role_ids:
576 self.api.AddRoleToPerson(role_id, person_id)
579 person = self.api.GetPersons([person_id])[0]
580 assert set(role_ids) == set(person['role_ids'])
583 self.api.UpdatePerson(person_id, {'enabled': True})
586 # Check that user is enabled
587 assert self.api.AuthCheck(auth)
589 # Associate user with site
590 self.api.AddPersonToSite(person_id, site_id)
591 self.api.SetPersonPrimarySite(person_id, site_id)
594 person = self.api.GetPersons([person_id])[0]
595 assert person['site_ids'][0] == site_id
598 print "Added user", person_id, "to site", site_id
600 def UpdatePersons(self):
602 Make random changes to any users we may have added.
605 for person_id in self.person_ids:
607 person_fields = random_person()
608 self.api.UpdatePerson(person_id, person_fields)
612 person = self.api.GetPersons([person_id])[0]
613 for field in person_fields:
614 if field != 'password':
615 assert person[field] == person_fields[field]
618 print "Updated person", person_id
620 person = self.api.GetPersons([person_id])[0]
622 # Associate user with a random set of sites
623 site_ids = random.sample(self.site_ids, randint(0, len(self.site_ids)))
624 for site_id in (set(site_ids) - set(person['site_ids'])):
625 self.api.AddPersonToSite(person_id, site_id)
626 for site_id in (set(person['site_ids']) - set(site_ids)):
627 self.api.DeletePersonFromSite(person_id, site_id)
630 self.api.SetPersonPrimarySite(person_id, site_ids[0])
633 person = self.api.GetPersons([person_id])[0]
634 assert set(site_ids) == set(person['site_ids'])
637 print "Updated person", person_id, "to sites", site_ids
639 def DeletePersons(self):
641 Delete any random users we may have added.
644 for person_id in self.person_ids:
646 person = self.api.GetPersons([person_id])[0]
647 for site_id in person['site_ids']:
648 self.api.DeletePersonFromSite(person_id, site_id)
651 person = self.api.GetPersons([person_id])[0]
652 assert not person['site_ids']
655 for role_id in person['role_ids']:
656 self.api.DeleteRoleFromPerson(role_id, person_id)
659 person = self.api.GetPersons([person_id])[0]
660 assert not person['role_ids']
663 self.api.UpdatePerson(person_id, {'enabled': False})
666 person = self.api.GetPersons([person_id])[0]
667 assert not person['enabled']
670 self.api.DeletePerson(person_id)
673 assert not self.api.GetPersons([person_id])
676 print "Deleted user", person_id
679 assert not self.api.GetPersons(self.person_ids)
683 def AddKeys(self, per_person = 2):
685 Add a number of random keys to each user.
688 key_types = self.api.GetKeyTypes()
690 raise Exception, "No key types"
692 for person_id in self.person_ids:
693 for i in range(per_person):
695 key_fields = random_key(key_types)
696 key_id = self.api.AddPersonKey(person_id, key_fields)
698 # Should return a unique key_id
699 assert key_id not in self.key_ids
700 self.key_ids.append(key_id)
704 key = self.api.GetKeys([key_id])[0]
705 for field in key_fields:
706 assert key[field] == key_fields[field]
708 # Add and immediately blacklist a key
709 key_fields = random_key(key_types)
710 key_id = self.api.AddPersonKey(person_id, key_fields)
712 self.api.BlacklistKey(key_id)
714 # Is effectively deleted
715 assert not self.api.GetKeys([key_id])
717 # Cannot be added again
719 key_id = self.api.AddPersonKey(person_id, key_fields)
725 print "Added key", key_id, "to user", person_id
727 def UpdateKeys(self):
729 Make random changes to any keys we may have added.
732 key_types = self.api.GetKeyTypes()
734 raise Exception, "No key types"
736 for key_id in self.key_ids:
738 key_fields = random_key(key_types)
739 self.api.UpdateKey(key_id, key_fields)
743 key = self.api.GetKeys([key_id])[0]
744 for field in key_fields:
745 assert key[field] == key_fields[field]
748 print "Updated key", key_id
750 def DeleteKeys(self):
752 Delete any random keys we may have added.
755 for key_id in self.key_ids:
756 self.api.DeleteKey(key_id)
759 assert not self.api.GetKeys([key_id])
762 print "Deleted key", key_id
765 assert not self.api.GetKeys(self.key_ids)
769 def AddNodeGroups(self, n = 10):
771 Add a number of random node groups.
776 nodegroup_fields = random_nodegroup()
777 nodegroup_id = self.api.AddNodeGroup(nodegroup_fields)
779 # Should return a unique nodegroup_id
780 assert nodegroup_id not in self.nodegroup_ids
781 self.nodegroup_ids.append(nodegroup_id)
785 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
786 for field in nodegroup_fields:
787 assert nodegroup[field] == nodegroup_fields[field]
790 print "Added node group", nodegroup_id
792 def UpdateNodeGroups(self):
794 Make random changes to any node groups we may have added.
797 for nodegroup_id in self.nodegroup_ids:
799 nodegroup_fields = random_nodegroup()
800 self.api.UpdateNodeGroup(nodegroup_id, nodegroup_fields)
804 nodegroup = self.api.GetNodeGroups([nodegroup_id])[0]
805 for field in nodegroup_fields:
806 assert nodegroup[field] == nodegroup_fields[field]
809 print "Updated node group", nodegroup_id
811 def DeleteNodeGroups(self):
813 Delete any random node groups we may have added.
816 for nodegroup_id in self.nodegroup_ids:
817 self.api.DeleteNodeGroup(nodegroup_id)
820 assert not self.api.GetNodeGroups([nodegroup_id])
823 print "Deleted node group", nodegroup_id
826 assert not self.api.GetNodeGroups(self.nodegroup_ids)
828 self.nodegroup_ids = []
830 def AddNodes(self, per_site = 2):
832 Add a number of random nodes to each site. Each node will also
833 be added to a random node group if AddNodeGroups() was
837 boot_states = self.api.GetBootStates()
839 raise Exception, "No boot states"
841 for site_id in self.site_ids:
842 for i in range(per_site):
844 node_fields = random_node(boot_states)
845 node_id = self.api.AddNode(site_id, node_fields)
847 # Should return a unique node_id
848 assert node_id not in self.node_ids
849 self.node_ids.append(node_id)
851 # Add to a random set of node groups
852 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
853 for nodegroup_id in nodegroup_ids:
854 self.api.AddNodeToNodeGroup(node_id, nodegroup_id)
858 node = self.api.GetNodes([node_id])[0]
859 for field in node_fields:
860 assert node[field] == node_fields[field]
863 print "Added node", node_id
865 def UpdateNodes(self):
867 Make random changes to any nodes we may have added.
870 boot_states = self.api.GetBootStates()
872 raise Exception, "No boot states"
874 for node_id in self.node_ids:
876 node_fields = random_node(boot_states)
877 self.api.UpdateNode(node_id, node_fields)
879 node = self.api.GetNodes([node_id])[0]
881 # Add to a random set of node groups
882 nodegroup_ids = random.sample(self.nodegroup_ids, randint(0, len(self.nodegroup_ids)))
883 for nodegroup_id in (set(nodegroup_ids) - set(node['nodegroup_ids'])):
884 self.api.AddNodeToNodeGroup(node_id, nodegroup_id)
885 for nodegroup_id in (set(node['nodegroup_ids']) - set(nodegroup_ids)):
886 self.api.DeleteNodeFromNodeGroup(node_id, nodegroup_id)
890 node = self.api.GetNodes([node_id])[0]
891 for field in node_fields:
892 assert node[field] == node_fields[field]
893 assert set(nodegroup_ids) == set(node['nodegroup_ids'])
896 print "Updated node", node_id
897 print "Added node", node_id, "to node groups", nodegroup_ids
899 def DeleteNodes(self):
901 Delete any random nodes we may have added.
904 for node_id in self.node_ids:
905 # Remove from node groups
906 node = self.api.GetNodes([node_id])[0]
907 for nodegroup_id in node['nodegroup_ids']:
908 self.api.DeleteNodeFromNodeGroup(node_id, nodegroup_id)
911 node = self.api.GetNodes([node_id])[0]
912 assert not node['nodegroup_ids']
914 self.api.DeleteNode(node_id)
917 assert not self.api.GetNodes([node_id])
920 print "Deleted node", node_id
923 assert not self.api.GetNodes(self.node_ids)
927 def AddNodeNetworks(self, per_node = 1):
929 Add a number of random network interfaces to each node.
932 network_methods = self.api.GetNetworkMethods()
933 if not network_methods:
934 raise Exception, "No network methods"
936 network_types = self.api.GetNetworkTypes()
937 if not network_types:
938 raise Exception, "No network types"
940 for node_id in self.node_ids:
941 for i in range(per_node):
942 method = random.sample(network_methods, 1)[0]
943 type = random.sample(network_types, 1)[0]
946 nodenetwork_fields = random_nodenetwork(method, type)
947 nodenetwork_id = self.api.AddNodeNetwork(node_id, nodenetwork_fields)
949 # Should return a unique nodenetwork_id
950 assert nodenetwork_id not in self.nodenetwork_ids
951 self.nodenetwork_ids.append(nodenetwork_id)
955 nodenetwork = self.api.GetNodeNetworks([nodenetwork_id])[0]
956 for field in nodenetwork_fields:
957 assert nodenetwork[field] == nodenetwork_fields[field]
960 print "Added node network", nodenetwork_id, "to node", node_id
962 def UpdateNodeNetworks(self):
964 Make random changes to any network interfaces we may have added.
967 network_methods = self.api.GetNetworkMethods()
968 if not network_methods:
969 raise Exception, "No network methods"
971 network_types = self.api.GetNetworkTypes()
972 if not network_types:
973 raise Exception, "No network types"
975 for nodenetwork_id in self.nodenetwork_ids:
976 method = random.sample(network_methods, 1)[0]
977 type = random.sample(network_types, 1)[0]
980 nodenetwork_fields = random_nodenetwork(method, type)
981 self.api.UpdateNodeNetwork(nodenetwork_id, nodenetwork_fields)
985 nodenetwork = self.api.GetNodeNetworks([nodenetwork_id])[0]
986 for field in nodenetwork_fields:
987 assert nodenetwork[field] == nodenetwork_fields[field]
990 print "Updated node network", nodenetwork_id
992 def DeleteNodeNetworks(self):
994 Delete any random network interfaces we may have added.
997 for nodenetwork_id in self.nodenetwork_ids:
998 self.api.DeleteNodeNetwork(nodenetwork_id)
1001 assert not self.api.GetNodeNetworks([nodenetwork_id])
1004 print "Deleted node network", nodenetwork_id
1007 assert not self.api.GetNodeNetworks(self.nodenetwork_ids)
1009 self.nodenetwork_ids = []
1011 def AddPCUs(self, per_site = 1):
1013 Add a number of random PCUs to each site. Each node at the
1014 site will be added to a port on the PCU if AddNodes() was
1018 for site_id in self.site_ids:
1019 for i in range(per_site):
1021 pcu_fields = random_pcu()
1022 pcu_id = self.api.AddPCU(site_id, pcu_fields)
1024 # Should return a unique pcu_id
1025 assert pcu_id not in self.pcu_ids
1026 self.pcu_ids.append(pcu_id)
1028 # Add each node at this site to a different port on this PCU
1029 site = self.api.GetSites([site_id])[0]
1030 port = randint(1, 10)
1031 for node_id in site['node_ids']:
1032 self.api.AddNodeToPCU(node_id, pcu_id, port)
1037 pcu = self.api.GetPCUs([pcu_id])[0]
1038 for field in pcu_fields:
1039 assert pcu[field] == pcu_fields[field]
1042 print "Added PCU", pcu_id, "to site", site_id
1044 def UpdatePCUs(self):
1046 Make random changes to any PCUs we may have added.
1049 for pcu_id in self.pcu_ids:
1051 pcu_fields = random_pcu()
1052 self.api.UpdatePCU(pcu_id, pcu_fields)
1056 pcu = self.api.GetPCUs([pcu_id])[0]
1057 for field in pcu_fields:
1058 assert pcu[field] == pcu_fields[field]
1061 print "Updated PCU", pcu_id
1063 def DeletePCUs(self):
1065 Delete any random nodes we may have added.
1068 for pcu_id in self.pcu_ids:
1069 # Remove nodes from PCU
1070 pcu = self.api.GetPCUs([pcu_id])[0]
1071 for node_id in pcu['node_ids']:
1072 self.api.DeleteNodeFromPCU(node_id, pcu_id)
1075 pcu = self.api.GetPCUs([pcu_id])[0]
1076 assert not pcu['node_ids']
1078 self.api.DeletePCU(pcu_id)
1081 assert not self.api.GetPCUs([pcu_id])
1084 print "Deleted PCU", pcu_id
1087 assert not self.api.GetPCUs(self.pcu_ids)
1091 def AddConfFiles(self, n = 10):
1093 Add a number of random global configuration files.
1099 # Add a random configuration file
1100 conf_files.append(random_conf_file())
1103 # Add a nodegroup override file
1104 nodegroup_conf_file = conf_files[0].copy()
1105 nodegroup_conf_file['source'] = randpath(255)
1106 conf_files.append(nodegroup_conf_file)
1108 # Add a node override file
1109 node_conf_file = conf_files[0].copy()
1110 node_conf_file['source'] = randpath(255)
1111 conf_files.append(node_conf_file)
1113 for conf_file_fields in conf_files:
1114 conf_file_id = self.api.AddConfFile(conf_file_fields)
1116 # Should return a unique conf_file_id
1117 assert conf_file_id not in self.conf_file_ids
1118 self.conf_file_ids.append(conf_file_id)
1121 if conf_file_fields == nodegroup_conf_file and self.nodegroup_ids:
1122 nodegroup_id = random.sample(self.nodegroup_ids, 1)[0]
1123 self.api.AddConfFileToNodeGroup(conf_file_id, nodegroup_id)
1128 if conf_file_fields == node_conf_file and self.node_ids:
1129 node_id = random.sample(self.node_ids, 1)[0]
1130 self.api.AddConfFileToNode(conf_file_id, node_id)
1135 # Check configuration file
1136 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1137 for field in conf_file_fields:
1138 assert conf_file[field] == conf_file_fields[field]
1141 print "Added configuration file", conf_file_id,
1142 if nodegroup_id is not None:
1143 print "to node group", nodegroup_id,
1144 elif node_id is not None:
1145 print "to node", node_id,
1148 def UpdateConfFiles(self):
1150 Make random changes to any configuration files we may have added.
1153 for conf_file_id in self.conf_file_ids:
1154 # Update configuration file
1155 conf_file_fields = random_conf_file()
1156 # Do not update dest so that it remains an override if set
1157 del conf_file_fields['dest']
1158 self.api.UpdateConfFile(conf_file_id, conf_file_fields)
1161 # Check configuration file
1162 conf_file = self.api.GetConfFiles([conf_file_id])[0]
1163 for field in conf_file_fields:
1164 assert conf_file[field] == conf_file_fields[field]
1167 print "Updated configuration file", conf_file_id
1169 def DeleteConfFiles(self):
1171 Delete any random configuration files we may have added.
1174 for conf_file_id in self.conf_file_ids:
1175 self.api.DeleteConfFile(conf_file_id)
1178 assert not self.api.GetConfFiles([conf_file_id])
1181 print "Deleted configuration file", conf_file_id
1184 assert not self.api.GetConfFiles(self.conf_file_ids)
1186 self.conf_file_ids = []
1188 def AddSliceAttributeTypes(self, n = 10):
1190 Add a number of random slice attribute types.
1193 roles = self.api.GetRoles()
1195 raise Exception, "No roles"
1196 role_ids = [role['role_id'] for role in roles]
1199 attribute_type_fields = random_attribute_type(role_ids)
1200 attribute_type_id = self.api.AddSliceAttributeType(attribute_type_fields)
1202 # Should return a unique attribute_type_id
1203 assert attribute_type_id not in self.attribute_type_ids
1204 self.attribute_type_ids.append(attribute_type_id)
1207 # Check slice attribute type
1208 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1209 for field in attribute_type_fields:
1210 assert attribute_type[field] == attribute_type_fields[field]
1213 print "Added slice attribute type", attribute_type_id
1215 def UpdateSliceAttributeTypes(self):
1217 Make random changes to any slice attribute types we may have added.
1220 roles = self.api.GetRoles()
1222 raise Exception, "No roles"
1223 role_ids = [role['role_id'] for role in roles]
1225 for attribute_type_id in self.attribute_type_ids:
1226 # Update slice attribute type
1227 attribute_type_fields = random_attribute_type(role_ids)
1228 self.api.UpdateSliceAttributeType(attribute_type_id, attribute_type_fields)
1231 # Check slice attribute type
1232 attribute_type = self.api.GetSliceAttributeTypes([attribute_type_id])[0]
1233 for field in attribute_type_fields:
1234 assert attribute_type[field] == attribute_type_fields[field]
1237 print "Updated slice attribute type", attribute_type_id
1239 def DeleteSliceAttributeTypes(self):
1241 Delete any random slice attribute types we may have added.
1244 for attribute_type_id in self.attribute_type_ids:
1245 self.api.DeleteSliceAttributeType(attribute_type_id)
1248 assert not self.api.GetSliceAttributeTypes([attribute_type_id])
1251 print "Deleted slice attribute type", attribute_type_id
1254 assert not self.api.GetSliceAttributeTypes(self.attribute_type_ids)
1256 self.attribute_type_ids = []
1258 def AddSlices(self, per_site = 10):
1260 Add a number of random slices per site.
1263 for site in self.api.GetSites(self.site_ids):
1264 for i in range(min(per_site, site['max_slices'])):
1266 slice_fields = random_slice(site['login_base'])
1267 slice_id = self.api.AddSlice(slice_fields)
1269 # Should return a unique slice_id
1270 assert slice_id not in self.slice_ids
1271 self.slice_ids.append(slice_id)
1273 # Add slice to a random set of nodes
1274 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1276 self.api.AddSliceToNodes(slice_id, node_ids)
1278 # Add random set of site users to slice
1279 person_ids = random.sample(site['person_ids'], randint(0, len(site['person_ids'])))
1280 for person_id in person_ids:
1281 self.api.AddPersonToSlice(person_id, slice_id)
1285 slice = self.api.GetSlices([slice_id])[0]
1286 for field in slice_fields:
1287 assert slice[field] == slice_fields[field]
1289 assert set(node_ids) == set(slice['node_ids'])
1290 assert set(person_ids) == set(slice['person_ids'])
1293 print "Added slice", slice_id, "to site", site['site_id'],
1295 print "and nodes", node_ids,
1298 print "Added users", site['person_ids'], "to slice", slice_id
1300 def UpdateSlices(self):
1302 Make random changes to any slices we may have added.
1305 for slice_id in self.slice_ids:
1307 slice_fields = random_slice("unused")
1308 # Cannot change slice name
1309 del slice_fields['name']
1310 self.api.UpdateSlice(slice_id, slice_fields)
1312 slice = self.api.GetSlices([slice_id])[0]
1314 # Add slice to a random set of nodes
1315 node_ids = random.sample(self.node_ids, randint(0, len(self.node_ids)))
1316 self.api.AddSliceToNodes(slice_id, list(set(node_ids) - set(slice['node_ids'])))
1317 self.api.DeleteSliceFromNodes(slice_id, list(set(slice['node_ids']) - set(node_ids)))
1319 # Add random set of users to slice
1320 person_ids = random.sample(self.person_ids, randint(0, len(self.person_ids)))
1321 for person_id in (set(person_ids) - set(slice['person_ids'])):
1322 self.api.AddPersonToSlice(person_id, slice_id)
1323 for person_id in (set(slice['person_ids']) - set(person_ids)):
1324 self.api.DeletePersonFromSlice(person_id, slice_id)
1327 slice = self.api.GetSlices([slice_id])[0]
1328 for field in slice_fields:
1329 assert slice[field] == slice_fields[field]
1330 assert set(node_ids) == set(slice['node_ids'])
1331 assert set(person_ids) == set(slice['person_ids'])
1334 print "Updated slice", slice_id
1335 print "Added nodes", node_ids, "to slice", slice_id
1336 print "Added persons", person_ids, "to slice", slice_id
1338 def DeleteSlices(self):
1340 Delete any random slices we may have added.
1343 for slice_id in self.slice_ids:
1344 self.api.DeleteSlice(slice_id)
1347 assert not self.api.GetSlices([slice_id])
1350 print "Deleted slice", slice_id
1353 assert not self.api.GetSlices(self.slice_ids)
1357 def AddSliceAttributes(self, per_slice = 2):
1359 Add a number of random slices per site.
1362 if not self.attribute_type_ids:
1365 for slice_id in self.slice_ids:
1366 slice = self.api.GetSlices([slice_id])[0]
1368 for i in range(per_slice):
1369 # Set a random slice/sliver attribute
1370 for attribute_type_id in random.sample(self.attribute_type_ids, 1):
1371 value = randstr(16, letters + '_' + digits)
1372 # Make it a sliver attribute with 50% probability
1373 if slice['node_ids']:
1374 node_id = random.sample(slice['node_ids'] + [None] * len(slice['node_ids']), 1)[0]
1378 # Add slice attribute
1380 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value)
1382 slice_attribute_id = self.api.AddSliceAttribute(slice_id, attribute_type_id, value, node_id)
1384 # Should return a unique slice_attribute_id
1385 assert slice_attribute_id not in self.slice_attribute_ids
1386 self.slice_attribute_ids.append(slice_attribute_id)
1389 # Check slice attribute
1390 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1391 for field in 'attribute_type_id', 'slice_id', 'node_id', 'slice_attribute_id', 'value':
1392 assert slice_attribute[field] == locals()[field]
1395 print "Added slice attribute", slice_attribute_id, "of type", attribute_type_id,
1396 if node_id is not None:
1397 print "to node", node_id,
1400 def UpdateSliceAttributes(self):
1402 Make random changes to any slice attributes we may have added.
1405 for slice_attribute_id in self.slice_attribute_ids:
1406 # Update slice attribute
1407 value = randstr(16, letters + '_' + digits)
1408 self.api.UpdateSliceAttribute(slice_attribute_id, value)
1410 # Check slice attribute again
1411 slice_attribute = self.api.GetSliceAttributes([slice_attribute_id])[0]
1412 assert slice_attribute['value'] == value
1415 print "Updated slice attribute", slice_attribute_id
1417 def DeleteSliceAttributes(self):
1419 Delete any random slice attributes we may have added.
1422 for slice_attribute_id in self.slice_attribute_ids:
1423 self.api.DeleteSliceAttribute(slice_attribute_id)
1426 assert not self.api.GetSliceAttributes([slice_attribute_id])
1429 print "Deleted slice attribute", slice_attribute_id
1432 assert not self.api.GetSliceAttributes(self.slice_attribute_ids)
1434 self.slice_attribute_ids = []
1437 parser = OptionParser()
1438 parser.add_option("-c", "--check", action = "store_true", default = False, help = "Check most actions (default: %default)")
1439 parser.add_option("-q", "--quiet", action = "store_true", default = False, help = "Be quiet (default: %default)")
1440 parser.add_option("-t", "--tiny", action = "store_true", default = False, help = "Run a tiny test (default: %default)")
1441 (options, args) = parser.parse_args()
1443 test = Test(api = Shell(),
1444 check = options.check,
1445 verbose = not options.quiet)
1450 params = Test.default
1454 if __name__ == "__main__":