|
|
@@ -1,124 +1,274 @@
|
|
|
# QDR Temporary Shared Storage - Testing Guide
|
|
|
|
|
|
-This document outlines a comprehensive testing strategy for the QDR Temporary Shared Storage plugin to ensure all components function correctly after refactoring.
|
|
|
+This document outlines a comprehensive testing strategy for the QDR Temporary Shared Storage plugin to ensure all components function correctly after the latest updates and refactoring.
|
|
|
|
|
|
## Manual Testing Procedures
|
|
|
|
|
|
### 1. Installation and Activation Testing
|
|
|
|
|
|
-- [ ] Upload plugin to a test WordPress site
|
|
|
+- [ ] Upload plugin to a test WordPress site (WordPress 6.8.1+ and PHP 8.2+)
|
|
|
- [ ] Activate the plugin
|
|
|
- [ ] Verify that activation creates:
|
|
|
- - [ ] The custom database table
|
|
|
- - [ ] The required upload directories
|
|
|
- - [ ] The download page
|
|
|
- - [ ] The default plugin settings
|
|
|
+ - [ ] The custom database table with proper schema (including `fileid` field)
|
|
|
+ - [ ] The required upload directories with `.htaccess` protection
|
|
|
+ - [ ] The download page with `[qdr_tss_download]` shortcode
|
|
|
+ - [ ] Default plugin settings including auto-generated API key
|
|
|
+ - [ ] Scheduled cron job for cleanup
|
|
|
|
|
|
### 2. Admin Interface Testing
|
|
|
|
|
|
-#### 2.1 Settings Page
|
|
|
+#### 2.1 Settings Page (Settings > Shared Storage)
|
|
|
|
|
|
- [ ] Navigate to Settings > Shared Storage
|
|
|
-- [ ] Verify all settings fields are displayed correctly
|
|
|
-- [ ] Test generating a new API key
|
|
|
+- [ ] Verify all settings fields are displayed correctly:
|
|
|
+ - [ ] API Key field with current key displayed
|
|
|
+ - [ ] Media Category field
|
|
|
+ - [ ] Maximum Storage Size field with current usage display
|
|
|
+- [ ] Test generating a new API key using "Generate New Key" button
|
|
|
- [ ] Change settings values and save
|
|
|
-- [ ] Refresh page and verify settings were saved
|
|
|
-- [ ] Test the "Purge Expired Files" button
|
|
|
+- [ ] Refresh page and verify settings were saved correctly
|
|
|
+- [ ] Test the "Purge Expired Files" button functionality
|
|
|
+- [ ] Verify storage usage bar displays correctly
|
|
|
|
|
|
-#### 2.2 Media Page
|
|
|
+#### 2.2 Media Page (Media > Shared Storage)
|
|
|
|
|
|
- [ ] Navigate to Media > Shared Storage
|
|
|
- [ ] Verify the table loads correctly (initially empty)
|
|
|
-- [ ] Upload a file through the REST API (see REST API testing)
|
|
|
-- [ ] Verify the file appears in the table
|
|
|
-- [ ] Test sorting by different columns
|
|
|
-- [ ] Test pagination (upload multiple files if needed)
|
|
|
+- [ ] Upload files through the REST API (see REST API testing section)
|
|
|
+- [ ] Verify files appear in the table with correct data:
|
|
|
+ - [ ] File ID (new `fileid` format)
|
|
|
+ - [ ] Original file name
|
|
|
+ - [ ] Description and message
|
|
|
+ - [ ] Active from/to dates
|
|
|
+ - [ ] Reference
|
|
|
+ - [ ] Upload date
|
|
|
+ - [ ] Download count
|
|
|
+ - [ ] Last download
|
|
|
+- [ ] Test sorting by different columns (click column headers)
|
|
|
+- [ ] Test pagination with multiple files
|
|
|
- [ ] Test searching by filename and reference
|
|
|
-- [ ] Test the "View Details" functionality
|
|
|
-- [ ] Test the "Edit" functionality:
|
|
|
- - [ ] Change description, message, dates, reference
|
|
|
- - [ ] Save and verify changes are applied
|
|
|
-- [ ] Test the "Delete" functionality
|
|
|
+- [ ] **Test new action buttons**:
|
|
|
+ - [ ] **Copy Permalink button** - verify it copies the correct URL to clipboard
|
|
|
+ - [ ] **Force Activate button** - verify it resets the active period from current time
|
|
|
+ - [ ] View Details button - verify modal opens with complete file information
|
|
|
+ - [ ] Edit button - verify modal allows property editing
|
|
|
+ - [ ] Delete button - verify confirmation dialog and file deletion
|
|
|
+
|
|
|
+#### 2.3 Enhanced Admin Features
|
|
|
+
|
|
|
+- [ ] Test responsive design on mobile devices
|
|
|
+- [ ] Verify modal dialogs work correctly
|
|
|
+- [ ] Test AJAX operations don't cause page refreshes
|
|
|
+- [ ] Verify loading indicators appear during operations
|
|
|
+- [ ] Test error handling in admin interface
|
|
|
|
|
|
### 3. REST API Testing
|
|
|
|
|
|
#### 3.1 Authentication
|
|
|
|
|
|
-- [ ] Attempt API requests without an API key (should fail)
|
|
|
-- [ ] Attempt API requests with an invalid API key (should fail)
|
|
|
+- [ ] Attempt API requests without an API key (should return 403)
|
|
|
+- [ ] Attempt API requests with an invalid API key (should return 403)
|
|
|
- [ ] Attempt API requests with the correct API key (should succeed)
|
|
|
-
|
|
|
-#### 3.2 File Upload
|
|
|
-
|
|
|
-- [ ] Test the complete chunked upload process:
|
|
|
- - [ ] Initialize upload
|
|
|
- - [ ] Upload chunks
|
|
|
- - [ ] Finalize upload
|
|
|
-- [ ] Verify the file is stored in the correct location
|
|
|
-- [ ] Verify the database record is created correctly
|
|
|
-- [ ] Test with various file sizes:
|
|
|
- - [ ] Small file (< 1MB)
|
|
|
- - [ ] Medium file (1-10MB)
|
|
|
- - [ ] Large file (> 10MB)
|
|
|
-- [ ] Test with different file types:
|
|
|
- - [ ] PDF
|
|
|
- - [ ] Image (JPEG, PNG)
|
|
|
- - [ ] Office document (DOCX, XLSX)
|
|
|
- - [ ] ZIP archive
|
|
|
-
|
|
|
-#### 3.3 File Management
|
|
|
-
|
|
|
-- [ ] Test retrieving file details via API
|
|
|
-- [ ] Test updating file properties via API
|
|
|
-- [ ] Test deleting a file via API
|
|
|
-- [ ] Test retrieving file collections with various query parameters:
|
|
|
- - [ ] Pagination
|
|
|
- - [ ] Sorting
|
|
|
- - [ ] Filtering
|
|
|
+- [ ] Test API key validation with various header formats
|
|
|
+
|
|
|
+#### 3.2 File Upload (Chunked)
|
|
|
+
|
|
|
+Test the complete chunked upload process:
|
|
|
+
|
|
|
+- [ ] **Initialize upload** (`POST /upload/init`):
|
|
|
+ - [ ] Valid file name and size
|
|
|
+ - [ ] Invalid parameters (missing fields)
|
|
|
+ - [ ] File size exceeding storage limit
|
|
|
+- [ ] **Upload chunks** (`POST /upload/chunk`):
|
|
|
+ - [ ] Sequential chunk upload
|
|
|
+ - [ ] Out-of-order chunk upload
|
|
|
+ - [ ] Missing chunks
|
|
|
+ - [ ] Invalid chunk data
|
|
|
+- [ ] **Finalize upload** (`POST /upload/finalize`):
|
|
|
+ - [ ] All required fields provided
|
|
|
+ - [ ] Missing required fields
|
|
|
+ - [ ] Invalid date formats
|
|
|
+ - [ ] Verify file stored in correct date-based directory structure
|
|
|
+ - [ ] Verify database record created with new `fileid` format
|
|
|
+ - [ ] Verify response includes `fileid`, `permalink`, and `shortcode`
|
|
|
+
|
|
|
+Test with various file types and sizes:
|
|
|
+- [ ] Small file (< 1MB) - should work with single chunk
|
|
|
+- [ ] Medium file (1-10MB) - test multiple chunks
|
|
|
+- [ ] Large file (> 10MB) - test many chunks
|
|
|
+- [ ] PDF documents
|
|
|
+- [ ] Image files (JPEG, PNG, GIF)
|
|
|
+- [ ] Office documents (DOCX, XLSX, PPTX)
|
|
|
+- [ ] Archive files (ZIP, RAR)
|
|
|
+- [ ] Text files
|
|
|
+- [ ] Video files (if within size limits)
|
|
|
+
|
|
|
+#### 3.3 File Management API
|
|
|
+
|
|
|
+- [ ] **Get file details** (`GET /media/{fileid}`):
|
|
|
+ - [ ] Valid file ID
|
|
|
+ - [ ] Invalid/non-existent file ID
|
|
|
+ - [ ] Verify password is not included in response
|
|
|
+- [ ] **Update file properties** (`PUT /media/{fileid}`):
|
|
|
+ - [ ] Update message
|
|
|
+ - [ ] Update active dates
|
|
|
+ - [ ] Update reference
|
|
|
+ - [ ] Update description
|
|
|
+ - [ ] Invalid date formats
|
|
|
+ - [ ] Empty update request
|
|
|
+- [ ] **Delete file** (`DELETE /media/{fileid}`):
|
|
|
+ - [ ] Valid file ID
|
|
|
+ - [ ] Invalid/non-existent file ID
|
|
|
+ - [ ] Verify file deleted from storage
|
|
|
+ - [ ] Verify database record removed
|
|
|
+- [ ] **List files** (`GET /media`):
|
|
|
+ - [ ] Default pagination
|
|
|
+ - [ ] Custom pagination parameters
|
|
|
+ - [ ] Sorting by different fields
|
|
|
+ - [ ] Filtering by filename
|
|
|
+ - [ ] Filtering by reference
|
|
|
+ - [ ] Combined filters and sorting
|
|
|
|
|
|
### 4. Public Interface Testing
|
|
|
|
|
|
-- [ ] Verify the download page exists and functions correctly
|
|
|
-- [ ] Test the download process with correct password and reference
|
|
|
-- [ ] Test the download process with incorrect password (should fail)
|
|
|
-- [ ] Test the download process with incorrect reference (should fail)
|
|
|
-- [ ] Test with expired files (should not allow download)
|
|
|
-- [ ] Test with future activation date (should not allow download)
|
|
|
-- [ ] Verify download count and last download are updated correctly
|
|
|
-
|
|
|
-### 5. Scheduled Tasks Testing
|
|
|
-
|
|
|
-- [ ] Manually trigger cron job to purge expired files
|
|
|
-- [ ] Verify expired files are deleted from storage
|
|
|
-- [ ] Verify expired records are deleted from database
|
|
|
-- [ ] Check that non-expired files are not affected
|
|
|
-
|
|
|
-### 6. Edge Cases Testing
|
|
|
-
|
|
|
-- [ ] Test with storage limit reached
|
|
|
-- [ ] Test with malformed inputs in API requests
|
|
|
-- [ ] Test with special characters in filenames, descriptions, etc.
|
|
|
-- [ ] Test with concurrent uploads
|
|
|
-- [ ] Test with extremely large files
|
|
|
-- [ ] Test with slow network connections (simulate with throttling)
|
|
|
+#### 4.1 Download Page Functionality
|
|
|
+
|
|
|
+- [ ] **Access download page** at `/shared-file-download/`
|
|
|
+- [ ] **Direct file access** via `/shared-file-download/{fileid}`
|
|
|
+- [ ] **Download form testing**:
|
|
|
+ - [ ] Correct password and reference (should allow download)
|
|
|
+ - [ ] Incorrect password (should show error)
|
|
|
+ - [ ] Incorrect reference when required (should show error)
|
|
|
+ - [ ] Missing password (should show error)
|
|
|
+ - [ ] Empty form submission
|
|
|
+- [ ] **File status testing**:
|
|
|
+ - [ ] Active file (current time between active_from and active_to)
|
|
|
+ - [ ] Expired file (current time > active_to)
|
|
|
+ - [ ] Future file (current time < active_from)
|
|
|
+- [ ] **Download process**:
|
|
|
+ - [ ] Verify correct file headers are sent
|
|
|
+ - [ ] Verify original filename is preserved
|
|
|
+ - [ ] Verify download count increments
|
|
|
+ - [ ] Verify last download time updates
|
|
|
+- [ ] **Shortcode testing**:
|
|
|
+ - [ ] `[qdr_tss_download]` - generic form
|
|
|
+ - [ ] `[qdr_tss_download id="fileid"]` - specific file form
|
|
|
+
|
|
|
+#### 4.2 URL Rewriting and Pretty URLs
|
|
|
+
|
|
|
+- [ ] Test pretty URLs: `/shared-file-download/{fileid}`
|
|
|
+- [ ] Test legacy URLs with query parameters
|
|
|
+- [ ] Test URL redirection and rewrite rules
|
|
|
+- [ ] Verify 404 handling for invalid file IDs
|
|
|
+
|
|
|
+### 5. Scheduled Tasks and Cleanup Testing
|
|
|
+
|
|
|
+- [ ] **Manual cron trigger**:
|
|
|
+ - [ ] Use admin "Purge Expired Files" button
|
|
|
+ - [ ] Verify expired files are deleted from storage
|
|
|
+ - [ ] Verify expired records are deleted from database
|
|
|
+ - [ ] Verify non-expired files are not affected
|
|
|
+- [ ] **Automatic cron job**:
|
|
|
+ - [ ] Wait for hourly cron execution or trigger manually
|
|
|
+ - [ ] Test with files having different expiration dates
|
|
|
+ - [ ] Verify empty directories are cleaned up
|
|
|
+- [ ] **Storage management**:
|
|
|
+ - [ ] Test storage limit enforcement
|
|
|
+ - [ ] Verify storage usage calculations
|
|
|
+ - [ ] Test behavior when approaching storage limit
|
|
|
+
|
|
|
+### 6. Security Testing
|
|
|
+
|
|
|
+#### 6.1 File Access Security
|
|
|
+
|
|
|
+- [ ] **Direct file access attempts**:
|
|
|
+ - [ ] Try to access files directly via URL (should be blocked)
|
|
|
+ - [ ] Verify `.htaccess` rules are working
|
|
|
+ - [ ] Test directory browsing prevention
|
|
|
+- [ ] **Download security**:
|
|
|
+ - [ ] Password protection enforcement
|
|
|
+ - [ ] Reference code validation
|
|
|
+ - [ ] Time-based access control
|
|
|
+ - [ ] CSRF protection on download forms
|
|
|
+
|
|
|
+#### 6.2 API Security
|
|
|
+
|
|
|
+- [ ] **Authentication bypass attempts**:
|
|
|
+ - [ ] Missing API key header
|
|
|
+ - [ ] Invalid API key values
|
|
|
+ - [ ] API key in wrong header format
|
|
|
+- [ ] **Input validation**:
|
|
|
+ - [ ] SQL injection attempts in API parameters
|
|
|
+ - [ ] XSS attempts in file names and descriptions
|
|
|
+ - [ ] Path traversal attempts in file operations
|
|
|
+ - [ ] Large payload attacks
|
|
|
+- [ ] **AJAX Security**:
|
|
|
+ - [ ] Nonce verification for admin AJAX requests
|
|
|
+ - [ ] Permission checks for admin operations
|
|
|
+ - [ ] Rate limiting considerations
|
|
|
+
|
|
|
+### 7. Edge Cases and Error Handling
|
|
|
+
|
|
|
+#### 7.1 File System Edge Cases
|
|
|
+
|
|
|
+- [ ] **Storage scenarios**:
|
|
|
+ - [ ] Storage limit reached during upload
|
|
|
+ - [ ] Disk space full
|
|
|
+ - [ ] Permission issues on upload directory
|
|
|
+ - [ ] Corrupted chunk uploads
|
|
|
+- [ ] **Concurrent operations**:
|
|
|
+ - [ ] Multiple simultaneous uploads
|
|
|
+ - [ ] Upload while cleanup is running
|
|
|
+ - [ ] Edit file while someone is downloading
|
|
|
+
|
|
|
+#### 7.2 Database Edge Cases
|
|
|
+
|
|
|
+- [ ] **Data integrity**:
|
|
|
+ - [ ] Database connection failures during upload
|
|
|
+ - [ ] Orphaned files (in storage but not in database)
|
|
|
+ - [ ] Orphaned records (in database but no file)
|
|
|
+ - [ ] Character encoding issues in file names
|
|
|
+
|
|
|
+#### 7.3 Network and Performance
|
|
|
+
|
|
|
+- [ ] **Network issues**:
|
|
|
+ - [ ] Interrupted chunk uploads
|
|
|
+ - [ ] Slow network connections
|
|
|
+ - [ ] Timeout scenarios
|
|
|
+- [ ] **Performance**:
|
|
|
+ - [ ] Large file uploads (test with largest possible file)
|
|
|
+ - [ ] High number of files in storage
|
|
|
+ - [ ] Database query performance with many records
|
|
|
+
|
|
|
+### 8. Internationalization Testing
|
|
|
+
|
|
|
+- [ ] **Translation testing**:
|
|
|
+ - [ ] Switch WordPress language to Czech (cs_CZ)
|
|
|
+ - [ ] Verify admin interface displays Czech translations
|
|
|
+ - [ ] Test download page in Czech
|
|
|
+ - [ ] Verify JavaScript strings are translated
|
|
|
+- [ ] **Character encoding**:
|
|
|
+ - [ ] Upload files with non-ASCII names
|
|
|
+ - [ ] Test descriptions with special characters
|
|
|
+ - [ ] Test various character sets
|
|
|
|
|
|
## Automated Testing
|
|
|
|
|
|
-To implement automated testing for this plugin, you can use the WordPress testing framework which is based on PHPUnit.
|
|
|
-
|
|
|
### Setting Up the Test Environment
|
|
|
|
|
|
-1. **Install PHPUnit**:
|
|
|
+1. **Install PHPUnit and Dependencies**:
|
|
|
```bash
|
|
|
composer require --dev phpunit/phpunit
|
|
|
+ composer require --dev brain/monkey
|
|
|
+ composer require --dev mockery/mockery
|
|
|
```
|
|
|
|
|
|
-2. **Install WordPress Test Library**:
|
|
|
+2. **WordPress Test Library Setup**:
|
|
|
```bash
|
|
|
bash bin/install-wp-tests.sh wordpress_test root '' localhost latest
|
|
|
```
|
|
|
|
|
|
-3. **Create a PHPUnit Configuration File** (`phpunit.xml`):
|
|
|
+3. **PHPUnit Configuration** (`phpunit.xml`):
|
|
|
```xml
|
|
|
<phpunit
|
|
|
bootstrap="tests/bootstrap.php"
|
|
|
@@ -133,88 +283,55 @@ To implement automated testing for this plugin, you can use the WordPress testin
|
|
|
<directory prefix="test-" suffix=".php">./tests/</directory>
|
|
|
</testsuite>
|
|
|
</testsuites>
|
|
|
+ <filter>
|
|
|
+ <whitelist>
|
|
|
+ <directory suffix=".php">./includes/</directory>
|
|
|
+ <directory suffix=".php">./admin/</directory>
|
|
|
+ <directory suffix=".php">./public/</directory>
|
|
|
+ <directory suffix=".php">./rest-api/</directory>
|
|
|
+ </whitelist>
|
|
|
+ </filter>
|
|
|
</phpunit>
|
|
|
```
|
|
|
|
|
|
-4. **Create Bootstrap File** (`tests/bootstrap.php`):
|
|
|
- ```php
|
|
|
- <?php
|
|
|
- /**
|
|
|
- * PHPUnit bootstrap file
|
|
|
- */
|
|
|
-
|
|
|
- // Require composer dependencies
|
|
|
- require_once dirname(dirname(__FILE__)) . '/vendor/autoload.php';
|
|
|
-
|
|
|
- // Load the WordPress test suite
|
|
|
- $_tests_dir = getenv('WP_TESTS_DIR');
|
|
|
- if (!$_tests_dir) {
|
|
|
- $_tests_dir = '/tmp/wordpress-tests-lib';
|
|
|
- }
|
|
|
-
|
|
|
- // Load WordPress test framework
|
|
|
- require_once $_tests_dir . '/includes/functions.php';
|
|
|
-
|
|
|
- /**
|
|
|
- * Load the plugin being tested
|
|
|
- */
|
|
|
- function _manually_load_plugin() {
|
|
|
- require dirname(dirname(__FILE__)) . '/qdr-temporary-shared-storage.php';
|
|
|
- }
|
|
|
- tests_add_filter('muplugins_loaded', '_manually_load_plugin');
|
|
|
-
|
|
|
- // Start up the WordPress test environment
|
|
|
- require $_tests_dir . '/includes/bootstrap.php';
|
|
|
- ```
|
|
|
-
|
|
|
-### Writing Test Cases
|
|
|
-
|
|
|
-#### Database Manager Tests
|
|
|
+### Unit Test Examples
|
|
|
|
|
|
-Create a file `tests/test-db-manager.php`:
|
|
|
+#### Database Manager Tests (`tests/test-db-manager.php`)
|
|
|
|
|
|
```php
|
|
|
<?php
|
|
|
-/**
|
|
|
- * Class TestDbManager
|
|
|
- *
|
|
|
- * @package QDR_Temporary_Shared_Storage
|
|
|
- */
|
|
|
-
|
|
|
class TestDbManager extends WP_UnitTestCase {
|
|
|
- /**
|
|
|
- * Setup function runs before each test
|
|
|
- */
|
|
|
- public function setUp() {
|
|
|
+ private $db_manager;
|
|
|
+
|
|
|
+ public function setUp(): void {
|
|
|
parent::setUp();
|
|
|
$this->db_manager = QDR_TSS_DB_Manager::instance();
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Test creating the database table
|
|
|
- */
|
|
|
public function test_create_table() {
|
|
|
global $wpdb;
|
|
|
|
|
|
- // Delete table if it exists
|
|
|
$table_name = $wpdb->prefix . QDR_TSS_PLUGIN_TABLE;
|
|
|
$wpdb->query("DROP TABLE IF EXISTS $table_name");
|
|
|
|
|
|
- // Create table
|
|
|
$result = $this->db_manager->create_table();
|
|
|
|
|
|
- // Check if table exists
|
|
|
$table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
|
|
|
-
|
|
|
$this->assertTrue($table_exists);
|
|
|
+
|
|
|
+ // Test table structure
|
|
|
+ $columns = $wpdb->get_results("DESCRIBE $table_name");
|
|
|
+ $column_names = wp_list_pluck($columns, 'Field');
|
|
|
+
|
|
|
+ $this->assertContains('fileid', $column_names);
|
|
|
+ $this->assertContains('original_file_name', $column_names);
|
|
|
+ $this->assertContains('active_from', $column_names);
|
|
|
+ $this->assertContains('active_to', $column_names);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Test inserting an item
|
|
|
- */
|
|
|
- public function test_insert_item() {
|
|
|
+ public function test_insert_and_get_item() {
|
|
|
$data = array(
|
|
|
- 'media_id' => 123456789,
|
|
|
+ 'fileid' => 'test123456789',
|
|
|
'original_file_name' => 'test.pdf',
|
|
|
'description' => 'Test description',
|
|
|
'message' => 'Test message',
|
|
|
@@ -227,46 +344,59 @@ class TestDbManager extends WP_UnitTestCase {
|
|
|
);
|
|
|
|
|
|
$item_id = $this->db_manager->insert_item($data);
|
|
|
-
|
|
|
$this->assertNotFalse($item_id);
|
|
|
$this->assertGreaterThan(0, $item_id);
|
|
|
|
|
|
- // Get the item and verify data
|
|
|
+ // Test get by ID
|
|
|
$item = $this->db_manager->get_item($item_id);
|
|
|
-
|
|
|
- $this->assertEquals($data['media_id'], $item->media_id);
|
|
|
+ $this->assertEquals($data['fileid'], $item->fileid);
|
|
|
$this->assertEquals($data['original_file_name'], $item->original_file_name);
|
|
|
- $this->assertEquals($data['description'], $item->description);
|
|
|
+
|
|
|
+ // Test get by fileid
|
|
|
+ $item_by_fileid = $this->db_manager->get_item_by_fileid($data['fileid']);
|
|
|
+ $this->assertEquals($item_id, $item_by_fileid->id);
|
|
|
}
|
|
|
|
|
|
- // Additional tests for update, delete, get operations...
|
|
|
+ public function test_get_items_with_pagination() {
|
|
|
+ // Insert test data
|
|
|
+ for ($i = 1; $i <= 15; $i++) {
|
|
|
+ $this->db_manager->insert_item([
|
|
|
+ 'fileid' => 'test' . $i,
|
|
|
+ 'original_file_name' => "test{$i}.pdf",
|
|
|
+ 'description' => "Test file {$i}",
|
|
|
+ 'active_from' => current_time('mysql'),
|
|
|
+ 'active_to' => date('Y-m-d H:i:s', strtotime('+30 days')),
|
|
|
+ 'password' => wp_hash_password('test'),
|
|
|
+ 'file_path' => "test/test{$i}.pdf",
|
|
|
+ 'file_size' => 1024 * $i
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test pagination
|
|
|
+ $result = $this->db_manager->get_items(['per_page' => 10, 'page' => 1]);
|
|
|
+ $this->assertEquals(10, count($result['items']));
|
|
|
+ $this->assertEquals(15, $result['total']);
|
|
|
+ $this->assertEquals(2, $result['total_pages']);
|
|
|
+
|
|
|
+ // Test second page
|
|
|
+ $result = $this->db_manager->get_items(['per_page' => 10, 'page' => 2]);
|
|
|
+ $this->assertEquals(5, count($result['items']));
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-#### File Manager Tests
|
|
|
-
|
|
|
-Create a file `tests/test-file-manager.php`:
|
|
|
+#### File Manager Tests (`tests/test-file-manager.php`)
|
|
|
|
|
|
```php
|
|
|
<?php
|
|
|
-/**
|
|
|
- * Class TestFileManager
|
|
|
- *
|
|
|
- * @package QDR_Temporary_Shared_Storage
|
|
|
- */
|
|
|
-
|
|
|
class TestFileManager extends WP_UnitTestCase {
|
|
|
- /**
|
|
|
- * Setup function runs before each test
|
|
|
- */
|
|
|
- public function setUp() {
|
|
|
+ private $file_manager;
|
|
|
+
|
|
|
+ public function setUp(): void {
|
|
|
parent::setUp();
|
|
|
$this->file_manager = QDR_TSS_File_Manager::instance();
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Test initializing the file system
|
|
|
- */
|
|
|
public function test_init_file_system() {
|
|
|
$result = $this->file_manager->init_file_system();
|
|
|
|
|
|
@@ -276,37 +406,60 @@ class TestFileManager extends WP_UnitTestCase {
|
|
|
$this->assertTrue(file_exists(QDR_TSS_UPLOADS_DIR . '.htaccess'));
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Test creating a dated directory
|
|
|
- */
|
|
|
- public function test_create_dated_directory() {
|
|
|
- $date = date('Y/m/d');
|
|
|
- $dir = $this->file_manager->create_dated_directory($date);
|
|
|
+ public function test_generate_fileid() {
|
|
|
+ $fileid1 = $this->file_manager->generate_fileid();
|
|
|
+ $fileid2 = $this->file_manager->generate_fileid();
|
|
|
|
|
|
- $this->assertTrue(file_exists($dir));
|
|
|
+ $this->assertNotEquals($fileid1, $fileid2);
|
|
|
+ $this->assertTrue(strlen($fileid1) > 40);
|
|
|
+ $this->assertMatchesRegularExpression('/^[a-zA-Z0-9]+$/', $fileid1);
|
|
|
}
|
|
|
|
|
|
- // Additional tests for chunked uploads, file deletion, etc...
|
|
|
+ public function test_chunked_upload_process() {
|
|
|
+ // Initialize upload
|
|
|
+ $upload_id = $this->file_manager->init_chunked_upload();
|
|
|
+ $this->assertNotFalse($upload_id);
|
|
|
+
|
|
|
+ // Create test chunk data
|
|
|
+ $chunk_data = 'This is test chunk data';
|
|
|
+ $temp_file = tempnam(sys_get_temp_dir(), 'test_chunk');
|
|
|
+ file_put_contents($temp_file, $chunk_data);
|
|
|
+
|
|
|
+ $file_array = [
|
|
|
+ 'tmp_name' => $temp_file,
|
|
|
+ 'name' => 'test_chunk',
|
|
|
+ 'size' => strlen($chunk_data)
|
|
|
+ ];
|
|
|
+
|
|
|
+ // Store chunk
|
|
|
+ $result = $this->file_manager->store_chunk($upload_id, 0, $file_array);
|
|
|
+ $this->assertTrue($result);
|
|
|
+
|
|
|
+ // Check all chunks (should return true for single chunk)
|
|
|
+ $all_chunks = $this->file_manager->check_all_chunks($upload_id, 1);
|
|
|
+ $this->assertTrue($all_chunks);
|
|
|
+
|
|
|
+ // Finalize upload
|
|
|
+ $final_result = $this->file_manager->finalize_chunked_upload($upload_id, 1, 'test.txt');
|
|
|
+ $this->assertIsArray($final_result);
|
|
|
+ $this->assertArrayHasKey('file_path', $final_result);
|
|
|
+ $this->assertArrayHasKey('file_size', $final_result);
|
|
|
+
|
|
|
+ // Cleanup
|
|
|
+ unlink($temp_file);
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-#### REST API Tests
|
|
|
-
|
|
|
-Create a file `tests/test-rest-api.php`:
|
|
|
+#### REST API Tests (`tests/test-rest-api.php`)
|
|
|
|
|
|
```php
|
|
|
<?php
|
|
|
-/**
|
|
|
- * Class TestRestApi
|
|
|
- *
|
|
|
- * @package QDR_Temporary_Shared_Storage
|
|
|
- */
|
|
|
-
|
|
|
class TestRestApi extends WP_UnitTestCase {
|
|
|
- /**
|
|
|
- * Setup function runs before each test
|
|
|
- */
|
|
|
- public function setUp() {
|
|
|
+ private $server;
|
|
|
+ private $api_key;
|
|
|
+
|
|
|
+ public function setUp(): void {
|
|
|
parent::setUp();
|
|
|
global $wp_rest_server;
|
|
|
$this->server = $wp_rest_server = new WP_REST_Server;
|
|
|
@@ -318,9 +471,6 @@ class TestRestApi extends WP_UnitTestCase {
|
|
|
$settings->update_setting('api_key', $this->api_key);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Test unauthorized access
|
|
|
- */
|
|
|
public function test_unauthorized_access() {
|
|
|
$request = new WP_REST_Request('GET', '/qdr-tss/v1/media');
|
|
|
$response = $this->server->dispatch($request);
|
|
|
@@ -328,9 +478,6 @@ class TestRestApi extends WP_UnitTestCase {
|
|
|
$this->assertEquals(403, $response->get_status());
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Test authorized access
|
|
|
- */
|
|
|
public function test_authorized_access() {
|
|
|
$request = new WP_REST_Request('GET', '/qdr-tss/v1/media');
|
|
|
$request->add_header('X-Api-Key', $this->api_key);
|
|
|
@@ -339,158 +486,262 @@ class TestRestApi extends WP_UnitTestCase {
|
|
|
$this->assertEquals(200, $response->get_status());
|
|
|
}
|
|
|
|
|
|
- // Additional tests for other API endpoints...
|
|
|
+ public function test_upload_init() {
|
|
|
+ $request = new WP_REST_Request('POST', '/qdr-tss/v1/upload/init');
|
|
|
+ $request->add_header('X-Api-Key', $this->api_key);
|
|
|
+ $request->set_param('original_file_name', 'test.pdf');
|
|
|
+ $request->set_param('file_size', 1024);
|
|
|
+
|
|
|
+ $response = $this->server->dispatch($request);
|
|
|
+
|
|
|
+ $this->assertEquals(200, $response->get_status());
|
|
|
+
|
|
|
+ $data = $response->get_data();
|
|
|
+ $this->assertArrayHasKey('upload_id', $data);
|
|
|
+ $this->assertArrayHasKey('status', $data);
|
|
|
+ $this->assertEquals('initialized', $data['status']);
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-### Running the Tests
|
|
|
-
|
|
|
-Run the tests using the PHPUnit command:
|
|
|
-
|
|
|
-```bash
|
|
|
-./vendor/bin/phpunit
|
|
|
-```
|
|
|
-
|
|
|
-## Integration Testing with Client Applications
|
|
|
+### Integration Testing Scripts
|
|
|
|
|
|
-To test integration with client applications, you can create simple client scripts in PHP, JavaScript, or other languages that communicate with your WordPress site's REST API.
|
|
|
-
|
|
|
-### Example PHP Client
|
|
|
+#### API Client Test Script (`tests/integration/api-client-test.php`)
|
|
|
|
|
|
```php
|
|
|
<?php
|
|
|
-// Define API credentials
|
|
|
-$api_url = 'https://your-wordpress-site.com/wp-json/qdr-tss/v1';
|
|
|
-$api_key = 'your-api-key-here';
|
|
|
+/**
|
|
|
+ * Integration test script for API client functionality
|
|
|
+ */
|
|
|
|
|
|
-// Test the API
|
|
|
-function test_api() {
|
|
|
- global $api_url, $api_key;
|
|
|
+class QDR_TSS_Integration_Test {
|
|
|
+ private $api_url;
|
|
|
+ private $api_key;
|
|
|
|
|
|
- // Test initialization
|
|
|
- $init_response = initialize_upload('test.txt', 1024);
|
|
|
- if (!isset($init_response['upload_id'])) {
|
|
|
- echo "FAIL: Initialize upload\n";
|
|
|
- return;
|
|
|
+ public function __construct($api_url, $api_key) {
|
|
|
+ $this->api_url = rtrim($api_url, '/');
|
|
|
+ $this->api_key = $api_key;
|
|
|
}
|
|
|
- echo "PASS: Initialize upload\n";
|
|
|
|
|
|
- // Test chunk upload
|
|
|
- $upload_id = $init_response['upload_id'];
|
|
|
- $chunk_response = upload_chunk($upload_id, 0, 1, 'Test content');
|
|
|
- if (!isset($chunk_response['status']) || $chunk_response['status'] !== 'chunk_uploaded') {
|
|
|
- echo "FAIL: Upload chunk\n";
|
|
|
- return;
|
|
|
+ public function run_all_tests() {
|
|
|
+ echo "Starting QDR TSS API Integration Tests\n";
|
|
|
+ echo "=====================================\n\n";
|
|
|
+
|
|
|
+ try {
|
|
|
+ $this->test_complete_upload_workflow();
|
|
|
+ $this->test_file_management();
|
|
|
+ $this->test_error_handling();
|
|
|
+
|
|
|
+ echo "\n✅ All tests passed!\n";
|
|
|
+ } catch (Exception $e) {
|
|
|
+ echo "\n❌ Test failed: " . $e->getMessage() . "\n";
|
|
|
+ }
|
|
|
}
|
|
|
- echo "PASS: Upload chunk\n";
|
|
|
|
|
|
- // Test finalize upload
|
|
|
- $finalize_response = finalize_upload($upload_id, 1, 'test.txt', 'Test description', 'test_password');
|
|
|
- if (!isset($finalize_response['media_id'])) {
|
|
|
- echo "FAIL: Finalize upload\n";
|
|
|
- return;
|
|
|
+ private function test_complete_upload_workflow() {
|
|
|
+ echo "Testing complete upload workflow...\n";
|
|
|
+
|
|
|
+ // Create test file
|
|
|
+ $test_content = "This is a test file for QDR TSS integration testing.";
|
|
|
+ $temp_file = tempnam(sys_get_temp_dir(), 'qdr_test');
|
|
|
+ file_put_contents($temp_file, $test_content);
|
|
|
+
|
|
|
+ try {
|
|
|
+ $result = $this->upload_file($temp_file, 'Integration Test File', 'test_password', 'INT_TEST_001');
|
|
|
+
|
|
|
+ echo " ✓ File uploaded successfully\n";
|
|
|
+ echo " ✓ File ID: {$result['fileid']}\n";
|
|
|
+ echo " ✓ Permalink: {$result['permalink']}\n";
|
|
|
+
|
|
|
+ // Store fileid for later tests
|
|
|
+ $this->test_fileid = $result['fileid'];
|
|
|
+
|
|
|
+ } finally {
|
|
|
+ unlink($temp_file);
|
|
|
+ }
|
|
|
}
|
|
|
- echo "PASS: Finalize upload\n";
|
|
|
|
|
|
- // Test get media
|
|
|
- $media_id = $finalize_response['media_id'];
|
|
|
- $get_response = get_media($media_id);
|
|
|
- if (!isset($get_response['media_id']) || $get_response['media_id'] != $media_id) {
|
|
|
- echo "FAIL: Get media\n";
|
|
|
- return;
|
|
|
+ private function test_file_management() {
|
|
|
+ echo "Testing file management operations...\n";
|
|
|
+
|
|
|
+ if (!isset($this->test_fileid)) {
|
|
|
+ throw new Exception("No test file ID available");
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test get file details
|
|
|
+ $details = $this->get_file_details($this->test_fileid);
|
|
|
+ echo " ✓ Retrieved file details\n";
|
|
|
+
|
|
|
+ // Test update file
|
|
|
+ $updated = $this->update_file($this->test_fileid, [
|
|
|
+ 'message' => 'Updated via integration test'
|
|
|
+ ]);
|
|
|
+ echo " ✓ Updated file properties\n";
|
|
|
+
|
|
|
+ // Test delete file
|
|
|
+ $this->delete_file($this->test_fileid);
|
|
|
+ echo " ✓ Deleted file\n";
|
|
|
}
|
|
|
- echo "PASS: Get media\n";
|
|
|
|
|
|
- // Test update media
|
|
|
- $update_response = update_media($media_id, ['message' => 'Updated message']);
|
|
|
- if (!isset($update_response['message']) || $update_response['message'] !== 'Updated message') {
|
|
|
- echo "FAIL: Update media\n";
|
|
|
- return;
|
|
|
+ private function test_error_handling() {
|
|
|
+ echo "Testing error handling...\n";
|
|
|
+
|
|
|
+ // Test with invalid API key
|
|
|
+ $old_key = $this->api_key;
|
|
|
+ $this->api_key = 'invalid_key';
|
|
|
+
|
|
|
+ try {
|
|
|
+ $this->get_file_list();
|
|
|
+ throw new Exception("Should have failed with invalid API key");
|
|
|
+ } catch (Exception $e) {
|
|
|
+ if (strpos($e->getMessage(), '403') !== false) {
|
|
|
+ echo " ✓ Invalid API key properly rejected\n";
|
|
|
+ } else {
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->api_key = $old_key;
|
|
|
+
|
|
|
+ // Test with non-existent file
|
|
|
+ try {
|
|
|
+ $this->get_file_details('nonexistent123');
|
|
|
+ throw new Exception("Should have failed with non-existent file");
|
|
|
+ } catch (Exception $e) {
|
|
|
+ if (strpos($e->getMessage(), '404') !== false) {
|
|
|
+ echo " ✓ Non-existent file properly handled\n";
|
|
|
+ } else {
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- echo "PASS: Update media\n";
|
|
|
|
|
|
- // Test delete media
|
|
|
- $delete_response = delete_media($media_id);
|
|
|
- if (!isset($delete_response['deleted']) || $delete_response['deleted'] !== true) {
|
|
|
- echo "FAIL: Delete media\n";
|
|
|
- return;
|
|
|
+ // API helper methods...
|
|
|
+ private function upload_file($file_path, $description, $password, $reference) {
|
|
|
+ // Implementation similar to previous examples
|
|
|
+ // ... (chunked upload implementation)
|
|
|
}
|
|
|
- echo "PASS: Delete media\n";
|
|
|
|
|
|
- echo "All tests passed!\n";
|
|
|
-}
|
|
|
-
|
|
|
-// API helper functions
|
|
|
-function initialize_upload($filename, $filesize) {
|
|
|
- global $api_url, $api_key;
|
|
|
+ private function get_file_details($fileid) {
|
|
|
+ // ... (implementation)
|
|
|
+ }
|
|
|
|
|
|
- $ch = curl_init("$api_url/upload/init");
|
|
|
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
|
- curl_setopt($ch, CURLOPT_POST, true);
|
|
|
- curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
|
- "X-Api-Key: $api_key",
|
|
|
- 'Content-Type: application/json'
|
|
|
- ]);
|
|
|
- curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
|
|
- 'original_file_name' => $filename,
|
|
|
- 'file_size' => $filesize
|
|
|
- ]));
|
|
|
+ private function update_file($fileid, $data) {
|
|
|
+ // ... (implementation)
|
|
|
+ }
|
|
|
|
|
|
- $response = curl_exec($ch);
|
|
|
- curl_close($ch);
|
|
|
+ private function delete_file($fileid) {
|
|
|
+ // ... (implementation)
|
|
|
+ }
|
|
|
|
|
|
- return json_decode($response, true);
|
|
|
+ private function get_file_list() {
|
|
|
+ // ... (implementation)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-// Implement other API helper functions...
|
|
|
-
|
|
|
// Run tests
|
|
|
-test_api();
|
|
|
+$tester = new QDR_TSS_Integration_Test(
|
|
|
+ 'https://your-test-site.com/wp-json/qdr-tss/v1',
|
|
|
+ 'your-test-api-key'
|
|
|
+);
|
|
|
+
|
|
|
+$tester->run_all_tests();
|
|
|
```
|
|
|
|
|
|
## Performance Testing
|
|
|
|
|
|
-To test the performance of the plugin, especially with large files and under high load, you can use tools like Apache JMeter or a simple script to simulate multiple concurrent uploads.
|
|
|
+### Load Testing Script
|
|
|
+
|
|
|
+```bash
|
|
|
+#!/bin/bash
|
|
|
+# Simple load test for file uploads
|
|
|
+
|
|
|
+API_URL="https://your-test-site.com/wp-json/qdr-tss/v1"
|
|
|
+API_KEY="your-test-api-key"
|
|
|
+CONCURRENT_UPLOADS=5
|
|
|
+TEST_FILE_SIZE=1048576 # 1MB
|
|
|
+
|
|
|
+echo "Starting load test with $CONCURRENT_UPLOADS concurrent uploads"
|
|
|
+
|
|
|
+for i in $(seq 1 $CONCURRENT_UPLOADS); do
|
|
|
+ (
|
|
|
+ # Create test file
|
|
|
+ dd if=/dev/zero of="test_file_$i.bin" bs=$TEST_FILE_SIZE count=1 2>/dev/null
|
|
|
+
|
|
|
+ # Upload file
|
|
|
+ echo "Starting upload $i"
|
|
|
+ start_time=$(date +%s)
|
|
|
+
|
|
|
+ # Your upload implementation here
|
|
|
+ # ...
|
|
|
+
|
|
|
+ end_time=$(date +%s)
|
|
|
+ duration=$((end_time - start_time))
|
|
|
+
|
|
|
+ echo "Upload $i completed in ${duration}s"
|
|
|
+
|
|
|
+ # Cleanup
|
|
|
+ rm "test_file_$i.bin"
|
|
|
+ ) &
|
|
|
+done
|
|
|
+
|
|
|
+wait
|
|
|
+echo "All uploads completed"
|
|
|
+```
|
|
|
+
|
|
|
+## Browser Testing Checklist
|
|
|
+
|
|
|
+### Admin Interface Browser Testing
|
|
|
|
|
|
-### Test Scenarios
|
|
|
+Test the admin interface across different browsers:
|
|
|
|
|
|
-1. **Large File Upload**: Test uploading a very large file (1GB+) and measure:
|
|
|
- - Total upload time
|
|
|
- - Memory usage
|
|
|
- - CPU usage
|
|
|
+- [ ] **Chrome (latest)**
|
|
|
+- [ ] **Firefox (latest)**
|
|
|
+- [ ] **Safari (latest)**
|
|
|
+- [ ] **Edge (latest)**
|
|
|
+- [ ] **Mobile Chrome**
|
|
|
+- [ ] **Mobile Safari**
|
|
|
|
|
|
-2. **Concurrent Uploads**: Test multiple clients uploading files simultaneously and measure:
|
|
|
- - Success rate
|
|
|
- - Average upload time
|
|
|
- - Server resource usage
|
|
|
+For each browser, test:
|
|
|
+- [ ] Media page layout and functionality
|
|
|
+- [ ] Settings page functionality
|
|
|
+- [ ] Modal dialogs
|
|
|
+- [ ] Action buttons (Copy Permalink, Force Activate)
|
|
|
+- [ ] AJAX operations
|
|
|
+- [ ] JavaScript error console (should be clean)
|
|
|
|
|
|
-3. **Storage Limit Testing**: Test behavior when approaching and exceeding storage limits.
|
|
|
+## Final Testing Checklist
|
|
|
|
|
|
-## Security Testing
|
|
|
+Before deploying to production:
|
|
|
|
|
|
-### Checklist
|
|
|
+- [ ] All manual tests pass
|
|
|
+- [ ] Unit tests pass (`./vendor/bin/phpunit`)
|
|
|
+- [ ] Integration tests pass
|
|
|
+- [ ] Security tests pass
|
|
|
+- [ ] Performance is acceptable
|
|
|
+- [ ] Documentation is updated
|
|
|
+- [ ] Translation files are current
|
|
|
+- [ ] Browser compatibility verified
|
|
|
+- [ ] Mobile responsiveness tested
|
|
|
+- [ ] Error logging reviewed
|
|
|
+- [ ] Backup and restore procedures tested
|
|
|
|
|
|
-1. **API Authentication**:
|
|
|
- - [ ] Test API requests with missing API key
|
|
|
- - [ ] Test API requests with invalid API key
|
|
|
- - [ ] Test API requests with valid API key
|
|
|
+## Troubleshooting Common Issues
|
|
|
|
|
|
-2. **File Access**:
|
|
|
- - [ ] Verify direct access to uploaded files is blocked
|
|
|
- - [ ] Verify download requires valid password
|
|
|
- - [ ] Verify download respects active dates
|
|
|
+### Database Issues
|
|
|
+- **Problem**: Table not created during activation
|
|
|
+- **Solution**: Check database user permissions, verify WordPress table prefix
|
|
|
|
|
|
-3. **Input Validation**:
|
|
|
- - [ ] Test with malformed JSON requests
|
|
|
- - [ ] Test with malicious file uploads
|
|
|
- - [ ] Test SQL injection attempts
|
|
|
- - [ ] Test XSS attempts in file names and descriptions
|
|
|
+### File Upload Issues
|
|
|
+- **Problem**: Chunks not uploading
|
|
|
+- **Solution**: Check file permissions, PHP memory limits, server timeout settings
|
|
|
|
|
|
-4. **File Operations**:
|
|
|
- - [ ] Test upload paths for directory traversal
|
|
|
- - [ ] Test file type restrictions
|
|
|
- - [ ] Test file size limits
|
|
|
+### API Issues
|
|
|
+- **Problem**: 403 errors with valid API key
|
|
|
+- **Solution**: Verify header format, check for mod_security rules, test with different HTTP clients
|
|
|
|
|
|
-## Conclusion
|
|
|
+### Download Issues
|
|
|
+- **Problem**: Files not downloading
|
|
|
+- **Solution**: Check file permissions, verify .htaccess rules, test rewrite rules
|
|
|
|
|
|
-This comprehensive testing approach will help ensure that the refactored QDR Temporary Shared Storage plugin works correctly across all components and integrates properly with WordPress and client applications. By following this guide, you can identify and fix any issues before deploying the plugin to production environments.
|
|
|
+This comprehensive testing approach ensures the plugin works reliably across all components and integrates properly with WordPress and client applications.
|