mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-17 13:23:42 +08:00
- Increment schema version from 11 to 12. - Modify ProxyResolver to use ICCID for device proxy binding resolution. - Update tests to reflect changes in proxy binding logic using ICCID. - Enhance DeviceBindingsDialog to manage eSIM profile bindings instead of device bindings. - Update UI components and translations to reflect the new profile binding terminology. - Implement pagination for automatic task runs in AutomaticTasksPage. - Create a new Pagination component for better navigation in lists.
121 lines
3.9 KiB
Go
121 lines
3.9 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestAutomaticTasksAreClaimedInDeviceQueueOrderAndAdvanceSchedule(t *testing.T) {
|
|
ctx := context.Background()
|
|
database := openTestStore(t, filepath.Join(t.TempDir(), "automatic-tasks.db"))
|
|
mustSaveDevice(t, database, "ec20", "EC20")
|
|
now := time.Now().UTC().Truncate(time.Second)
|
|
for index := 0; index < 2; index++ {
|
|
payload, _ := json.Marshal(map[string]any{"phone": "10086", "message": "test"})
|
|
if _, err := database.SaveAutomaticTask(ctx, AutomaticTask{
|
|
Name: "task", Enabled: true, DeviceID: "ec20", ProfileICCID: "8944100000000000000",
|
|
TaskType: "sms", Environment: "vowifi", IntervalDays: 2,
|
|
StartDate: "2026-08-10", RunTime: "12:00", Timezone: "Asia/Shanghai", Payload: payload,
|
|
NextRunAt: now.Add(time.Duration(index-2) * time.Minute),
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
runs, err := database.ClaimDueAutomaticTasks(ctx, now, 10)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(runs) != 2 || runs[0].DeviceID != "ec20" || runs[1].DeviceID != "ec20" || runs[0].TaskID >= runs[1].TaskID {
|
|
t.Fatalf("claimed runs = %+v", runs)
|
|
}
|
|
tasks, err := database.ListAutomaticTasks(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, task := range tasks {
|
|
if !task.NextRunAt.After(now) {
|
|
t.Fatalf("task %d next run was not advanced: %v", task.ID, task.NextRunAt)
|
|
}
|
|
}
|
|
second, err := database.ClaimDueAutomaticTasks(ctx, now, 10)
|
|
if err != nil || len(second) != 0 {
|
|
t.Fatalf("same schedule claimed twice: %+v, %v", second, err)
|
|
}
|
|
}
|
|
|
|
func TestDeletingAutomaticTaskRemovesRunHistory(t *testing.T) {
|
|
ctx := context.Background()
|
|
database := openTestStore(t, filepath.Join(t.TempDir(), "automatic-task-delete.db"))
|
|
mustSaveDevice(t, database, "ec20", "EC20")
|
|
task, err := database.SaveAutomaticTask(ctx, AutomaticTask{
|
|
Name: "task", Enabled: true, DeviceID: "ec20", ProfileICCID: "one",
|
|
TaskType: "call", Environment: "cellular", IntervalDays: 1,
|
|
StartDate: "2026-08-10", RunTime: "12:00", Timezone: "Asia/Shanghai", Payload: []byte(`{"phone":"10086","duration_seconds":10}`),
|
|
NextRunAt: time.Now().Add(time.Hour),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := database.QueueAutomaticTaskNow(ctx, task); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := database.DeleteAutomaticTask(ctx, task.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
runs, err := database.ListAutomaticTaskRuns(ctx, 10)
|
|
if err != nil || len(runs) != 0 {
|
|
t.Fatalf("orphan runs = %+v, %v", runs, err)
|
|
}
|
|
}
|
|
|
|
func TestListAutomaticTaskRunsPaginated(t *testing.T) {
|
|
ctx := context.Background()
|
|
database := openTestStore(t, filepath.Join(t.TempDir(), "automatic-task-runs-page.db"))
|
|
mustSaveDevice(t, database, "ec20", "EC20")
|
|
task, err := database.SaveAutomaticTask(ctx, AutomaticTask{
|
|
Name: "task", Enabled: true, DeviceID: "ec20", ProfileICCID: "one",
|
|
TaskType: "call", Environment: "cellular", IntervalDays: 1,
|
|
StartDate: "2026-08-10", RunTime: "12:00", Timezone: "Asia/Shanghai", Payload: []byte(`{"phone":"10086","duration_seconds":10}`),
|
|
NextRunAt: time.Now().Add(time.Hour),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for index := 0; index < 5; index++ {
|
|
if _, err := database.QueueAutomaticTaskNow(ctx, task); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
first, total, err := database.ListAutomaticTaskRunsPaginated(ctx, 2, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if total != 5 || len(first) != 2 {
|
|
t.Fatalf("first page: total = %d, runs = %+v", total, first)
|
|
}
|
|
if first[0].ID <= first[1].ID {
|
|
t.Fatalf("runs not newest-first: %+v", first)
|
|
}
|
|
|
|
last, total, err := database.ListAutomaticTaskRunsPaginated(ctx, 2, 4)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if total != 5 || len(last) != 1 {
|
|
t.Fatalf("last page: total = %d, runs = %+v", total, last)
|
|
}
|
|
|
|
// Out-of-range paging inputs are clamped to defaults, not errors.
|
|
all, total, err := database.ListAutomaticTaskRunsPaginated(ctx, 0, -5)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if total != 5 || len(all) != 5 {
|
|
t.Fatalf("clamped page: total = %d, runs = %+v", total, all)
|
|
}
|
|
}
|