Skip to content

Commit 6889bed

Browse files
committed
test catalogd api returns jsonl format, cleanup
This adds additional unit test cases to make sure catalogd web api returns data in valid jsonl format both when serving via /all and /metas endpoints. Additionally, it: - removes unused suite_test.go and - fixes a typo in storage/http_preconditions_check.go
1 parent bf13d14 commit 6889bed

File tree

3 files changed

+92
-35
lines changed

3 files changed

+92
-35
lines changed
File renamed without changes.

catalogd/internal/storage/localdir_test.go

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package storage
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"fmt"
@@ -15,7 +16,10 @@ import (
1516
"testing"
1617
"testing/fstest"
1718

19+
"github.com/stretchr/testify/assert"
1820
"github.com/stretchr/testify/require"
21+
22+
"github.com/operator-framework/operator-registry/alpha/declcfg"
1923
)
2024

2125
const urlPrefix = "/catalogs/"
@@ -169,15 +173,45 @@ func TestLocalDirStoraget(t *testing.T) {
169173
}
170174

171175
func TestLocalDirServerHandler(t *testing.T) {
176+
testMultiLineData := `{
177+
"defaultChannel": "stable-v6.x",
178+
"name": "cockroachdb",
179+
"schema": "olm.package"
180+
}
181+
{
182+
"entries": [
183+
{
184+
"name": "cockroachdb.v5.0.3"
185+
},
186+
{
187+
"name": "cockroachdb.v5.0.4",
188+
"replaces": "cockroachdb.v5.0.3"
189+
}
190+
],
191+
"name": "stable-5.x",
192+
"package": "cockroachdb",
193+
"schema": "olm.channel"
194+
}
195+
`
196+
172197
store := &LocalDirV1{RootDir: t.TempDir(), RootURL: &url.URL{Path: urlPrefix}}
173198
testFS := fstest.MapFS{
174199
"meta.json": &fstest.MapFile{
175200
Data: []byte(`{"foo":"bar"}`),
176201
},
177202
}
203+
testMultiLineFS := fstest.MapFS{
204+
"multi-line-data.json": &fstest.MapFile{
205+
Data: []byte(testMultiLineData),
206+
},
207+
}
178208
if store.Store(context.Background(), "test-catalog", testFS) != nil {
179209
t.Fatal("failed to store test catalog and start server")
180210
}
211+
if store.Store(context.Background(), "test-multi-line-catalog", testMultiLineFS) != nil {
212+
t.Fatal("failed to store test multi-line catalog and start server")
213+
}
214+
181215
testServer := httptest.NewServer(store.StorageServerHandler())
182216
defer testServer.Close()
183217

@@ -247,6 +281,12 @@ func TestLocalDirServerHandler(t *testing.T) {
247281
expectedContent: `{"foo":"bar"}`,
248282
URLPath: "/catalogs/test-catalog/api/v1/all",
249283
},
284+
{
285+
name: "Server returns 200 and json-lines formatted data when path '/catalogs/<catalog>/api/v1/all' is queried, when catalog exists",
286+
expectedStatusCode: http.StatusOK,
287+
expectedContent: generateJSONLinesOrFail(t, []byte(testMultiLineData)),
288+
URLPath: "/catalogs/test-multi-line-catalog/api/v1/all",
289+
},
250290
} {
251291
t.Run(tc.name, func(t *testing.T) {
252292
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/%s", testServer.URL, tc.URLPath), nil)
@@ -256,11 +296,14 @@ func TestLocalDirServerHandler(t *testing.T) {
256296
require.NoError(t, err)
257297

258298
require.Equal(t, tc.expectedStatusCode, resp.StatusCode)
299+
if resp.StatusCode == http.StatusOK {
300+
assert.Equal(t, "application/jsonl", resp.Header.Get("Content-Type"))
301+
}
259302

260-
var actualContent []byte
261-
actualContent, err = io.ReadAll(resp.Body)
303+
actualContent, err := io.ReadAll(resp.Body)
262304
require.NoError(t, err)
263-
require.Equal(t, tc.expectedContent, strings.TrimSpace(string(actualContent)))
305+
306+
require.Equal(t, strings.TrimSpace(tc.expectedContent), strings.TrimSpace(string(actualContent)))
264307
require.NoError(t, resp.Body.Close())
265308
})
266309
}
@@ -322,6 +365,12 @@ func TestQueryEndpoint(t *testing.T) {
322365
expectedStatusCode: http.StatusOK,
323366
expectedContent: `{"image":"quaydock.io/namespace/bundle:0.0.3","name":"bundle.v0.0.1","package":"webhook_operator_test","properties":[{"type":"olm.bundle.object","value":{"data":"dW5pbXBvcnRhbnQK"}},{"type":"some.other","value":{"data":"arbitrary-info"}}],"relatedImages":[{"image":"testimage:latest","name":"test"}],"schema":"olm.bundle"}`,
324367
},
368+
{
369+
name: "valid query with multi-json, json-lines formatted response",
370+
queryParams: "?schema=olm.channel",
371+
expectedStatusCode: http.StatusOK,
372+
expectedContent: `{"entries":[{"name":"bundle.v0.0.1"}],"name":"preview_test","package":"webhook_operator_test","schema":"olm.channel"}` + "\n" + `{"entries":[{"name":"multi-bundle.v0.0.1"}],"name":"review_test","package":"multi_operator_test","schema":"olm.channel"}`,
373+
},
325374
{
326375
name: "query with non-existent schema",
327376
queryParams: "?schema=non_existent_schema",
@@ -354,6 +403,9 @@ func TestQueryEndpoint(t *testing.T) {
354403
defer resp.Body.Close()
355404

356405
require.Equal(t, tc.expectedStatusCode, resp.StatusCode)
406+
if resp.StatusCode == http.StatusOK {
407+
assert.Equal(t, "application/jsonl", resp.Header.Get("Content-Type"))
408+
}
357409

358410
actualContent, err := io.ReadAll(resp.Body)
359411
require.NoError(t, err)
@@ -540,12 +592,46 @@ entries:
540592
testPackageName := "webhook_operator_test"
541593
testChannelName := "preview_test"
542594

595+
testMultiPackageName := "multi_operator_test"
596+
testMultiChannelName := "review_test"
597+
testMultiBundleName := "multi-bundle.v0.0.1"
598+
543599
testPackage := fmt.Sprintf(testPackageTemplate, testPackageDefaultChannel, testPackageName)
544600
testBundle := fmt.Sprintf(testBundleTemplate, testBundleImage, testBundleName, testPackageName, testBundleRelatedImageName, testBundleRelatedImageImage, testBundleObjectData)
545601
testChannel := fmt.Sprintf(testChannelTemplate, testPackageName, testChannelName, testBundleName)
602+
testMultiChannel := fmt.Sprintf(testChannelTemplate, testMultiPackageName, testMultiChannelName, testMultiBundleName)
546603
return &fstest.MapFS{
547-
"bundle.yaml": {Data: []byte(testBundle), Mode: os.ModePerm},
548-
"package.yaml": {Data: []byte(testPackage), Mode: os.ModePerm},
549-
"channel.yaml": {Data: []byte(testChannel), Mode: os.ModePerm},
604+
"bundle.yaml": {Data: []byte(testBundle), Mode: os.ModePerm},
605+
"package.yaml": {Data: []byte(testPackage), Mode: os.ModePerm},
606+
"channel.yaml": {Data: []byte(testChannel), Mode: os.ModePerm},
607+
"multi-channel.yaml": {Data: []byte(testMultiChannel), Mode: os.ModePerm},
550608
}
551609
}
610+
611+
// generateJSONLinesOrFail takes a byte slice of concatenated JSON objects and returns a JSONlines-formatted string
612+
// or raises a test failure in case of encountering any internal errors
613+
func generateJSONLinesOrFail(t *testing.T, in []byte) string {
614+
var out strings.Builder
615+
reader := bytes.NewReader(in)
616+
617+
err := declcfg.WalkMetasReader(reader, func(meta *declcfg.Meta, err error) error {
618+
if err != nil {
619+
return err
620+
}
621+
622+
if meta != nil && meta.Blob != nil {
623+
if meta.Blob[len(meta.Blob)-1] != '\n' {
624+
return fmt.Errorf("blob does not end with newline")
625+
}
626+
}
627+
628+
_, err = out.Write(meta.Blob)
629+
if err != nil {
630+
return err
631+
}
632+
return nil
633+
})
634+
require.NoError(t, err)
635+
636+
return out.String()
637+
}

catalogd/internal/storage/suite_test.go

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)