1212from selenium .webdriver .common .by import By
1313from selenium .webdriver .support import expected_conditions as EC
1414from selenium .webdriver .support .ui import WebDriverWait
15- from utils import TestUtilities
15+ from utils import BaseTestUtils , FunctionalTestUtils
1616
1717
18- class Pretest (TestUtilities , unittest .TestCase ):
18+ # 0 in the name is on purpose for alphabetical discovery
19+ class Test0Preconditions (BaseTestUtils , unittest .TestCase ):
1920 """Checks to perform before tests"""
2021
2122 def test_wait_for_services (self ):
@@ -60,49 +61,14 @@ def test_wait_for_services(self):
6061 self .fail (f"All celery workers are not online: { online_workers } " )
6162
6263
63- class TestServices (TestUtilities , unittest .TestCase ):
64+ class TestServices (FunctionalTestUtils , unittest .TestCase ):
6465 custom_static_token = None
6566
6667 @property
6768 def failureException (self ):
6869 TestServices .failed_test = True
6970 return super ().failureException
7071
71- @classmethod
72- def _execute_docker_compose_command (cls , cmd_args , use_text_mode = False ):
73- """Execute a docker compose command and log output.
74-
75- Args:
76- cmd_args: List of command arguments for subprocess.Popen
77- use_text_mode: If True, use text mode for subprocess output
78-
79- Returns:
80- Tuple of (output, error) from command execution
81- """
82- kwargs = {
83- "stdout" : subprocess .PIPE ,
84- "stderr" : subprocess .PIPE ,
85- "cwd" : cls .root_location ,
86- }
87- if use_text_mode :
88- kwargs ["text" ] = True
89- cmd = subprocess .run (cmd_args , check = False , ** kwargs )
90- if use_text_mode :
91- output , error = cmd .stdout , cmd .stderr
92- else :
93- output = cmd .stdout .decode ("utf-8" , errors = "replace" ) if cmd .stdout else ""
94- error = cmd .stderr .decode ("utf-8" , errors = "replace" ) if cmd .stderr else ""
95- output , error = map (str , (cmd .stdout , cmd .stderr ))
96- with open (cls .config ["logs_file" ], "a" ) as logs_file :
97- logs_file .write (output )
98- logs_file .write (error )
99- if cmd .returncode != 0 :
100- raise RuntimeError (
101- f"docker compose command failed "
102- f"({ cmd .returncode } ): { ' ' .join (cmd_args )} "
103- )
104- return output , error
105-
10672 @classmethod
10773 def _setup_admin_theme_links (cls ):
10874 """Configure admin theme links during tests.
@@ -125,8 +91,8 @@ def _setup_admin_theme_links(cls):
12591 f"body{{--openwisp-test: { cls .custom_static_token } ;}}"
12692 )
12793 script = rf"""
128- grep -q OPENWISP_ADMIN_THEME_LINKS /opt/openwisp/openwisp/settings.py || \
129- printf "\nOPENWISP_ADMIN_THEME_LINKS=[{{\"type\":\"text/css\",\"href\":\"/static/admin/css/openwisp.css\",\"rel\":\"stylesheet\",\"media\":\"all\"}},{{\"type\":\"text/css\",\"href\":\"/static/{ cls .config ["custom_css_filename" ]} \",\"rel\":\"stylesheet\",\"media\":\"all\"}},{{\"type\":\"image/x-icon \",\"href\":\"ui/openwisp/images/favicon.png \",\"rel\":\"icon\"}}]\n" >> /opt/openwisp/openwisp/settings.py &&
94+ sed -i '/^ OPENWISP_ADMIN_THEME_LINKS[[:space:]]*=/d' /opt/openwisp/openwisp/settings.py &&
95+ printf "\nOPENWISP_ADMIN_THEME_LINKS=[{{\"type\":\"text/css\",\"href\":\"/static/admin/css/openwisp.css\",\"rel\":\"stylesheet\",\"media\":\"all\"}},{{\"type\":\"text/css\",\"href\":\"/static/{ cls .config ["custom_css_filename" ]} \",\"rel\":\"stylesheet\",\"media\":\"all\"}},{{\"type\":\"image/svg+xml \",\"href\":\"/static/ ui/openwisp/images/favicon.svg \",\"rel\":\"icon\"}}]\n" >> /opt/openwisp/openwisp/settings.py &&
13096 python collectstatic.py &&
13197 uwsgi --reload uwsgi.pid
13298 """ # noqa: E501
@@ -153,27 +119,7 @@ def _cleanup_stale_test_data(cls):
153119 avoid any Selenium dependency during setup.
154120 """
155121 try :
156- cls ._execute_docker_compose_command (
157- [
158- "docker" ,
159- "compose" ,
160- "exec" ,
161- "-T" ,
162- "dashboard" ,
163- "python" ,
164- "manage.py" ,
165- "shell" ,
166- "-c" ,
167- (
168- "from openwisp_users.models import User; "
169- "User.objects.filter("
170- "username__in=['signup-user', 'test_superuser', "
171- "'test_superuser2']"
172- ").delete()"
173- ),
174- ],
175- use_text_mode = True ,
176- )
122+ cls .delete_test_users ("signup-user" , "test_superuser" , "test_superuser2" )
177123 except Exception as e :
178124 exc_type = type (e ).__name__
179125 print (
@@ -223,6 +169,12 @@ def setUpClass(cls):
223169
224170 @classmethod
225171 def tearDownClass (cls ):
172+ try :
173+ cls .delete_test_users (* cls .test_usernames_to_delete )
174+ cls .test_usernames_to_delete .clear ()
175+ except Exception as e :
176+ exc_type = type (e ).__name__
177+ print (f"Unable to delete test users: { exc_type } : { e } " )
226178 for resource_link in cls .objects_to_delete :
227179 try :
228180 cls ._delete_object (resource_link )
@@ -277,6 +229,13 @@ def test_admin_login(self):
277229 def test_custom_static_files_loaded (self ):
278230 self .login ()
279231 self .open ("/admin/" )
232+ favicon_href = self .web_driver .find_element (
233+ By .CSS_SELECTOR , 'link[rel="icon"]'
234+ ).get_attribute ("href" )
235+ self .assertRegex (
236+ favicon_href ,
237+ r"/static/ui/openwisp/images/favicon(\.[0-9a-f]+)?\.svg$" ,
238+ )
280239 # Check if the custom CSS variable is applied
281240 value = self .web_driver .execute_script (
282241 "return getComputedStyle(document.body)"
@@ -362,6 +321,7 @@ def test_add_superuser(self):
362321 def test_forgot_password (self ):
363322 """Test forgot password to ensure that postfix is working properly."""
364323
324+ self .login ()
365325 self .logout ()
366326 try :
367327 WebDriverWait (self .base_driver , 3 ).until (
@@ -463,23 +423,22 @@ def _test_celery_task_registered(container_name):
463423 def test_radius_user_registration (self ):
464424 """Ensure users can register using the RADIUS API."""
465425 url = f"{ self .config ['api_url' ]} /api/v1/radius/organization/default/account/"
466- response = requests .post (
467- url ,
468- json = {
469- "username" : "signup-user" ,
470- "email" : "user@signup.com" ,
471- "password1" : "rLx6OH%[" ,
472- "password2" : "rLx6OH%[" ,
473- },
474- verify = False ,
475- )
476- self .assertEqual (response .status_code , 201 )
477- # Delete the created user
478- self .login ()
479- self .get_resource (
480- "signup-user" , "/admin/openwisp_users/user/" , "field-username"
481- )
482- self .objects_to_delete .append (self .base_driver .current_url )
426+ username = "signup-user"
427+ try :
428+ response = requests .post (
429+ url ,
430+ json = {
431+ "username" : username ,
432+ "email" : "user@signup.com" ,
433+ "password1" : "rLx6OH%[" ,
434+ "password2" : "rLx6OH%[" ,
435+ },
436+ verify = False ,
437+ timeout = 10 ,
438+ )
439+ self .assertEqual (response .status_code , 201 , response .text )
440+ finally :
441+ self .delete_test_users (username )
483442
484443 def test_freeradius (self ):
485444 """Ensure freeradius service is working correctly."""
@@ -532,8 +491,8 @@ def test_containers_down(self):
532491 )
533492
534493
535- class TestUtils ( TestUtilities , unittest .TestCase ):
536- """Other tests """
494+ class TestLocalUtils ( BaseTestUtils , unittest .TestCase ):
495+ """Tests for local utilities """
537496
538497 def test_update_version_updates_only_version_file (self ):
539498 repository_root = Path (__file__ ).resolve ().parents [1 ]
0 commit comments