116
120
self.assertEqual('diane', parsed_result['hostname'])
117
121
self.assertNotEqual(0, len(parsed_result.get('system_id')))
118
122
[diane] = Node.objects.filter(hostname='diane')
119
self.assertEqual(2, diane.after_commissioning_action)
123
# XXX JeroenVermeulen 2012-04-12, bug=979539: re-enable.
124
#self.assertEqual(2, diane.after_commissioning_action)
120
125
self.assertEqual(architecture, diane.architecture)
122
def test_POST_new_anonymous_creates_node_in_declared_state(self):
123
# Upon anonymous enlistment, a node goes into the Declared
124
# state. Deliberate approval is required before we start
125
# reinstalling the system, wiping its disks etc.
126
response = self.client.post(
127
self.get_uri('nodes/'),
130
'hostname': factory.getRandomString(),
131
'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES),
132
'after_commissioning_action': '2',
133
'mac_addresses': ['aa:bb:cc:dd:ee:ff'],
135
self.assertEqual(httplib.OK, response.status_code)
136
system_id = json.loads(response.content)['system_id']
138
NODE_STATUS.DECLARED,
139
Node.objects.get(system_id=system_id).status)
141
127
def test_POST_new_power_type_defaults_to_asking_config(self):
142
128
architecture = factory.getRandomChoice(ARCHITECTURE_CHOICES)
143
129
response = self.client.post(
318
286
self.assertIn('application/json', response['Content-Type'])
319
287
self.assertItemsEqual(['architecture'], parsed_result)
290
class NonAdminEnlistmentAPITest(EnlistmentAPITest):
291
# This is a mixin containing enlistement tests for non-admin users.
293
def test_POST_non_admin_creates_node_in_declared_state(self):
294
# Upon non-admin enlistment, a node goes into the Declared
295
# state. Deliberate approval is required before we start
296
# reinstalling the system, wiping its disks etc.
297
response = self.client.post(
298
self.get_uri('nodes/'),
301
'hostname': factory.getRandomString(),
302
'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES),
303
'after_commissioning_action': '2',
304
'mac_addresses': ['aa:bb:cc:dd:ee:ff'],
306
self.assertEqual(httplib.OK, response.status_code)
307
system_id = json.loads(response.content)['system_id']
309
NODE_STATUS.DECLARED,
310
Node.objects.get(system_id=system_id).status)
313
class AnonymousEnlistmentAPITest(NonAdminEnlistmentAPITest, TestCase):
314
# This is an actual test case that uses the NonAdminEnlistmentAPITest
315
# mixin and adds enlistement tests specific to anonymous users.
321
317
def test_POST_accept_not_allowed(self):
322
318
# An anonymous user is not allowed to accept an anonymously
323
319
# enlisted node. That would defeat the whole purpose of holding
329
325
(httplib.UNAUTHORIZED, "You must be logged in to accept nodes."),
330
326
(response.status_code, response.content))
328
def test_POST_returns_limited_fields(self):
329
response = self.client.post(
330
self.get_uri('nodes/'),
333
'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES),
334
'hostname': factory.getRandomString(),
335
'after_commissioning_action': '2',
336
'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'],
338
parsed_result = json.loads(response.content)
339
self.assertItemsEqual(
341
'hostname', 'system_id', 'macaddress_set', 'architecture',
347
class SimpleUserLoggedInEnlistmentAPITest(NonAdminEnlistmentAPITest,
349
# This is an actual test case that uses the NonAdminEnlistmentAPITest
350
# mixin plus enlistement tests specific to simple (non-admin) users.
352
def test_POST_accept_not_allowed(self):
353
# An non-admin user is not allowed to accept an anonymously
354
# enlisted node. That would defeat the whole purpose of holding
355
# those nodes for approval.
356
node_id = factory.make_node(status=NODE_STATUS.DECLARED).system_id
357
response = self.client.post(
358
self.get_uri('nodes/'), {'op': 'accept', 'nodes': [node_id]})
361
"You don't have the required permission to accept the "
362
"following node(s): %s." % node_id),
363
(response.status_code, response.content))
365
def test_POST_returns_limited_fields(self):
366
response = self.client.post(
367
self.get_uri('nodes/'),
370
'hostname': factory.getRandomString(),
371
'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES),
372
'after_commissioning_action': '2',
373
'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'],
375
parsed_result = json.loads(response.content)
376
self.assertItemsEqual(
378
'hostname', 'system_id', 'macaddress_set', 'architecture',
379
'status', 'resource_uri',
384
class AdminLoggedInEnlistmentAPITest(EnlistmentAPITest,
385
AdminLoggedInTestCase):
386
# This is an actual test case that uses the EnlistmentAPITest mixin
387
# and adds enlistement tests specific to admin users.
389
def test_POST_admin_creates_node_in_commissioning_state(self):
390
# When an admin user enlists a node, it goes into the
391
# Commissioning state.
392
response = self.client.post(
393
self.get_uri('nodes/'),
396
'hostname': factory.getRandomString(),
397
'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES),
398
'after_commissioning_action': '2',
399
'mac_addresses': ['aa:bb:cc:dd:ee:ff'],
401
self.assertEqual(httplib.OK, response.status_code)
402
system_id = json.loads(response.content)['system_id']
404
NODE_STATUS.COMMISSIONING,
405
Node.objects.get(system_id=system_id).status)
407
def test_POST_returns_limited_fields(self):
408
response = self.client.post(
409
self.get_uri('nodes/'),
412
'hostname': factory.getRandomString(),
413
'architecture': factory.getRandomChoice(ARCHITECTURE_CHOICES),
414
'after_commissioning_action': '2',
415
'mac_addresses': ['aa:bb:cc:dd:ee:ff', '22:bb:cc:dd:ee:ff'],
417
parsed_result = json.loads(response.content)
418
self.assertItemsEqual(
420
'hostname', 'system_id', 'macaddress_set', 'architecture',
421
'status', 'resource_uri',
426
class AnonymousIsRegisteredAPITest(APIv10TestMixin, TestCase):
428
def test_is_registered_returns_True_if_node_registered(self):
429
mac_address = factory.getRandomMACAddress()
430
factory.make_mac_address(mac_address)
431
response = self.client.get(
432
self.get_uri('nodes/'),
433
{'op': 'is_registered', 'mac_address': mac_address})
435
(httplib.OK, "true"),
436
(response.status_code, response.content))
438
def test_is_registered_returns_False_if_mac_registered_node_retired(self):
439
mac_address = factory.getRandomMACAddress()
440
mac = factory.make_mac_address(mac_address)
441
mac.node.status = NODE_STATUS.RETIRED
443
response = self.client.get(
444
self.get_uri('nodes/'),
445
{'op': 'is_registered', 'mac_address': mac_address})
447
(httplib.OK, "false"),
448
(response.status_code, response.content))
450
def test_is_registered_normalizes_mac_address(self):
451
# These two non-normalized MAC Addresses are the same.
452
non_normalized_mac_address = 'AA-bb-cc-dd-ee-ff'
453
non_normalized_mac_address2 = 'aabbccddeeff'
454
factory.make_mac_address(non_normalized_mac_address)
455
response = self.client.get(
456
self.get_uri('nodes/'),
458
'op': 'is_registered',
459
'mac_address': non_normalized_mac_address2
462
(httplib.OK, "true"),
463
(response.status_code, response.content))
465
def test_is_registered_returns_False_if_node_not_registered(self):
466
mac_address = factory.getRandomMACAddress()
467
response = self.client.get(
468
self.get_uri('nodes/'),
469
{'op': 'is_registered', 'mac_address': mac_address})
471
(httplib.OK, "false"),
472
(response.status_code, response.content))
333
475
class NodeAnonAPITest(APIv10TestMixin, TestCase):
335
477
def test_anon_nodes_GET(self):
336
# Anonymous requests to the API are denied.
478
# Anonymous requests to the API without a specified operation
479
# get a "Bad Request" response.
337
480
response = self.client.get(self.get_uri('nodes/'))
339
self.assertEqual(httplib.UNAUTHORIZED, response.status_code)
482
self.assertEqual(httplib.BAD_REQUEST, response.status_code)
341
484
def test_anon_api_doc(self):
342
485
# The documentation is accessible to anon users.