|
| 1 | +import csv |
1 | 2 | import io |
2 | 3 | import json |
3 | 4 | import os |
@@ -653,6 +654,68 @@ def test_change_device_group_action_perms(self): |
653 | 654 | extra_payload={"device_group": group.pk, "apply": True}, |
654 | 655 | ) |
655 | 656 |
|
| 657 | + def test_device_export_includes_deactivated_config_status(self): |
| 658 | + device = self._create_device_config() |
| 659 | + device.deactivate() |
| 660 | + response = self.client.post( |
| 661 | + reverse(f"admin:{self.app_label}_device_export"), {"format": "0"} |
| 662 | + ) |
| 663 | + self.assertNotContains(response, "error") |
| 664 | + rows = list(csv.reader(response.content.decode().splitlines())) |
| 665 | + header = rows[0] |
| 666 | + status_col = header.index("config_status") |
| 667 | + self.assertEqual(rows[1][status_col], "deactivated") |
| 668 | + |
| 669 | + def test_device_import_deactivated_config_status_ignored(self): |
| 670 | + # config_status is readonly=True in DeviceResource, so importing a |
| 671 | + # row with config_status=deactivated must NOT create a deactivated device. |
| 672 | + org = self._get_org(org_name="default") |
| 673 | + contents = ( |
| 674 | + "name,mac_address,organization,group,model,os,system,notes,last_ip," |
| 675 | + "management_ip,config_status,config_backend,config_data,config_context," |
| 676 | + "config_templates,created,modified,id,key,organization_id,group_id\n" |
| 677 | + "test-deactivated,00:11:22:33:44:66,{org_name},,,,,,,," |
| 678 | + "deactivated,netjsonconfig.OpenWrt,,,," |
| 679 | + "2022-10-17 15:26:51,2022-10-17 15:26:51," |
| 680 | + "559871c5-ce3d-4c7e-9176-fb6623d562f3,934d0799b1ce3a454bbb585cda1d7a49," |
| 681 | + "{org_id}," |
| 682 | + ).strip() |
| 683 | + contents = contents.format(org_name=org.name, org_id=org.id) |
| 684 | + csv_file = ContentFile(contents) |
| 685 | + response = self.client.post( |
| 686 | + reverse(f"admin:{self.app_label}_device_import"), |
| 687 | + {"format": "0", "import_file": csv_file, "file_name": "test.csv"}, |
| 688 | + ) |
| 689 | + self.assertFalse(response.context["result"].has_errors()) |
| 690 | + confirm_form = response.context["confirm_form"] |
| 691 | + data = confirm_form.initial |
| 692 | + response = self.client.post( |
| 693 | + reverse(f"admin:{self.app_label}_device_process_import"), data, follow=True |
| 694 | + ) |
| 695 | + self.assertEqual(response.status_code, 200) |
| 696 | + device = Device.objects.get(name="test-deactivated") |
| 697 | + self.assertFalse(device._is_deactivated) |
| 698 | + self.assertTrue(device._has_config()) |
| 699 | + self.assertNotEqual(device.config.status, "deactivated") |
| 700 | + |
| 701 | + def test_change_group_action_skips_deactivated_device(self): |
| 702 | + path = reverse(f"admin:{self.app_label}_device_changelist") |
| 703 | + org = self._get_org(org_name="default") |
| 704 | + group = self._create_device_group(name="test-group", organization=org) |
| 705 | + device = self._create_device(organization=org) |
| 706 | + device.deactivate() |
| 707 | + post_data = { |
| 708 | + "_selected_action": [device.pk], |
| 709 | + "action": "change_group", |
| 710 | + "csrfmiddlewaretoken": "test", |
| 711 | + "apply": True, |
| 712 | + "device_group": group.pk, |
| 713 | + } |
| 714 | + response = self.client.post(path, post_data, follow=True) |
| 715 | + self.assertEqual(response.status_code, 200) |
| 716 | + device.refresh_from_db() |
| 717 | + self.assertIsNone(device.group) |
| 718 | + |
656 | 719 | def test_device_import_with_group_apply_templates(self): |
657 | 720 | org = self._get_org(org_name="default") |
658 | 721 | template = self._create_template(name="template") |
@@ -3038,6 +3101,26 @@ def test_change_device_group_action_changes_templates(self): |
3038 | 3101 | self.assertEqual(response.status_code, 200) |
3039 | 3102 | self.assertEqual(len(mocked.call_args_list), 2) |
3040 | 3103 |
|
| 3104 | + with self.subTest("Change group skips deactivated devices in signals"): |
| 3105 | + device3 = self._create_device( |
| 3106 | + organization=org1, |
| 3107 | + group=dg1, |
| 3108 | + name="default.test.device3", |
| 3109 | + mac_address="AA:BB:CC:DD:EE:01", |
| 3110 | + ) |
| 3111 | + device3.deactivate() |
| 3112 | + data = post_data.copy() |
| 3113 | + data["_selected_action"] = [device1.pk, device3.pk] |
| 3114 | + data["device_group"] = str(dg2.pk) |
| 3115 | + with patch.object(Device, "_send_device_group_changed_signal") as mocked: |
| 3116 | + response = self.client.post(path, data, follow=True) |
| 3117 | + self.assertEqual(response.status_code, 200) |
| 3118 | + self.assertEqual(len(mocked.call_args_list), 1) |
| 3119 | + device1.refresh_from_db() |
| 3120 | + device3.refresh_from_db() |
| 3121 | + self.assertEqual(device1.group_id, dg2.id) |
| 3122 | + self.assertEqual(device3.group_id, dg1.id) |
| 3123 | + |
3041 | 3124 | device2.organization = org2 |
3042 | 3125 | device2.save() |
3043 | 3126 |
|
|
0 commit comments