""" Test data generator for ATS load testing. This module provides utilities to generate realistic test data for load testing scenarios including jobs, users, and applications. """ import os import json import random from datetime import datetime, timedelta from faker import Faker from typing import List, Dict, Any import django from django.conf import settings # Initialize Faker fake = Faker() class TestDataGenerator: """Generates test data for ATS load testing.""" def __init__(self): self.job_titles = [ "Software Engineer", "Senior Developer", "Frontend Developer", "Backend Developer", "Full Stack Developer", "DevOps Engineer", "Data Scientist", "Machine Learning Engineer", "Product Manager", "UX Designer", "UI Designer", "Business Analyst", "Project Manager", "Scrum Master", "QA Engineer", "System Administrator", "Network Engineer", "Security Analyst", "Database Administrator", "Cloud Engineer", "Mobile Developer" ] self.departments = [ "Engineering", "Product", "Design", "Marketing", "Sales", "HR", "Finance", "Operations", "Customer Support", "IT" ] self.locations = [ "Riyadh", "Jeddah", "Dammam", "Mecca", "Medina", "Khobar", "Tabuk", "Abha", "Hail", "Najran" ] self.skills = [ "Python", "JavaScript", "Java", "C++", "Go", "Rust", "React", "Vue.js", "Angular", "Django", "Flask", "FastAPI", "PostgreSQL", "MySQL", "MongoDB", "Redis", "Elasticsearch", "Docker", "Kubernetes", "AWS", "Azure", "GCP", "Git", "CI/CD", "Agile", "Scrum", "TDD" ] def generate_job_posting(self, job_id: int = None) -> Dict[str, Any]: """Generate a realistic job posting.""" if job_id is None: job_id = random.randint(1, 1000) title = random.choice(self.job_titles) department = random.choice(self.departments) location = random.choice(self.locations) # Generate job description description = f""" We are seeking a talented {title} to join our {department} team in {location}. Responsibilities: - Design, develop, and maintain high-quality software solutions - Collaborate with cross-functional teams to deliver projects - Participate in code reviews and technical discussions - Mentor junior developers and share knowledge - Stay updated with latest technologies and best practices Requirements: - Bachelor's degree in Computer Science or related field - {random.randint(3, 8)}+ years of relevant experience - Strong programming skills in relevant technologies - Excellent problem-solving and communication skills - Experience with agile development methodologies """ # Generate qualifications qualifications = f""" Required Skills: - {random.choice(self.skills)} - {random.choice(self.skills)} - {random.choice(self.skills)} - Experience with version control (Git) - Strong analytical and problem-solving skills Preferred Skills: - {random.choice(self.skills)} - {random.choice(self.skills)} - Cloud computing experience - Database design and optimization """ # Generate benefits benefits = """ Competitive salary and benefits package Health insurance and medical coverage Professional development opportunities Flexible work arrangements Annual performance bonuses Employee wellness programs """ # Generate application instructions application_instructions = """ To apply for this position: 1. Submit your updated resume 2. Include a cover letter explaining your interest 3. Provide portfolio or GitHub links if applicable 4. Complete the online assessment 5. Wait for our recruitment team to contact you """ # Generate deadlines and dates posted_date = fake.date_between(start_date="-30d", end_date="today") application_deadline = posted_date + timedelta(days=random.randint(30, 90)) return { "id": job_id, "title": title, "slug": f"{title.lower().replace(' ', '-')}-{job_id}", "description": description.strip(), "qualifications": qualifications.strip(), "benefits": benefits.strip(), "application_instructions": application_instructions.strip(), "department": department, "location": location, "employment_type": random.choice(["Full-time", "Part-time", "Contract", "Temporary"]), "experience_level": random.choice(["Entry", "Mid", "Senior", "Lead"]), "salary_min": random.randint(5000, 15000), "salary_max": random.randint(15000, 30000), "is_active": True, "posted_date": posted_date.isoformat(), "application_deadline": application_deadline.isoformat(), "internal_job_id": f"JOB-{job_id:06d}", "hash_tags": f"#{title.replace(' ', '')},#{department},#{location},#hiring", "application_url": f"/jobs/{title.lower().replace(' ', '-')}-{job_id}/apply/" } def generate_user_profile(self, user_id: int = None) -> Dict[str, Any]: """Generate a realistic user profile.""" if user_id is None: user_id = random.randint(1, 1000) first_name = fake.first_name() last_name = fake.last_name() email = fake.email() return { "id": user_id, "username": f"{first_name.lower()}.{last_name.lower()}{user_id}", "email": email, "first_name": first_name, "last_name": last_name, "phone": fake.phone_number(), "location": fake.city(), "bio": fake.text(max_nb_chars=200), "linkedin_profile": f"https://linkedin.com/in/{first_name.lower()}-{last_name.lower()}{user_id}", "github_profile": f"https://github.com/{first_name.lower()}{last_name.lower()}{user_id}", "portfolio_url": f"https://{first_name.lower()}{last_name.lower()}{user_id}.com", "is_staff": random.choice([True, False]), "is_active": True, "date_joined": fake.date_between(start_date="-2y", end_date="today").isoformat(), "last_login": fake.date_between(start_date="-30d", end_date="today").isoformat() } def generate_application(self, application_id: int = None, job_id: int = None, user_id: int = None) -> Dict[str, Any]: """Generate a realistic job application.""" if application_id is None: application_id = random.randint(1, 5000) if job_id is None: job_id = random.randint(1, 100) if user_id is None: user_id = random.randint(1, 500) statuses = ["PENDING", "REVIEWING", "SHORTLISTED", "INTERVIEW", "OFFER", "HIRED", "REJECTED"] status = random.choice(statuses) # Generate application date applied_date = fake.date_between(start_date="-60d", end_date="today") # Generate cover letter cover_letter = f""" Dear Hiring Manager, I am writing to express my strong interest in the position at your organization. With my background and experience, I believe I would be a valuable addition to your team. {fake.text(max_nb_chars=300)} I look forward to discussing how my skills and experience align with your needs. Best regards, {fake.name()} """ return { "id": application_id, "job_id": job_id, "user_id": user_id, "status": status, "applied_date": applied_date.isoformat(), "cover_letter": cover_letter.strip(), "resume_file": f"resume_{application_id}.pdf", "portfolio_url": fake.url() if random.choice([True, False]) else None, "linkedin_url": fake.url() if random.choice([True, False]) else None, "github_url": fake.url() if random.choice([True, False]) else None, "expected_salary": random.randint(5000, 25000), "available_start_date": (fake.date_between(start_date="+1w", end_date="+2m")).isoformat(), "notice_period": random.choice(["Immediate", "1 week", "2 weeks", "1 month"]), "source": random.choice(["LinkedIn", "Company Website", "Referral", "Job Board", "Social Media"]), "notes": fake.text(max_nb_chars=100) if random.choice([True, False]) else None } def generate_interview(self, interview_id: int = None, application_id: int = None) -> Dict[str, Any]: """Generate a realistic interview schedule.""" if interview_id is None: interview_id = random.randint(1, 2000) if application_id is None: application_id = random.randint(1, 500) interview_types = ["Phone Screen", "Technical Interview", "Behavioral Interview", "Final Interview", "HR Interview"] interview_type = random.choice(interview_types) # Generate interview date and time interview_datetime = fake.date_time_between(start_date="-30d", end_date="+30d") return { "id": interview_id, "application_id": application_id, "type": interview_type, "scheduled_date": interview_datetime.isoformat(), "duration": random.randint(30, 120), # minutes "location": random.choice(["Office", "Video Call", "Phone Call"]), "interviewer": fake.name(), "interviewer_email": fake.email(), "status": random.choice(["SCHEDULED", "COMPLETED", "CANCELLED", "RESCHEDULED"]), "notes": fake.text(max_nb_chars=200) if random.choice([True, False]) else None, "meeting_id": f"meeting_{interview_id}" if random.choice([True, False]) else None, "meeting_url": f"https://zoom.us/j/{interview_id}" if random.choice([True, False]) else None } def generate_message(self, message_id: int = None, sender_id: int = None, recipient_id: int = None) -> Dict[str, Any]: """Generate a realistic message between users.""" if message_id is None: message_id = random.randint(1, 3000) if sender_id is None: sender_id = random.randint(1, 500) if recipient_id is None: recipient_id = random.randint(1, 500) message_types = ["DIRECT", "SYSTEM", "NOTIFICATION"] message_type = random.choice(message_types) return { "id": message_id, "sender_id": sender_id, "recipient_id": recipient_id, "subject": fake.sentence(nb_words=6), "content": fake.text(max_nb_chars=500), "message_type": message_type, "is_read": random.choice([True, False]), "created_at": fake.date_time_between(start_date="-30d", end_date="today").isoformat(), "read_at": fake.date_time_between(start_date="-29d", end_date="today").isoformat() if random.choice([True, False]) else None } def generate_bulk_data(self, config: Dict[str, int]) -> Dict[str, List[Dict]]: """Generate bulk test data based on configuration.""" data = { "jobs": [], "users": [], "applications": [], "interviews": [], "messages": [] } # Generate jobs for i in range(config.get("job_count", 100)): data["jobs"].append(self.generate_job_posting(i + 1)) # Generate users for i in range(config.get("user_count", 50)): data["users"].append(self.generate_user_profile(i + 1)) # Generate applications for i in range(config.get("application_count", 500)): job_id = random.randint(1, len(data["jobs"])) user_id = random.randint(1, len(data["users"])) data["applications"].append(self.generate_application(i + 1, job_id, user_id)) # Generate interviews (for some applications) interview_count = len(data["applications"]) // 2 # Half of applications have interviews for i in range(interview_count): application_id = random.randint(1, len(data["applications"])) data["interviews"].append(self.generate_interview(i + 1, application_id)) # Generate messages message_count = config.get("user_count", 50) * 5 # 5 messages per user on average for i in range(message_count): sender_id = random.randint(1, len(data["users"])) recipient_id = random.randint(1, len(data["users"])) data["messages"].append(self.generate_message(i + 1, sender_id, recipient_id)) return data def save_test_data(self, data: Dict[str, List[Dict]], output_dir: str = "load_tests/test_data"): """Save generated test data to JSON files.""" os.makedirs(output_dir, exist_ok=True) for data_type, records in data.items(): filename = os.path.join(output_dir, f"{data_type}.json") with open(filename, 'w') as f: json.dump(records, f, indent=2, default=str) print(f"Saved {len(records)} {data_type} to {filename}") def create_test_files(self, count: int = 100, output_dir: str = "load_tests/test_files"): """Create test files for upload testing.""" os.makedirs(output_dir, exist_ok=True) for i in range(count): # Create a simple text file content = fake.text(max_nb_chars=1000) filename = os.path.join(output_dir, f"test_file_{i + 1}.txt") with open(filename, 'w') as f: f.write(content) print(f"Created {count} test files in {output_dir}") if __name__ == "__main__": # Example usage generator = TestDataGenerator() # Generate test data config = { "job_count": 50, "user_count": 25, "application_count": 200 } test_data = generator.generate_bulk_data(config) generator.save_test_data(test_data) generator.create_test_files(50) print("Test data generation completed!")