190
184
class TestModuleHelpers(TestCase):
192
def make_fake_request(self, auth_header):
193
"""Create a very simple fake request, with just an auth header."""
194
FakeRequest = namedtuple('FakeRequest', ['META'])
195
return FakeRequest(META={'HTTP_AUTHORIZATION': auth_header})
197
def test_extract_oauth_key_from_auth_header_returns_key(self):
198
token = factory.getRandomString(18)
201
extract_oauth_key_from_auth_header(
202
factory.make_oauth_header(oauth_token=token)))
204
def test_extract_oauth_key_from_auth_header_returns_None_if_missing(self):
205
self.assertIs(None, extract_oauth_key_from_auth_header(''))
207
def test_extract_oauth_key_raises_Unauthorized_if_no_auth_header(self):
210
extract_oauth_key, self.make_fake_request(None))
212
def test_extract_oauth_key_raises_Unauthorized_if_no_key(self):
215
extract_oauth_key, self.make_fake_request(''))
217
def test_extract_oauth_key_returns_key(self):
218
token = factory.getRandomString(18)
221
extract_oauth_key(self.make_fake_request(
222
factory.make_oauth_header(oauth_token=token))))
224
def test_get_oauth_token_finds_token(self):
225
user = factory.make_user()
226
consumer, token = user.get_profile().create_authorisation_token()
230
self.make_fake_request(
231
factory.make_oauth_header(oauth_token=token.key))))
233
def test_get_oauth_token_raises_Unauthorized_for_unknown_token(self):
234
fake_token = factory.getRandomString(18)
235
header = factory.make_oauth_header(oauth_token=fake_token)
238
get_oauth_token, self.make_fake_request(header))
240
186
def test_extract_constraints_ignores_unknown_parameters(self):
241
187
unknown_parameter = "%s=%s" % (
242
188
factory.getRandomString(),
4566
4520
self.assertEqual(httplib.FORBIDDEN, response.status_code)
4522
def test_import_boot_images_calls_script_for_all_accepted_clusters(self):
4523
recorder = self.patch(nodegroup_module, 'import_boot_images')
4524
proxy = factory.make_name('proxy')
4525
Config.objects.set_config('http_proxy', proxy)
4526
accepted_nodegroups = [
4527
factory.make_node_group(status=NODEGROUP_STATUS.ACCEPTED),
4528
factory.make_node_group(status=NODEGROUP_STATUS.ACCEPTED),
4530
factory.make_node_group(status=NODEGROUP_STATUS.REJECTED)
4531
factory.make_node_group(status=NODEGROUP_STATUS.PENDING)
4532
admin = factory.make_admin()
4533
client = OAuthAuthenticatedClient(admin)
4534
response = client.post(
4535
reverse('nodegroups_handler'), {'op': 'import_boot_images'})
4537
httplib.OK, response.status_code,
4538
explain_unexpected_response(httplib.OK, response))
4541
for args, kwargs in recorder.apply_async.call_args_list]
4542
self.assertItemsEqual(
4543
[nodegroup.work_queue for nodegroup in accepted_nodegroups],
4546
def test_import_boot_images_denied_if_not_admin(self):
4547
user = factory.make_user()
4548
client = OAuthAuthenticatedClient(user)
4549
response = client.post(
4550
reverse('nodegroups_handler'), {'op': 'import_boot_images'})
4552
httplib.FORBIDDEN, response.status_code,
4553
explain_unexpected_response(httplib.FORBIDDEN, response))
4569
4556
def log_in_as_normal_user(client):
4570
4557
"""Log `client` in as a normal user."""
4660
4645
parsed_result = json.loads(response.content)
4661
4646
self.assertItemsEqual([node.system_id], parsed_result)
4648
def test_nodegroup_import_boot_images_calls_script(self):
4649
recorder = self.patch(tasks, 'check_call')
4650
proxy = factory.getRandomString()
4651
Config.objects.set_config('http_proxy', proxy)
4652
nodegroup = factory.make_node_group()
4653
admin = factory.make_admin()
4654
client = OAuthAuthenticatedClient(admin)
4655
response = client.post(
4656
reverse('nodegroup_handler', args=[nodegroup.uuid]),
4657
{'op': 'import_boot_images'})
4659
httplib.OK, response.status_code,
4660
explain_unexpected_response(httplib.OK, response))
4661
recorder.assert_called_once_with(
4662
['sudo', '-n', '-E', 'maas-import-pxe-files'], env=ANY)
4664
def test_nodegroup_import_boot_images_denied_if_not_admin(self):
4665
nodegroup = factory.make_node_group()
4666
user = factory.make_user()
4667
client = OAuthAuthenticatedClient(user)
4668
response = client.post(
4669
reverse('nodegroup_handler', args=[nodegroup.uuid]),
4670
{'op': 'import_boot_images'})
4672
httplib.FORBIDDEN, response.status_code,
4673
explain_unexpected_response(httplib.FORBIDDEN, response))
4663
4675
def make_node_hardware_details_request(self, client, nodegroup=None):
4664
4676
if nodegroup is None:
4665
4677
nodegroup = factory.make_node_group()
4868
4880
images=ANY, nodegroup=ANY)
4883
class AdminCommissioningScriptsAPITest(APIv10TestMixin, AdminLoggedInTestCase):
4884
"""Tests for `CommissioningScriptsHandler`."""
4887
return reverse('commissioning_scripts_handler')
4889
def test_GET_lists_commissioning_scripts(self):
4890
# Use lower-case names. The database and the test may use
4891
# different collation orders with different ideas about case
4893
names = {factory.make_name('script').lower() for counter in range(5)}
4895
factory.make_commissioning_script(name=name)
4897
response = self.client.get(self.get_url())
4900
(httplib.OK, sorted(names)),
4901
(response.status_code, json.loads(response.content)))
4903
def test_POST_creates_commissioning_script(self):
4904
# This uses Piston's built-in POST code, so there are no tests for
4905
# corner cases (like "script already exists") here.
4906
name = factory.make_name('script')
4907
content = factory.getRandomString().encode('ascii')
4909
# Every uploaded file also has a name. But this is completely
4910
# unrelated to the name we give to the commissioning script.
4911
response = self.client.post(
4915
'content': factory.make_file_upload(content=content),
4917
self.assertEqual(httplib.OK, response.status_code)
4919
returned_script = json.loads(response.content)
4922
(returned_script['name'], returned_script['content']))
4924
stored_script = CommissioningScript.objects.get(name=name)
4925
self.assertEqual(content, stored_script.content)
4928
class CommissioningScriptsAPITest(APITestCase):
4931
return reverse('commissioning_scripts_handler')
4933
def test_GET_is_forbidden(self):
4934
response = self.client.get(self.get_url())
4935
self.assertEqual(httplib.FORBIDDEN, response.status_code)
4937
def test_POST_is_forbidden(self):
4938
response = self.client.post(
4940
{'name': factory.make_name('script')})
4941
self.assertEqual(httplib.FORBIDDEN, response.status_code)
4944
class AdminCommissioningScriptAPITest(APIv10TestMixin, AdminLoggedInTestCase):
4945
"""Tests for `CommissioningScriptHandler`."""
4947
def get_url(self, script_name):
4948
return reverse('commissioning_script_handler', args=[script_name])
4950
def test_GET_returns_script_contents(self):
4951
script = factory.make_commissioning_script()
4952
response = self.client.get(self.get_url(script.name))
4953
self.assertEqual(httplib.OK, response.status_code)
4954
self.assertEqual(script.content, response.content)
4956
def test_GET_preserves_binary_data(self):
4957
script = factory.make_commissioning_script(content=sample_binary_data)
4958
response = self.client.get(self.get_url(script.name))
4959
self.assertEqual(httplib.OK, response.status_code)
4960
self.assertEqual(sample_binary_data, response.content)
4962
def test_PUT_updates_contents(self):
4963
old_content = b'old:%s' % factory.getRandomString().encode('ascii')
4964
script = factory.make_commissioning_script(content=old_content)
4965
new_content = b'new:%s' % factory.getRandomString().encode('ascii')
4967
response = self.client.put(
4968
self.get_url(script.name),
4969
{'content': factory.make_file_upload(content=new_content)})
4970
self.assertEqual(httplib.OK, response.status_code)
4972
self.assertEqual(new_content, reload_object(script).content)
4974
def test_DELETE_deletes_script(self):
4975
script = factory.make_commissioning_script()
4976
self.client.delete(self.get_url(script.name))
4977
self.assertItemsEqual(
4979
CommissioningScript.objects.filter(name=script.name))
4982
class CommissioningScriptAPITest(APITestCase):
4984
def get_url(self, script_name):
4985
return reverse('commissioning_script_handler', args=[script_name])
4987
def test_GET_is_forbidden(self):
4988
# It's not inconceivable that commissioning scripts contain
4989
# credentials of some sort. There is no need for regular users
4990
# (consumers of the MAAS) to see these.
4991
script = factory.make_commissioning_script()
4992
response = self.client.get(self.get_url(script.name))
4993
self.assertEqual(httplib.FORBIDDEN, response.status_code)
4995
def test_PUT_is_forbidden(self):
4996
script = factory.make_commissioning_script()
4997
response = self.client.put(
4998
self.get_url(script.name), {'content': factory.getRandomString()})
4999
self.assertEqual(httplib.FORBIDDEN, response.status_code)
5001
def test_DELETE_is_forbidden(self):
5002
script = factory.make_commissioning_script()
5003
response = self.client.put(self.get_url(script.name))
5004
self.assertEqual(httplib.FORBIDDEN, response.status_code)
5007
class NodeCommissionResultHandlerAPITest(APITestCase):
5009
def test_list_returns_commissioning_results(self):
5010
commissioning_results = [
5011
factory.make_node_commission_result()
5012
for counter in range(3)]
5013
url = reverse('commissioning_results_handler')
5014
response = self.client.get(url, {'op': 'list'})
5015
self.assertEqual(httplib.OK, response.status_code, response.content)
5016
parsed_results = json.loads(response.content)
5017
self.assertItemsEqual(
5019
commissioning_result.name,
5020
commissioning_result.script_result,
5021
commissioning_result.data,
5022
commissioning_result.node.system_id,
5024
for commissioning_result in commissioning_results
5028
result.get('script_result'),
5030
result.get('node').get('system_id')
5032
for result in parsed_results
5035
def test_list_can_be_filtered_by_node(self):
5036
commissioning_results = [
5037
factory.make_node_commission_result()
5038
for counter in range(3)]
5039
url = reverse('commissioning_results_handler')
5040
response = self.client.get(
5046
commissioning_results[0].node.system_id,
5047
commissioning_results[1].node.system_id,
5051
self.assertEqual(httplib.OK, response.status_code, response.content)
5052
parsed_results = json.loads(response.content)
5053
self.assertItemsEqual(
5054
[commissioning_results[0].data, commissioning_results[1].data],
5055
[result.get('data') for result in parsed_results])
5057
def test_list_can_be_filtered_by_name(self):
5058
commissioning_results = [
5059
factory.make_node_commission_result()
5060
for counter in range(3)]
5061
url = reverse('commissioning_results_handler')
5062
response = self.client.get(
5066
'name': commissioning_results[0].name
5069
self.assertEqual(httplib.OK, response.status_code, response.content)
5070
parsed_results = json.loads(response.content)
5071
self.assertItemsEqual(
5072
[commissioning_results[0].data],
5073
[result.get('data') for result in parsed_results])
5075
def test_list_displays_only_visible_nodes(self):
5076
node = factory.make_node(owner=factory.make_user())
5077
factory.make_node_commission_result(node)
5078
url = reverse('commissioning_results_handler')
5079
response = self.client.get(url, {'op': 'list'})
5080
self.assertEqual(httplib.OK, response.status_code, response.content)
5081
parsed_results = json.loads(response.content)
5082
self.assertEqual([], parsed_results)
4871
5085
class TestDescribe(AnonAPITestCase):
4872
5086
"""Tests for the `describe` view."""