1
# Copyright 2012 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Test node filtering on specific constraints."""
6
from __future__ import (
15
from maasserver.enum import ARCHITECTURE
16
from maasserver.exceptions import InvalidConstraint
17
from maasserver.models import Node
18
from maasserver.models.node_constraint_filter import (
20
generate_architecture_wildcards,
22
from maasserver.testing.factory import factory
23
from maasserver.testing.testcase import TestCase
24
from maasserver.utils import ignore_unused
27
class TestConstrainNodes(TestCase):
29
def assertConstrainedNodes(self, expected_nodes, constraints):
30
nodes = constrain_nodes(Node.objects.all(), constraints)
31
self.assertItemsEqual(expected_nodes, nodes)
33
def test_generate_architecture_wildcards(self):
34
# Create a test architecture choice list of one architecture that only
35
# has one available subarch (single_subarch) and two architectures that
36
# have a matching primary architecture (double_subarch_{1,2})
37
single_subarch = factory.make_name('arch'), factory.make_name('arch')
38
double_subarch_1 = factory.make_name('arch'), factory.make_name('arch')
39
double_subarch_2 = double_subarch_1[0], factory.make_name('arch')
41
('/'.join(single_subarch), None),
42
('/'.join(double_subarch_1), None),
43
('/'.join(double_subarch_2), None),
46
# single_subarch should end up in the dict essentially unchanged, and
47
# the double_subarchs should have been flattened into a single dict
48
# element with a list of them.
50
single_subarch[0]: frozenset([choices[0][0]]),
51
double_subarch_1[0]: frozenset([choices[1][0], choices[2][0]]),
53
generate_architecture_wildcards(choices=choices)
56
def test_no_constraints(self):
57
node1 = factory.make_node()
58
node2 = factory.make_node()
59
self.assertConstrainedNodes([node1, node2], None)
60
self.assertConstrainedNodes([node1, node2], {})
62
def test_hostname(self):
63
node1 = factory.make_node()
64
node2 = factory.make_node()
65
self.assertConstrainedNodes([node1], {'hostname': node1.hostname})
66
self.assertConstrainedNodes([node2], {'hostname': node2.hostname})
67
self.assertConstrainedNodes([], {'hostname': 'unknown-name'})
69
def test_cpu_count(self):
70
node1 = factory.make_node(cpu_count=1)
71
node2 = factory.make_node(cpu_count=2)
72
self.assertConstrainedNodes([node1, node2], {'cpu_count': '0'})
73
self.assertConstrainedNodes([node1, node2], {'cpu_count': '1'})
74
self.assertConstrainedNodes([node2], {'cpu_count': '2'})
75
self.assertConstrainedNodes([], {'cpu_count': '4'})
76
self.assertConstrainedNodes([node2], {'cpu_count': '2.0'})
77
self.assertConstrainedNodes([node2], {'cpu_count': '1.2'})
78
self.assertRaises(InvalidConstraint,
79
self.assertConstrainedNodes, [], {'cpu_count': 'notint'})
81
def test_memory(self):
82
node1 = factory.make_node(memory=1024)
83
node2 = factory.make_node(memory=4096)
84
self.assertConstrainedNodes([node1, node2], {'memory': '512'})
85
self.assertConstrainedNodes([node1, node2], {'memory': '1024'})
86
self.assertConstrainedNodes([node2], {'memory': '2048'})
87
self.assertConstrainedNodes([node2], {'memory': '4096'})
88
self.assertConstrainedNodes([], {'memory': '8192'})
89
self.assertConstrainedNodes([node2], {'memory': '4096.0'})
90
self.assertRaises(InvalidConstraint,
91
self.assertConstrainedNodes, [], {'memory': 'notint'})
94
tag_big = factory.make_tag(name='big')
95
tag_burly = factory.make_tag(name='burly')
96
node_big = factory.make_node()
97
node_big.tags.add(tag_big)
98
node_burly = factory.make_node()
99
node_burly.tags.add(tag_burly)
100
node_bignburly = factory.make_node()
101
node_bignburly.tags.add(tag_big)
102
node_bignburly.tags.add(tag_burly)
103
self.assertConstrainedNodes([node_big, node_bignburly],
105
self.assertConstrainedNodes([node_burly, node_bignburly],
107
self.assertConstrainedNodes([node_bignburly],
108
{'tags': 'big,burly'})
109
self.assertConstrainedNodes([node_bignburly],
110
{'tags': 'big burly'})
111
self.assertRaises(InvalidConstraint,
112
self.assertConstrainedNodes, [], {'tags': 'big unknown'})
114
def test_combined_constraints(self):
115
tag_big = factory.make_tag(name='big')
116
node_big = factory.make_node(architecture=ARCHITECTURE.i386)
117
node_big.tags.add(tag_big)
118
node_small = factory.make_node(architecture=ARCHITECTURE.i386)
119
ignore_unused(node_small)
120
node_big_arm = factory.make_node(
121
architecture=ARCHITECTURE.armhf_highbank)
122
node_big_arm.tags.add(tag_big)
123
self.assertConstrainedNodes([node_big, node_big_arm],
125
self.assertConstrainedNodes(
126
[node_big], {'architecture': 'i386/generic', 'tags': 'big'})
129
class TestConstrainNodesByArchitecture(TestCase):
132
super(TestConstrainNodesByArchitecture, self).setUp()
133
self.node1 = factory.make_node(architecture=ARCHITECTURE.i386)
134
self.node2 = factory.make_node(
135
architecture=ARCHITECTURE.armhf_highbank)
137
def assertArchConstrainsNodes(self, expected_nodes, architecture):
138
nodes = constrain_nodes(
139
Node.objects.all(), dict(architecture=architecture))
140
self.assertItemsEqual(expected_nodes, nodes)
142
def test_full_arch_name_i386_generic(self):
143
self.assertArchConstrainsNodes([self.node1], 'i386/generic')
145
def test_full_arch_name_armhf_highbank(self):
146
self.assertArchConstrainsNodes([self.node2], 'armhf/highbank')
148
def test_primary_arch_name_i386(self):
149
self.assertArchConstrainsNodes([self.node1], 'i386')
151
def test_primary_arch_name_armhf(self):
152
self.assertArchConstrainsNodes([self.node2], 'armhf')
154
def test_arm_alias(self):
155
self.assertArchConstrainsNodes([self.node2], 'arm')
157
def test_invalid_full_architecture_raises_exception(self):
159
InvalidConstraint, constrain_nodes, Node.objects.all(),
160
dict(architecture='armhf/generic'))
162
def test_invalid_primary_architecture_raises_exception(self):
164
InvalidConstraint, constrain_nodes, Node.objects.all(),
165
dict(architecture='sparc'))