@@ -863,6 +863,7 @@ def test_device_action_selection(self):
863863 name = "device-org2" , mac_address = "00:11:22:33:44:09" , organization = org2
864864 )
865865 self ._login ()
866+
866867 with self .subTest ("the selection prefills the form" ):
867868 response = self ._post_device_action (devices )
868869 self .assertEqual (response .status_code , 200 )
@@ -875,20 +876,23 @@ def test_device_action_selection(self):
875876 self .assertEqual (form .fields ["organization" ].initial , str (org .pk ))
876877 for field_name in ("organization" , "group" , "location" ):
877878 self .assertTrue (form .fields [field_name ].disabled )
879+
878880 with self .subTest ("the selection is announced and the wider targets hidden" ):
879881 self .assertContains (
880882 response , "The command will run on the 2 devices you selected."
881883 )
882884 self .assertContains (response , 'name="devices"' )
883885 self .assertNotContains (response , 'name="group"' )
884886 self .assertNotContains (response , 'name="location"' )
887+
885888 with self .subTest ("devices of different organizations are refused" ):
886889 response = self ._post_device_action ([devices [0 ], device_org2 ])
887890 self .assertRedirects (response , self .device_changelist_url )
888891 self .assertIn (
889892 "All devices must belong to the same organization" ,
890893 " " .join (self ._messages (response )),
891894 )
895+
892896 with self .subTest ("the selection travels to the review step" ):
893897 response = self ._post_execute (devices = self ._pk_list (devices ))
894898 self .assertEqual (response .status_code , 302 )
@@ -900,23 +904,52 @@ def test_device_action_selection(self):
900904 self .assertEqual (response .context ["device_count" ], 2 )
901905 self .assertEqual (response .context ["targets_display" ], "2 selected devices" )
902906 self .assertEqual (set (response .context ["cl" ].queryset ), set (devices ))
907+
903908 with self .subTest ("only the selected devices are executed" ):
904909 self ._post_confirm (wizard ["token" ])
905910 batch = BatchCommand .objects .get ()
906911 self .assertEqual (set (batch .devices .all ()), set (devices ))
907- with self .subTest ("a single device is announced in the singular" ):
912+
913+ with self .subTest ("the texts use the singular when one device is selected" ):
908914 response = self ._post_device_action (devices [:1 ])
909915 self .assertContains (
910916 response , "The command will run on the device you selected."
911917 )
918+ self .assertNotContains (response , "devices you selected" )
912919 self ._start_wizard (devices = self ._pk_list (devices [:1 ]))
913920 response = self .client .get (self .confirm_url )
914921 self .assertEqual (response .context ["targets_display" ], "1 selected device" )
915922
923+ with self .subTest ("the selection is kept when going back to edit" ):
924+ self ._create_device (
925+ name = "device-not-selected" ,
926+ mac_address = "00:11:22:33:44:08" ,
927+ organization = org ,
928+ )
929+ selected = {str (device .pk ) for device in devices }
930+ self ._start_wizard (devices = self ._pk_list (devices ))
931+ self .client .get (self .confirm_url )
932+ response = self .client .get (f"{ self .execute_url } ?back=1" )
933+ form = response .context ["form" ]
934+ self .assertEqual (set (form .device_ids ), selected )
935+ for field_name in ("organization" , "group" , "location" ):
936+ self .assertTrue (form .fields [field_name ].disabled )
937+ self .assertContains (
938+ response , "The command will run on the 2 devices you selected."
939+ )
940+ self ._start_wizard (
941+ devices = form .fields ["devices" ].initial or "" , label = "edited-label"
942+ )
943+ wizard = self .client .session [BatchCommandAdmin .session_key ]
944+ self .assertEqual (wizard ["label" ], "edited-label" )
945+ self .assertEqual (set (wizard ["device_ids" ]), selected )
946+ response = self .client .get (self .confirm_url )
947+ self .assertEqual (set (response .context ["cl" ].queryset ), set (devices ))
948+
916949 def test_device_action_system_wide (self ):
917950 org = self ._get_org ()
918951 org2 = self ._create_org (name = "org2" , slug = "org2" )
919- devices = [
952+ org1_devices = [
920953 self ._create_device (
921954 name = f"device{ index } " ,
922955 mac_address = f"00:11:22:33:44:0{ index } " ,
@@ -928,10 +961,10 @@ def test_device_action_system_wide(self):
928961 name = "device-org2" , mac_address = "00:11:22:33:44:09" , organization = org2
929962 )
930963 self ._login ()
931- with self . subTest ( "selecting every device is system wide" ):
932- response = self . _post_device_action (
933- devices + [device_org2 ], select_across = True
934- )
964+
965+ with self . subTest ( "selecting every device runs the command on all of them" ):
966+ all_devices = org1_devices + [device_org2 ]
967+ response = self . _post_device_action ( all_devices , select_across = True )
935968 self .assertEqual (response .status_code , 200 )
936969 form = response .context ["form" ]
937970 self .assertEqual (form .device_ids , [])
@@ -943,6 +976,19 @@ def test_device_action_system_wide(self):
943976 self .assertNotContains (response , 'name="organization"' )
944977 self .assertNotContains (response , 'name="group"' )
945978 self .assertNotContains (response , 'name="location"' )
979+ wizard = self ._start_wizard ()
980+ response = self .client .get (self .confirm_url )
981+ self .assertEqual (response .context ["targets_display" ], "All devices" )
982+ self .assertEqual (set (response .context ["cl" ].queryset ), set (all_devices ))
983+ response = self ._post_confirm (wizard ["token" ])
984+ self .assertIn (
985+ "Mass command executed successfully." , self ._messages (response )
986+ )
987+ batch = BatchCommand .objects .get ()
988+ self .assertIsNone (batch .organization_id )
989+ self .assertEqual (set (batch .devices .all ()), set (all_devices ))
990+ BatchCommand .objects .all ().delete ()
991+
946992 with self .subTest ("the excluded devices are left out of the batch" ):
947993 wizard = self ._start_wizard ()
948994 self .client .get (self .confirm_url )
@@ -955,15 +1001,16 @@ def test_device_action_system_wide(self):
9551001 self .assertIsNone (batch .organization_id )
9561002 self .assertIsNone (batch .group_id )
9571003 self .assertIsNone (batch .location_id )
958- self .assertEqual (set (batch .devices .all ()), set (devices ))
1004+ self .assertEqual (set (batch .devices .all ()), set (org1_devices ))
1005+
9591006 with self .subTest ("a partial multi organization selection is refused" ):
9601007 self ._create_device (
9611008 name = "excluded-by-the-search" ,
9621009 mac_address = "00:11:22:33:44:08" ,
9631010 organization = org2 ,
9641011 )
9651012 response = self ._post_device_action (
966- devices + [device_org2 ],
1013+ org1_devices + [device_org2 ],
9671014 select_across = True ,
9681015 query = {"q" : "device" },
9691016 )
@@ -983,6 +1030,7 @@ def test_device_action_permissions_and_scope(self):
9831030 device_admin = admin .site .get_model_admin (Device )
9841031 request = RequestFactory ().get (self .device_changelist_url )
9851032 action_name = "execute_mass_command_admin_action"
1033+
9861034 with self .subTest ("the device change permission is required" ):
9871035 viewer = self ._create_operator (
9881036 organizations = [org ], username = "viewer" , email = "viewer@test.com"
@@ -993,10 +1041,12 @@ def test_device_action_permissions_and_scope(self):
9931041 )
9941042 request .user = viewer
9951043 self .assertNotIn (action_name , device_admin .get_actions (request ))
1044+
9961045 with self .subTest ("the operator group can use the action" ):
9971046 operator = self ._create_operator (organizations = [org ])
9981047 request .user = operator
9991048 self .assertIn (action_name , device_admin .get_actions (request ))
1049+
10001050 with self .subTest ("the batch command add permission is enforced" ):
10011051 viewer .user_permissions .set (
10021052 Permission .objects .filter (
@@ -1005,6 +1055,7 @@ def test_device_action_permissions_and_scope(self):
10051055 )
10061056 self .client .force_login (viewer )
10071057 self .assertEqual (self ._post_device_action ([device ]).status_code , 403 )
1058+
10081059 with self .subTest ("devices of unmanaged organizations are dropped" ):
10091060 self .client .force_login (operator )
10101061 response = self ._post_execute (devices = self ._pk_list ([device , device2 ]))
@@ -1014,10 +1065,12 @@ def test_device_action_permissions_and_scope(self):
10141065 "Some of the selected devices are no longer available." ,
10151066 form .errors ["__all__" ],
10161067 )
1068+
10171069 with self .subTest ("devices which disappeared are dropped" ):
10181070 self ._login ()
10191071 response = self ._post_execute (devices = f"{ device .pk } ,{ uuid4 ()} " )
10201072 self .assertEqual (response .context ["form" ].device_ids , [str (device .pk )])
1073+
10211074 with self .subTest ("mixed organizations are refused by the form" ):
10221075 response = self ._post_execute (devices = self ._pk_list ([device , device2 ]))
10231076 form = response .context ["form" ]
@@ -1026,6 +1079,7 @@ def test_device_action_permissions_and_scope(self):
10261079 "All devices must belong to the same organization" ,
10271080 " " .join (form .errors ["__all__" ]),
10281081 )
1082+
10291083 with self .subTest ("selecting every device is not system wide for operators" ):
10301084 multi_operator = self ._create_operator (
10311085 organizations = [org , org2 ], username = "multi" , email = "multi@test.com"
@@ -1037,6 +1091,7 @@ def test_device_action_permissions_and_scope(self):
10371091 "All devices must belong to the same organization" ,
10381092 " " .join (self ._messages (response )),
10391093 )
1094+
10401095 with self .subTest ("an operator executes the devices it manages" ):
10411096 self .client .force_login (operator )
10421097 wizard = self ._start_wizard (devices = self ._pk_list ([device ]))
0 commit comments