mirror of
https://github.com/cooperspencer/gickup.git
synced 2026-10-20 08:18:38 +00:00
112 lines
3.6 KiB
Go
112 lines
3.6 KiB
Go
package webui
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
//nolint:paralleltest // These handlers use Global, which each test temporarily replaces.
|
|
func TestRunningTracksOverlappingRuns(t *testing.T) {
|
|
old := Global
|
|
Global = &store{}
|
|
defer func() { Global = old }()
|
|
check := func(want string) {
|
|
t.Helper()
|
|
w := httptest.NewRecorder()
|
|
handleRunning(w, httptest.NewRequest(http.MethodGet, "/api/running", nil))
|
|
if strings.TrimSpace(w.Body.String()) != want {
|
|
t.Fatalf("running = %s, want %s", w.Body.String(), want)
|
|
}
|
|
}
|
|
Global.BeginRun()
|
|
Global.BeginRun()
|
|
check(`{"running":true}`)
|
|
Global.EndRun()
|
|
check(`{"running":true}`)
|
|
w := httptest.NewRecorder()
|
|
handleRun(w, httptest.NewRequest(http.MethodPost, "/api/run", strings.NewReader(`{"index":-1}`)))
|
|
if w.Code != http.StatusConflict {
|
|
t.Fatalf("got %d, want conflict", w.Code)
|
|
}
|
|
Global.EndRun()
|
|
check(`{"running":false}`)
|
|
}
|
|
|
|
//nolint:paralleltest // These handlers use Global, which each test temporarily replaces.
|
|
func TestAPIRunReservationDoesNotClearScheduledRun(t *testing.T) {
|
|
old := Global
|
|
Global = &store{}
|
|
defer func() { Global = old }()
|
|
finished := make(chan struct{})
|
|
Global.SetRunFunc(func(int) {
|
|
// Simulate a scheduled run starting while the API reservation is held.
|
|
Global.BeginRun()
|
|
close(finished)
|
|
})
|
|
w := httptest.NewRecorder()
|
|
handleRun(w, httptest.NewRequest(http.MethodPost, "/api/run", strings.NewReader(`{"index":-1}`)))
|
|
if w.Code != http.StatusAccepted {
|
|
t.Fatalf("got %d, want accepted", w.Code)
|
|
}
|
|
<-finished
|
|
// Wait for the API goroutine to release its reservation.
|
|
deadline := time.Now().Add(time.Second)
|
|
for {
|
|
w = httptest.NewRecorder()
|
|
handleRun(w, httptest.NewRequest(http.MethodPost, "/api/run", nil))
|
|
if w.Code != http.StatusConflict {
|
|
t.Fatalf("active scheduled run lost: %d", w.Code)
|
|
}
|
|
if atomic.LoadInt32(&Global.running) == 1 {
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatal("API reservation not released")
|
|
}
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
Global.EndRun()
|
|
}
|
|
|
|
//nolint:paralleltest // These handlers use Global, which each test temporarily replaces.
|
|
func TestConfigCreatesMissingFileAndRejectsInvalidDocuments(t *testing.T) {
|
|
old := Global
|
|
Global = &store{}
|
|
defer func() { Global = old }()
|
|
file := filepath.Join(t.TempDir(), "config", "conf.yml")
|
|
Global.SetConfigFiles([]string{file})
|
|
w := httptest.NewRecorder()
|
|
handleConfig(w, httptest.NewRequest(http.MethodGet, "/api/config", nil))
|
|
if w.Code != http.StatusOK || w.Body.Len() != 0 {
|
|
t.Fatalf("missing config: %d %s", w.Code, w.Body.String())
|
|
}
|
|
valid := "source:\n any:\n - url: /repo\ndestination:\n local:\n - path: /backups\n"
|
|
w = httptest.NewRecorder()
|
|
handleConfig(w, httptest.NewRequest(http.MethodPost, "/api/config", strings.NewReader(valid)))
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("create config: %d %s", w.Code, w.Body.String())
|
|
}
|
|
for _, invalid := range []string{"", "# comment only", "{}", valid + "---\nsource: ["} {
|
|
w = httptest.NewRecorder()
|
|
handleConfig(w, httptest.NewRequest(http.MethodPost, "/api/config", strings.NewReader(invalid)))
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Fatalf("invalid config accepted: %q (%d)", invalid, w.Code)
|
|
}
|
|
data, err := os.ReadFile(file)
|
|
if err != nil || string(data) != valid {
|
|
t.Fatalf("existing config changed: %q, %v", data, err)
|
|
}
|
|
}
|
|
w = httptest.NewRecorder()
|
|
handleConfig(w, httptest.NewRequest(http.MethodPost, "/api/config", strings.NewReader(valid+"---\n"+valid)))
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("multiple valid documents rejected: %s", w.Body.String())
|
|
}
|
|
}
|