package http_test import ( "context" "fmt" "io" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/maxatome/go-testdeep/td" "code.icb4dc0.de/prskr/nurse/check" "code.icb4dc0.de/prskr/nurse/grammar" httpcheck "code.icb4dc0.de/prskr/nurse/protocols/http" ) func TestChecks_Execute(t *testing.T) { t.Parallel() httpModule := httpcheck.Module() type serverResponse struct { status int body io.Reader err error } tests := []struct { name string check string resp serverResponse wantErr bool }{ { name: "GET check without validation", check: `http.GET("%s/api/books")`, resp: serverResponse{ status: 200, }, wantErr: false, }, { name: "GET check - status validation", check: `http.GET("%s/api/books") => Status(200)`, resp: serverResponse{ status: 200, }, wantErr: false, }, { name: "GET check - JSON path validation", check: `http.GET("%s/api/books") => JSONPath("$.firstName", "Homer")`, resp: serverResponse{ status: 200, body: strings.NewReader(`{"firstName": "Homer"}`), }, wantErr: false, }, { name: "GET check - Status and JSON path validation", check: `http.GET("%s/api/books") => Status(200) -> JSONPath("$.firstName", "Homer")`, resp: serverResponse{ status: 200, body: strings.NewReader(`{"firstName": "Homer"}`), }, wantErr: false, }, { name: "POST check without validation", check: `http.POST("%s/api/books")`, resp: serverResponse{ status: 204, }, wantErr: false, }, { name: "POST check - Status validation", check: `http.POST("%s/api/books") => Status(204)`, resp: serverResponse{ status: 204, }, wantErr: false, }, { name: "PUT check without validation", check: `http.PUT("%s/api/books/1")`, resp: serverResponse{ status: 200, }, wantErr: false, }, { name: "DELETE check without validation", check: `http.DELETE("%s/api/books/1")`, resp: serverResponse{ status: 200, }, wantErr: false, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() testServer := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { if tt.resp.err != nil { writer.WriteHeader(http.StatusInternalServerError) _, _ = writer.Write([]byte(tt.resp.err.Error())) return } writer.WriteHeader(tt.resp.status) if tt.resp.body != nil { _, _ = io.Copy(writer, tt.resp.body) } })) t.Cleanup(testServer.Close) parser, err := grammar.NewParser[grammar.Check]() td.CmpNoError(t, err, "grammar.NewParser()") parsedCheck, err := parser.Parse(fmt.Sprintf(tt.check, testServer.URL)) td.CmpNoError(t, err, "parser.Parse()") chk, err := httpModule.Lookup(*parsedCheck, nil) td.CmpNoError(t, err, "http.LookupCheck()") if clientInjectable, ok := chk.(httpcheck.ClientInjectable); !ok { t.Fatal("Failed to inject client to check") } else { clientInjectable.SetClient(testServer.Client()) } ctx, cancel := check.AttemptsContext(context.Background(), 100, 100*time.Millisecond) t.Cleanup(cancel) if tt.wantErr { td.CmpError(t, chk.Execute(ctx)) } else { td.CmpNoError(t, chk.Execute(ctx)) } }) } }