TestStateSync verifies that the TUI uses the shared state object from the worker, allowing external progress updates to be seen.
(t *testing.T)
| 18 | // TestStateSync verifies that the TUI uses the shared state object |
| 19 | // from the worker, allowing external progress updates to be seen. |
| 20 | func TestStateSync(t *testing.T) { |
| 21 | // Setup temp DB to avoid auto-resuming real downloads (which causes panic if pool is nil) |
| 22 | tmpDir, err := os.MkdirTemp("", "surge-test-sync") |
| 23 | if err != nil { |
| 24 | t.Fatal(err) |
| 25 | } |
| 26 | defer func() { _ = os.RemoveAll(tmpDir) }() |
| 27 | |
| 28 | dbPath := filepath.Join(tmpDir, "surge.db") |
| 29 | state.Configure(dbPath) |
| 30 | defer state.CloseDB() |
| 31 | |
| 32 | // Provide a dummy pool to avoid panics if logic tries to use it |
| 33 | progressChan := make(chan any, 10) |
| 34 | pool := download.NewWorkerPool(progressChan, 1) |
| 35 | |
| 36 | // Initialize model with progress channel and service |
| 37 | m := InitialRootModel(1700, "test-version", core.NewLocalDownloadServiceWithInput(pool, progressChan), processing.NewLifecycleManager(nil, nil), false) |
| 38 | |
| 39 | downloadID := "external-id" |
| 40 | // Create the "worker" state - this is the source of truth |
| 41 | workerState := types.NewProgressState(downloadID, 1000) |
| 42 | |
| 43 | p := tea.NewProgram(m, tea.WithoutRenderer(), tea.WithInput(nil)) |
| 44 | |
| 45 | go func() { |
| 46 | // Simulate download start (from external source) |
| 47 | // Current implementation of DownloadStartedMsg doesn't carry state |
| 48 | // So TUI will create its own state (BUG). |
| 49 | time.Sleep(200 * time.Millisecond) |
| 50 | p.Send(events.DownloadStartedMsg{ |
| 51 | DownloadID: downloadID, |
| 52 | Filename: "external.file", |
| 53 | Total: 1000, |
| 54 | URL: "http://example.com/external", |
| 55 | DestPath: "/tmp/external.file", |
| 56 | State: workerState, |
| 57 | }) |
| 58 | |
| 59 | // Simulate worker updating the state -> Send Progress Event |
| 60 | // Note: The ProgressReporter reads from VerifiedProgress (via GetProgress) |
| 61 | time.Sleep(300 * time.Millisecond) |
| 62 | workerState.VerifiedProgress.Store(500) |
| 63 | p.Send(events.ProgressMsg{ |
| 64 | DownloadID: downloadID, |
| 65 | Downloaded: 500, |
| 66 | Total: 1000, |
| 67 | Speed: 100, // Dummy speed |
| 68 | Elapsed: 10 * time.Second, |
| 69 | }) |
| 70 | |
| 71 | // Wait effectively for 2 poll cycles (150ms * 2 = 300ms) + buffer |
| 72 | time.Sleep(500 * time.Millisecond) |
| 73 | p.Quit() |
| 74 | }() |
| 75 | |
| 76 | finalModel, err := p.Run() |
| 77 | if err != nil { |
nothing calls this directly
no test coverage detected