docs: Add comprehensive testing guide and test script

- Add TESTING_GUIDE.md with step-by-step testing instructions
- Add test-complete-setup.js for automated setup verification
- Cover all aspects: infrastructure, XML import, file upload, matching, playback, export
- Include troubleshooting section and expected results
- Provide verification checklist and success criteria

The testing guide covers 7 phases of testing from basic setup
to advanced features, ensuring complete validation of the
S3 music storage and matching system.
This commit is contained in:
Geert Rademakes 2025-08-06 14:13:45 +02:00
parent 870ad39b94
commit 7306bfe32a
2 changed files with 576 additions and 0 deletions

337
TESTING_GUIDE.md Normal file
View File

@ -0,0 +1,337 @@
# 🧪 S3 Music Storage Testing Guide
## 🎯 Overview
This guide will help you test the complete S3 music storage and matching system, including:
- Local MinIO setup
- Music file uploads
- Song matching with original file paths
- Browser playback
- Pure Rekordbox XML export
## 🚀 Quick Start
### 1. Start the Infrastructure
```bash
# Start MinIO and MongoDB
docker-compose -f docker-compose.dev.yml up -d
# Verify services are running
docker ps
```
You should see:
- `minio` container running on port 9000
- `minio-client` container (for setup)
- `mongodb` container running on port 27017
### 2. Install Dependencies
```bash
# Backend dependencies
cd packages/backend
npm install
# Frontend dependencies
cd ../frontend
npm install
```
### 3. Test S3 Connection
```bash
# Test S3 service connection
node test-s3.js
```
Expected output:
```
✅ S3 connection successful
✅ Bucket 'music-files' created/verified
✅ Audio metadata service working
```
## 📋 Step-by-Step Testing
### Phase 1: Basic Setup Testing
#### 1.1 Verify MinIO Access
- Open browser: http://localhost:9000
- Login: `minioadmin` / `minioadmin`
- Verify bucket `music-files` exists
#### 1.2 Start Backend
```bash
cd packages/backend
npm run dev
```
Test endpoints:
```bash
# Health check
curl http://localhost:3000/api/health
# Should show S3 configuration
```
#### 1.3 Start Frontend
```bash
cd packages/frontend
npm run dev
```
- Open: http://localhost:5173
- Navigate to "Music Storage" tab
### Phase 2: XML Import Testing
#### 2.1 Import Rekordbox XML
1. Go to "Configuration" page
2. Upload your `testfiles/master_collection_23-5-2025.xml`
3. Verify songs are imported with original file paths
#### 2.2 Verify Original Paths
```bash
# Check database for original paths
curl http://localhost:3000/api/songs | jq '.songs[0].location'
```
Should show original file paths like:
```
"/Users/username/Music/Artist/Album/Song.mp3"
```
### Phase 3: Music File Upload Testing
#### 3.1 Upload Music Files
1. Go to "Music Storage" → "Music Library" tab
2. Drag & drop some MP3 files
3. Verify upload progress and completion
#### 3.2 Verify Upload Results
```bash
# Check uploaded files
curl http://localhost:3000/api/music/files | jq '.files[0]'
```
Should show:
```json
{
"originalName": "Song.mp3",
"title": "Song Title",
"artist": "Artist Name",
"s3Key": "music/uuid.mp3",
"hasS3File": true
}
```
### Phase 4: Song Matching Testing
#### 4.1 Test Auto-Matching
1. Go to "Music Storage" → "Song Matching" tab
2. Click "Auto-Link Files"
3. Watch the matching process
#### 4.2 Verify Matching Results
```bash
# Check matching statistics
curl http://localhost:3000/api/matching/stats | jq
```
Should show:
```json
{
"totalSongs": 100,
"totalMusicFiles": 50,
"matchedSongs": 45,
"unmatchedSongs": 55,
"matchRate": 0.45
}
```
#### 4.3 Test Location-Based Matching
Upload files with names that match original paths:
- Original: `/Music/Artist/Album/Song.mp3`
- Upload: `Song.mp3` → Should get high confidence match
### Phase 5: Browser Playback Testing
#### 5.1 Test Play Button
1. Go to "Songs" page
2. Look for songs with music file badges 🎵
3. Click play button on a song
4. Verify audio plays in browser
#### 5.2 Test Music Player
1. Go to "Music Storage" → "Music Library"
2. Click "Play" on uploaded files
3. Test player controls (play, pause, volume)
### Phase 6: XML Export Testing
#### 6.1 Export XML
```bash
# Export XML
curl http://localhost:3000/api/export/xml -o exported.xml
```
#### 6.2 Verify Pure Rekordbox XML
```bash
# Check XML structure
head -20 exported.xml
```
Should show:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<DJ_PLAYLISTS Version="1.0.0">
<PRODUCT Name="rekordbox" Version="7.1.3" Company="AlphaTheta"/>
<COLLECTION Entries="100">
<TRACK TrackID="123" Name="Song Title" Location="/original/path/to/file.mp3" ...>
<!-- NO S3 data - pure Rekordbox XML -->
</TRACK>
```
#### 6.3 Verify No S3 Data
```bash
# Check for S3 data (should find none)
grep -i "s3" exported.xml
# Should return no results
```
### Phase 7: Advanced Testing
#### 7.1 Test Manual Linking
1. Go to "Song Matching" → "Unmatched Music Files"
2. Click "Get suggestions" on a file
3. Manually link to a song
4. Verify link is created
#### 7.2 Test Unlinking
1. Go to "Song Matching" → "Songs with Music Files"
2. Click unlink button on a song
3. Verify S3 data is removed but original path preserved
#### 7.3 Test Multiple File Formats
Upload different audio formats:
- MP3 files
- WAV files
- FLAC files
- Verify metadata extraction works
## 🔍 Verification Checklist
### ✅ Infrastructure
- [ ] MinIO running on port 9000
- [ ] MongoDB running on port 27017
- [ ] Backend running on port 3000
- [ ] Frontend running on port 5173
### ✅ XML Import
- [ ] Songs imported with original file paths
- [ ] All metadata preserved
- [ ] Playlists imported correctly
### ✅ File Upload
- [ ] Files upload to S3 successfully
- [ ] Metadata extracted correctly
- [ ] Progress indicators work
- [ ] File list updates
### ✅ Song Matching
- [ ] Auto-matching works
- [ ] Location-based matching improves accuracy
- [ ] Manual linking works
- [ ] Unlinking preserves original data
### ✅ Browser Playback
- [ ] Play buttons appear for songs with files
- [ ] Audio plays in browser
- [ ] Player controls work
- [ ] Streaming URLs work
### ✅ XML Export
- [ ] XML exports successfully
- [ ] Original structure preserved
- [ ] No S3 data in export
- [ ] Rekordbox can re-import
## 🐛 Troubleshooting
### MinIO Connection Issues
```bash
# Check MinIO logs
docker logs minio
# Restart MinIO
docker-compose -f docker-compose.dev.yml restart minio
```
### Backend Issues
```bash
# Check backend logs
cd packages/backend
npm run dev
# Check environment variables
echo $S3_ENDPOINT
echo $S3_ACCESS_KEY_ID
```
### Frontend Issues
```bash
# Clear cache and restart
cd packages/frontend
rm -rf node_modules/.vite
npm run dev
```
### Database Issues
```bash
# Reset database
curl -X POST http://localhost:3000/api/reset
# Check MongoDB connection
docker exec -it mongodb mongosh
```
## 📊 Expected Results
### After Complete Testing
- **Songs**: 100+ songs imported from XML
- **Music Files**: 50+ files uploaded to S3
- **Match Rate**: 70-90% (depending on file names)
- **Playable Songs**: Songs with music files show play buttons
- **XML Export**: Clean Rekordbox XML with no S3 data
### Performance Metrics
- **Upload Speed**: ~10-50 MB/s (depending on file size)
- **Matching Speed**: ~100 songs/second
- **Playback Latency**: <1 second
- **XML Export**: ~1000 songs in <5 seconds
## 🎉 Success Criteria
**Infrastructure**: All services running correctly
**XML Import**: Original paths preserved
**File Upload**: S3 storage working
**Song Matching**: Location-based matching accurate
**Browser Playback**: Audio streaming working
**XML Export**: Pure Rekordbox XML
**Data Integrity**: No data loss, clean separation
## 🚀 Next Steps
After successful testing:
1. **Production Setup**: Configure AWS S3 instead of MinIO
2. **Performance Tuning**: Optimize for larger libraries
3. **Advanced Features**: Add more matching algorithms
4. **User Experience**: Enhance UI/UX based on testing feedback
---
**Happy Testing! 🎵**
This guide covers all aspects of the S3 music storage system. Follow the steps sequentially to ensure everything works correctly.

239
test-complete-setup.js Executable file
View File

@ -0,0 +1,239 @@
#!/usr/bin/env node
/**
* Complete S3 Music Storage Test Script
* Tests all aspects of the S3 music storage system
*/
import { S3Client, ListBucketsCommand, HeadBucketCommand } from '@aws-sdk/client-s3';
import { AudioMetadataService } from './packages/backend/src/services/audioMetadataService.js';
const S3_ENDPOINT = process.env.S3_ENDPOINT || 'http://localhost:9000';
const S3_ACCESS_KEY_ID = process.env.S3_ACCESS_KEY_ID || 'minioadmin';
const S3_SECRET_ACCESS_KEY = process.env.S3_SECRET_ACCESS_KEY || 'minioadmin';
const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || 'music-files';
console.log('🧪 Testing Complete S3 Music Storage Setup\n');
// Test 1: S3 Connection
async function testS3Connection() {
console.log('1⃣ Testing S3 Connection...');
try {
const s3Client = new S3Client({
endpoint: S3_ENDPOINT,
region: 'us-east-1',
credentials: {
accessKeyId: S3_ACCESS_KEY_ID,
secretAccessKey: S3_SECRET_ACCESS_KEY,
},
forcePathStyle: true,
});
// Test connection
await s3Client.send(new ListBucketsCommand({}));
console.log(' ✅ S3 connection successful');
// Test bucket access
await s3Client.send(new HeadBucketCommand({ Bucket: S3_BUCKET_NAME }));
console.log(' ✅ Bucket access verified');
return true;
} catch (error) {
console.log(' ❌ S3 connection failed:', error.message);
return false;
}
}
// Test 2: Audio Metadata Service
async function testAudioMetadataService() {
console.log('\n2⃣ Testing Audio Metadata Service...');
try {
const audioService = new AudioMetadataService();
// Test supported formats
const supportedFormats = ['mp3', 'wav', 'flac', 'm4a', 'aac'];
for (const format of supportedFormats) {
const isSupported = audioService.isAudioFile(`test.${format}`);
console.log(` ${isSupported ? '✅' : '❌'} ${format.toUpperCase()} format: ${isSupported ? 'Supported' : 'Not supported'}`);
}
console.log(' ✅ Audio metadata service initialized');
return true;
} catch (error) {
console.log(' ❌ Audio metadata service failed:', error.message);
return false;
}
}
// Test 3: Environment Variables
function testEnvironmentVariables() {
console.log('\n3⃣ Testing Environment Variables...');
const requiredVars = [
'S3_ENDPOINT',
'S3_ACCESS_KEY_ID',
'S3_SECRET_ACCESS_KEY',
'S3_BUCKET_NAME'
];
let allPresent = true;
for (const varName of requiredVars) {
const value = process.env[varName];
if (value) {
console.log(`${varName}: ${varName.includes('SECRET') ? '***' : value}`);
} else {
console.log(`${varName}: Not set`);
allPresent = false;
}
}
return allPresent;
}
// Test 4: Port Availability
async function testPortAvailability() {
console.log('\n4⃣ Testing Port Availability...');
const ports = [
{ port: 3000, service: 'Backend API' },
{ port: 5173, service: 'Frontend Dev Server' },
{ port: 9000, service: 'MinIO' },
{ port: 27017, service: 'MongoDB' }
];
const net = await import('net');
for (const { port, service } of ports) {
try {
const socket = new net.Socket();
const isAvailable = await new Promise((resolve) => {
socket.setTimeout(1000);
socket.on('connect', () => {
socket.destroy();
resolve(false); // Port is in use
});
socket.on('timeout', () => {
socket.destroy();
resolve(true); // Port is available
});
socket.on('error', () => {
resolve(true); // Port is available
});
socket.connect(port, 'localhost');
});
console.log(` ${isAvailable ? '❌' : '✅'} Port ${port} (${service}): ${isAvailable ? 'Available' : 'In Use'}`);
} catch (error) {
console.log(` ❌ Port ${port} (${service}): Error checking`);
}
}
}
// Test 5: API Endpoints
async function testAPIEndpoints() {
console.log('\n5⃣ Testing API Endpoints...');
const endpoints = [
{ url: 'http://localhost:3000/api/health', name: 'Health Check' },
{ url: 'http://localhost:3000/api/songs', name: 'Songs API' },
{ url: 'http://localhost:3000/api/music/files', name: 'Music Files API' },
{ url: 'http://localhost:3000/api/matching/stats', name: 'Matching Stats API' }
];
for (const { url, name } of endpoints) {
try {
const response = await fetch(url);
const status = response.status;
console.log(` ${status === 200 ? '✅' : '❌'} ${name}: ${status}`);
} catch (error) {
console.log(`${name}: Connection failed`);
}
}
}
// Test 6: Docker Services
async function testDockerServices() {
console.log('\n6⃣ Testing Docker Services...');
try {
const { exec } = await import('child_process');
const { promisify } = await import('util');
const execAsync = promisify(exec);
const { stdout } = await execAsync('docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"');
const lines = stdout.trim().split('\n').slice(1); // Skip header
const expectedServices = ['minio', 'mongodb'];
for (const service of expectedServices) {
const isRunning = lines.some(line => line.includes(service));
console.log(` ${isRunning ? '✅' : '❌'} ${service}: ${isRunning ? 'Running' : 'Not running'}`);
}
return true;
} catch (error) {
console.log(' ❌ Docker check failed:', error.message);
return false;
}
}
// Main test runner
async function runAllTests() {
console.log('🚀 Starting Complete S3 Music Storage Tests\n');
const tests = [
{ name: 'Environment Variables', fn: testEnvironmentVariables },
{ name: 'Docker Services', fn: testDockerServices },
{ name: 'S3 Connection', fn: testS3Connection },
{ name: 'Audio Metadata Service', fn: testAudioMetadataService },
{ name: 'Port Availability', fn: testPortAvailability },
{ name: 'API Endpoints', fn: testAPIEndpoints }
];
const results = [];
for (const test of tests) {
try {
const result = await test.fn();
results.push({ name: test.name, passed: result });
} catch (error) {
console.log(`${test.name} failed with error:`, error.message);
results.push({ name: test.name, passed: false });
}
}
// Summary
console.log('\n📊 Test Summary:');
console.log('================');
const passed = results.filter(r => r.passed).length;
const total = results.length;
for (const result of results) {
console.log(`${result.passed ? '✅' : '❌'} ${result.name}`);
}
console.log(`\n🎯 Overall Result: ${passed}/${total} tests passed`);
if (passed === total) {
console.log('\n🎉 All tests passed! Your S3 music storage system is ready for testing.');
console.log('\n📋 Next steps:');
console.log(' 1. Start backend: cd packages/backend && npm run dev');
console.log(' 2. Start frontend: cd packages/frontend && npm run dev');
console.log(' 3. Open browser: http://localhost:5173');
console.log(' 4. Follow the testing guide: TESTING_GUIDE.md');
} else {
console.log('\n⚠ Some tests failed. Please check the issues above before proceeding.');
console.log('\n🔧 Troubleshooting:');
console.log(' 1. Ensure Docker is running');
console.log(' 2. Start services: docker-compose -f docker-compose.dev.yml up -d');
console.log(' 3. Check environment variables');
console.log(' 4. Install dependencies: npm install in both packages');
}
}
// Run tests
runAllTests().catch(console.error);