132 lines
4.2 KiB
Go
132 lines
4.2 KiB
Go
package ws
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"everypublish/server/internal/config"
|
|
"everypublish/server/internal/models"
|
|
"everypublish/server/internal/platform"
|
|
"everypublish/server/internal/task"
|
|
|
|
gormsqlite "gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type testPlatformAdapter struct {
|
|
mu sync.Mutex
|
|
called int
|
|
block bool
|
|
canceled chan struct{}
|
|
}
|
|
|
|
func (a *testPlatformAdapter) Platform() string { return "test-platform" }
|
|
func (a *testPlatformAdapter) BeginLogin(context.Context) (platform.LoginSession, error) {
|
|
return platform.LoginSession{}, nil
|
|
}
|
|
func (a *testPlatformAdapter) PollLogin(context.Context, string) (platform.LoginPoll, error) {
|
|
return platform.LoginPoll{}, nil
|
|
}
|
|
func (a *testPlatformAdapter) SaveCredentials(uint64, uint64, string) error { return nil }
|
|
func (a *testPlatformAdapter) Publish(ctx context.Context, in platform.PublishInput) (platform.PublishResult, error) {
|
|
a.mu.Lock()
|
|
a.called++
|
|
a.mu.Unlock()
|
|
if a.block {
|
|
select {
|
|
case <-ctx.Done():
|
|
close(a.canceled)
|
|
return platform.PublishResult{}, ctx.Err()
|
|
case <-time.After(2 * time.Second):
|
|
}
|
|
}
|
|
return platform.PublishResult{URL: "https://example.test/task/" + in.Title, Receipt: "receipt"}, nil
|
|
}
|
|
|
|
func platformTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
db, err := gorm.Open(gormsqlite.Open(filepath.Join(t.TempDir(), "dispatcher.db")), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = db.AutoMigrate(&models.Task{}, &models.TaskEvent{}, &models.Account{}, &models.Material{}, &models.TransferToken{}, &models.Notification{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func TestDispatcherUsesRegisteredPlatformAndPublishesPerAccount(t *testing.T) {
|
|
db := platformTestDB(t)
|
|
account := models.Account{WorkspaceID: 1, Platform: "test-platform", Status: "active"}
|
|
material := models.Material{WorkspaceID: 1, Name: "video.mp4", Status: "ready", StorageKey: "1/video.mp4"}
|
|
if err := db.Create(&account).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.Create(&material).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
row := models.Task{WorkspaceID: 1, Title: "platform", Status: task.Queued, AccountIDs: "[1]", MaterialIDs: "[1]"}
|
|
if err := db.Create(&row).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
adapter := &testPlatformAdapter{}
|
|
registry := platform.NewRegistry()
|
|
if err := registry.Register(adapter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d := NewDispatcher(db, NewHub(), &config.Config{ExecutorMode: "web", BaseURL: "http://127.0.0.1:8090"})
|
|
d.Registry = registry
|
|
if !d.TryDispatch(row.ID) {
|
|
t.Fatal("registered adapter should accept queued task")
|
|
}
|
|
deadline := time.Now().Add(2 * time.Second)
|
|
for time.Now().Before(deadline) {
|
|
var got models.Task
|
|
if err := db.First(&got, row.ID).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Status == task.Success {
|
|
if got.PublishedURLs != `["https://example.test/task/platform"]` || got.Receipts != `["receipt"]` {
|
|
t.Fatalf("unexpected platform result: urls=%s receipts=%s", got.PublishedURLs, got.Receipts)
|
|
}
|
|
adapter.mu.Lock()
|
|
called := adapter.called
|
|
adapter.mu.Unlock()
|
|
if called != 1 {
|
|
t.Fatalf("adapter called %d times", called)
|
|
}
|
|
return
|
|
}
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
t.Fatal("platform task did not reach success")
|
|
}
|
|
|
|
func TestDispatcherCancelStopsRegisteredPlatform(t *testing.T) {
|
|
db := platformTestDB(t)
|
|
account := models.Account{WorkspaceID: 1, Platform: "test-platform", Status: "active"}
|
|
material := models.Material{WorkspaceID: 1, Name: "video.mp4", Status: "ready", StorageKey: "1/video.mp4"}
|
|
_ = db.Create(&account).Error
|
|
_ = db.Create(&material).Error
|
|
row := models.Task{WorkspaceID: 1, Title: "cancel", Status: task.Queued, AccountIDs: "[1]", MaterialIDs: "[1]"}
|
|
_ = db.Create(&row).Error
|
|
adapter := &testPlatformAdapter{block: true, canceled: make(chan struct{})}
|
|
registry := platform.NewRegistry()
|
|
_ = registry.Register(adapter)
|
|
d := NewDispatcher(db, NewHub(), &config.Config{ExecutorMode: "web", BaseURL: "http://127.0.0.1:8090"})
|
|
d.Registry = registry
|
|
if !d.TryDispatch(row.ID) {
|
|
t.Fatal("registered adapter should accept queued task")
|
|
}
|
|
time.Sleep(60 * time.Millisecond)
|
|
d.Cancel(row.ID)
|
|
select {
|
|
case <-adapter.canceled:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("adapter context was not cancelled")
|
|
}
|
|
}
|