diff options
Diffstat (limited to 'cmd/mbf/internal/pkgserver/api_test.go')
| -rw-r--r-- | cmd/mbf/internal/pkgserver/api_test.go | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/cmd/mbf/internal/pkgserver/api_test.go b/cmd/mbf/internal/pkgserver/api_test.go new file mode 100644 index 00000000..8449c234 --- /dev/null +++ b/cmd/mbf/internal/pkgserver/api_test.go @@ -0,0 +1,181 @@ +package pkgserver + +import ( + "net/http" + "net/http/httptest" + "slices" + "strconv" + "testing" + + "hakurei.app/internal/info" + "hakurei.app/internal/rosa" +) + +// prefix is prepended to every API path. +const prefix = "/api/" + apiVersion + "/" + +func TestAPIInfo(t *testing.T) { + t.Parallel() + + w := httptest.NewRecorder() + handleInfo(w, httptest.NewRequestWithContext( + t.Context(), + http.MethodGet, + prefix+"info", + nil, + )) + + resp := w.Result() + checkStatus(t, resp, http.StatusOK) + checkAPIHeader(t, w.Header()) + + checkPayload(t, resp, struct { + Count int `json:"count"` + HakureiVersion string `json:"hakurei_version"` + }{int(rosa.PresetUnexportedStart), info.Version()}) +} + +func TestAPIGet(t *testing.T) { + t.Parallel() + const target = prefix + "get" + + index := newIndex(t) + newRequest := func(suffix string) *httptest.ResponseRecorder { + w := httptest.NewRecorder() + index.handleGet(w, httptest.NewRequestWithContext( + t.Context(), + http.MethodGet, + target+suffix, + nil, + )) + return w + } + + checkValidate := func(t *testing.T, suffix string, vmin, vmax int, wantErr string) { + t.Run("invalid", func(t *testing.T) { + t.Parallel() + + w := newRequest("?" + suffix + "=invalid") + resp := w.Result() + checkError(t, resp, wantErr, http.StatusBadRequest) + }) + + t.Run("min", func(t *testing.T) { + t.Parallel() + + w := newRequest("?" + suffix + "=" + strconv.Itoa(vmin-1)) + resp := w.Result() + checkError(t, resp, wantErr, http.StatusBadRequest) + + w = newRequest("?" + suffix + "=" + strconv.Itoa(vmin)) + resp = w.Result() + checkStatus(t, resp, http.StatusOK) + }) + + t.Run("max", func(t *testing.T) { + t.Parallel() + + w := newRequest("?" + suffix + "=" + strconv.Itoa(vmax+1)) + resp := w.Result() + checkError(t, resp, wantErr, http.StatusBadRequest) + + w = newRequest("?" + suffix + "=" + strconv.Itoa(vmax)) + resp = w.Result() + checkStatus(t, resp, http.StatusOK) + }) + } + + t.Run("limit", func(t *testing.T) { + t.Parallel() + checkValidate( + t, "index=0&sort=0&limit", 1, 100, + "limit must be an integer between 1 and 100", + ) + }) + + t.Run("index", func(t *testing.T) { + t.Parallel() + checkValidate( + t, "limit=1&sort=0&index", 0, int(rosa.PresetUnexportedStart-1), + "index must be an integer between 0 and "+strconv.Itoa(int(rosa.PresetUnexportedStart-1)), + ) + }) + + t.Run("sort", func(t *testing.T) { + t.Parallel() + checkValidate( + t, "index=0&limit=1&sort", 0, int(sortOrderEnd), + "sort must be an integer between 0 and "+strconv.Itoa(int(sortOrderEnd)), + ) + }) + + checkWithSuffix := func(name, suffix string, want []*metadata) { + t.Run(name, func(t *testing.T) { + t.Parallel() + + w := newRequest(suffix) + resp := w.Result() + checkStatus(t, resp, http.StatusOK) + checkAPIHeader(t, w.Header()) + checkPayloadFunc(t, resp, func(got *struct { + Values []*metadata `json:"values"` + }) bool { + return slices.EqualFunc(got.Values, want, func(a, b *metadata) bool { + return (a.Version == b.Version || + a.Version == rosa.Unversioned || + b.Version == rosa.Unversioned) && + a.HasReport == b.HasReport && + a.Name == b.Name && + a.Description == b.Description && + a.Website == b.Website + }) + }) + + }) + } + + checkWithSuffix("declarationAscending", "?limit=2&index=1&sort=0", []*metadata{ + { + Metadata: rosa.GetMetadata(1), + Version: rosa.Std.Version(1), + }, + { + Metadata: rosa.GetMetadata(2), + Version: rosa.Std.Version(2), + }, + }) + checkWithSuffix("declarationAscending offset", "?limit=3&index=5&sort=0", []*metadata{ + { + Metadata: rosa.GetMetadata(5), + Version: rosa.Std.Version(5), + }, + { + Metadata: rosa.GetMetadata(6), + Version: rosa.Std.Version(6), + }, + { + Metadata: rosa.GetMetadata(7), + Version: rosa.Std.Version(7), + }, + }) + checkWithSuffix("declarationDescending", "?limit=3&index=0&sort=1", []*metadata{ + { + Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 1), + Version: rosa.Std.Version(rosa.PresetUnexportedStart - 1), + }, + { + Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 2), + Version: rosa.Std.Version(rosa.PresetUnexportedStart - 2), + }, + { + Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 3), + Version: rosa.Std.Version(rosa.PresetUnexportedStart - 3), + }, + }) + checkWithSuffix("declarationDescending offset", "?limit=1&index=37&sort=1", []*metadata{ + { + Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 38), + Version: rosa.Std.Version(rosa.PresetUnexportedStart - 38), + }, + }) +} |
