|
| 1 | +import json |
1 | 2 | from unittest import mock |
2 | 3 |
|
| 4 | +from django.contrib.auth.models import User |
3 | 5 | from django.urls import reverse # type: ignore |
4 | 6 | from django_webtest import WebTest # type: ignore |
5 | 7 |
|
6 | | -from orthos2.data.models import Architecture, Machine, ServerConfig, System |
| 8 | +from orthos2.data.models import ( |
| 9 | + BMC, |
| 10 | + Architecture, |
| 11 | + Machine, |
| 12 | + RemotePowerType, |
| 13 | + SerialConsole, |
| 14 | + SerialConsoleType, |
| 15 | + ServerConfig, |
| 16 | + System, |
| 17 | +) |
7 | 18 | from orthos2.data.models.domain import Domain |
8 | 19 |
|
9 | 20 |
|
@@ -52,6 +63,34 @@ def setUp(self, m_is_dns_resolvable: mock.MagicMock): |
52 | 63 |
|
53 | 64 | m2.save() |
54 | 65 |
|
| 66 | + ipmi_fence_agent = RemotePowerType.objects.create( |
| 67 | + name="ipmilanplus", device="bmc" |
| 68 | + ) |
| 69 | + ipmi_console_type = SerialConsoleType.objects.create( |
| 70 | + name="IPMI", |
| 71 | + command=( |
| 72 | + "ipmitool -I lanplus -H {{ machine.bmc.fqdn }} " |
| 73 | + "-U {{ ipmi.user}} -P {{ ipmi.password }} sol activate" |
| 74 | + ), |
| 75 | + comment="IPMI", |
| 76 | + ) |
| 77 | + |
| 78 | + BMC.objects.create( |
| 79 | + username="root", |
| 80 | + password="root", |
| 81 | + fqdn="testsys-sp.orthos2.test", |
| 82 | + mac="AA:BB:CC:DD:EE:FF", |
| 83 | + machine=m2, |
| 84 | + fence_agent=ipmi_fence_agent, |
| 85 | + ) |
| 86 | + SerialConsole.objects.create( |
| 87 | + machine=m2, |
| 88 | + stype=ipmi_console_type, |
| 89 | + kernel_device="ttyS", |
| 90 | + kernel_device_num=1, |
| 91 | + baud_rate=115200, |
| 92 | + ) |
| 93 | + |
55 | 94 | def test_visible_fieldsets_non_administrative_systems(self) -> None: |
56 | 95 | """Test for fieldsets.""" |
57 | 96 | # Act |
@@ -93,3 +132,50 @@ def test_visible_inlines_administrative_systems(self) -> None: |
93 | 132 | # Assert |
94 | 133 | self.assertContains(page, "Add another Serial Console") # type: ignore |
95 | 134 | self.assertContains(page, "Remote Power") # type: ignore |
| 135 | + |
| 136 | + def test_deactivate_sol_button_visible_for_ipmi_console(self) -> None: |
| 137 | + """The machine detail page should expose the SOL deactivate action for IPMI consoles.""" |
| 138 | + |
| 139 | + page = self.app.get( # type: ignore |
| 140 | + reverse("frontend:detail", args=["2"]), user="superuser" |
| 141 | + ) |
| 142 | + |
| 143 | + self.assertContains(page, "Queue SOL Deactivation") # type: ignore |
| 144 | + |
| 145 | + def test_deactivate_sol_button_hidden_without_serialconsole(self) -> None: |
| 146 | + """The machine detail page should not expose the SOL action if no serial console exists.""" |
| 147 | + |
| 148 | + page = self.app.get( # type: ignore |
| 149 | + reverse("frontend:detail", args=["1"]), user="superuser" |
| 150 | + ) |
| 151 | + |
| 152 | + self.assertNotContains(page, "Queue SOL Deactivation") # type: ignore |
| 153 | + |
| 154 | + @mock.patch("orthos2.frontend.views.ajax.Machine.deactivate_sol") |
| 155 | + def test_ajax_deactivate_sol(self, mocked_deactivate_sol: mock.MagicMock) -> None: |
| 156 | + """The AJAX endpoint should queue the machine action and return a success payload.""" |
| 157 | + |
| 158 | + mocked_deactivate_sol.return_value = True |
| 159 | + self.client.force_login(User.objects.get(username="superuser")) |
| 160 | + |
| 161 | + response = self.client.post(reverse("frontend:ajax_deactivate_sol", args=["2"])) |
| 162 | + |
| 163 | + self.assertEqual(response.status_code, 200) |
| 164 | + payload = json.loads(response.content) |
| 165 | + self.assertEqual(payload["cls"], "success") |
| 166 | + self.assertEqual( |
| 167 | + payload["message"], |
| 168 | + "SOL deactivation was queued and will run in the background.", |
| 169 | + ) |
| 170 | + mocked_deactivate_sol.assert_called_once_with(user=mock.ANY) |
| 171 | + |
| 172 | + def test_ajax_deactivate_sol_rejects_get(self) -> None: |
| 173 | + """The SOL deactivation endpoint should reject GET requests.""" |
| 174 | + |
| 175 | + page = self.app.get( # type: ignore |
| 176 | + reverse("frontend:ajax_deactivate_sol", args=["2"]), |
| 177 | + user="superuser", |
| 178 | + expect_errors=True, |
| 179 | + ) |
| 180 | + |
| 181 | + self.assertEqual(page.status_int, 405) # type: ignore[attr-defined] |
0 commit comments