Skip to content

Commit

Permalink
Added testing
Browse files Browse the repository at this point in the history
  • Loading branch information
unknown committed Apr 3, 2025
1 parent 2cc5345 commit 2b0f204
Show file tree
Hide file tree
Showing 17 changed files with 279 additions and 17 deletions.
1 change: 1 addition & 0 deletions backend/media/users/2/workout.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_content
1 change: 1 addition & 0 deletions backend/media/users/2/workout.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions backend/media/users/2/workout_0VoSyYu.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_content
1 change: 1 addition & 0 deletions backend/media/users/2/workout_K5ZHqrC.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions backend/media/users/2/workout_KdxpL6y.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_content
1 change: 1 addition & 0 deletions backend/media/users/2/workout_UiKNdnZ.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions backend/media/users/2/workout_Ybf0O0e.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_content
1 change: 1 addition & 0 deletions backend/media/users/2/workout_erGV1l4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions backend/media/users/2/workout_oIN0AMU.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions backend/media/users/2/workout_tlB5n5j.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_content
1 change: 1 addition & 0 deletions backend/media/users/2/workout_wTd9rjn.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
file_content
1 change: 1 addition & 0 deletions backend/media/users/2/workout_zuR6pI5.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion backend/secfit/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,12 @@
]

PASSWORD_HASHERS = [
'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.ScryptPasswordHasher',
#'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher',
]


Expand Down
Empty file added backend/tests/__init__.py
Empty file.
241 changes: 241 additions & 0 deletions backend/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
from django.test import TestCase
from rest_framework.test import APIClient
from django.contrib.auth import get_user_model
from django.urls import reverse
from workouts.models import Exercise, Workout
from users.models import AthleteFile
from datetime import datetime
from django.utils.timezone import make_aware
from django.core.files.uploadedfile import SimpleUploadedFile
import json

User = get_user_model()

# Test Case 001: Focuses on workout creation functionality
# Verifies that workouts can be created with valid inputs and proper relationships
class WorkoutCreationTest(TestCase):
"""TC_001: Equivalence class testing for workout creation"""
def setUp(self):
# Setup test athlete user and authentication token
self.client = APIClient()
self.athlete = User.objects.create_user(
username='athlete',
password='athletepass123',
email='athlete@example.com',
isCoach=False
)
# Get JWT token for athlete
response = self.client.post(
reverse('token_obtain_pair'),
{'username': 'athlete', 'password': 'athletepass123'},
format='json'
)
self.token = response.data['access']
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.token}')

# Create test exercise to use in workout
self.exercise = Exercise.objects.create(
name="Squats",
description="Bodyweight squats",
unit="reps"
)

# Tests successful workout creation with all required valid fields
def test_valid_workout_creation(self):
"""Verify workout creation with valid inputs"""
data = {
'name': 'Morning Run',
'date': make_aware(datetime(2025, 4, 1)).isoformat(),
'exercise_instances': [{
'exercise': f'http://testserver/api/exercises/{self.exercise.id}/',
'sets': 3,
'number': 1, # Added required 'number' field
'units': 'reps'
}],
'notes': 'Felt strong today',
'visibility': 'PU',
'owner': f'http://testserver/api/users/{self.athlete.id}/'
}

response = self.client.post(
reverse('workout-list'),
data=data,
format='json'
)

self.assertEqual(response.status_code, 201, response.data)
self.assertTrue(Workout.objects.filter(name='Morning Run').exists())

# Test Case 002: Focuses on user registration validation
# Verifies password rules and proper user type assignment
class UserRegistrationTest(TestCase):
"""TC_002: Boundary value testing for password/user type validation"""
def setUp(self):
# Setup API client and registration endpoint
self.client = APIClient()
self.register_url = reverse('user-list')

# Tests successful user registration with valid credentials
def test_valid_registration(self):
"""Verify system enforces password rules and user type"""
data = {
'username': 'TestUser',
'password': 'SecurePass123!',
'password1': 'SecurePass123!',
'email': 'test@example.com',
'first_name': 'Test',
'last_name': 'User',
'isCoach': False,
'athletes': [],
'workouts': [],
'coach_files': [],
'athlete_files': []
}

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

self.assertEqual(response.status_code, 201, response.data)
user = User.objects.get(username='TestUser')
self.assertEqual(user.email, 'test@example.com')
self.assertFalse(user.isCoach)

# Test Case 003: Focuses on workout visibility permissions
# Verifies access control for private workouts
class WorkoutVisibilityTest(TestCase):
"""TC_003: Robust boundary value testing for private workouts"""
def setUp(self):
# Setup test athlete and private workout
self.client = APIClient()
self.athlete = User.objects.create_user(
username='athlete',
password='athletepass123',
isCoach=False
)
self.workout = Workout.objects.create(
name='Private Workout',
owner=self.athlete,
visibility='PR',
date=make_aware(datetime(2025, 4, 1)),
notes='Test workout'
)

# Tests that unauthenticated users cannot access private workouts
def test_visitor_access_private_workout(self):
"""Verify visitors can't access private workouts"""
# Clear any authentication
self.client.credentials()
response = self.client.get(
reverse('workout-detail', kwargs={'pk': self.workout.id})
)
self.assertEqual(response.status_code, 401,
"Visitors should get 401 Unauthorized")

# Test Case 004: Focuses on file upload functionality
# Verifies file type validation and coach-athlete relationship
class FileUploadTest(TestCase):
"""TC_004: Special value testing for file uploads"""
def setUp(self):
# Setup coach and athlete users with authentication
self.client = APIClient()
self.coach = User.objects.create_user(
username='coach',
password='coachpass123',
isCoach=True
)
self.athlete = User.objects.create_user(
username='athlete',
password='athletepass123',
isCoach=False
)
# Get JWT token for coach
response = self.client.post(
reverse('token_obtain_pair'),
{'username': 'coach', 'password': 'coachpass123'},
format='json'
)
self.token = response.data['access']
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.token}')

# Tests file upload with different file types
def test_file_upload_validation(self):
"""Verify file upload works with different file types"""
# First, ensure coach is assigned to athlete
self.athlete.coach = self.coach
self.athlete.save()

# Test with valid JPEG file (should succeed)
jpg_file = SimpleUploadedFile(
"workout.jpg",
b"file_content",
content_type="image/jpeg"
)
response = self.client.post(
reverse('athlete-file-list'),
{
'file': jpg_file,
'athlete': f'http://testserver/api/users/{self.athlete.id}/',
'owner': f'http://testserver/api/users/{self.coach.id}/'
},
format='multipart'
)
self.assertEqual(response.status_code, 201,
f"Expected 201, got {response.status_code}. Response: {response.data}")

# Test with potentially dangerous EXE file (reveals security issue)
exe_file = SimpleUploadedFile(
"workout.exe",
b"file_content",
content_type="application/octet-stream"
)
response = self.client.post(
reverse('athlete-file-list'),
{
'file': exe_file,
'athlete': f'http://testserver/api/users/{self.athlete.id}/',
'owner': f'http://testserver/api/users/{self.coach.id}/'
},
format='multipart'
)
self.assertEqual(response.status_code, 201,
"Currently accepts all file types since validator isn't properly configured")

class ExerciseValidationTest(TestCase):
"""TC_005: Testing exercise creation"""
def setUp(self):
self.client = APIClient()
self.coach = User.objects.create_user(
username='coach',
password='coachpass123',
isCoach=True
)
# Get JWT token for coach
response = self.client.post(
reverse('token_obtain_pair'),
{'username': 'coach', 'password': 'coachpass123'},
format='json'
)
self.token = response.data['access']
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.token}')

def test_exercise_creation_with_any_unit(self):
"""Verify system currently accepts any unit value"""
data = {
'name': 'Custom Exercise',
'description': 'This tests unit validation',
'unit': 'unexpected_unit' # Should pass since validation isn't enforced
}

response = self.client.post(
reverse('exercise-list'),
data=data,
format='json'
)

self.assertEqual(response.status_code, 201,
"Currently accepts any unit value")
self.assertTrue(Exercise.objects.filter(name='Custom Exercise').exists(),
"Exercise should be created regardless of unit value")
16 changes: 0 additions & 16 deletions backend/tests/test_template.py

This file was deleted.

20 changes: 20 additions & 0 deletions backend/users/migrations/0004_alter_athletefile_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.2 on 2025-04-03 20:28

import users.models
import users.validators
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('users', '0003_user_specialism'),
]

operations = [
migrations.AlterField(
model_name='athletefile',
name='file',
field=models.FileField(upload_to=users.models.athlete_directory_path, validators=[users.validators.FileValidator(allowed_extensions='', allowed_mimetypes='', max_size=5242880)]),
),
]

0 comments on commit 2b0f204

Please sign in to comment.