Simple File Upload Testing

Basic file upload API testing for single files, multiple files, and large file handling

LoadForge can record your browser, graphically build tests, scan your site with a wizard and more. Sign up now to run your first test.

Sign up now


This guide shows how to test file upload APIs with different file types, sizes, and upload scenarios.

Use Cases

  • Test file upload functionality and limits
  • Validate file type restrictions and validation
  • Test large file upload performance
  • Check concurrent upload handling

Simple Implementation

from locust import task, HttpUser
import random
import io

class FileUploadTestUser(HttpUser):
    def on_start(self):
        # File upload endpoints
        self.upload_endpoints = {
            "single": "/api/upload/single",
            "multiple": "/api/upload/multiple",
            "large": "/api/upload/large",
            "validate": "/api/upload/validate"
        }
        
        # File types for testing
        self.file_types = {
            "image": {"ext": "jpg", "mime": "image/jpeg"},
            "document": {"ext": "pdf", "mime": "application/pdf"},
            "text": {"ext": "txt", "mime": "text/plain"},
            "video": {"ext": "mp4", "mime": "video/mp4"}
        }
        
        # File sizes (in bytes)
        self.file_sizes = {
            "small": 1024,      # 1KB
            "medium": 1024*100, # 100KB
            "large": 1024*1024, # 1MB
            "xlarge": 1024*1024*10  # 10MB
        }

    def create_test_file(self, file_type="text", size="small"):
        """Create a test file in memory"""
        file_info = self.file_types[file_type]
        file_size = self.file_sizes[size]
        
        # Create file content
        if file_type == "text":
            content = b"A" * file_size
        elif file_type == "image":
            # Minimal JPEG header + data
            content = b'\xff\xd8\xff\xe0\x00\x10JFIF' + b"X" * (file_size - 14)
        else:
            content = b"TESTFILE" + b"X" * (file_size - 8)
        
        filename = f"test_file_{random.randint(1000, 9999)}.{file_info['ext']}"
        
        return {
            "content": content,
            "filename": filename,
            "mime_type": file_info["mime"]
        }

    @task(4)
    def test_single_file_upload(self):
        """Test uploading a single file"""
        file_type = random.choice(list(self.file_types.keys()))
        file_size = random.choice(["small", "medium"])
        
        test_file = self.create_test_file(file_type, file_size)
        
        files = {
            "file": (test_file["filename"], test_file["content"], test_file["mime_type"])
        }
        
        data = {
            "description": f"Test {file_type} upload",
            "category": file_type
        }
        
        with self.client.post(
            self.upload_endpoints["single"],
            files=files,
            data=data,
            name="Single File Upload"
        ) as response:
            if response.status_code == 200:
                try:
                    result = response.json()
                    file_id = result.get("file_id") or result.get("id")
                    uploaded_size = result.get("size", 0)
                    
                    print(f"Single upload success: {test_file['filename']} ({uploaded_size} bytes)")
                    
                    # Validate uploaded file size
                    if uploaded_size != len(test_file["content"]):
                        response.failure(f"Size mismatch: expected {len(test_file['content'])}, got {uploaded_size}")
                    
                except Exception as e:
                    response.failure(f"Invalid response: {str(e)}")
            elif response.status_code == 413:
                print("File too large (expected for large files)")
            elif response.status_code == 415:
                print("Unsupported file type (may be expected)")
            else:
                response.failure(f"Single file upload failed: {response.status_code}")

    @task(3)
    def test_multiple_file_upload(self):
        """Test uploading multiple files"""
        num_files = random.randint(2, 4)
        files = {}
        data = {"batch_description": "Multiple file upload test"}
        
        for i in range(num_files):
            file_type = random.choice(list(self.file_types.keys()))
            test_file = self.create_test_file(file_type, "small")
            
            files[f"file_{i}"] = (test_file["filename"], test_file["content"], test_file["mime_type"])
        
        with self.client.post(
            self.upload_endpoints["multiple"],
            files=files,
            data=data,
            name="Multiple File Upload"
        ) as response:
            if response.status_code == 200:
                try:
                    result = response.json()
                    uploaded_files = result.get("files", [])
                    
                    print(f"Multiple upload success: {len(uploaded_files)} files")
                    
                    # Validate number of uploaded files
                    if len(uploaded_files) != num_files:
                        response.failure(f"File count mismatch: expected {num_files}, got {len(uploaded_files)}")
                    
                except Exception as e:
                    response.failure(f"Invalid response: {str(e)}")
            else:
                response.failure(f"Multiple file upload failed: {response.status_code}")

    @task(2)
    def test_large_file_upload(self):
        """Test uploading large files"""
        file_size = random.choice(["large", "xlarge"])
        test_file = self.create_test_file("document", file_size)
        
        files = {
            "large_file": (test_file["filename"], test_file["content"], test_file["mime_type"])
        }
        
        data = {
            "upload_type": "large_file",
            "expected_size": len(test_file["content"])
        }
        
        with self.client.post(
            self.upload_endpoints["large"],
            files=files,
            data=data,
            name="Large File Upload",
            timeout=60  # Longer timeout for large files
        ) as response:
            if response.status_code == 200:
                try:
                    result = response.json()
                    file_id = result.get("file_id")
                    
                    print(f"Large file upload success: {test_file['filename']} ({file_size})")
                    
                except Exception as e:
                    response.failure(f"Invalid response: {str(e)}")
            elif response.status_code == 413:
                print(f"Large file rejected (size limit): {file_size}")
            elif response.status_code == 408:
                print(f"Large file upload timeout: {file_size}")
            else:
                response.failure(f"Large file upload failed: {response.status_code}")

    @task(2)
    def test_file_validation(self):
        """Test file upload validation and restrictions"""
        # Test invalid file type
        invalid_file = self.create_test_file("text", "small")
        invalid_file["filename"] = "malicious.exe"
        invalid_file["mime_type"] = "application/x-executable"
        
        files = {
            "file": (invalid_file["filename"], invalid_file["content"], invalid_file["mime_type"])
        }
        
        with self.client.post(
            self.upload_endpoints["validate"],
            files=files,
            name="Invalid File Upload"
        ) as response:
            if response.status_code == 415:
                print("Invalid file type correctly rejected")
            elif response.status_code == 400:
                print("Invalid file correctly rejected (bad request)")
            elif response.status_code == 200:
                response.failure("Invalid file type was accepted")
            else:
                print(f"Invalid file upload returned: {response.status_code}")

    @task(1)
    def test_empty_file_upload(self):
        """Test uploading empty files"""
        empty_file = {
            "content": b"",
            "filename": "empty.txt",
            "mime_type": "text/plain"
        }
        
        files = {
            "file": (empty_file["filename"], empty_file["content"], empty_file["mime_type"])
        }
        
        with self.client.post(
            self.upload_endpoints["single"],
            files=files,
            name="Empty File Upload"
        ) as response:
            if response.status_code == 400:
                print("Empty file correctly rejected")
            elif response.status_code == 200:
                print("Empty file accepted (may be valid)")
            else:
                print(f"Empty file upload returned: {response.status_code}")

    @task(1)
    def test_file_upload_limits(self):
        """Test file upload size and count limits"""
        # Try to upload many small files
        max_files = 10
        files = {}
        
        for i in range(max_files):
            test_file = self.create_test_file("text", "small")
            files[f"file_{i}"] = (test_file["filename"], test_file["content"], test_file["mime_type"])
        
        with self.client.post(
            self.upload_endpoints["multiple"],
            files=files,
            name="Upload Limit Test"
        ) as response:
            if response.status_code == 200:
                print(f"Upload limit test: {max_files} files accepted")
            elif response.status_code == 413:
                print(f"Upload limit reached (expected): {max_files} files")
            elif response.status_code == 400:
                print(f"Upload limit validation: {max_files} files rejected")
            else:
                print(f"Upload limit test returned: {response.status_code}")

Setup Instructions

  1. Replace upload endpoints with your actual file upload API URLs
  2. Adjust file types and MIME types for your application requirements
  3. Update file size limits based on your server configuration
  4. Configure timeout values for large file uploads

What This Tests

  • Single File Upload: Tests basic file upload functionality
  • Multiple File Upload: Tests batch file upload handling
  • Large File Upload: Tests performance with large files
  • File Validation: Tests file type and size restrictions
  • Empty Files: Tests edge case handling
  • Upload Limits: Tests file count and size limitations

Best Practices

  • Test various file types and sizes relevant to your application
  • Monitor upload performance and timeout handling
  • Test file validation and security restrictions
  • Validate uploaded file integrity and metadata
  • Test concurrent uploads from multiple users

Common Issues

  • File Size Limits: Server may have maximum file size restrictions
  • MIME Type Validation: Ensure file type validation works correctly
  • Timeout Issues: Large files may require longer timeout settings
  • Memory Usage: Large file uploads can consume significant server memory

Ready to run your test?
Run your test today with LoadForge.