package registrar import ( "crypto/tls" "crypto/x509" "encoding/json" "io" "net/http" "net/http/httptest" "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.fixergrid.net/servicedemon/pkg/pubsub" ) type TestRequest http.Request func NewTestRequest(t *testing.T, method string, url string, body io.Reader) TestRequest { req, err := http.NewRequest(method, url, body) require.NoError(t, err) return TestRequest(*req) } func (tr TestRequest) WithFakeTLSState(dnsName string) TestRequest { cert := x509.Certificate{ DNSNames: []string{ dnsName, }, } tr.TLS = &tls.ConnectionState{ PeerCertificates: []*x509.Certificate{&cert}, } return tr } func (tr TestRequest) Create() *http.Request { req := http.Request(tr) return &req } type AppState struct { Name string State string } type TestAppRepo []AppState func (repo TestAppRepo) IsRegistered(name string) bool { for _, app := range repo { if name == app.Name && app.State == "registered" { return true } } return false } func (repo TestAppRepo) PendingApprovalCount() int { count := 0 for _, app := range repo { if app.State == "pending_approval" { count += 1 } } return count } func (repo *TestAppRepo) StartAppRegistration(name string) uuid.UUID { *repo = append(*repo, AppState{ Name: name, State: "pending_approval", }) return uuid.New() } func TestHandleRegisterPendingApproval(t *testing.T) { resp := httptest.NewRecorder() req := NewTestRequest(t, http.MethodPost, "http://example.com/v1/register", nil). WithFakeTLSState("dev-app-1.delivery.engineering"). Create() repo := &TestAppRepo{} pubsub := pubsub.New() subscriber := pubsub.Subscribe(REGISTRATION_TOPIC) NewRegistrar(pubsub, repo).HandleRegistration(resp, req) assert.Equal(t, http.StatusCreated, resp.Code) body, err := io.ReadAll(resp.Body) require.NoError(t, err) assert.Equal(t, []byte(`{"status": "pending_approval"}`), body) assert.Equal(t, 1, repo.PendingApprovalCount()) expectedEvent := map[string]string{ "name": "dev-app-1.delivery.engineering", "type": "ApplicationRegistrationSubmitted", } assertMessage(t, expectedEvent, subscriber) } func TestHandleRegisterAlreadyRegistered(t *testing.T) { resp := httptest.NewRecorder() req := NewTestRequest(t, http.MethodPost, "http://example.com/v1/register", nil). WithFakeTLSState("dev-app-1.delivery.engineering"). Create() pubsub := pubsub.New() repo := &TestAppRepo{ AppState{ Name: "dev-app-1.delivery.engineering", State: "registered", }, } NewRegistrar(pubsub, repo).HandleRegistration(resp, req) assert.Equal(t, http.StatusOK, resp.Code) body, err := io.ReadAll(resp.Body) require.NoError(t, err) assert.Equal(t, []byte(`{"status": "registered"}`), body) } func assertMessage(t *testing.T, expected map[string]string, sender <-chan string) { timer := time.After(2 * time.Second) for { select { case msg := <-sender: compareMessage(t, expected, msg) return case <-timer: t.Fatal("failed waiting for message") } } } func compareMessage(t *testing.T, expected map[string]string, observed string) { observedEvent := map[string]string{} require.NoError(t, json.Unmarshal([]byte(observed), &observedEvent)) assert.NotEmpty(t, observedEvent["id"]) for k, v := range expected { assert.Equal(t, v, observedEvent[k]) } }