181 lines
4.5 KiB
Go
181 lines
4.5 KiB
Go
package download_test
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"radiantwavetech.com/radiantwave/internal/db"
|
|
"radiantwavetech.com/radiantwave/internal/download"
|
|
)
|
|
|
|
func md5Hex(data []byte) string {
|
|
return fmt.Sprintf("%x", md5.Sum(data))
|
|
}
|
|
|
|
// TestDownloadFileHashChanged verifies that when the server manifest reports a
|
|
// new MD5 for an existing local file, the old file is removed, the new version
|
|
// is downloaded, and the database record is updated with the new hash.
|
|
func TestDownloadFileHashChanged(t *testing.T) {
|
|
audioDir := t.TempDir()
|
|
dbDir := t.TempDir()
|
|
|
|
gdb, err := gorm.Open(sqlite.Open(filepath.Join(dbDir, "test.db")), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB, err := gdb.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB.SetMaxOpenConns(1)
|
|
sqlDB.SetMaxIdleConns(1)
|
|
|
|
if err := gdb.AutoMigrate(&db.AudioTrack{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
oldContent := []byte("this is the OLD version of the audio file")
|
|
oldMD5 := md5Hex(oldContent)
|
|
newContent := []byte("this is the NEW version of the audio file")
|
|
newMD5 := md5Hex(newContent)
|
|
|
|
track := db.AudioTrack{
|
|
Filename: "174Hz.wav",
|
|
Name: "174 Hz",
|
|
AssignedFrequency: 174,
|
|
MD5: oldMD5,
|
|
Selected: true,
|
|
Order: 2,
|
|
}
|
|
if err := gdb.Create(&track).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
oldPath := filepath.Join(audioDir, "174Hz.wav")
|
|
if err := os.WriteFile(oldPath, oldContent, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.URL.Path {
|
|
case "/checksums.md5":
|
|
w.WriteHeader(http.StatusOK)
|
|
fmt.Fprintf(w, "%s 174Hz.wav\n", newMD5)
|
|
case "/174Hz.wav":
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(newContent)
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
|
|
progress := make(chan download.DownloadStatus, 100)
|
|
done := make(chan struct{})
|
|
go func() {
|
|
download.DownloadAudioFiles(progress, gdb, audioDir, server.URL+"/")
|
|
close(done)
|
|
}()
|
|
for range progress {
|
|
}
|
|
<-done
|
|
|
|
newPath := filepath.Join(audioDir, "174Hz.wav")
|
|
gotContent, err := os.ReadFile(newPath)
|
|
if err != nil {
|
|
t.Fatalf("reading new file: %v", err)
|
|
}
|
|
if string(gotContent) != string(newContent) {
|
|
t.Errorf("new file content = %q, want %q", string(gotContent), string(newContent))
|
|
}
|
|
|
|
var updated db.AudioTrack
|
|
if err := gdb.First(&updated, track.ID).Error; err != nil {
|
|
t.Fatalf("fetching updated track: %v", err)
|
|
}
|
|
if updated.MD5 != newMD5 {
|
|
t.Errorf("DB MD5 = %q, want %q", updated.MD5, newMD5)
|
|
}
|
|
}
|
|
|
|
// TestDownloadOrphanRemoval verifies that files and DB records not in the
|
|
// manifest are removed.
|
|
func TestDownloadOrphanRemoval(t *testing.T) {
|
|
audioDir := t.TempDir()
|
|
dbDir := t.TempDir()
|
|
|
|
gdb, err := gorm.Open(sqlite.Open(filepath.Join(dbDir, "test.db")), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB, err := gdb.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB.SetMaxOpenConns(1)
|
|
sqlDB.SetMaxIdleConns(1)
|
|
|
|
if err := gdb.AutoMigrate(&db.AudioTrack{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
orphanPath := filepath.Join(audioDir, "orphan.wav")
|
|
if err := os.WriteFile(orphanPath, []byte("orphan"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
gdb.Create(&db.AudioTrack{Filename: "ghost.wav", Name: "Ghost Track", Order: 99})
|
|
|
|
keptContent := []byte("kept file")
|
|
keptMD5 := md5Hex(keptContent)
|
|
keptPath := filepath.Join(audioDir, "kept.wav")
|
|
if err := os.WriteFile(keptPath, keptContent, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.URL.Path {
|
|
case "/checksums.md5":
|
|
w.WriteHeader(http.StatusOK)
|
|
fmt.Fprintf(w, "%s kept.wav\n", keptMD5)
|
|
case "/kept.wav":
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(keptContent)
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
|
|
progress := make(chan download.DownloadStatus, 100)
|
|
done := make(chan struct{})
|
|
go func() {
|
|
download.DownloadAudioFiles(progress, gdb, audioDir, server.URL+"/")
|
|
close(done)
|
|
}()
|
|
for range progress {
|
|
}
|
|
<-done
|
|
|
|
if _, err := os.Stat(orphanPath); !os.IsNotExist(err) {
|
|
t.Errorf("orphan file %s should have been removed", orphanPath)
|
|
}
|
|
|
|
var count int64
|
|
gdb.Model(&db.AudioTrack{}).Where("filename = ?", "ghost.wav").Count(&count)
|
|
if count != 0 {
|
|
t.Errorf("orphan DB record ghost.wav should have been deleted, count=%d", count)
|
|
}
|
|
|
|
if _, err := os.Stat(keptPath); os.IsNotExist(err) {
|
|
t.Errorf("kept file %s should still exist after download", keptPath)
|
|
}
|
|
}
|