From 294a9610b9f2a0af9601855de7e533e259912314 Mon Sep 17 00:00:00 2001 From: alfredeen Date: Fri, 20 Dec 2024 15:17:56 +0100 Subject: [PATCH] Large refactoring of app status. The model AppStatus is being replaced by two new fields and a model annotation. This is still in progress. --- apps/admin.py | 3 +- apps/helpers.py | 34 ++++++-- apps/models/base/__init__.py | 2 + apps/models/base/base.py | 100 ++++++++++++++++++++++-- apps/tasks.py | 16 +++- apps/tests/test_app_helper_utils.py | 56 +++++++++++++ apps/tests/test_app_instance.py | 43 +++++++++- apps/tests/test_app_instance_manager.py | 62 +++++++++++++++ apps/tests/test_app_settings_view.py | 5 +- apps/tests/test_create_app_view.py | 15 ++-- apps/tests/test_delete_app_view.py | 14 +--- apps/tests/test_forms.py | 8 +- apps/tests/test_get_status_view.py | 15 ++-- studio/tests.py | 6 +- 14 files changed, 325 insertions(+), 54 deletions(-) create mode 100644 apps/tests/test_app_helper_utils.py diff --git a/apps/admin.py b/apps/admin.py index 96d3cce0..e55d26a9 100644 --- a/apps/admin.py +++ b/apps/admin.py @@ -62,8 +62,9 @@ class K8sUserAppStatusAdmin(admin.ModelAdmin): class BaseAppAdmin(admin.ModelAdmin): + # TODO: Change status use to new status list_display = ("name", "display_owner", "display_project", "display_status", "display_subdomain", "chart") - readonly_fields = ("id", "created_on") + readonly_fields = ("app_status", "id", "created_on") list_filter = ["owner", "project", "app_status__status", "chart"] actions = ["redeploy_apps", "deploy_resources", "delete_resources"] diff --git a/apps/helpers.py b/apps/helpers.py index 106764ab..38dc59bd 100644 --- a/apps/helpers.py +++ b/apps/helpers.py @@ -9,7 +9,7 @@ from apps.types_.subdomain import SubdomainCandidateName, SubdomainTuple from studio.utils import get_logger -from .models import Apps, AppStatus, BaseAppInstance, K8sUserAppStatus, Subdomain +from .models import Apps, BaseAppInstance, K8sUserAppStatus, Subdomain logger = get_logger(__name__) @@ -202,6 +202,7 @@ def _handle_update_status_request_old( raise Exception("This method has been deprecated. To be removed.") + """ if len(new_status) > 15: new_status = new_status[:15] @@ -266,6 +267,7 @@ def _handle_update_status_request_old( except Exception as err: logger.error(f"Unable to fetch or update the specified app instance with release={release}. {err}, {type(err)}") raise + """ @transaction.atomic @@ -351,6 +353,7 @@ def get_URI(instance): return URI +# TODO: Status. Unit test this. mock deploy_resource() @transaction.atomic def create_instance_from_form(form, project, app_slug, app_id=None): """ @@ -380,7 +383,11 @@ def create_instance_from_form(form, project, app_slug, app_id=None): if new_app: do_deploy = True + user_action = "Creating" else: + # Update an existing app + user_action = "Changing" + # Only re-deploy existing apps if one of the following fields was changed: redeployment_fields = [ "subdomain", @@ -409,24 +416,32 @@ def create_instance_from_form(form, project, app_slug, app_id=None): instance = form.save(commit=False) # Handle status creation or retrieval - status = get_or_create_status(instance, app_id) + # TODO: Status. Check this use. + # We no longer update the app status based on user actions. + # status = get_or_create_status(instance, app_id) + # Retrieve or create the subdomain subdomain, created = Subdomain.objects.get_or_create( subdomain=subdomain_name, project=project, is_created_by_user=is_created_by_user ) - if app_id: + if not new_app: + # Previously: if app_id: handle_subdomain_change(instance, subdomain, subdomain_name) app_slug = handle_shiny_proxy_case(instance, app_slug, app_id) app = get_app(app_slug) - setup_instance(instance, subdomain, app, project, status) + # TODO: Status. Check this use: + setup_instance(instance, subdomain, app, project, user_action) save_instance_and_related_data(instance, form) if do_deploy: logger.debug(f"Now deploying resource app with app_id = {app_id}") + + # TODO: Status. Also set the last user action to Updating + deploy_resource.delay(instance.serialize()) else: logger.debug(f"Not re-deploying this app with app_id = {app_id}") @@ -440,7 +455,8 @@ def get_subdomain_name(form): def get_or_create_status(instance, app_id): - return instance.app_status if app_id else AppStatus.objects.create() + raise Exception("Deprecated function.") + # return instance.app_status if app_id else AppStatus.objects.create() def handle_subdomain_change(instance, subdomain, subdomain_name): @@ -474,13 +490,17 @@ def get_app(app_slug): raise ValueError(f"App with slug {app_slug} not found") -def setup_instance(instance, subdomain, app, project, status, is_created_by_user=False): +# TODO: Status. +def setup_instance(instance, subdomain, app, project, user_action=None, is_created_by_user=False): instance.subdomain = subdomain instance.app = app instance.chart = instance.app.chart instance.project = project instance.owner = project.owner - instance.app_status = status + # TODO: Status. Is this unit tested? + instance.latest_user_action = user_action + # TODO: Status. We do not set app status any longer. + # instance.app_status = status def save_instance_and_related_data(instance, form): diff --git a/apps/models/base/__init__.py b/apps/models/base/__init__.py index 33df44dd..a68d785b 100644 --- a/apps/models/base/__init__.py +++ b/apps/models/base/__init__.py @@ -1,4 +1,6 @@ from .app_categories import AppCategories + +# TODO: Status. from .app_status import AppStatus from .app_template import Apps from .base import AppInstanceManager, BaseAppInstance diff --git a/apps/models/base/base.py b/apps/models/base/base.py index 51d0063f..e10b16cf 100644 --- a/apps/models/base/base.py +++ b/apps/models/base/base.py @@ -5,7 +5,7 @@ from django.contrib.auth import get_user_model from django.core import serializers from django.db import models -from django.db.models import Q +from django.db.models import Case, CharField, F, Q, Value, When from apps.models.base.app_status import AppStatus from apps.models.base.app_template import Apps @@ -24,15 +24,70 @@ class AppInstanceManager(models.Manager): model_type = "appinstance" + def with_app_status(self): + """ + Define and add a reusable, chainable annotation app_status. + The atn prefix is used to clarify that this value is computed on the fly. + """ + return self.get_queryset().annotate( + atn_app_status=Case( + When(latest_user_action="Deleting", then=Value("Deleted")), + When( + k8s_user_app_status__status__in=["CrashLoopBackoff", "ErrImagePull", "PostStartHookError"], + then=Value("Error"), + ), + When( + latest_user_action__in=["Creating", "Changing"], + k8s_user_app_status__status="NotFound", + then=Value("Error (NotFound)"), + ), + When( + latest_user_action__in=["Creating", "Changing"], + k8s_user_app_status__status="Running", + then=Value("Running"), + ), + When( + latest_user_action="Creating", + k8s_user_app_status__status__in=["ContainerCreating", "PodInitializing"], + then=Value("Creating"), + ), + When( + latest_user_action="Changing", + k8s_user_app_status__status__in=["ContainerCreating", "PodInitializing"], + then=Value("Changing"), + ), + default=Value("Unknown"), + output_field=CharField(), + ) + ) + + def _hide_with_app_status(self): + """Define and add a reusable, chainable annotation app_status.""" + # TODO: Call a function from above + # The atn prefix is used to clarify that this value is computed on the fly + return self.get_queryset().annotate( + atn_app_status=BaseAppInstance.convert_to_app_status(F("latest_user_action"), F("k8s_user_app_status")) + ) + + def get_apps_not_deleted(self): + """A queryset returning all user apps excluding Deleted apps.""" + # TODO: Define a reusable queryset that returns all apps not set to Deleted. + queryset = self.with_app_status().exclude(atn_app_status="Deleted") + print(str(queryset.query)) + return self.with_app_status().exclude(atn_app_status="Deleted") + def get_app_instances_of_project_filter(self, user, project, include_deleted=False, deleted_time_delta=None): q = Q() if not include_deleted: if deleted_time_delta is None: - q &= ~Q(app_status__status="Deleted") + # TODO: Status. Replace this + q &= self.get_apps_not_deleted() + # q &= ~Q(app_status__status="Deleted") else: time_threshold = datetime.now() - timedelta(minutes=deleted_time_delta) - q &= ~Q(app_status__status="Deleted") | Q(deleted_on__gte=time_threshold) + # q &= get_app_status()="Deleted" | Q(deleted_on__gte=time_threshold) + q &= self.get_apps_not_deleted() | Q(deleted_on__gte=time_threshold) if hasattr(self.model, "access"): q &= Q(owner=user) | Q( @@ -83,7 +138,8 @@ def user_can_create(self, user, project, app_slug): return False num_of_app_instances = self.filter( - ~Q(app_status__status="Deleted"), + self.get_apps_not_deleted(), + # ~Q(app_status__status="Deleted"), app__slug=app_slug, project=project, ).count() @@ -129,9 +185,22 @@ class BaseAppInstance(models.Model): k8s_user_app_status = models.OneToOneField( K8sUserAppStatus, on_delete=models.RESTRICT, related_name="%(class)s", null=True ) - # TODO: Break connection to model AppStatus and deprecate AppStatus + + # 20241216: Refactoring of app status. + # TODO: Status. Break connection to model AppStatus and deprecate AppStatus + # Also need to migrate the model? + + # Old: The model AppStatus and related FK app_status is retained for historical reasons + # Remove or make read-only? + # Check the db, is the field still there? app_status = models.OneToOneField(AppStatus, on_delete=models.RESTRICT, related_name="%(class)s", null=True) + # TODO: Status. Create function to get app_status + def get_app_status(self): + # This model function replaces the old app_status field and related AppStatus model. + # TODO: Implement + raise Exception("Not yet implemented") + url = models.URLField(blank=True, null=True) updated_on = models.DateTimeField(auto_now=True) @@ -171,3 +240,24 @@ def set_k8s_values(self): def serialize(self): return json.loads(serializers.serialize("json", [self]))[0] + + @staticmethod + def convert_to_app_status(latest_user_action: str, k8s_user_app_status: str) -> str: + """Converts latest user action and k8s pod status to app status""" + match latest_user_action, k8s_user_app_status: + case "Deleting", _: + return "Deleted" + case "Creating", "ContainerCreating" | "PodInitializing": + return "Creating" + case "Changing", "ContainerCreating" | "PodInitializing": + return "Changing" + case _, "NotFound": + return "Error (NotFound)" + case _, "CrashLoopBackoff" | "ErrImagePull" | "PostStartHookError": + return "Error" + case _, "Running": + return "Running" + case _, _: + return f"Invalid input. No match for input {latest_user_action}, {k8s_user_app_status}" + + raise ValueError("Invalid input") diff --git a/apps/tasks.py b/apps/tasks.py index 2a310864..a4db7a5b 100644 --- a/apps/tasks.py +++ b/apps/tasks.py @@ -248,10 +248,11 @@ def deploy_resource(serialized_instance): helm_info = {"success": success, "info": {"stdout": output, "stderr": error}} + # TODO: Status. Here we no longer save an app_status property. instance.info = dict(helm=helm_info) - instance.app_status.status = "Created" if success else "Failed" + # instance.app_status.status = "Created" if success else "Failed" - instance.app_status.save() + # instance.app_status.save() instance.save() # In development, also generate and validate the k8s deployment manifest @@ -276,18 +277,25 @@ def delete_resource(serialized_instance): output, error = helm_delete(values["subdomain"], values["namespace"]) success = not error + # TODO: Status. Save this to K8sUserAppStatus instead of app_status. if success: + # TODO: Status. User actions are now saved by views: + """ if instance.app.slug in ("volumeK8s", "netpolicy"): instance.app_status.status = "Deleted" else: instance.app_status.status = "Deleting..." + """ + logger.info(f"Successfully deleted resource type {instance.app.slug}, {values['subdomain']}") else: - instance.app_status.status = "FailedToDelete" + instance.k8s_user_app_status.status = "FailedToDelete" + instance.k8s_user_app_status.save() + # instance.app_status.status = "FailedToDelete" helm_info = {"success": success, "info": {"stdout": output, "stderr": error}} instance.info = dict(helm=helm_info) - instance.app_status.save() + # instance.app_status.save() instance.save() diff --git a/apps/tests/test_app_helper_utils.py b/apps/tests/test_app_helper_utils.py new file mode 100644 index 00000000..bc754536 --- /dev/null +++ b/apps/tests/test_app_helper_utils.py @@ -0,0 +1,56 @@ +"""This module is used to test the helper functions that are used by user app instance functionality.""" + +from unittest.mock import patch + +from django.contrib.auth import get_user_model +from django.test import TestCase + +from projects.models import Project + +from ..models import Apps, JupyterInstance, K8sUserAppStatus + +User = get_user_model() + + +class CreateAppInstanceTestCase(TestCase): + """Test case for testing create_instance_from_form""" + + def setUp(self): + self.user = User.objects.create_user("foo1", "foo@test.com", "bar") + + def test_create_instance_from_form_valid_input(self): + self.assertTrue(1 == 0) + + def test_create_instance_from_form_invalid_input(self): + self.assertTrue(1 == 0) + + +class UpdateExistingAppInstanceTestCase(TestCase): + """Test case for test create_instance_from_form and an existing user app instance.""" + + def setUp(self) -> None: + self.user = User.objects.create_user("foo1", "foo@test.com", "bar") + self.app = Apps.objects.create( + name="Custom App", + slug="customapp", + ) + + self.project = Project.objects.create_project(name="test-perm", owner=self.user, description="") + + k8s_user_app_status = K8sUserAppStatus.objects.create() + self.app_instance = JupyterInstance.objects.create( + access="public", + owner=self.user, + name="test_app_instance_public", + app=self.app, + project=self.project, + k8s_user_app_status=k8s_user_app_status, + ) + + def test_create_instance_from_form_valid_input(self): + # TODO: Status. Implement + self.assertTrue(1 == 0) + + def test_create_instance_from_form_invalid_input(self): + # TODO: Status. Implement + self.assertTrue(1 == 0) diff --git a/apps/tests/test_app_instance.py b/apps/tests/test_app_instance.py index 76196b4a..ac4a9c4c 100644 --- a/apps/tests/test_app_instance.py +++ b/apps/tests/test_app_instance.py @@ -1,3 +1,4 @@ +import pytest from django.contrib.auth import get_user_model from django.db.models.signals import post_save from django.test import TestCase @@ -6,7 +7,6 @@ from ..models import ( Apps, - AppStatus, BaseAppInstance, CustomAppInstance, FilemanagerInstance, @@ -44,7 +44,8 @@ def get_data(self, access): for i, model_class in enumerate(MODELS_LIST): subdomain = Subdomain.objects.create(subdomain=f"test_internal_{i}") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # TODO: Status. + # app_status = AppStatus.objects.create(status="Created") app_instance = model_class.objects.create( access=access, @@ -54,7 +55,7 @@ def get_data(self, access): project=project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, ) app_instance_list.append(app_instance) @@ -103,3 +104,39 @@ def test_permission_remove_if_changed_from_project(self): result_list = [self.user.has_perm("can_access_app", app_instance) for app_instance in app_instance_list] print(result_list) self.assertFalse(any(result_list)) + + +@pytest.mark.parametrize( + "latest_user_action, k8s_user_app_status, expected", + [ + # Creating / Changing + ("Creating", "ContainerCreating", "Creating"), + ("Creating", "PodInitializing", "Creating"), + ("Changing", "ContainerCreating", "Changing"), + ("Changing", "PodInitializing", "Changing"), + # Error (NotFound) + ("Creating", "NotFound", "Error (NotFound)"), + ("Changing", "NotFound", "Error (NotFound)"), + # Error + ("Creating", "CrashLoopBackoff", "Error"), + ("Creating", "ErrImagePull", "Error"), + ("Creating", "PostStartHookError", "Error"), + ("Changing", "CrashLoopBackoff", "Error"), + ("Changing", "ErrImagePull", "Error"), + ("Changing", "PostStartHookError", "Error"), + # Running + ("Creating", "Running", "Running"), + ("Changing", "Running", "Running"), + # Deleting + ("Deleting", "ContainerCreating", "Deleted"), + ("Deleting", "PodInitializing", "Deleted"), + ("Deleting", "NotFound", "Deleted"), + ("Deleting", "CrashLoopBackoff", "Deleted"), + ("Deleting", "ErrImagePull", "Deleted"), + ("Deleting", "PostStartHookError", "Deleted"), + ("Deleting", "Running", "Deleted"), + ], +) +def test_convert_to_app_status(latest_user_action, k8s_user_app_status, expected): + """Tests the static method BaseAppInstance.convert_to_app_status""" + assert BaseAppInstance.convert_to_app_status(latest_user_action, k8s_user_app_status) == expected diff --git a/apps/tests/test_app_instance_manager.py b/apps/tests/test_app_instance_manager.py index 199eaa1a..212e9876 100644 --- a/apps/tests/test_app_instance_manager.py +++ b/apps/tests/test_app_instance_manager.py @@ -1,3 +1,4 @@ +import pytest from django.contrib.auth import get_user_model from django.db.models import Q from django.test import TestCase, override_settings @@ -10,6 +11,7 @@ CustomAppInstance, FilemanagerInstance, JupyterInstance, + K8sUserAppStatus, RStudioInstance, ShinyInstance, Subdomain, @@ -139,3 +141,63 @@ def test_get_app_instances_of_project_order_by(self): self.assertEqual(len(result), len(MODELS_LIST)) self.assertEqual(result.first().name, f"test_app_instance_{len(MODELS_LIST)-1}") self.assertEqual(result.last().name, "test_app_instance_0") + + def test_get_apps_not_deleted(self): + # TODO: Status + self.assertEqual(1, 0) + + +@pytest.mark.parametrize( + "latest_user_action, k8s_user_app_status, expected_app_status", + [ + # Creating / Changing + ("Creating", "ContainerCreating", "Creating"), + ("Creating", "PodInitializing", "Creating"), + ("Changing", "ContainerCreating", "Changing"), + ("Changing", "PodInitializing", "Changing"), + # Error (NotFound) + ("Creating", "NotFound", "Error (NotFound)"), + ("Changing", "NotFound", "Error (NotFound)"), + # Error + ("Creating", "CrashLoopBackoff", "Error"), + ("Creating", "ErrImagePull", "Error"), + ("Creating", "PostStartHookError", "Error"), + ("Changing", "CrashLoopBackoff", "Error"), + ("Changing", "ErrImagePull", "Error"), + ("Changing", "PostStartHookError", "Error"), + # Running + ("Creating", "Running", "Running"), + ("Changing", "Running", "Running"), + # Deleting + ("Deleting", "ContainerCreating", "Deleted"), + ("Deleting", "PodInitializing", "Deleted"), + ("Deleting", "NotFound", "Deleted"), + ("Deleting", "CrashLoopBackoff", "Deleted"), + ("Deleting", "ErrImagePull", "Deleted"), + ("Deleting", "PostStartHookError", "Deleted"), + ("Deleting", "Running", "Deleted"), + ], +) +@pytest.mark.django_db +def test_with_app_status(latest_user_action, k8s_user_app_status, expected_app_status): + """Tests the AppInstanceManager model mananger annotation atn_app_status.""" + # Setup + user = User.objects.create_user("foo1", "foo@test.com", "bar") + project = Project.objects.create_project(name="test-perm", owner=user, description="") + app = Apps.objects.create(name="Serve App", slug="serve-app") + + k8s_user_app_status = K8sUserAppStatus.objects.create(status=k8s_user_app_status) + + app_instance = BaseAppInstance.objects.create( + latest_user_action=latest_user_action, + k8s_user_app_status=k8s_user_app_status, + owner=user, + app=app, + project=project, + ) + + # Apply the annotation + annotated_app = BaseAppInstance.objects.with_app_status().get(id=app_instance.id) + + # Verify the annotated values + assert annotated_app.atn_app_status == expected_app_status diff --git a/apps/tests/test_app_settings_view.py b/apps/tests/test_app_settings_view.py index 78070cc0..6177996d 100644 --- a/apps/tests/test_app_settings_view.py +++ b/apps/tests/test_app_settings_view.py @@ -32,7 +32,8 @@ def setUp(self) -> None: subdomain = Subdomain.objects.create(subdomain="test_internal") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # TODO: Status. + # app_status = AppStatus.objects.create(status="Created") self.app_instance = CustomAppInstance.objects.create( access="public", owner=self.user, @@ -41,7 +42,7 @@ def setUp(self) -> None: project=self.project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, k8s_values={ "environment": {"pk": ""}, }, diff --git a/apps/tests/test_create_app_view.py b/apps/tests/test_create_app_view.py index 61d04330..78137ce4 100644 --- a/apps/tests/test_create_app_view.py +++ b/apps/tests/test_create_app_view.py @@ -147,7 +147,8 @@ def test_has_permission_project_level(self): subdomain = Subdomain.objects.create(subdomain="test_internal") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # TODO: Status. + # app_status = AppStatus.objects.create(status="Created") _ = JupyterInstance.objects.create( access="private", owner=self.user, @@ -156,7 +157,7 @@ def test_has_permission_project_level(self): project=project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, ) response = c.get(f"/projects/{project.slug}/apps/create/jupyter-lab") @@ -220,7 +221,8 @@ def test_app_limit_is_per_project(self): subdomain = Subdomain.objects.create(subdomain="test_internal") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # TODO: Status. + # app_status = AppStatus.objects.create(status="Created") _ = JupyterInstance.objects.create( access="private", owner=self.user, @@ -229,7 +231,7 @@ def test_app_limit_is_per_project(self): project=project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, ) response = c.get(f"/projects/{project.slug}/apps/create/jupyter-lab") @@ -276,7 +278,8 @@ def test_app_limit_altered_for_project_v2(self): subdomain = Subdomain.objects.create(subdomain="test_internal") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # TODO: Status. + # app_status = AppStatus.objects.create(status="Created") _ = JupyterInstance.objects.create( access="private", owner=self.user, @@ -285,7 +288,7 @@ def test_app_limit_altered_for_project_v2(self): project=project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, ) response = c.get(f"/projects/{project.slug}/apps/create/jupyter-lab") diff --git a/apps/tests/test_delete_app_view.py b/apps/tests/test_delete_app_view.py index c17657b5..c3c699e8 100644 --- a/apps/tests/test_delete_app_view.py +++ b/apps/tests/test_delete_app_view.py @@ -5,20 +5,14 @@ from projects.models import Project -from ..models import ( - AppCategories, - Apps, - AppStatus, - JupyterInstance, - K8sUserAppStatus, - Subdomain, -) +from ..models import AppCategories, Apps, JupyterInstance, K8sUserAppStatus, Subdomain User = get_user_model() test_user = {"username": "foo1", "email": "foo@test.com", "password": "bar"} +# TODO: Add K8sUserAppStatus? class DeleteAppViewTestCase(TestCase): def setUp(self) -> None: self.user = User.objects.create_user(test_user["username"], test_user["email"], test_user["password"]) @@ -34,7 +28,7 @@ def setUp(self) -> None: subdomain = Subdomain.objects.create(subdomain="test_internal") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # app_status = AppStatus.objects.create(status="Created") self.app_instance = JupyterInstance.objects.create( access="public", owner=self.user, @@ -43,7 +37,7 @@ def setUp(self) -> None: project=self.project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, ) def get_data(self, user=None): diff --git a/apps/tests/test_forms.py b/apps/tests/test_forms.py index 17d88374..1f18ec93 100644 --- a/apps/tests/test_forms.py +++ b/apps/tests/test_forms.py @@ -6,7 +6,7 @@ from apps.forms import CustomAppForm from apps.helpers import validate_path_k8s_label_compatible -from apps.models import Apps, AppStatus, Subdomain, VolumeInstance +from apps.models import Apps, K8sUserAppStatus, Subdomain, VolumeInstance from apps.models.app_types.custom.custom import validate_default_url_subpath from projects.models import Flavor, Project @@ -27,7 +27,8 @@ def setUp(self): project=self.project, size=1, subdomain=Subdomain.objects.create(subdomain="subdomain", project=self.project), - app_status=AppStatus.objects.create(status="Created"), + k8s_user_app_status=K8sUserAppStatus.objects.create(), + # app_status=AppStatus.objects.create(status="Created"), ) self.flavor = Flavor.objects.create(name="flavor", project=self.project) @@ -84,7 +85,8 @@ def test_valid_path_if_set_in_admin_panel(self): instance = form.save(commit=False) instance.project = self.project instance.owner = self.user - instance.app_status = AppStatus.objects.create(status="Created") + instance.k8s_user_app_status = K8sUserAppStatus.objects.create() + # instance.app_status = AppStatus.objects.create(status="Created") instance.app = self.app # Fetch subdomain and set diff --git a/apps/tests/test_get_status_view.py b/apps/tests/test_get_status_view.py index cc3f0b45..1db56829 100644 --- a/apps/tests/test_get_status_view.py +++ b/apps/tests/test_get_status_view.py @@ -3,20 +3,14 @@ from projects.models import Project -from ..models import ( - AppCategories, - Apps, - AppStatus, - JupyterInstance, - K8sUserAppStatus, - Subdomain, -) +from ..models import AppCategories, Apps, JupyterInstance, K8sUserAppStatus, Subdomain User = get_user_model() test_user = {"username": "foo@test.com", "email": "foo@test.com", "password": "bar"} +# TODO: Add K8sUserAppStatus? class GetStatusViewTestCase(TestCase): def setUp(self) -> None: self.user = User.objects.create_user(test_user["username"], test_user["email"], test_user["password"]) @@ -32,7 +26,8 @@ def setUp(self) -> None: subdomain = Subdomain.objects.create(subdomain="test_internal") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # TODO: Status. + # app_status = AppStatus.objects.create(status="Created") self.app_instance = JupyterInstance.objects.create( access="public", owner=self.user, @@ -41,7 +36,7 @@ def setUp(self) -> None: project=self.project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, ) def test_user_has_access(self): diff --git a/studio/tests.py b/studio/tests.py index 39554fc3..78b1ccaa 100644 --- a/studio/tests.py +++ b/studio/tests.py @@ -5,7 +5,7 @@ from django.test import TestCase from guardian.shortcuts import assign_perm, remove_perm -from apps.models import Apps, AppStatus, JupyterInstance, K8sUserAppStatus, Subdomain +from apps.models import Apps, JupyterInstance, K8sUserAppStatus, Subdomain from common.models import EmailVerificationTable, UserProfile from projects.models import Project from scripts.app_instance_permissions import run @@ -23,7 +23,7 @@ def get_data(self, user, access): subdomain = Subdomain.objects.create(subdomain="test_internal") k8s_user_app_status = K8sUserAppStatus.objects.create() - app_status = AppStatus.objects.create(status="Created") + # app_status = AppStatus.objects.create(status="Created") app_instance = JupyterInstance.objects.create( access=access, owner=user, @@ -32,7 +32,7 @@ def get_data(self, user, access): project=project, subdomain=subdomain, k8s_user_app_status=k8s_user_app_status, - app_status=app_status, + # app_status=app_status, ) return [project, app, app_instance]