def test_hardware_updates_tags_match(self): tag1 = factory.make_tag(factory.getRandomString(10), "/node") tag2 = factory.make_tag(factory.getRandomString(10), "//node") node = factory.make_node() xmlbytes = '<node/>' node.set_hardware_details(xmlbytes) node = reload_object(node) self.assertEqual([tag1, tag2], list(node.tags.all()))
def test_POST_acquire_fails_without_all_tags(self): # Asking for particular tags does not acquire if no node has all tags. node1 = factory.make_node(status=NODE_STATUS.READY) node1.tags = [factory.make_tag(t) for t in ("fast", "stable", "cute")] node2 = factory.make_node(status=NODE_STATUS.READY) node2.tags = [factory.make_tag("cheap")] response = self.client.post(reverse('nodes_handler'), { 'op': 'acquire', 'tags': 'fast, cheap', }) self.assertResponseCode(httplib.CONFLICT, response)
def test_hardware_updates_tags_no_match(self): tag1 = factory.make_tag(factory.getRandomString(10), "/missing") ignore_unused(tag1) tag2 = factory.make_tag(factory.getRandomString(10), "/nothing") node = factory.make_node() node.tags = [tag2] node.save() xmlbytes = '<node/>' node.set_hardware_details(xmlbytes) node = reload_object(node) self.assertEqual([], list(node.tags.all()))
def test_doesnt_touch_other_tags(self): node1 = factory.make_node() inject_lshw_result(node1, b'<node><foo /></node>') node2 = factory.make_node() inject_lshw_result(node2, b'<node><bar /></node>') tag1 = factory.make_tag(definition='//node/foo') self.assertItemsEqual([tag1.name], node1.tag_names()) self.assertItemsEqual([], node2.tag_names()) tag2 = factory.make_tag(definition='//node/bar') self.assertItemsEqual([tag1.name], node1.tag_names()) self.assertItemsEqual([tag2.name], node2.tag_names())
def test_ignores_tags_with_unrecognised_namespaces(self): node = factory.make_node() factory.make_node_commission_result( node, commissioningscript.LSHW_OUTPUT_NAME, 0, b"<foo/>") tags = [ factory.make_tag("foo", "/foo"), factory.make_tag("lou", "//nge:bar"), ] populate_tags_for_single_node(tags, node) # Look mom, no exception! self.assertSequenceEqual( ["foo"], [tag.name for tag in node.tags.all()])
def test_doesnt_touch_other_tags(self): node1 = factory.make_node() node1.set_hardware_details('<node><foo /></node>') node2 = factory.make_node() node2.set_hardware_details('<node><bar /></node>') tag1 = factory.make_tag(definition='/node/foo') self.assertItemsEqual([tag1.name], node1.tag_names()) self.assertItemsEqual([], node2.tag_names()) tag2 = factory.make_tag(definition='/node/bar') self.assertItemsEqual([tag1.name], node1.tag_names()) self.assertItemsEqual([tag2.name], node2.tag_names())
def test_POST_acquire_fails_without_all_tags(self): # Asking for particular tags does not acquire if no node has all tags. node1 = factory.make_node(status=NODE_STATUS.READY) node1.tags = [factory.make_tag(t) for t in ("fast", "stable", "cute")] node2 = factory.make_node(status=NODE_STATUS.READY) node2.tags = [factory.make_tag("cheap")] response = self.client.post(reverse('nodes_handler'), { 'op': 'acquire', 'tags': 'fast, cheap', }) self.assertResponseCode(httplib.CONFLICT, response)
def test_use_traditional_installer_complains_when_tag_has_expression(self): # use_traditional_installer() complains when the use-fastpath-installer # tag exists and is defined with an expression. node = factory.make_node() factory.make_tag( name="use-fastpath-installer", definition="//something") error = self.assertRaises( RuntimeError, node.use_traditional_installer) self.assertIn( "The use-fastpath-installer tag is defined with an expression", unicode(error))
def test_hardware_updates_ignores_empty_tags(self): # Tags with empty definitions are ignored when # update_hardware_details gets called. factory.make_tag(definition='') node = factory.make_node() node.save() xmlbytes = '<node/>'.encode("utf-8") update_hardware_details(node, xmlbytes, 0) node = reload_object(node) # The real test is that update_hardware_details does not blow # up, see bug 1131418. self.assertEqual([], list(node.tags.all()))
def test_hardware_updates_ignores_empty_tags(self): # Tags with empty definitions are ignored when # update_hardware_details gets called. factory.make_tag(definition='') node = factory.make_node() node.save() xmlbytes = '<node/>'.encode("utf-8") update_hardware_details(node, xmlbytes, 0) node = reload_object(node) # The real test is that update_hardware_details does not blow # up, see bug 1131418. self.assertEqual([], list(node.tags.all()))
def test_get_effective_kernel_options_uses_first_real_tag_value(self): node = factory.make_node() # Intentionally create them in reverse order, so the default 'db' order # doesn't work, and we have asserted that we sort them. tag3 = factory.make_tag(factory.make_name('tag-03-'), kernel_opts=factory.getRandomString()) tag2 = factory.make_tag(factory.make_name('tag-02-'), kernel_opts=factory.getRandomString()) tag1 = factory.make_tag(factory.make_name('tag-01-'), kernel_opts=None) self.assertTrue(tag1.name < tag2.name) self.assertTrue(tag2.name < tag3.name) node.tags.add(tag1, tag2, tag3) self.assertEqual( (tag2, tag2.kernel_opts), node.get_effective_kernel_options())
def test_updates_node_with_all_applicable_tags(self): node = factory.make_node() factory.make_node_commission_result( node, commissioningscript.LSHW_OUTPUT_NAME, 0, b"<foo/>") factory.make_node_commission_result( node, commissioningscript.LLDP_OUTPUT_NAME, 0, b"<bar/>") tags = [ factory.make_tag("foo", "/foo"), factory.make_tag("bar", "//lldp:bar"), factory.make_tag("baz", "/foo/bar"), ] populate_tags_for_single_node(tags, node) self.assertItemsEqual( ["foo", "bar"], [tag.name for tag in node.tags.all()])
def test_get_effective_kernel_options_uses_first_real_tag_value(self): node = factory.make_node() # Intentionally create them in reverse order, so the default 'db' order # doesn't work, and we have asserted that we sort them. tag3 = factory.make_tag(factory.make_name('tag-03-'), kernel_opts=factory.getRandomString()) tag2 = factory.make_tag(factory.make_name('tag-02-'), kernel_opts=factory.getRandomString()) tag1 = factory.make_tag(factory.make_name('tag-01-'), kernel_opts=None) self.assertTrue(tag1.name < tag2.name) self.assertTrue(tag2.name < tag3.name) node.tags.add(tag1, tag2, tag3) self.assertEqual( (tag2, tag2.kernel_opts), node.get_effective_kernel_options())
def test_view_node_contains_tag_names(self): node = factory.make_node(owner=self.logged_in_user) tag_a = factory.make_tag() tag_b = factory.make_tag() node.tags.add(tag_a) node.tags.add(tag_b) node_link = reverse('node-view', args=[node.system_id]) response = self.client.get(node_link) doc = fromstring(response.content) tag_text = doc.cssselect('#node_tags')[0].text_content() self.assertThat(tag_text, ContainsAll([tag_a.name, tag_b.name])) self.assertItemsEqual( [reverse('tag-view', args=[t.name]) for t in (tag_a, tag_b)], [link for link in get_content_links(response) if link.startswith('/tags/')])
def test_tags(self): tag_big = factory.make_tag(name='big') tag_burly = factory.make_tag(name='burly') node_big = factory.make_node() node_big.tags.add(tag_big) node_burly = factory.make_node() node_burly.tags.add(tag_burly) node_bignburly = factory.make_node() node_bignburly.tags.add(tag_big) node_bignburly.tags.add(tag_burly) self.assertConstrainedNodes( [node_big, node_bignburly], {'tags': ['big']}) self.assertConstrainedNodes( [node_burly, node_bignburly], {'tags': ['burly']}) self.assertConstrainedNodes( [node_bignburly], {'tags': ['big', 'burly']})
def test_populate_tags_task_routed_to_nodegroup_worker(self): nodegroup = factory.make_node_group() tag = factory.make_tag() task = self.patch(populate_tags_module, 'update_node_tags') populate_tags(tag) args, kwargs = task.apply_async.call_args self.assertEqual(nodegroup.work_queue, kwargs['queue'])
def test_add_tag_to_node(self): node = factory.make_node() tag = factory.make_tag() tag.save() node.tags.add(tag) self.assertEqual([tag.id], [t.id for t in node.tags.all()]) self.assertEqual([node.id], [n.id for n in tag.node_set.all()])
def test_tags(self): tag_big = factory.make_tag(name='big') tag_burly = factory.make_tag(name='burly') node_big = factory.make_node() node_big.tags.add(tag_big) node_burly = factory.make_node() node_burly.tags.add(tag_burly) node_bignburly = factory.make_node() node_bignburly.tags.add(tag_big) node_bignburly.tags.add(tag_burly) self.assertConstrainedNodes([node_big, node_bignburly], {'tags': ['big']}) self.assertConstrainedNodes([node_burly, node_bignburly], {'tags': ['burly']}) self.assertConstrainedNodes([node_bignburly], {'tags': ['big', 'burly']})
def test_get_nodes_doesnt_return_other_owned_nodes(self): user1 = factory.make_user() user2 = factory.make_user() node1 = factory.make_node(owner=user1) tag = factory.make_tag() node1.tags.add(tag) self.assertItemsEqual([], Tag.objects.get_nodes(tag.name, user2))
def test_GET_nodes_with_no_nodes(self): tag = factory.make_tag() response = self.client.get(self.get_tag_uri(tag), {'op': 'nodes'}) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual([], parsed_result)
def test_view_tag_num_queries_is_independent_of_num_nodes(self): tag = factory.make_tag() tag_link = reverse('tag-view', args=[tag.name]) nodegroup = factory.make_node_group() nodes = [ factory.make_node(nodegroup=nodegroup, mac=True) for i in range(20) ] for node in nodes[:10]: node.tags.add(tag) num_queries, response = self.getNumQueries(self.client.get, tag_link) self.assertEqual( 10, len([ link for link in get_content_links(response) if link.startswith('/nodes/node') ])) # Need to get the tag, and the nodes, and the macs of the nodes self.assertTrue(num_queries > 3) for node in nodes[10:]: node.tags.add(tag) num_bonus_queries, response = self.getNumQueries( self.client.get, tag_link) self.assertEqual(num_queries, num_bonus_queries) self.assertEqual( 20, len([ link for link in get_content_links(response) if link.startswith('/nodes/node') ]))
def test_add_tag_to_node(self): node = factory.make_node() tag = factory.make_tag() tag.save() node.tags.add(tag) self.assertEqual([tag.id], [t.id for t in node.tags.all()]) self.assertEqual([node.id], [n.id for n in tag.node_set.all()])
def test_node_list_sort_preserves_other_params(self): # Set a very small page size to save creating lots of nodes page_size = 2 self.patch(nodes_views.NodeListView, 'paginate_by', page_size) nodes = [] tag = factory.make_tag('shiny') for name in ('bbb', 'ccc', 'ddd', 'aaa'): node = factory.make_node(hostname=name) node.tags = [tag] nodes.append(node) params = { 'sort': 'hostname', 'dir': 'asc', 'page': '1', 'query': 'maas-tags=shiny'} response = self.client.get(reverse('node-list'), params) document = fromstring(response.content) header_links = document.xpath("//div[@id='nodes']/table//th/a/@href") fields = iter(('hostname', 'status')) field_dirs = iter(('desc', 'asc')) for link in header_links: self.assertThat( parse_qsl(urlparse(link).query), ContainsAll([ ('page', '1'), ('query', 'maas-tags=shiny'), ('sort', next(fields)), ('dir', next(field_dirs))]))
def test_GET_nodes_with_no_nodes(self): tag = factory.make_tag() response = self.client.get(self.get_tag_uri(tag), {'op': 'nodes'}) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual([], parsed_result)
def test_populate_tags_task_routed_to_nodegroup_worker(self): nodegroup = factory.make_node_group() tag = factory.make_tag() task = self.patch(populate_tags_module, 'update_node_tags') populate_tags(tag) args, kwargs = task.apply_async.call_args self.assertEqual(nodegroup.work_queue, kwargs['queue'])
def test_rollsback_invalid_xpath(self): node = factory.make_node() inject_lshw_result(node, b'<node><foo /></node>') tag = factory.make_tag(definition='//node/foo') self.assertItemsEqual([tag.name], node.tag_names()) tag.definition = 'invalid::tag' self.assertRaises(ValidationError, tag.save) self.assertItemsEqual([tag.name], node.tag_names())
def test_factory_make_tag_with_hardware_details(self): tag = factory.make_tag('a-tag', 'true', kernel_opts="console=ttyS0") self.assertEqual('a-tag', tag.name) self.assertEqual('true', tag.definition) self.assertEqual('', tag.comment) self.assertEqual('console=ttyS0', tag.kernel_opts) self.assertIsNot(None, tag.updated) self.assertIsNot(None, tag.created)
def test_get_effective_kernel_options_not_confused_by_empty_tag(self): node = factory.make_node() tag = factory.make_tag() node.tags.add(tag) kernel_opts = factory.getRandomString() Config.objects.set_config('kernel_opts', kernel_opts) self.assertEqual( (None, kernel_opts), node.get_effective_kernel_options())
def test_get_effective_kernel_options_tag_overrides_global(self): node = factory.make_node() global_opts = factory.getRandomString() Config.objects.set_config('kernel_opts', global_opts) tag = factory.make_tag(kernel_opts=factory.getRandomString()) node.tags.add(tag) self.assertEqual( (tag, tag.kernel_opts), node.get_effective_kernel_options())
def test_get_effective_kernel_options_not_confused_by_empty_str_opts(self): node = factory.make_node() tag = factory.make_tag(kernel_opts="") node.tags.add(tag) kernel_opts = factory.getRandomString() Config.objects.set_config('kernel_opts', kernel_opts) self.assertEqual( (None, kernel_opts), node.get_effective_kernel_options())
def test_get_effective_kernel_options_multiple_tags_with_opts(self): # In this scenario: # global kernel_opts='fish-n-chips' # tag_a kernel_opts=null # tag_b kernel_opts='' # tag_c kernel_opts='bacon-n-eggs' # we require that 'bacon-n-eggs' is chosen as it is the first # tag with a valid kernel option. Config.objects.set_config('kernel_opts', 'fish-n-chips') node = factory.make_node() node.tags.add(factory.make_tag('tag_a')) node.tags.add(factory.make_tag('tag_b', kernel_opts='')) tag_c = factory.make_tag('tag_c', kernel_opts='bacon-n-eggs') node.tags.add(tag_c) self.assertEqual( (tag_c, 'bacon-n-eggs'), node.get_effective_kernel_options())
def test_get_effective_kernel_options_tag_overrides_global(self): node = factory.make_node() global_opts = factory.getRandomString() Config.objects.set_config('kernel_opts', global_opts) tag = factory.make_tag(kernel_opts=factory.getRandomString()) node.tags.add(tag) self.assertEqual( (tag, tag.kernel_opts), node.get_effective_kernel_options())
def test_applies_tags_to_nodes(self): node1 = factory.make_node() inject_lshw_result(node1, b'<node><child /></node>') node2 = factory.make_node() inject_lshw_result(node2, b'<node />') tag = factory.make_tag(definition='//node/child') self.assertItemsEqual([tag.name], node1.tag_names()) self.assertItemsEqual([], node2.tag_names())
def test_rollsback_invalid_xpath(self): node = factory.make_node() node.set_hardware_details('<node><foo /></node>') tag = factory.make_tag(definition='/node/foo') self.assertItemsEqual([tag.name], node.tag_names()) tag.definition = 'invalid::tag' self.assertRaises(ValidationError, tag.save) self.assertItemsEqual([tag.name], node.tag_names())
def test_factory_make_tag_with_hardware_details(self): tag = factory.make_tag('a-tag', 'true', kernel_opts="console=ttyS0") self.assertEqual('a-tag', tag.name) self.assertEqual('true', tag.definition) self.assertEqual('', tag.comment) self.assertEqual('console=ttyS0', tag.kernel_opts) self.assertIsNot(None, tag.updated) self.assertIsNot(None, tag.created)
def test_applies_tags_to_nodes(self): node1 = factory.make_node() node1.set_hardware_details('<node><child /></node>') node2 = factory.make_node() node2.set_hardware_details('<node />') tag = factory.make_tag(definition='/node/child') self.assertItemsEqual([tag.name], node1.tag_names()) self.assertItemsEqual([], node2.tag_names())
def test_POST_update_nodes_rejects_normal_user(self): tag = factory.make_tag() node = factory.make_node() response = self.client.post(self.get_tag_uri(tag), { 'op': 'update_nodes', 'add': [node.system_id], }) self.assertEqual(httplib.FORBIDDEN, response.status_code) self.assertItemsEqual([], tag.node_set.all())
def test_GET_returns_associated_tag(self): node = factory.make_node() tag = factory.make_tag() node.tags.add(tag) response = self.client.get(self.get_node_uri(node)) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual([tag.name], parsed_result['tag_names'])
def test_get_available_node_with_tag(self): """An available node can be selected off a given tag""" nodes = [self.make_node() for i in range(2)] tag = factory.make_tag('strong') user = factory.make_user() nodes[1].tags.add(tag) available_node = Node.objects.get_available_node_for_acquisition( user, {'tags': "strong"}) self.assertEqual(nodes[1], available_node)
def test_view_tag_shows_kernel_params(self): tag = factory.make_tag(kernel_opts='--test tag params') node = factory.make_node() node.tags = [tag] tag_link = reverse('tag-view', args=[tag.name]) response = self.client.get(tag_link) doc = fromstring(response.content) kernel_opts = doc.cssselect('.kernel-opts-tag')[0].text_content() self.assertIn('Kernel Parameters', kernel_opts) self.assertIn(tag.kernel_opts, kernel_opts)
def test_view_tag_shows_kernel_params(self): tag = factory.make_tag(kernel_opts='--test tag params') node = factory.make_node() node.tags = [tag] tag_link = reverse('tag-view', args=[tag.name]) response = self.client.get(tag_link) doc = fromstring(response.content) kernel_opts = doc.cssselect('.kernel-opts-tag')[0].text_content() self.assertIn('Kernel Parameters', kernel_opts) self.assertIn(tag.kernel_opts, kernel_opts)
def test_POST_update_nodes_rejects_normal_user(self): tag = factory.make_tag() node = factory.make_node() response = self.client.post( self.get_tag_uri(tag), { 'op': 'update_nodes', 'add': [node.system_id], }) self.assertEqual(httplib.FORBIDDEN, response.status_code) self.assertItemsEqual([], tag.node_set.all())
def test_POST_rebuild_leaves_manual_tags(self): tag = factory.make_tag(definition='') node = factory.make_node() node.tags.add(tag) self.assertItemsEqual([node], tag.node_set.all()) self.become_admin() response = self.client.post(self.get_tag_uri(tag), {'op': 'rebuild'}) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual({'rebuilding': tag.name}, parsed_result) self.assertItemsEqual([node], tag.node_set.all())
def test_GET_returns_tag(self): # The api allows for fetching a single Node (using system_id). tag = factory.make_tag('tag-name') url = reverse('tag_handler', args=['tag-name']) response = self.client.get(url) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual(tag.name, parsed_result['name']) self.assertEqual(tag.definition, parsed_result['definition']) self.assertEqual(tag.comment, parsed_result['comment'])
def test_POST_acquire_fails_with_unknown_tags(self): # Asking for a tag that does not exist gives a specific error. node = factory.make_node(status=NODE_STATUS.READY) node.tags = [factory.make_tag("fast")] response = self.client.post(reverse('nodes_handler'), { 'op': 'acquire', 'tags': 'fast, hairy, boo', }) self.assertEqual(httplib.BAD_REQUEST, response.status_code) self.assertEqual(dict(tags=["No such tag(s): 'hairy', 'boo'."]), json.loads(response.content))
def test_view_tag_displays_tag_info(self): # The tag page features the basic information about the tag. tag = factory.make_tag(name='the-named-tag', comment='Human description of the tag', definition='//xpath') tag_link = reverse('tag-view', args=[tag.name]) response = self.client.get(tag_link) doc = fromstring(response.content) content_text = doc.cssselect('#content')[0].text_content() self.assertThat(content_text, ContainsAll([tag.comment, tag.definition]))
def test_POST_rebuild_leaves_manual_tags(self): tag = factory.make_tag(definition='') node = factory.make_node() node.tags.add(tag) self.assertItemsEqual([node], tag.node_set.all()) self.become_admin() response = self.client.post(self.get_tag_uri(tag), {'op': 'rebuild'}) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual({'rebuilding': tag.name}, parsed_result) self.assertItemsEqual([node], tag.node_set.all())
def test_GET_returns_tag(self): # The api allows for fetching a single Node (using system_id). tag = factory.make_tag('tag-name') url = reverse('tag_handler', args=['tag-name']) response = self.client.get(url) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual(tag.name, parsed_result['name']) self.assertEqual(tag.definition, parsed_result['definition']) self.assertEqual(tag.comment, parsed_result['comment'])
def test_get_nodes_returns_everything_for_superuser(self): user1 = factory.make_user() user2 = factory.make_user() user2.is_superuser = True node1 = factory.make_node(owner=user1) node2 = factory.make_node() tag = factory.make_tag() node1.tags.add(tag) node2.tags.add(tag) self.assertItemsEqual([node1, node2], Tag.objects.get_nodes(tag.name, user2))
def test_POST_acquire_allocates_node_by_tags_mixed_input(self): node = factory.make_node(status=NODE_STATUS.READY) node_tag_names = ["fast", "stable", "cute"] node.tags = [factory.make_tag(t) for t in node_tag_names] # Mixed call using comma-separated tags in a list. response = self.client.post(reverse('nodes_handler'), { 'op': 'acquire', 'tags': ['fast, stable', 'cute'], }) self.assertResponseCode(httplib.OK, response) response_json = json.loads(response.content) self.assertEqual(node_tag_names, response_json['tag_names'])
def test_GET_nodes_returns_nodes(self): tag = factory.make_tag() node1 = factory.make_node() # Create a second node that isn't tagged. factory.make_node() node1.tags.add(tag) response = self.client.get(self.get_tag_uri(tag), {'op': 'nodes'}) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertEqual([node1.system_id], [r['system_id'] for r in parsed_result])
def test_POST_update_nodes_refuses_unidentified_nodegroup_worker(self): tag = factory.make_tag() nodegroup = factory.make_node_group() node = factory.make_node(nodegroup=nodegroup) client = make_worker_client(nodegroup) # We don't pass nodegroup:uuid so we get refused response = client.post(self.get_tag_uri(tag), { 'op': 'update_nodes', 'add': [node.system_id], }) self.assertEqual(httplib.FORBIDDEN, response.status_code) self.assertItemsEqual([], tag.node_set.all())
def test_POST_update_nodes_refuses_non_nodegroup_worker(self): tag = factory.make_tag() nodegroup = factory.make_node_group() node = factory.make_node(nodegroup=nodegroup) response = self.client.post( self.get_tag_uri(tag), { 'op': 'update_nodes', 'add': [node.system_id], 'nodegroup': nodegroup.uuid, }) self.assertEqual(httplib.FORBIDDEN, response.status_code) self.assertItemsEqual([], tag.node_set.all())
def test_view_tag_hides_private_nodes(self): tag = factory.make_tag() node = factory.make_node() node2 = factory.make_node(owner=factory.make_user()) node.tags.add(tag) node2.tags.add(tag) tag_link = reverse('tag-view', args=[tag.name]) response = self.client.get(tag_link) doc = fromstring(response.content) content_text = doc.cssselect('#content')[0].text_content() self.assertIn(node.hostname, content_text) self.assertNotIn(node2.hostname, content_text)