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:
parent
870ad39b94
commit
7306bfe32a
337
TESTING_GUIDE.md
Normal file
337
TESTING_GUIDE.md
Normal 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
239
test-complete-setup.js
Executable 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);
|
||||
Loading…
x
Reference in New Issue
Block a user