~allenap/maas/xxx-a-thon

« back to all changes in this revision

Viewing changes to src/maasserver/api/tests/test_machine.py

  • Committer: LaMont Jones
  • Date: 2016-03-07 23:20:52 UTC
  • mfrom: (4657.1.84 maas)
  • mto: (4657.1.93 maas)
  • mto: This revision was merged to the branch mainline in revision 4660.
  • Revision ID: lamont@canonical.com-20160307232052-rgfxbq7dujj6s093
MergeĀ fromĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
 
8
8
from base64 import b64encode
9
9
import http.client
10
 
from io import StringIO
11
 
import sys
12
10
 
13
 
import bson
14
11
from django.conf import settings
15
12
from django.core.urlresolvers import reverse
16
13
from django.db import transaction
20
17
    INTERFACE_TYPE,
21
18
    IPADDRESS_TYPE,
22
19
    NODE_STATUS,
23
 
    NODE_STATUS_CHOICES,
24
20
    NODE_STATUS_CHOICES_DICT,
25
21
    NODE_TYPE,
26
22
    NODE_TYPE_CHOICES,
66
62
from metadataserver.nodeinituser import get_node_init_user
67
63
from mock import ANY
68
64
from netaddr import IPNetwork
69
 
from provisioningserver.refresh.node_info_scripts import (
70
 
    LLDP_OUTPUT_NAME,
71
 
    LSHW_OUTPUT_NAME,
72
 
)
73
65
from provisioningserver.rpc.exceptions import PowerActionAlreadyInProgress
74
66
from provisioningserver.utils.enum import map_enum
75
67
from twisted.internet import defer
78
70
 
79
71
class MachineAnonAPITest(MAASServerTestCase):
80
72
 
81
 
    def setUp(self):
82
 
        super(MachineAnonAPITest, self).setUp()
83
 
        self.patch(node_module.Node, '_start')
84
 
        self.patch(node_module.Node, '_stop')
85
 
 
86
 
    def test_anon_api_doc(self):
87
 
        # The documentation is accessible to anon users.
88
 
        self.patch(sys, "stderr", StringIO())
89
 
        response = self.client.get(reverse('api-doc'))
90
 
        self.assertEqual(http.client.OK, response.status_code)
91
 
        # No error or warning are emitted by docutils.
92
 
        self.assertEqual("", sys.stderr.getvalue())
93
 
 
94
73
    def test_machine_init_user_cannot_access(self):
95
74
        token = NodeKey.objects.get_token_for_node(factory.make_Node())
96
75
        client = OAuthAuthenticatedClient(get_node_init_user(), token)
147
126
        domain_name = Domain.objects.get_default_domain().name
148
127
        self.assertEqual(
149
128
            "%s.%s" % (machine.hostname, domain_name),
150
 
            parsed_result['hostname'])
 
129
            parsed_result['fqdn'])
151
130
        self.assertEqual(machine.system_id, parsed_result['system_id'])
152
131
 
153
132
    def test_GET_returns_associated_tag(self):
924
903
        self.assertEqual(http.client.OK, response.status_code)
925
904
        domain_name = Domain.objects.get_default_domain().name
926
905
        self.assertEqual(
927
 
            'francis.%s' % domain_name, parsed_result['hostname'])
 
906
            'francis.%s' % domain_name, parsed_result['fqdn'])
928
907
        self.assertEqual(0, Machine.objects.filter(hostname='diane').count())
929
908
        self.assertEqual(1, Machine.objects.filter(hostname='francis').count())
930
909
 
1480
1459
            response.content)
1481
1460
 
1482
1461
 
1483
 
class TestGetDetails(APITestCase):
1484
 
    """Tests for /api/2.0/machines/<machine>/?op=details."""
1485
 
 
1486
 
    def make_lshw_result(self, machine, script_result=0):
1487
 
        return factory.make_NodeResult_for_commissioning(
1488
 
            node=machine, name=LSHW_OUTPUT_NAME,
1489
 
            script_result=script_result)
1490
 
 
1491
 
    def make_lldp_result(self, machine, script_result=0):
1492
 
        return factory.make_NodeResult_for_commissioning(
1493
 
            node=machine, name=LLDP_OUTPUT_NAME, script_result=script_result)
1494
 
 
1495
 
    def get_details(self, machine):
1496
 
        url = reverse('machine_handler', args=[machine.system_id])
1497
 
        response = self.client.get(url, {'op': 'details'})
1498
 
        self.assertEqual(http.client.OK, response.status_code)
1499
 
        self.assertEqual('application/bson', response['content-type'])
1500
 
        return bson.BSON(response.content).decode()
1501
 
 
1502
 
    def test_GET_returns_empty_details_when_there_are_none(self):
1503
 
        machine = factory.make_Node()
1504
 
        self.assertDictEqual(
1505
 
            {"lshw": None, "lldp": None},
1506
 
            self.get_details(machine))
1507
 
 
1508
 
    def test_GET_returns_all_details(self):
1509
 
        machine = factory.make_Node()
1510
 
        lshw_result = self.make_lshw_result(machine)
1511
 
        lldp_result = self.make_lldp_result(machine)
1512
 
        self.assertDictEqual(
1513
 
            {"lshw": lshw_result.data,
1514
 
             "lldp": lldp_result.data},
1515
 
            self.get_details(machine))
1516
 
 
1517
 
    def test_GET_returns_only_those_details_that_exist(self):
1518
 
        machine = factory.make_Node()
1519
 
        lshw_result = self.make_lshw_result(machine)
1520
 
        self.assertDictEqual(
1521
 
            {"lshw": lshw_result.data,
1522
 
             "lldp": None},
1523
 
            self.get_details(machine))
1524
 
 
1525
 
    def test_GET_returns_not_found_when_machine_does_not_exist(self):
1526
 
        url = reverse('machine_handler', args=['does-not-exist'])
1527
 
        response = self.client.get(url, {'op': 'details'})
1528
 
        self.assertEqual(http.client.NOT_FOUND, response.status_code)
1529
 
 
1530
 
 
1531
 
class TestMarkBroken(APITestCase):
1532
 
    """Tests for /api/2.0/machines/<machine>/?op=mark_broken"""
1533
 
 
1534
 
    def get_machine_uri(self, machine):
1535
 
        """Get the API URI for `machine`."""
1536
 
        return reverse('machine_handler', args=[machine.system_id])
1537
 
 
1538
 
    def test_mark_broken_changes_status(self):
1539
 
        machine = factory.make_Node(
1540
 
            status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
1541
 
        response = self.client.post(
1542
 
            self.get_machine_uri(machine), {'op': 'mark_broken'})
1543
 
        self.assertEqual(http.client.OK, response.status_code)
1544
 
        self.assertEqual(NODE_STATUS.BROKEN, reload_object(machine).status)
1545
 
 
1546
 
    def test_mark_broken_updates_error_description(self):
1547
 
        # 'error_description' parameter was renamed 'comment' for consistency
1548
 
        # make sure this comment updates the machine's error_description
1549
 
        machine = factory.make_Node(
1550
 
            status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
1551
 
        comment = factory.make_name('comment')
1552
 
        response = self.client.post(
1553
 
            self.get_machine_uri(machine),
1554
 
            {'op': 'mark_broken', 'comment': comment})
1555
 
        self.assertEqual(http.client.OK, response.status_code)
1556
 
        machine = reload_object(machine)
1557
 
        self.assertEqual(
1558
 
            (NODE_STATUS.BROKEN, comment),
1559
 
            (machine.status, machine.error_description)
1560
 
        )
1561
 
 
1562
 
    def test_mark_broken_updates_error_description_compatibility(self):
1563
 
        # test old 'error_description' parameter is honored for compatibility
1564
 
        machine = factory.make_Node(
1565
 
            status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
1566
 
        error_description = factory.make_name('error_description')
1567
 
        response = self.client.post(
1568
 
            self.get_machine_uri(machine),
1569
 
            {'op': 'mark_broken', 'error_description': error_description})
1570
 
        self.assertEqual(http.client.OK, response.status_code)
1571
 
        machine = reload_object(machine)
1572
 
        self.assertEqual(
1573
 
            (NODE_STATUS.BROKEN, error_description),
1574
 
            (machine.status, machine.error_description)
1575
 
        )
1576
 
 
1577
 
    def test_mark_broken_passes_comment(self):
1578
 
        machine = factory.make_Node(
1579
 
            status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
1580
 
        machine_mark_broken = self.patch(node_module.Machine, 'mark_broken')
1581
 
        comment = factory.make_name('comment')
1582
 
        self.client.post(
1583
 
            self.get_machine_uri(machine),
1584
 
            {'op': 'mark_broken', 'comment': comment})
1585
 
        self.assertThat(
1586
 
            machine_mark_broken,
1587
 
            MockCalledOnceWith(self.logged_in_user, comment))
1588
 
 
1589
 
    def test_mark_broken_handles_missing_comment(self):
1590
 
        machine = factory.make_Node(
1591
 
            status=NODE_STATUS.COMMISSIONING, owner=self.logged_in_user)
1592
 
        machine_mark_broken = self.patch(node_module.Machine, 'mark_broken')
1593
 
        self.client.post(
1594
 
            self.get_machine_uri(machine), {'op': 'mark_broken'})
1595
 
        self.assertThat(
1596
 
            machine_mark_broken,
1597
 
            MockCalledOnceWith(self.logged_in_user, None))
1598
 
 
1599
 
    def test_mark_broken_requires_ownership(self):
1600
 
        machine = factory.make_Node(status=NODE_STATUS.COMMISSIONING)
1601
 
        response = self.client.post(
1602
 
            self.get_machine_uri(machine), {'op': 'mark_broken'})
1603
 
        self.assertEqual(http.client.FORBIDDEN, response.status_code)
1604
 
 
1605
 
    def test_mark_broken_allowed_from_any_other_state(self):
1606
 
        self.patch(node_module.Node, "_stop")
1607
 
        for status, _ in NODE_STATUS_CHOICES:
1608
 
            if status == NODE_STATUS.BROKEN:
1609
 
                continue
1610
 
 
1611
 
            machine = factory.make_Node(
1612
 
                status=status, owner=self.logged_in_user)
1613
 
            response = self.client.post(
1614
 
                self.get_machine_uri(machine), {'op': 'mark_broken'})
1615
 
            self.expectThat(
1616
 
                response.status_code, Equals(http.client.OK), response)
1617
 
            machine = reload_object(machine)
1618
 
            self.expectThat(machine.status, Equals(NODE_STATUS.BROKEN))
1619
 
 
1620
 
 
1621
 
class TestMarkFixed(APITestCase):
1622
 
    """Tests for /api/2.0/machines/<machine>/?op=mark_fixed"""
1623
 
 
1624
 
    def get_machine_uri(self, machine):
1625
 
        """Get the API URI for `machine`."""
1626
 
        return reverse('machine_handler', args=[machine.system_id])
1627
 
 
1628
 
    def test_mark_fixed_changes_status(self):
1629
 
        self.become_admin()
1630
 
        machine = factory.make_Node(status=NODE_STATUS.BROKEN)
1631
 
        response = self.client.post(
1632
 
            self.get_machine_uri(machine), {'op': 'mark_fixed'})
1633
 
        self.assertEqual(http.client.OK, response.status_code)
1634
 
        self.assertEqual(NODE_STATUS.READY, reload_object(machine).status)
1635
 
 
1636
 
    def test_mark_fixed_requires_admin(self):
1637
 
        machine = factory.make_Node(status=NODE_STATUS.BROKEN)
1638
 
        response = self.client.post(
1639
 
            self.get_machine_uri(machine), {'op': 'mark_fixed'})
1640
 
        self.assertEqual(http.client.FORBIDDEN, response.status_code)
1641
 
 
1642
 
    def test_mark_fixed_passes_comment(self):
1643
 
        self.become_admin()
1644
 
        machine = factory.make_Node(status=NODE_STATUS.BROKEN)
1645
 
        machine_mark_fixed = self.patch(node_module.Machine, 'mark_fixed')
1646
 
        comment = factory.make_name('comment')
1647
 
        self.client.post(
1648
 
            self.get_machine_uri(machine),
1649
 
            {'op': 'mark_fixed', 'comment': comment})
1650
 
        self.assertThat(
1651
 
            machine_mark_fixed,
1652
 
            MockCalledOnceWith(self.logged_in_user, comment))
1653
 
 
1654
 
    def test_mark_fixed_handles_missing_comment(self):
1655
 
        self.become_admin()
1656
 
        machine = factory.make_Node(status=NODE_STATUS.BROKEN)
1657
 
        machine_mark_fixed = self.patch(node_module.Machine, 'mark_fixed')
1658
 
        self.client.post(
1659
 
            self.get_machine_uri(machine), {'op': 'mark_fixed'})
1660
 
        self.assertThat(
1661
 
            machine_mark_fixed,
1662
 
            MockCalledOnceWith(self.logged_in_user, None))
1663
 
 
1664
 
 
1665
1462
class TestPowerParameters(APITestCase):
1666
1463
    def get_machine_uri(self, machine):
1667
1464
        """Get the API URI for `machine`."""