def test_get_enums(self): # This file contains a single enum, named "ENUM". enums = get_enums(getsourcefile(TestFunctions)) self.assertEqual(["ENUM"], [enum.__name__ for enum in enums]) [enum] = enums # Because the module has been executed in a different namespace, the # enum we've found is not the same object as the one in the current # global namespace. self.assertIsNot(ENUM, enum) # It does, however, have the same values. self.assertEqual(map_enum(ENUM), map_enum(enum))
class TestRenderPreseed(MAASServerTestCase): """Tests for `render_preseed`. These tests check that the templates render (i.e. that no variable is missing). """ # Create a scenario for each possible value of PRESEED_TYPE except # enlistment. Those have their own test case. scenarios = [(name, { 'preseed': value }) for name, value in map_enum(PRESEED_TYPE).items() if not value.startswith('enlist')] def test_render_preseed(self): node = factory.make_node() preseed = render_preseed(node, self.preseed, "precise") # The test really is that the preseed is rendered without an # error. self.assertIsInstance(preseed, bytes) def test_get_preseed_uses_nodegroup_maas_url(self): ng_url = 'http://%s' % factory.make_hostname() ng = factory.make_node_group(maas_url=ng_url) maas_url = 'http://%s' % factory.make_hostname() node = factory.make_node(nodegroup=ng, status=NODE_STATUS.COMMISSIONING) self.patch(settings, 'DEFAULT_MAAS_URL', maas_url) preseed = render_preseed(node, self.preseed, "precise") self.assertThat( preseed, MatchesAll( *[Contains(ng_url), Not(Contains(maas_url))]))
def test_accept_enlistment_rejects_bad_state_change(self): # If a node is neither Declared nor in one of the "accepted" # states where acceptance is a safe no-op, accept_enlistment # raises a node state violation and leaves the node's state # unchanged. all_states = map_enum(NODE_STATUS).values() acceptable_states = [ NODE_STATUS.DECLARED, NODE_STATUS.COMMISSIONING, NODE_STATUS.READY, ] unacceptable_states = set(all_states) - set(acceptable_states) nodes = { status: factory.make_node(status=status) for status in unacceptable_states} exceptions = {status: False for status in unacceptable_states} for status, node in nodes.items(): try: node.accept_enlistment(factory.make_user()) except NodeStateViolation: exceptions[status] = True self.assertEqual( {status: True for status in unacceptable_states}, exceptions) self.assertEqual( {status: status for status in unacceptable_states}, {status: node.status for status, node in nodes.items()})
def test_POST_accept_rejects_impossible_state_changes(self): self.become_admin() acceptable_states = set([ NODE_STATUS.DECLARED, NODE_STATUS.COMMISSIONING, NODE_STATUS.READY, ]) unacceptable_states = ( set(map_enum(NODE_STATUS).values()) - acceptable_states) nodes = { status: factory.make_node(status=status) for status in unacceptable_states} responses = { status: self.client.post( reverse('nodes_handler'), { 'op': 'accept', 'nodes': [node.system_id], }) for status, node in nodes.items()} # All of these attempts are rejected with Conflict errors. self.assertEqual( {status: httplib.CONFLICT for status in unacceptable_states}, { status: responses[status].status_code for status in unacceptable_states}) for status, response in responses.items(): # Each error describes the problem. self.assertIn("Cannot accept node enlistment", response.content) # Each error names the node it encountered a problem with. self.assertIn(nodes[status].system_id, response.content) # Each error names the node state that the request conflicted # with. self.assertIn(NODE_STATUS_CHOICES_DICT[status], response.content)
def test_POST_release_rejects_impossible_state_changes(self): acceptable_states = { NODE_STATUS.ALLOCATED, NODE_STATUS.RESERVED, NODE_STATUS.READY, } unacceptable_states = ( set(map_enum(NODE_STATUS).values()) - acceptable_states) owner = self.logged_in_user nodes = [ factory.make_node(status=status, owner=owner) for status in unacceptable_states] response = self.client.post( reverse('nodes_handler'), { 'op': 'release', 'nodes': [node.system_id for node in nodes], }) # Awkward parsing again, because a string is returned, not JSON expected = [ "%s ('%s')" % (node.system_id, node.display_status()) for node in nodes if node.status not in acceptable_states] s = response.content returned = s[s.rfind(':') + 2:s.rfind('.')].split(', ') self.assertEqual(httplib.CONFLICT, response.status_code) self.assertIn( "Node(s) cannot be released in their current state:", response.content) self.assertItemsEqual(expected, returned)
def test_POST_release_rejects_impossible_state_changes(self): acceptable_states = { NODE_STATUS.ALLOCATED, NODE_STATUS.RESERVED, NODE_STATUS.READY, } unacceptable_states = (set(map_enum(NODE_STATUS).values()) - acceptable_states) owner = self.logged_in_user nodes = [ factory.make_node(status=status, owner=owner) for status in unacceptable_states ] response = self.client.post( reverse('nodes_handler'), { 'op': 'release', 'nodes': [node.system_id for node in nodes], }) # Awkward parsing again, because a string is returned, not JSON expected = [ "%s ('%s')" % (node.system_id, node.display_status()) for node in nodes if node.status not in acceptable_states ] s = response.content returned = s[s.rfind(':') + 2:s.rfind('.')].split(', ') self.assertEqual(httplib.CONFLICT, response.status_code) self.assertIn("Node(s) cannot be released in their current state:", response.content) self.assertItemsEqual(expected, returned)
def test_map_enum_includes_all_enum_values(self): class Enum: ONE = 1 TWO = 2 self.assertItemsEqual(['ONE', 'TWO'], map_enum(Enum).keys())
def test_map_enum_maps_values(self): class Enum: ONE = 1 THREE = 3 self.assertEqual({'ONE': 1, 'THREE': 3}, map_enum(Enum))
def test_refresh_workers_skips_unaccepted_cluster_controllers(self): self.patch(nodegroup_module, 'refresh_worker') for status in map_enum(NODEGROUP_STATUS).values(): if status != NODEGROUP_STATUS.ACCEPTED: factory.make_node_group(status=status) NodeGroup.objects.refresh_workers() self.assertEqual(0, nodegroup_module.refresh_worker.call_count)
class TestRenderEnlistmentPreseed(MAASServerTestCase): """Tests for `render_enlistment_preseed`.""" # Create a scenario for each possible value of PRESEED_TYPE for # enlistment. The rest have their own test case. scenarios = [(name, { 'preseed': value }) for name, value in map_enum(PRESEED_TYPE).items() if value.startswith('enlist')] def test_render_enlistment_preseed(self): preseed = render_enlistment_preseed(self.preseed, "precise") # The test really is that the preseed is rendered without an # error. self.assertIsInstance(preseed, bytes) def test_render_enlistment_preseed_valid_yaml(self): preseed = render_enlistment_preseed(self.preseed, "precise") self.assertTrue(yaml.safe_load(preseed)) def test_get_preseed_uses_nodegroup_maas_url(self): ng_url = 'http://%s' % factory.make_hostname() maas_url = 'http://%s' % factory.make_hostname() self.patch(settings, 'DEFAULT_MAAS_URL', maas_url) nodegroup = factory.make_node_group(maas_url=ng_url) preseed = render_enlistment_preseed(self.preseed, "precise", nodegroup=nodegroup) self.assertThat( preseed, MatchesAll( *[Contains(ng_url), Not(Contains(maas_url))]))
def test_get_effective_power_type_reads_node_field(self): power_types = list(map_enum(POWER_TYPE).values()) power_types.remove(POWER_TYPE.DEFAULT) nodes = [ factory.make_node(power_type=power_type) for power_type in power_types] self.assertEqual( power_types, [node.get_effective_power_type() for node in nodes])
def test_get_effective_power_type_defaults_to_config(self): power_types = list(map_enum(POWER_TYPE).values()) power_types.remove(POWER_TYPE.DEFAULT) node = factory.make_node(power_type=POWER_TYPE.DEFAULT) effective_types = [] for power_type in power_types: Config.objects.set_config('node_power_type', power_type) effective_types.append(node.get_effective_power_type()) self.assertEqual(power_types, effective_types)
def getRandomEnum(self, enum, but_not=None): """Pick a random item from an enumeration class. :param enum: An enumeration class such as `NODE_STATUS`. :return: The value of one of its items. :param but_not: A list of choices' IDs to exclude. :type but_not: Sequence. """ if but_not is None: but_not = () return random.choice([ value for value in list(map_enum(enum).values()) if value not in but_not])
def test_view_node_shows_message_for_commissioning_node(self): statuses_with_message = ( NODE_STATUS.READY, NODE_STATUS.COMMISSIONING) help_link = "https://wiki.ubuntu.com/ServerTeam/MAAS/AvahiBoot" for status in map_enum(NODE_STATUS).values(): node = factory.make_node(status=status) node_link = reverse('node-view', args=[node.system_id]) response = self.client.get(node_link) links = get_content_links(response, '#flash-messages') if status in statuses_with_message: self.assertIn(help_link, links) else: self.assertNotIn(help_link, links)
def getRandomEnum(self, enum, but_not=None): """Pick a random item from an enumeration class. :param enum: An enumeration class such as `NODE_STATUS`. :return: The value of one of its items. :param but_not: A list of choices' IDs to exclude. :type but_not: Sequence. """ if but_not is None: but_not = () return random.choice([ value for value in list(map_enum(enum).values()) if value not in but_not ])
def test_map_enum_omits_private_or_special_methods(self): class Enum: def __init__(self): pass def __repr__(self): return "Enum" def _save(self): pass VALUE = 9 self.assertItemsEqual(['VALUE'], map_enum(Enum).keys())
class UseDI(NodeAction): """Set this node to use d-i for installation.""" name = "usedi" display = "Use the default installer" display_bulk = "Mark nodes as using the default installer" actionable_statuses = map_enum(NODE_STATUS).values() permission = NODE_PERMISSION.EDIT def is_permitted(self): permitted = super(UseDI, self).is_permitted() return permitted and self.node.should_use_fastpath_installer() def execute(self, allow_redirect=True): """See `NodeAction.execute`.""" self.node.use_traditional_installer() return "Node marked as using the default installer."
def test_POST_release_fails_for_other_node_states(self): releasable_statuses = [ NODE_STATUS.RESERVED, NODE_STATUS.ALLOCATED, NODE_STATUS.READY, ] unreleasable_statuses = [ status for status in map_enum(NODE_STATUS).values() if status not in releasable_statuses ] nodes = [ factory.make_node(status=status, owner=self.logged_in_user) for status in unreleasable_statuses] responses = [ self.client.post(self.get_node_uri(node), {'op': 'release'}) for node in nodes] self.assertEqual( [httplib.CONFLICT] * len(unreleasable_statuses), [response.status_code for response in responses]) self.assertItemsEqual( unreleasable_statuses, [node.status for node in reload_objects(Node, nodes)])
def test_POST_accept_rejects_impossible_state_changes(self): self.become_admin() acceptable_states = set([ NODE_STATUS.DECLARED, NODE_STATUS.COMMISSIONING, NODE_STATUS.READY, ]) unacceptable_states = (set(map_enum(NODE_STATUS).values()) - acceptable_states) nodes = { status: factory.make_node(status=status) for status in unacceptable_states } responses = { status: self.client.post(reverse('nodes_handler'), { 'op': 'accept', 'nodes': [node.system_id], }) for status, node in nodes.items() } # All of these attempts are rejected with Conflict errors. self.assertEqual( {status: httplib.CONFLICT for status in unacceptable_states}, { status: responses[status].status_code for status in unacceptable_states }) for status, response in responses.items(): # Each error describes the problem. self.assertIn("Cannot accept node enlistment", response.content) # Each error names the node it encountered a problem with. self.assertIn(nodes[status].system_id, response.content) # Each error names the node state that the request conflicted # with. self.assertIn(NODE_STATUS_CHOICES_DICT[status], response.content)
def test_POWER_TYPE_PARAMETERS_is_dict_with_power_type_keys(self): power_types = set(map_enum(POWER_TYPE).values()) self.assertIsInstance(POWER_TYPE_PARAMETERS, dict) self.assertThat(power_types, ContainsAll(POWER_TYPE_PARAMETERS))
from maasserver.utils import map_enum import maastesting.factory from maastesting.factory import NO_VALUE from metadataserver.fields import Bin from metadataserver.models import ( CommissioningScript, NodeCommissionResult, ) from netaddr import IPAddress # We have a limited number of public keys: # src/maasserver/tests/data/test_rsa{0, 1, 2, 3, 4}.pub MAX_PUBLIC_KEYS = 5 ALL_NODE_STATES = map_enum(NODE_STATUS).values() class Factory(maastesting.factory.Factory): def make_file_upload(self, name=None, content=None): """Create a file-like object for upload in http POST or PUT. To upload a file using the Django test client, just include a parameter that maps not to a string, but to a file upload as produced by this method. :param name: Name of the file to be uploaded. If omitted, one will be made up. :type name: `unicode` :param content: Contents for the uploaded file. If omitted, some
) from maasserver.utils import map_enum import maastesting.factory from maastesting.factory import NO_VALUE from metadataserver.fields import Bin from metadataserver.models import ( CommissioningScript, NodeCommissionResult, ) from netaddr import IPAddress # We have a limited number of public keys: # src/maasserver/tests/data/test_rsa{0, 1, 2, 3, 4}.pub MAX_PUBLIC_KEYS = 5 ALL_NODE_STATES = map_enum(NODE_STATUS).values() class Factory(maastesting.factory.Factory): def make_file_upload(self, name=None, content=None): """Create a file-like object for upload in http POST or PUT. To upload a file using the Django test client, just include a parameter that maps not to a string, but to a file upload as produced by this method. :param name: Name of the file to be uploaded. If omitted, one will be made up. :type name: `unicode` :param content: Contents for the uploaded file. If omitted, some contents will be made up.
def serialize_enum(enum): """Represent a MAAS enum class in JavaScript.""" return "module.%s = %s;\n" % ( enum.__name__, json.dumps(map_enum(enum), indent=4, sort_keys=True))
def get_random_component(): return random.choice(map_enum(COMPONENT).values())