test(02-02): rewrite all tests to use per-test in-memory databases via NewTestServer
All checks were successful
CI / build-test (push) Successful in 1m42s
All checks were successful
CI / build-test (push) Successful in 1m42s
- Remove TestMain (no longer needed; each test is isolated) - Replace all diun.UpdatesReset() with diun.NewTestServer() per test - Replace all diun.SetWebhookSecret/ResetWebhookSecret with NewTestServerWithSecret - Replace all diun.WebhookHandler etc with srv.WebhookHandler (method calls) - Replace diun.UpdateEvent with srv.TestUpsertEvent - Replace diun.GetUpdatesMap with srv.TestGetUpdatesMap - Update helper functions postTag/postTagAndGetID to accept *diun.Server parameter - Change t.Fatalf to t.Errorf inside goroutine in TestConcurrentUpdateEvent - Add error check on second TestUpsertEvent in TestDismissHandler_ReappearsAfterNewWebhook - All 32 tests pass with zero failures
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -15,13 +14,11 @@ import (
|
|||||||
diun "awesomeProject/pkg/diunwebhook"
|
diun "awesomeProject/pkg/diunwebhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
diun.UpdatesReset()
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateEventAndGetUpdates(t *testing.T) {
|
func TestUpdateEventAndGetUpdates(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
event := diun.DiunEvent{
|
event := diun.DiunEvent{
|
||||||
DiunVersion: "1.0",
|
DiunVersion: "1.0",
|
||||||
Hostname: "host",
|
Hostname: "host",
|
||||||
@@ -34,12 +31,12 @@ func TestUpdateEventAndGetUpdates(t *testing.T) {
|
|||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
Platform: "linux/amd64",
|
Platform: "linux/amd64",
|
||||||
}
|
}
|
||||||
if err := diun.UpdateEvent(event); err != nil {
|
if err := srv.TestUpsertEvent(event); err != nil {
|
||||||
t.Fatalf("test setup: UpdateEvent failed: %v", err)
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
}
|
}
|
||||||
got, err := diun.GetUpdates()
|
got, err := srv.TestGetUpdates()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("GetUpdates error: %v", err)
|
t.Fatalf("TestGetUpdates error: %v", err)
|
||||||
}
|
}
|
||||||
if len(got) != 1 {
|
if len(got) != 1 {
|
||||||
t.Fatalf("expected 1 update, got %d", len(got))
|
t.Fatalf("expected 1 update, got %d", len(got))
|
||||||
@@ -50,7 +47,10 @@ func TestUpdateEventAndGetUpdates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler(t *testing.T) {
|
func TestWebhookHandler(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
event := diun.DiunEvent{
|
event := diun.DiunEvent{
|
||||||
DiunVersion: "2.0",
|
DiunVersion: "2.0",
|
||||||
Hostname: "host2",
|
Hostname: "host2",
|
||||||
@@ -66,94 +66,106 @@ func TestWebhookHandler(t *testing.T) {
|
|||||||
body, _ := json.Marshal(event)
|
body, _ := json.Marshal(event)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusOK {
|
if rec.Code != http.StatusOK {
|
||||||
t.Errorf("expected status 200, got %d", rec.Code)
|
t.Errorf("expected status 200, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
if len(diun.GetUpdatesMap()) != 1 {
|
if len(srv.TestGetUpdatesMap()) != 1 {
|
||||||
t.Errorf("expected 1 update, got %d", len(diun.GetUpdatesMap()))
|
t.Errorf("expected 1 update, got %d", len(srv.TestGetUpdatesMap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_Unauthorized(t *testing.T) {
|
func TestWebhookHandler_Unauthorized(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServerWithSecret("my-secret")
|
||||||
diun.SetWebhookSecret("my-secret")
|
if err != nil {
|
||||||
defer diun.ResetWebhookSecret()
|
t.Fatalf("NewTestServerWithSecret: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
event := diun.DiunEvent{Image: "nginx:latest"}
|
event := diun.DiunEvent{Image: "nginx:latest"}
|
||||||
body, _ := json.Marshal(event)
|
body, _ := json.Marshal(event)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusUnauthorized {
|
if rec.Code != http.StatusUnauthorized {
|
||||||
t.Errorf("expected 401, got %d", rec.Code)
|
t.Errorf("expected 401, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_WrongToken(t *testing.T) {
|
func TestWebhookHandler_WrongToken(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServerWithSecret("my-secret")
|
||||||
diun.SetWebhookSecret("my-secret")
|
if err != nil {
|
||||||
defer diun.ResetWebhookSecret()
|
t.Fatalf("NewTestServerWithSecret: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
event := diun.DiunEvent{Image: "nginx:latest"}
|
event := diun.DiunEvent{Image: "nginx:latest"}
|
||||||
body, _ := json.Marshal(event)
|
body, _ := json.Marshal(event)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
req.Header.Set("Authorization", "wrong-token")
|
req.Header.Set("Authorization", "wrong-token")
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusUnauthorized {
|
if rec.Code != http.StatusUnauthorized {
|
||||||
t.Errorf("expected 401, got %d", rec.Code)
|
t.Errorf("expected 401, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_ValidToken(t *testing.T) {
|
func TestWebhookHandler_ValidToken(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServerWithSecret("my-secret")
|
||||||
diun.SetWebhookSecret("my-secret")
|
if err != nil {
|
||||||
defer diun.ResetWebhookSecret()
|
t.Fatalf("NewTestServerWithSecret: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
event := diun.DiunEvent{Image: "nginx:latest"}
|
event := diun.DiunEvent{Image: "nginx:latest"}
|
||||||
body, _ := json.Marshal(event)
|
body, _ := json.Marshal(event)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
req.Header.Set("Authorization", "my-secret")
|
req.Header.Set("Authorization", "my-secret")
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusOK {
|
if rec.Code != http.StatusOK {
|
||||||
t.Errorf("expected 200, got %d", rec.Code)
|
t.Errorf("expected 200, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_NoSecretConfigured(t *testing.T) {
|
func TestWebhookHandler_NoSecretConfigured(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
diun.ResetWebhookSecret()
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
event := diun.DiunEvent{Image: "nginx:latest"}
|
event := diun.DiunEvent{Image: "nginx:latest"}
|
||||||
body, _ := json.Marshal(event)
|
body, _ := json.Marshal(event)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusOK {
|
if rec.Code != http.StatusOK {
|
||||||
t.Errorf("expected 200 (no secret configured), got %d", rec.Code)
|
t.Errorf("expected 200 (no secret configured), got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_BadRequest(t *testing.T) {
|
func TestWebhookHandler_BadRequest(t *testing.T) {
|
||||||
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader([]byte("not-json")))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader([]byte("not-json")))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Errorf("expected 400 for bad JSON, got %d", rec.Code)
|
t.Errorf("expected 400 for bad JSON, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdatesHandler(t *testing.T) {
|
func TestUpdatesHandler(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
event := diun.DiunEvent{Image: "busybox:latest"}
|
event := diun.DiunEvent{Image: "busybox:latest"}
|
||||||
if err := diun.UpdateEvent(event); err != nil {
|
if err := srv.TestUpsertEvent(event); err != nil {
|
||||||
t.Fatalf("test setup: UpdateEvent failed: %v", err)
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
}
|
}
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/updates", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/updates", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.UpdatesHandler(rec, req)
|
srv.UpdatesHandler(rec, req)
|
||||||
if rec.Code != http.StatusOK {
|
if rec.Code != http.StatusOK {
|
||||||
t.Errorf("expected status 200, got %d", rec.Code)
|
t.Errorf("expected status 200, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
@@ -175,17 +187,25 @@ func (f failWriter) Write([]byte) (int, error) { return 0, errors.New("forced er
|
|||||||
func (f failWriter) WriteHeader(_ int) {}
|
func (f failWriter) WriteHeader(_ int) {}
|
||||||
|
|
||||||
func TestUpdatesHandler_EncodeError(t *testing.T) {
|
func TestUpdatesHandler_EncodeError(t *testing.T) {
|
||||||
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
rec := failWriter{httptest.NewRecorder()}
|
rec := failWriter{httptest.NewRecorder()}
|
||||||
diun.UpdatesHandler(rec, httptest.NewRequest(http.MethodGet, "/api/updates", nil))
|
srv.UpdatesHandler(rec, httptest.NewRequest(http.MethodGet, "/api/updates", nil))
|
||||||
// No panic = pass
|
// No panic = pass
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_MethodNotAllowed(t *testing.T) {
|
func TestWebhookHandler_MethodNotAllowed(t *testing.T) {
|
||||||
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
methods := []string{http.MethodGet, http.MethodPut, http.MethodDelete}
|
methods := []string{http.MethodGet, http.MethodPut, http.MethodDelete}
|
||||||
for _, method := range methods {
|
for _, method := range methods {
|
||||||
req := httptest.NewRequest(method, "/webhook", nil)
|
req := httptest.NewRequest(method, "/webhook", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusMethodNotAllowed {
|
if rec.Code != http.StatusMethodNotAllowed {
|
||||||
t.Errorf("method %s: expected 405, got %d", method, rec.Code)
|
t.Errorf("method %s: expected 405, got %d", method, rec.Code)
|
||||||
}
|
}
|
||||||
@@ -195,52 +215,61 @@ func TestWebhookHandler_MethodNotAllowed(t *testing.T) {
|
|||||||
body, _ := json.Marshal(event)
|
body, _ := json.Marshal(event)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code == http.StatusMethodNotAllowed {
|
if rec.Code == http.StatusMethodNotAllowed {
|
||||||
t.Errorf("POST should not return 405")
|
t.Errorf("POST should not return 405")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_EmptyImage(t *testing.T) {
|
func TestWebhookHandler_EmptyImage(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
body, _ := json.Marshal(diun.DiunEvent{Image: ""})
|
body, _ := json.Marshal(diun.DiunEvent{Image: ""})
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Errorf("expected 400 for empty image, got %d", rec.Code)
|
t.Errorf("expected 400 for empty image, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
if len(diun.GetUpdatesMap()) != 0 {
|
if len(srv.TestGetUpdatesMap()) != 0 {
|
||||||
t.Errorf("expected map to stay empty, got %d entries", len(diun.GetUpdatesMap()))
|
t.Errorf("expected map to stay empty, got %d entries", len(srv.TestGetUpdatesMap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConcurrentUpdateEvent(t *testing.T) {
|
func TestConcurrentUpdateEvent(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
const n = 100
|
const n = 100
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(n)
|
wg.Add(n)
|
||||||
for i := range n {
|
for i := range n {
|
||||||
go func(i int) {
|
go func(i int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
if err := diun.UpdateEvent(diun.DiunEvent{Image: fmt.Sprintf("image:%d", i)}); err != nil {
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: fmt.Sprintf("image:%d", i)}); err != nil {
|
||||||
t.Fatalf("test setup: UpdateEvent[%d] failed: %v", i, err)
|
t.Errorf("test setup: TestUpsertEvent[%d] failed: %v", i, err)
|
||||||
}
|
}
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
if got := len(diun.GetUpdatesMap()); got != n {
|
if got := len(srv.TestGetUpdatesMap()); got != n {
|
||||||
t.Errorf("expected %d entries, got %d", n, got)
|
t.Errorf("expected %d entries, got %d", n, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMainHandlerIntegration(t *testing.T) {
|
func TestMainHandlerIntegration(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path == "/webhook" {
|
if r.URL.Path == "/webhook" {
|
||||||
diun.WebhookHandler(w, r)
|
srv.WebhookHandler(w, r)
|
||||||
} else if r.URL.Path == "/api/updates" {
|
} else if r.URL.Path == "/api/updates" {
|
||||||
diun.UpdatesHandler(w, r)
|
srv.UpdatesHandler(w, r)
|
||||||
} else {
|
} else {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
}
|
}
|
||||||
@@ -279,18 +308,21 @@ func TestMainHandlerIntegration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDismissHandler_Success(t *testing.T) {
|
func TestDismissHandler_Success(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
if err := diun.UpdateEvent(diun.DiunEvent{Image: "nginx:latest"}); err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test setup: UpdateEvent failed: %v", err)
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "nginx:latest"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPatch, "/api/updates/nginx:latest", nil)
|
req := httptest.NewRequest(http.MethodPatch, "/api/updates/nginx:latest", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.DismissHandler(rec, req)
|
srv.DismissHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Errorf("expected 204, got %d", rec.Code)
|
t.Errorf("expected 204, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
m := diun.GetUpdatesMap()
|
m := srv.TestGetUpdatesMap()
|
||||||
if len(m) != 1 {
|
if len(m) != 1 {
|
||||||
t.Errorf("expected entry to remain after acknowledge, got %d entries", len(m))
|
t.Errorf("expected entry to remain after acknowledge, got %d entries", len(m))
|
||||||
}
|
}
|
||||||
@@ -300,38 +332,48 @@ func TestDismissHandler_Success(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDismissHandler_NotFound(t *testing.T) {
|
func TestDismissHandler_NotFound(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPatch, "/api/updates/does-not-exist:latest", nil)
|
req := httptest.NewRequest(http.MethodPatch, "/api/updates/does-not-exist:latest", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.DismissHandler(rec, req)
|
srv.DismissHandler(rec, req)
|
||||||
if rec.Code != http.StatusNotFound {
|
if rec.Code != http.StatusNotFound {
|
||||||
t.Errorf("expected 404, got %d", rec.Code)
|
t.Errorf("expected 404, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDismissHandler_EmptyImage(t *testing.T) {
|
func TestDismissHandler_EmptyImage(t *testing.T) {
|
||||||
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
req := httptest.NewRequest(http.MethodPatch, "/api/updates/", nil)
|
req := httptest.NewRequest(http.MethodPatch, "/api/updates/", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.DismissHandler(rec, req)
|
srv.DismissHandler(rec, req)
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Errorf("expected 400, got %d", rec.Code)
|
t.Errorf("expected 400, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDismissHandler_SlashInImageName(t *testing.T) {
|
func TestDismissHandler_SlashInImageName(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
if err := diun.UpdateEvent(diun.DiunEvent{Image: "ghcr.io/user/image:tag"}); err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test setup: UpdateEvent failed: %v", err)
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "ghcr.io/user/image:tag"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPatch, "/api/updates/ghcr.io/user/image:tag", nil)
|
req := httptest.NewRequest(http.MethodPatch, "/api/updates/ghcr.io/user/image:tag", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.DismissHandler(rec, req)
|
srv.DismissHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Errorf("expected 204, got %d", rec.Code)
|
t.Errorf("expected 204, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
m := diun.GetUpdatesMap()
|
m := srv.TestGetUpdatesMap()
|
||||||
if len(m) != 1 {
|
if len(m) != 1 {
|
||||||
t.Errorf("expected entry to remain after acknowledge, got %d entries", len(m))
|
t.Errorf("expected entry to remain after acknowledge, got %d entries", len(m))
|
||||||
}
|
}
|
||||||
@@ -341,23 +383,28 @@ func TestDismissHandler_SlashInImageName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDismissHandler_ReappearsAfterNewWebhook(t *testing.T) {
|
func TestDismissHandler_ReappearsAfterNewWebhook(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
if err := diun.UpdateEvent(diun.DiunEvent{Image: "nginx:latest"}); err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test setup: UpdateEvent failed: %v", err)
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "nginx:latest"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPatch, "/api/updates/nginx:latest", nil)
|
req := httptest.NewRequest(http.MethodPatch, "/api/updates/nginx:latest", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.DismissHandler(rec, req)
|
srv.DismissHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Fatalf("expected 204 on acknowledge, got %d", rec.Code)
|
t.Fatalf("expected 204 on acknowledge, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
if !diun.GetUpdatesMap()["nginx:latest"].Acknowledged {
|
if !srv.TestGetUpdatesMap()["nginx:latest"].Acknowledged {
|
||||||
t.Errorf("expected entry to be acknowledged after PATCH")
|
t.Errorf("expected entry to be acknowledged after PATCH")
|
||||||
}
|
}
|
||||||
|
|
||||||
diun.UpdateEvent(diun.DiunEvent{Image: "nginx:latest", Status: "update"})
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "nginx:latest", Status: "update"}); err != nil {
|
||||||
m := diun.GetUpdatesMap()
|
t.Fatalf("second TestUpsertEvent failed: %v", err)
|
||||||
|
}
|
||||||
|
m := srv.TestGetUpdatesMap()
|
||||||
if len(m) != 1 {
|
if len(m) != 1 {
|
||||||
t.Errorf("expected entry to remain, got %d entries", len(m))
|
t.Errorf("expected entry to remain, got %d entries", len(m))
|
||||||
}
|
}
|
||||||
@@ -371,21 +418,21 @@ func TestDismissHandler_ReappearsAfterNewWebhook(t *testing.T) {
|
|||||||
|
|
||||||
// --- Tag handler tests ---
|
// --- Tag handler tests ---
|
||||||
|
|
||||||
func postTag(t *testing.T, name string) (int, int) {
|
func postTag(t *testing.T, srv *diun.Server, name string) (int, int) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
body, _ := json.Marshal(map[string]string{"name": name})
|
body, _ := json.Marshal(map[string]string{"name": name})
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagsHandler(rec, req)
|
srv.TagsHandler(rec, req)
|
||||||
return rec.Code, rec.Body.Len()
|
return rec.Code, rec.Body.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
func postTagAndGetID(t *testing.T, name string) int {
|
func postTagAndGetID(t *testing.T, srv *diun.Server, name string) int {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
body, _ := json.Marshal(map[string]string{"name": name})
|
body, _ := json.Marshal(map[string]string{"name": name})
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagsHandler(rec, req)
|
srv.TagsHandler(rec, req)
|
||||||
if rec.Code != http.StatusCreated {
|
if rec.Code != http.StatusCreated {
|
||||||
t.Fatalf("expected 201 creating tag %q, got %d", name, rec.Code)
|
t.Fatalf("expected 201 creating tag %q, got %d", name, rec.Code)
|
||||||
}
|
}
|
||||||
@@ -395,11 +442,14 @@ func postTagAndGetID(t *testing.T, name string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateTagHandler_Success(t *testing.T) {
|
func TestCreateTagHandler_Success(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
body, _ := json.Marshal(map[string]string{"name": "nextcloud"})
|
body, _ := json.Marshal(map[string]string{"name": "nextcloud"})
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagsHandler(rec, req)
|
srv.TagsHandler(rec, req)
|
||||||
if rec.Code != http.StatusCreated {
|
if rec.Code != http.StatusCreated {
|
||||||
t.Fatalf("expected 201, got %d", rec.Code)
|
t.Fatalf("expected 201, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
@@ -416,30 +466,39 @@ func TestCreateTagHandler_Success(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateTagHandler_DuplicateName(t *testing.T) {
|
func TestCreateTagHandler_DuplicateName(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
postTag(t, "monitoring")
|
if err != nil {
|
||||||
code, _ := postTag(t, "monitoring")
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
postTag(t, srv, "monitoring")
|
||||||
|
code, _ := postTag(t, srv, "monitoring")
|
||||||
if code != http.StatusConflict {
|
if code != http.StatusConflict {
|
||||||
t.Errorf("expected 409, got %d", code)
|
t.Errorf("expected 409, got %d", code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateTagHandler_EmptyName(t *testing.T) {
|
func TestCreateTagHandler_EmptyName(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
body, _ := json.Marshal(map[string]string{"name": ""})
|
body, _ := json.Marshal(map[string]string{"name": ""})
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagsHandler(rec, req)
|
srv.TagsHandler(rec, req)
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Errorf("expected 400, got %d", rec.Code)
|
t.Errorf("expected 400, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTagsHandler_Empty(t *testing.T) {
|
func TestGetTagsHandler_Empty(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/tags", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/tags", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagsHandler(rec, req)
|
srv.TagsHandler(rec, req)
|
||||||
if rec.Code != http.StatusOK {
|
if rec.Code != http.StatusOK {
|
||||||
t.Fatalf("expected 200, got %d", rec.Code)
|
t.Fatalf("expected 200, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
@@ -451,12 +510,15 @@ func TestGetTagsHandler_Empty(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTagsHandler_WithTags(t *testing.T) {
|
func TestGetTagsHandler_WithTags(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
postTag(t, "alpha")
|
if err != nil {
|
||||||
postTag(t, "beta")
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
postTag(t, srv, "alpha")
|
||||||
|
postTag(t, srv, "beta")
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/tags", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/tags", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagsHandler(rec, req)
|
srv.TagsHandler(rec, req)
|
||||||
if rec.Code != http.StatusOK {
|
if rec.Code != http.StatusOK {
|
||||||
t.Fatalf("expected 200, got %d", rec.Code)
|
t.Fatalf("expected 200, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
@@ -468,36 +530,47 @@ func TestGetTagsHandler_WithTags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteTagHandler_Success(t *testing.T) {
|
func TestDeleteTagHandler_Success(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
id := postTagAndGetID(t, "to-delete")
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
id := postTagAndGetID(t, srv, "to-delete")
|
||||||
req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/api/tags/%d", id), nil)
|
req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/api/tags/%d", id), nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagByIDHandler(rec, req)
|
srv.TagByIDHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Errorf("expected 204, got %d", rec.Code)
|
t.Errorf("expected 204, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteTagHandler_NotFound(t *testing.T) {
|
func TestDeleteTagHandler_NotFound(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
req := httptest.NewRequest(http.MethodDelete, "/api/tags/9999", nil)
|
req := httptest.NewRequest(http.MethodDelete, "/api/tags/9999", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagByIDHandler(rec, req)
|
srv.TagByIDHandler(rec, req)
|
||||||
if rec.Code != http.StatusNotFound {
|
if rec.Code != http.StatusNotFound {
|
||||||
t.Errorf("expected 404, got %d", rec.Code)
|
t.Errorf("expected 404, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteTagHandler_CascadesAssignment(t *testing.T) {
|
func TestDeleteTagHandler_CascadesAssignment(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
diun.UpdateEvent(diun.DiunEvent{Image: "nginx:latest"})
|
if err != nil {
|
||||||
id := postTagAndGetID(t, "cascade-test")
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "nginx:latest"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
|
}
|
||||||
|
id := postTagAndGetID(t, srv, "cascade-test")
|
||||||
|
|
||||||
// Assign the tag
|
// Assign the tag
|
||||||
body, _ := json.Marshal(map[string]interface{}{"image": "nginx:latest", "tag_id": id})
|
body, _ := json.Marshal(map[string]interface{}{"image": "nginx:latest", "tag_id": id})
|
||||||
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Fatalf("expected 204 on assign, got %d", rec.Code)
|
t.Fatalf("expected 204 on assign, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
@@ -505,43 +578,53 @@ func TestDeleteTagHandler_CascadesAssignment(t *testing.T) {
|
|||||||
// Delete the tag
|
// Delete the tag
|
||||||
req = httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/api/tags/%d", id), nil)
|
req = httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/api/tags/%d", id), nil)
|
||||||
rec = httptest.NewRecorder()
|
rec = httptest.NewRecorder()
|
||||||
diun.TagByIDHandler(rec, req)
|
srv.TagByIDHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Fatalf("expected 204 on delete, got %d", rec.Code)
|
t.Fatalf("expected 204 on delete, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm assignment cascaded
|
// Confirm assignment cascaded
|
||||||
m := diun.GetUpdatesMap()
|
m := srv.TestGetUpdatesMap()
|
||||||
if m["nginx:latest"].Tag != nil {
|
if m["nginx:latest"].Tag != nil {
|
||||||
t.Errorf("expected tag to be nil after cascade delete, got %+v", m["nginx:latest"].Tag)
|
t.Errorf("expected tag to be nil after cascade delete, got %+v", m["nginx:latest"].Tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTagAssignmentHandler_Assign(t *testing.T) {
|
func TestTagAssignmentHandler_Assign(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
diun.UpdateEvent(diun.DiunEvent{Image: "alpine:latest"})
|
if err != nil {
|
||||||
id := postTagAndGetID(t, "assign-test")
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "alpine:latest"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
|
}
|
||||||
|
id := postTagAndGetID(t, srv, "assign-test")
|
||||||
|
|
||||||
body, _ := json.Marshal(map[string]interface{}{"image": "alpine:latest", "tag_id": id})
|
body, _ := json.Marshal(map[string]interface{}{"image": "alpine:latest", "tag_id": id})
|
||||||
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Errorf("expected 204, got %d", rec.Code)
|
t.Errorf("expected 204, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTagAssignmentHandler_Reassign(t *testing.T) {
|
func TestTagAssignmentHandler_Reassign(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
diun.UpdateEvent(diun.DiunEvent{Image: "redis:latest"})
|
if err != nil {
|
||||||
id1 := postTagAndGetID(t, "group-a")
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
id2 := postTagAndGetID(t, "group-b")
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "redis:latest"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
|
}
|
||||||
|
id1 := postTagAndGetID(t, srv, "group-a")
|
||||||
|
id2 := postTagAndGetID(t, srv, "group-b")
|
||||||
|
|
||||||
assign := func(tagID int) {
|
assign := func(tagID int) {
|
||||||
body, _ := json.Marshal(map[string]interface{}{"image": "redis:latest", "tag_id": tagID})
|
body, _ := json.Marshal(map[string]interface{}{"image": "redis:latest", "tag_id": tagID})
|
||||||
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Fatalf("expected 204, got %d", rec.Code)
|
t.Fatalf("expected 204, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
@@ -550,51 +633,61 @@ func TestTagAssignmentHandler_Reassign(t *testing.T) {
|
|||||||
assign(id1)
|
assign(id1)
|
||||||
assign(id2)
|
assign(id2)
|
||||||
|
|
||||||
m := diun.GetUpdatesMap()
|
m := srv.TestGetUpdatesMap()
|
||||||
if m["redis:latest"].Tag == nil || m["redis:latest"].Tag.ID != id2 {
|
if m["redis:latest"].Tag == nil || m["redis:latest"].Tag.ID != id2 {
|
||||||
t.Errorf("expected tag id %d after reassign, got %+v", id2, m["redis:latest"].Tag)
|
t.Errorf("expected tag id %d after reassign, got %+v", id2, m["redis:latest"].Tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTagAssignmentHandler_Unassign(t *testing.T) {
|
func TestTagAssignmentHandler_Unassign(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
diun.UpdateEvent(diun.DiunEvent{Image: "busybox:latest"})
|
if err != nil {
|
||||||
id := postTagAndGetID(t, "unassign-test")
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "busybox:latest"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
|
}
|
||||||
|
id := postTagAndGetID(t, srv, "unassign-test")
|
||||||
|
|
||||||
body, _ := json.Marshal(map[string]interface{}{"image": "busybox:latest", "tag_id": id})
|
body, _ := json.Marshal(map[string]interface{}{"image": "busybox:latest", "tag_id": id})
|
||||||
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
|
|
||||||
// Now unassign
|
// Now unassign
|
||||||
body, _ = json.Marshal(map[string]string{"image": "busybox:latest"})
|
body, _ = json.Marshal(map[string]string{"image": "busybox:latest"})
|
||||||
req = httptest.NewRequest(http.MethodDelete, "/api/tag-assignments", bytes.NewReader(body))
|
req = httptest.NewRequest(http.MethodDelete, "/api/tag-assignments", bytes.NewReader(body))
|
||||||
rec = httptest.NewRecorder()
|
rec = httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Errorf("expected 204, got %d", rec.Code)
|
t.Errorf("expected 204, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := diun.GetUpdatesMap()
|
m := srv.TestGetUpdatesMap()
|
||||||
if m["busybox:latest"].Tag != nil {
|
if m["busybox:latest"].Tag != nil {
|
||||||
t.Errorf("expected tag nil after unassign, got %+v", m["busybox:latest"].Tag)
|
t.Errorf("expected tag nil after unassign, got %+v", m["busybox:latest"].Tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUpdates_IncludesTag(t *testing.T) {
|
func TestGetUpdates_IncludesTag(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
diun.UpdateEvent(diun.DiunEvent{Image: "postgres:latest"})
|
if err != nil {
|
||||||
id := postTagAndGetID(t, "databases")
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "postgres:latest"}); err != nil {
|
||||||
|
t.Fatalf("test setup: TestUpsertEvent failed: %v", err)
|
||||||
|
}
|
||||||
|
id := postTagAndGetID(t, srv, "databases")
|
||||||
|
|
||||||
body, _ := json.Marshal(map[string]interface{}{"image": "postgres:latest", "tag_id": id})
|
body, _ := json.Marshal(map[string]interface{}{"image": "postgres:latest", "tag_id": id})
|
||||||
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Fatalf("expected 204, got %d", rec.Code)
|
t.Fatalf("expected 204, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := diun.GetUpdatesMap()
|
m := srv.TestGetUpdatesMap()
|
||||||
entry, ok := m["postgres:latest"]
|
entry, ok := m["postgres:latest"]
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("expected postgres:latest in updates")
|
t.Fatal("expected postgres:latest in updates")
|
||||||
@@ -611,6 +704,10 @@ func TestGetUpdates_IncludesTag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWebhookHandler_OversizedBody(t *testing.T) {
|
func TestWebhookHandler_OversizedBody(t *testing.T) {
|
||||||
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
// Generate a body that exceeds 1 MB (maxBodyBytes = 1<<20 = 1,048,576 bytes).
|
// Generate a body that exceeds 1 MB (maxBodyBytes = 1<<20 = 1,048,576 bytes).
|
||||||
// Use a valid JSON prefix so the decoder reads past the limit before failing,
|
// Use a valid JSON prefix so the decoder reads past the limit before failing,
|
||||||
// ensuring MaxBytesReader triggers a 413 rather than a JSON parse 400.
|
// ensuring MaxBytesReader triggers a 413 rather than a JSON parse 400.
|
||||||
@@ -619,50 +716,61 @@ func TestWebhookHandler_OversizedBody(t *testing.T) {
|
|||||||
oversized := append(prefix, padding...)
|
oversized := append(prefix, padding...)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(oversized))
|
req := httptest.NewRequest(http.MethodPost, "/webhook", bytes.NewReader(oversized))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.WebhookHandler(rec, req)
|
srv.WebhookHandler(rec, req)
|
||||||
if rec.Code != http.StatusRequestEntityTooLarge {
|
if rec.Code != http.StatusRequestEntityTooLarge {
|
||||||
t.Errorf("expected 413 for oversized body, got %d", rec.Code)
|
t.Errorf("expected 413 for oversized body, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTagsHandler_OversizedBody(t *testing.T) {
|
func TestTagsHandler_OversizedBody(t *testing.T) {
|
||||||
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
prefix := []byte(`{"name":"`)
|
prefix := []byte(`{"name":"`)
|
||||||
padding := bytes.Repeat([]byte("x"), 1<<20+1)
|
padding := bytes.Repeat([]byte("x"), 1<<20+1)
|
||||||
oversized := append(prefix, padding...)
|
oversized := append(prefix, padding...)
|
||||||
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(oversized))
|
req := httptest.NewRequest(http.MethodPost, "/api/tags", bytes.NewReader(oversized))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagsHandler(rec, req)
|
srv.TagsHandler(rec, req)
|
||||||
if rec.Code != http.StatusRequestEntityTooLarge {
|
if rec.Code != http.StatusRequestEntityTooLarge {
|
||||||
t.Errorf("expected 413 for oversized body, got %d", rec.Code)
|
t.Errorf("expected 413 for oversized body, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTagAssignmentHandler_OversizedBody(t *testing.T) {
|
func TestTagAssignmentHandler_OversizedBody(t *testing.T) {
|
||||||
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
prefix := []byte(`{"image":"`)
|
prefix := []byte(`{"image":"`)
|
||||||
padding := bytes.Repeat([]byte("x"), 1<<20+1)
|
padding := bytes.Repeat([]byte("x"), 1<<20+1)
|
||||||
oversized := append(prefix, padding...)
|
oversized := append(prefix, padding...)
|
||||||
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(oversized))
|
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(oversized))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
if rec.Code != http.StatusRequestEntityTooLarge {
|
if rec.Code != http.StatusRequestEntityTooLarge {
|
||||||
t.Errorf("expected 413 for oversized body, got %d", rec.Code)
|
t.Errorf("expected 413 for oversized body, got %d", rec.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateEvent_PreservesTagOnUpsert(t *testing.T) {
|
func TestUpdateEvent_PreservesTagOnUpsert(t *testing.T) {
|
||||||
diun.UpdatesReset()
|
srv, err := diun.NewTestServer()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTestServer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Insert image
|
// Insert image
|
||||||
if err := diun.UpdateEvent(diun.DiunEvent{Image: "nginx:latest", Status: "new"}); err != nil {
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "nginx:latest", Status: "new"}); err != nil {
|
||||||
t.Fatalf("first UpdateEvent failed: %v", err)
|
t.Fatalf("first TestUpsertEvent failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign tag
|
// Assign tag
|
||||||
tagID := postTagAndGetID(t, "webservers")
|
tagID := postTagAndGetID(t, srv, "webservers")
|
||||||
body, _ := json.Marshal(map[string]interface{}{"image": "nginx:latest", "tag_id": tagID})
|
body, _ := json.Marshal(map[string]interface{}{"image": "nginx:latest", "tag_id": tagID})
|
||||||
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
req := httptest.NewRequest(http.MethodPut, "/api/tag-assignments", bytes.NewReader(body))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
diun.TagAssignmentHandler(rec, req)
|
srv.TagAssignmentHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Fatalf("tag assignment failed: got %d", rec.Code)
|
t.Fatalf("tag assignment failed: got %d", rec.Code)
|
||||||
}
|
}
|
||||||
@@ -670,24 +778,24 @@ func TestUpdateEvent_PreservesTagOnUpsert(t *testing.T) {
|
|||||||
// Dismiss (acknowledge) the image — second event must reset this
|
// Dismiss (acknowledge) the image — second event must reset this
|
||||||
req = httptest.NewRequest(http.MethodPatch, "/api/updates/nginx:latest", nil)
|
req = httptest.NewRequest(http.MethodPatch, "/api/updates/nginx:latest", nil)
|
||||||
rec = httptest.NewRecorder()
|
rec = httptest.NewRecorder()
|
||||||
diun.DismissHandler(rec, req)
|
srv.DismissHandler(rec, req)
|
||||||
if rec.Code != http.StatusNoContent {
|
if rec.Code != http.StatusNoContent {
|
||||||
t.Fatalf("dismiss failed: got %d", rec.Code)
|
t.Fatalf("dismiss failed: got %d", rec.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive a second event for the same image
|
// Receive a second event for the same image
|
||||||
if err := diun.UpdateEvent(diun.DiunEvent{Image: "nginx:latest", Status: "update"}); err != nil {
|
if err := srv.TestUpsertEvent(diun.DiunEvent{Image: "nginx:latest", Status: "update"}); err != nil {
|
||||||
t.Fatalf("second UpdateEvent failed: %v", err)
|
t.Fatalf("second TestUpsertEvent failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag must survive the second event
|
// Tag must survive the second event
|
||||||
m := diun.GetUpdatesMap()
|
m := srv.TestGetUpdatesMap()
|
||||||
entry, ok := m["nginx:latest"]
|
entry, ok := m["nginx:latest"]
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("nginx:latest missing from updates after second event")
|
t.Fatal("nginx:latest missing from updates after second event")
|
||||||
}
|
}
|
||||||
if entry.Tag == nil {
|
if entry.Tag == nil {
|
||||||
t.Error("tag was lost after second UpdateEvent — UPSERT bug not fixed")
|
t.Error("tag was lost after second TestUpsertEvent — UPSERT bug not fixed")
|
||||||
}
|
}
|
||||||
if entry.Tag != nil && entry.Tag.ID != tagID {
|
if entry.Tag != nil && entry.Tag.ID != tagID {
|
||||||
t.Errorf("tag ID changed: expected %d, got %d", tagID, entry.Tag.ID)
|
t.Errorf("tag ID changed: expected %d, got %d", tagID, entry.Tag.ID)
|
||||||
|
|||||||
Reference in New Issue
Block a user