130 lines
3.7 KiB
Go
130 lines
3.7 KiB
Go
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/shcizo/package-updater/internal/master/model"
|
|
"github.com/shcizo/package-updater/internal/master/webhook"
|
|
"github.com/shcizo/package-updater/internal/protocol"
|
|
)
|
|
|
|
// webhookServer mounts the webhook handler on a test server, wired to the
|
|
// job environment's store, jobs service and broker.
|
|
func (e *jobEnv) webhookServer(t *testing.T) *httptest.Server {
|
|
t.Helper()
|
|
h := webhook.New(e.store, e.jobs, e.m.broker, webhook.Config{
|
|
Token: "ci-key", Timeout: 5 * time.Second, PublicURL: "https://updater.example.com",
|
|
}, slog.New(slog.NewTextHandler(io.Discard, nil)))
|
|
srv := httptest.NewServer(h)
|
|
t.Cleanup(srv.Close)
|
|
return srv
|
|
}
|
|
|
|
func (e *jobEnv) setAuto(id int64) {
|
|
e.store.mu.Lock()
|
|
defer e.store.mu.Unlock()
|
|
svc := e.store.svcRows[id]
|
|
svc.UpdateMode = model.ModeAuto
|
|
e.store.svcRows[id] = svc
|
|
}
|
|
|
|
type webhookResponse struct {
|
|
Matched int `json:"matched"`
|
|
Results []struct {
|
|
Status string `json:"status"`
|
|
JobID int64 `json:"job_id"`
|
|
ToRef string `json:"to_ref"`
|
|
Error string `json:"error"`
|
|
} `json:"results"`
|
|
}
|
|
|
|
func callWebhook(t *testing.T, srv *httptest.Server, body string) (int, webhookResponse) {
|
|
t.Helper()
|
|
req, err := http.NewRequest(http.MethodPost, srv.URL, strings.NewReader(body))
|
|
require.NoError(t, err)
|
|
req.Header.Set("Authorization", "Bearer ci-key")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
var out webhookResponse
|
|
require.NoError(t, json.NewDecoder(resp.Body).Decode(&out))
|
|
return resp.StatusCode, out
|
|
}
|
|
|
|
func TestWebhookWaitsForAutoJob(t *testing.T) {
|
|
e := newJobEnv(t)
|
|
e.setAuto(1)
|
|
srv := e.webhookServer(t)
|
|
|
|
type reply struct {
|
|
code int
|
|
body webhookResponse
|
|
}
|
|
done := make(chan reply, 1)
|
|
go func() {
|
|
code, body := callWebhook(t, srv, `{"image":"`+slusk+`:ignored","tag":"2.0.0"}`)
|
|
done <- reply{code, body}
|
|
}()
|
|
|
|
e.waitStarted(t)
|
|
select {
|
|
case <-done:
|
|
t.Fatal("the webhook answered before the job finished")
|
|
case <-time.After(100 * time.Millisecond):
|
|
}
|
|
close(e.exec.release)
|
|
|
|
var r reply
|
|
select {
|
|
case r = <-done:
|
|
case <-time.After(waitFor):
|
|
t.Fatal("the webhook never answered")
|
|
}
|
|
require.Equal(t, http.StatusOK, r.code)
|
|
require.Len(t, r.body.Results, 1)
|
|
assert.Equal(t, "succeeded", r.body.Results[0].Status)
|
|
assert.Equal(t, slusk+":2.0.0", r.body.Results[0].ToRef)
|
|
|
|
job := e.job(t, r.body.Results[0].JobID)
|
|
assert.Equal(t, model.TriggerWebhook, job.Trigger)
|
|
assert.Equal(t, model.JobSucceeded, job.Status)
|
|
assert.Equal(t, slusk+":2.0.0@sha256:e2e", job.ToRef)
|
|
svc, err := e.store.GetService(context.Background(), 1)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, svc.AvailableRef, "the job deployed the suggestion, so it is cleared")
|
|
}
|
|
|
|
func TestWebhookFailedAutoJobIs500(t *testing.T) {
|
|
e := newJobEnv(t)
|
|
e.setAuto(1)
|
|
srv := e.webhookServer(t)
|
|
e.agent.stopConn() // no agent connection: the job fails at once with "agent offline"
|
|
require.Eventually(t, func() bool {
|
|
svc, _ := e.store.GetService(context.Background(), 1)
|
|
_, err := e.m.hub.Route(svc, protocol.MinJobVersion)
|
|
return err != nil
|
|
}, waitFor, pollEvery)
|
|
|
|
code, body := callWebhook(t, srv, `{"image":"`+slusk+`","tag":"2.0.0"}`)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, code)
|
|
require.Len(t, body.Results, 1)
|
|
assert.Equal(t, "failed", body.Results[0].Status)
|
|
assert.Equal(t, "agent offline", body.Results[0].Error)
|
|
assert.Equal(t, model.JobFailed, e.job(t, body.Results[0].JobID).Status)
|
|
svc, err := e.store.GetService(context.Background(), 1)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, slusk+":2.0.0", svc.AvailableRef, "a failed job keeps the suggestion")
|
|
}
|