Skip to content

Commit aef513b

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 aef513b

File tree

3 files changed

+91
-35
lines changed

3 files changed

+91
-35
lines changed
File renamed without changes.

catalogd/internal/storage/localdir_test.go

Lines changed: 91 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,45 @@ 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+
// generateJSONLines takes a byte slice of concatenated JSON objects and returns a JSONlines-formatted string.
612+
func generateJSONLinesOrFail(t *testing.T, in []byte) string {
613+
var out strings.Builder
614+
reader := bytes.NewReader(in)
615+
616+
err := declcfg.WalkMetasReader(reader, func(meta *declcfg.Meta, err error) error {
617+
if err != nil {
618+
return err
619+
}
620+
621+
if meta != nil && meta.Blob != nil {
622+
if meta.Blob[len(meta.Blob)-1] != '\n' {
623+
return fmt.Errorf("blob does not end with newline")
624+
}
625+
}
626+
627+
_, err = out.Write(meta.Blob)
628+
if err != nil {
629+
return err
630+
}
631+
return nil
632+
})
633+
require.NoError(t, err)
634+
635+
return out.String()
636+
}

catalogd/internal/storage/suite_test.go

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

0 commit comments

Comments
 (0)