Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 82 additions & 1 deletion backend/core/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
AIProvider,
Integration,
AppIntegration,
NotificationProfile
NotificationProfile,
LLMModel,
ChatRoom,
KnowledgeBase,
AppModel,
AppNotificationProfile,
ApplicationAPIKey,
ApplicationWidgetToken
)

fake = RealFaker()
Expand Down Expand Up @@ -77,3 +84,77 @@ def set_config(obj, create, extracted, **kwargs):
obj.config = extracted if extracted else {'email': fake.email()}
else:
obj.config = extracted if extracted else {'webhookUrl': f'https://hooks.{obj.type}.com/test/webhook'}


class LLMModelFactory(factory.django.DjangoModelFactory):
class Meta:
model = LLMModel

name = factory.Sequence(lambda n: f"LLM Model {n}")
api_key = factory.Faker('password')
api_key_preview = factory.LazyAttribute(lambda obj: obj.api_key[:4] + '****')
base_url = factory.Faker('url')
model_name = factory.Iterator(['gpt-4', 'gpt-3.5-turbo', 'claude-3'])
model_type = factory.Iterator(['text', 'embedding', 'image'])
is_default = False
owner = factory.SubFactory(UserFactory)


class ChatRoomFactory(factory.django.DjangoModelFactory):
class Meta:
model = ChatRoom

name = factory.Sequence(lambda n: f"Chat Room {n}")
application = factory.SubFactory(ApplicationFactory)
ai_provider = factory.SubFactory(AIProviderFactory)
model = factory.Iterator(['gpt-4', 'gpt-3.5-turbo'])
is_escalated = False


class KnowledgeBaseFactory(factory.django.DjangoModelFactory):
class Meta:
model = KnowledgeBase

application = factory.SubFactory(ApplicationFactory)
source_type = factory.Iterator(['url', 'file', 'text', 'github'])
path = factory.Faker('file_path')
metadata = factory.LazyFunction(lambda: {'content': fake.text()})
status = 'processed'


class AppModelFactory(factory.django.DjangoModelFactory):
class Meta:
model = AppModel

application = factory.SubFactory(ApplicationFactory)
llm_model = factory.SubFactory(LLMModelFactory)


class AppNotificationProfileFactory(factory.django.DjangoModelFactory):
class Meta:
model = AppNotificationProfile

application = factory.SubFactory(ApplicationFactory)
notification_profile = factory.SubFactory(NotificationProfileFactory)


class ApplicationAPIKeyFactory(factory.django.DjangoModelFactory):
class Meta:
model = ApplicationAPIKey

application = factory.SubFactory(ApplicationFactory)
name = factory.Sequence(lambda n: f"API Key {n}")
hashed_api_key = factory.Faker('password')
permissions = factory.LazyFunction(lambda: ['read'])
owner = factory.SubFactory(UserFactory)


class ApplicationWidgetTokenFactory(factory.django.DjangoModelFactory):
class Meta:
model = ApplicationWidgetToken

application = factory.SubFactory(ApplicationFactory)
label = factory.Sequence(lambda n: f"Widget Token {n}")
rate_limit_count = 60
rate_limit_period = 60
is_active = True
41 changes: 41 additions & 0 deletions backend/core/tests/test_app_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import pytest
from rest_framework import status

from core.models import AppModel
from core.tests.conftest import BaseAPITestCase
from core.tests.factories import (
UserFactory,
ApplicationFactory,
LLMModelFactory
)


@pytest.mark.api
class TestAppModelAPI(BaseAPITestCase):
def setUp(self):
super().setUp()

def test_configure_models_other_users_application(self):
user_a = UserFactory()
user_b = UserFactory()

app_b = ApplicationFactory(owner=user_b, name="User B's App")
llm_model_a = LLMModelFactory(owner=user_a, name="User A's Model")

self.client.force_authenticate(user=user_a)

url = f'/api/applications/{app_b.uuid}/models/'
data = {
'models': [
{
'llm_model_id': llm_model_a.id
}
]
}

response = self.client.post(url, data, format='json')

self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

app_models_count = AppModel.objects.filter(application=app_b).count()
self.assertEqual(app_models_count, 0)
37 changes: 37 additions & 0 deletions backend/core/tests/test_app_notification_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from rest_framework import status

from core.models import AppNotificationProfile
from core.tests.conftest import BaseAPITestCase
from core.tests.factories import (
UserFactory,
ApplicationFactory,
NotificationProfileFactory
)


@pytest.mark.api
class TestAppNotificationProfileAPI(BaseAPITestCase):
def setUp(self):
super().setUp()

def test_update_notifications_other_users_application(self):
user_a = UserFactory()
user_b = UserFactory()

app_b = ApplicationFactory(owner=user_b, name="User B's App")
profile_a = NotificationProfileFactory(owner=user_a, name="User A's Profile", type="email")

self.client.force_authenticate(user=user_a)

url = f'/api/applications/{app_b.uuid}/notification-profiles/'
data = {
'profile_uuids': [str(profile_a.uuid)]
}

response = self.client.patch(url, data, format='json')

self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

app_notification_profiles_count = AppNotificationProfile.objects.filter(application=app_b).count()
self.assertEqual(app_notification_profiles_count, 0)
113 changes: 113 additions & 0 deletions backend/core/tests/test_application.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import pytest
from rest_framework import status

from core.models import Application
from core.tests.conftest import BaseAPITestCase
from core.tests.factories import UserFactory, ApplicationFactory


@pytest.mark.api
class TestApplicationAPI(BaseAPITestCase):
def setUp(self):
super().setUp()
self.list_url = '/api/applications/'

def test_list_applications_authenticated_user(self):
user = UserFactory()
self.client.force_authenticate(user=user)

app1 = ApplicationFactory(owner=user, name="App 1")
app2 = ApplicationFactory(owner=user, name="App 2")

other_user = UserFactory()
other_app = ApplicationFactory(owner=other_user, name="Other App")

response = self.client.get(self.list_url)

self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()
self.assertEqual(len(data['results']), 2)

app_names = [app['name'] for app in data['results']]
self.assertIn("App 1", app_names)
self.assertIn("App 2", app_names)
self.assertNotIn("Other App", app_names)

def test_list_applications_unauthenticated(self):
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_retrieve_other_users_application(self):
user_a = UserFactory()
user_b = UserFactory()

app_b = ApplicationFactory(owner=user_b, name="User B's App")

self.client.force_authenticate(user=user_a)

detail_url = f'/api/applications/{app_b.uuid}/'
response = self.client.get(detail_url)

self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

def test_update_other_users_application(self):
user_a = UserFactory()
user_b = UserFactory()

app_b = ApplicationFactory(owner=user_b, name="User B's App")

self.client.force_authenticate(user=user_a)

detail_url = f'/api/applications/{app_b.uuid}/'
update_data = {'name': 'Hacked Name'}
response = self.client.patch(detail_url, update_data, format='json')

self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)

def test_delete_other_users_application(self):
user_a = UserFactory()
user_b = UserFactory()

app_b = ApplicationFactory(owner=user_b, name="User B's App")

self.client.force_authenticate(user=user_a)

detail_url = f'/api/applications/{app_b.uuid}/'
response = self.client.delete(detail_url)

self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

def test_create_application(self):
user = UserFactory()
self.client.force_authenticate(user=user)

create_data = {
'name': 'My Application',
}

response = self.client.post(self.list_url, create_data, format='json')

self.assertEqual(response.status_code, status.HTTP_201_CREATED)
data = response.json()

self.assertEqual(data['name'], 'My Application')
self.assertEqual(data['owner']['id'], user.id)

app = Application.objects.get(uuid=data['uuid'])
self.assertEqual(app.owner, user)
self.assertEqual(app.name, 'My Application')

def test_delete_own_application(self):
user = UserFactory()
self.client.force_authenticate(user=user)

app = ApplicationFactory(owner=user, name="App to Delete")

detail_url = f'/api/applications/{app.uuid}/'
response = self.client.delete(detail_url)

self.assertEqual(response.status_code, status.HTTP_200_OK)

with self.assertRaises(Application.DoesNotExist):
Application.objects.get(id=app.id)
35 changes: 35 additions & 0 deletions backend/core/tests/test_application_api_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import pytest
from rest_framework import status

from core.models import ApplicationAPIKey
from core.tests.conftest import BaseAPITestCase
from core.tests.factories import UserFactory, ApplicationFactory


@pytest.mark.api
class TestApplicationAPIKeyAPI(BaseAPITestCase):
def setUp(self):
super().setUp()

def test_delete_other_users_api_key(self):
user_a = UserFactory()
user_b = UserFactory()

app_b = ApplicationFactory(owner=user_b, name="User B's App")
api_key_b = ApplicationAPIKey.objects.create(
application=app_b,
name="User B's Key",
hashed_api_key="hashed_key",
permissions=['read'],
owner=user_b
)

self.client.force_authenticate(user=user_a)

detail_url = f'/api/applications/{app_b.uuid}/api-keys/{api_key_b.id}/'
response = self.client.delete(detail_url)

self.assertIn(response.status_code, [status.HTTP_404_NOT_FOUND, status.HTTP_403_FORBIDDEN])

api_key_exists = ApplicationAPIKey.objects.filter(id=api_key_b.id).exists()
self.assertTrue(api_key_exists)
Loading
Loading