Skip to content

Commit

Permalink
Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
anik120 committed Jan 24, 2025
1 parent 5cc755d commit d8dcf61
Show file tree
Hide file tree
Showing 5 changed files with 773 additions and 396 deletions.
27 changes: 15 additions & 12 deletions catalogd/internal/serverutil/serverutil.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package serverutil

import (
"context"
"crypto/tls"
"fmt"
"io"
Expand All @@ -11,9 +10,9 @@ import (

"github.com/go-logr/logr"
"github.com/gorilla/handlers"
"github.com/klauspost/compress/gzhttp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"

catalogdmetrics "github.com/operator-framework/operator-controller/catalogd/internal/metrics"
Expand Down Expand Up @@ -44,20 +43,12 @@ func AddCatalogServerToManager(mgr ctrl.Manager, cfg CatalogServerConfig, tlsFil
}

shutdownTimeout := 30 * time.Second

l := mgr.GetLogger().WithName("catalogd-http-server")
handler := catalogdmetrics.AddMetricsToHandler(cfg.LocalStorage.StorageServerHandler())
handler = logrLoggingHandler(l, handler)

catalogServer := manager.Server{
Name: "catalogs",
OnlyServeWhenLeader: true,
Server: &http.Server{
Addr: cfg.CatalogAddr,
Handler: handler,
BaseContext: func(_ net.Listener) context.Context {
return log.IntoContext(context.Background(), mgr.GetLogger().WithName("http.catalogs"))
},
Addr: cfg.CatalogAddr,
Handler: storageServerHandlerWrapped(mgr, cfg),
ReadTimeout: 5 * time.Second,
// TODO: Revert this to 10 seconds if/when the API
// evolves to have significantly smaller responses
Expand Down Expand Up @@ -102,3 +93,15 @@ func logrLoggingHandler(l logr.Logger, handler http.Handler) http.Handler {
l.Info("handled request", "host", host, "username", username, "method", params.Request.Method, "uri", uri, "protocol", params.Request.Proto, "status", params.StatusCode, "size", params.Size)
})
}

func storageServerHandlerWrapped(mgr ctrl.Manager, cfg CatalogServerConfig) http.Handler {

handler := cfg.LocalStorage.StorageServerHandler()
handler = gzhttp.GzipHandler(handler)
handler = catalogdmetrics.AddMetricsToHandler(handler)

l := mgr.GetLogger().WithName("catalogd-http-server")
handler = logrLoggingHandler(l, handler)
return handler

}
254 changes: 254 additions & 0 deletions catalogd/internal/serverutil/serverutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
package serverutil

import (
"compress/gzip"
"context"
"io"
"io/fs"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/require"
ctrl "sigs.k8s.io/controller-runtime"
)

func TestStorageServerHandlerWrapped_Gzip(t *testing.T) {
tests := []struct {
name string
acceptEncoding string
responseContent string
expectCompressed bool
expectedStatus int
}{
{
name: "compresses large response when client accepts gzip",
acceptEncoding: "gzip",
responseContent: testCompressableJSON,
expectCompressed: true,
expectedStatus: http.StatusOK,
},
{
name: "does not compress small response even when client accepts gzip",
acceptEncoding: "gzip",
responseContent: `{"foo":"bar"}`,
expectCompressed: false,
expectedStatus: http.StatusOK,
},
{
name: "does not compress when client doesn't accept gzip",
acceptEncoding: "",
responseContent: testCompressableJSON,
expectCompressed: false,
expectedStatus: http.StatusOK,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a mock storage instance that returns our test content
mockStorage := &mockStorageInstance{
content: tt.responseContent,
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
require.NoError(t, err)

cfg := CatalogServerConfig{
LocalStorage: mockStorage,
}
handler := storageServerHandlerWrapped(mgr, cfg)

// Create test request
req := httptest.NewRequest("GET", "/test", nil)
if tt.acceptEncoding != "" {
req.Header.Set("Accept-Encoding", tt.acceptEncoding)
}

// Create response recorder
rec := httptest.NewRecorder()

// Handle the request
handler.ServeHTTP(rec, req)

// Check status code
require.Equal(t, tt.expectedStatus, rec.Code)

// Check if response was compressed
wasCompressed := rec.Header().Get("Content-Encoding") == "gzip"
require.Equal(t, tt.expectCompressed, wasCompressed)

// Get the response body
var responseBody []byte
if wasCompressed {
// Decompress the response
gzipReader, err := gzip.NewReader(rec.Body)
require.NoError(t, err)
responseBody, err = io.ReadAll(gzipReader)
require.NoError(t, err)
require.NoError(t, gzipReader.Close())
} else {
responseBody = rec.Body.Bytes()
}

// Verify the response content
require.Equal(t, tt.responseContent, string(responseBody))
})
}
}

const testCompressableJSON = `{
"defaultChannel": "stable-v6.x",
"name": "cockroachdb",
"schema": "olm.package"
}
{
"entries": [
{
"name": "cockroachdb.v5.0.3"
},
{
"name": "cockroachdb.v5.0.4",
"replaces": "cockroachdb.v5.0.3"
}
],
"name": "stable-5.x",
"package": "cockroachdb",
"schema": "olm.channel"
}
{
"entries": [
{
"name": "cockroachdb.v6.0.0",
"skipRange": "<6.0.0"
}
],
"name": "stable-v6.x",
"package": "cockroachdb",
"schema": "olm.channel"
}
{
"image": "quay.io/openshift-community-operators/cockroachdb@sha256:a5d4f4467250074216eb1ba1c36e06a3ab797d81c431427fc2aca97ecaf4e9d8",
"name": "cockroachdb.v5.0.3",
"package": "cockroachdb",
"properties": [
{
"type": "olm.gvk",
"value": {
"group": "charts.operatorhub.io",
"kind": "Cockroachdb",
"version": "v1alpha1"
}
},
{
"type": "olm.package",
"value": {
"packageName": "cockroachdb",
"version": "5.0.3"
}
}
],
"relatedImages": [
{
"name": "",
"image": "quay.io/helmoperators/cockroachdb:v5.0.3"
},
{
"name": "",
"image": "quay.io/openshift-community-operators/cockroachdb@sha256:a5d4f4467250074216eb1ba1c36e06a3ab797d81c431427fc2aca97ecaf4e9d8"
}
],
"schema": "olm.bundle"
}
{
"image": "quay.io/openshift-community-operators/cockroachdb@sha256:f42337e7b85a46d83c94694638e2312e10ca16a03542399a65ba783c94a32b63",
"name": "cockroachdb.v5.0.4",
"package": "cockroachdb",
"properties": [
{
"type": "olm.gvk",
"value": {
"group": "charts.operatorhub.io",
"kind": "Cockroachdb",
"version": "v1alpha1"
}
},
{
"type": "olm.package",
"value": {
"packageName": "cockroachdb",
"version": "5.0.4"
}
}
],
"relatedImages": [
{
"name": "",
"image": "quay.io/helmoperators/cockroachdb:v5.0.4"
},
{
"name": "",
"image": "quay.io/openshift-community-operators/cockroachdb@sha256:f42337e7b85a46d83c94694638e2312e10ca16a03542399a65ba783c94a32b63"
}
],
"schema": "olm.bundle"
}
{
"image": "quay.io/openshift-community-operators/cockroachdb@sha256:d3016b1507515fc7712f9c47fd9082baf9ccb070aaab58ed0ef6e5abdedde8ba",
"name": "cockroachdb.v6.0.0",
"package": "cockroachdb",
"properties": [
{
"type": "olm.gvk",
"value": {
"group": "charts.operatorhub.io",
"kind": "Cockroachdb",
"version": "v1alpha1"
}
},
{
"type": "olm.package",
"value": {
"packageName": "cockroachdb",
"version": "6.0.0"
}
}
],
"relatedImages": [
{
"name": "",
"image": "quay.io/cockroachdb/cockroach-helm-operator:6.0.0"
},
{
"name": "",
"image": "quay.io/openshift-community-operators/cockroachdb@sha256:d3016b1507515fc7712f9c47fd9082baf9ccb070aaab58ed0ef6e5abdedde8ba"
}
],
"schema": "olm.bundle"
}
`

// mockStorageInstance implements storage.Instance interface for testing
type mockStorageInstance struct {
content string
}

func (m *mockStorageInstance) StorageServerHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(m.content))

Check failure on line 237 in catalogd/internal/serverutil/serverutil_test.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `w.Write` is not checked (errcheck)
})
}

func (m *mockStorageInstance) Store(ctx context.Context, catalogName string, fs fs.FS) error {
return nil
}

func (m *mockStorageInstance) Delete(catalogName string) error {
return nil
}

func (m *mockStorageInstance) ContentExists(catalog string) bool {
return true
}
func (m *mockStorageInstance) BaseURL(catalog string) string {
return ""
}
15 changes: 13 additions & 2 deletions catalogd/internal/storage/localdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ type LocalDirV1 struct {
sf singleflight.Group
}

var (
_ Instance = &LocalDirV1{}
ErrInvalidParams = errors.New("invalid parameters")
)

func (s *LocalDirV1) Store(ctx context.Context, catalog string, fsys fs.FS) error {
s.m.Lock()
defer s.m.Unlock()
Expand All @@ -56,9 +61,13 @@ func (s *LocalDirV1) Store(ctx context.Context, catalog string, fsys fs.FS) erro
eg, egCtx = errgroup.WithContext(ctx)
metaChans []chan *declcfg.Meta
)
for i, f := range storeMetaFuncs {
for range storeMetaFuncs {
metaChans = append(metaChans, make(chan *declcfg.Meta, 1))
eg.Go(func() error { return f(tmpCatalogDir, metaChans[i]) })
}
for i, f := range storeMetaFuncs {
eg.Go(func() error {
return f(tmpCatalogDir, metaChans[i])
})
}
err = declcfg.WalkMetasFS(egCtx, fsys, func(path string, meta *declcfg.Meta, err error) error {
if err != nil {
Expand Down Expand Up @@ -249,6 +258,8 @@ func httpError(w http.ResponseWriter, err error) {
code = http.StatusNotFound
case errors.Is(err, fs.ErrPermission):
code = http.StatusForbidden
case errors.Is(err, ErrInvalidParams):
code = http.StatusBadRequest
default:
code = http.StatusInternalServerError
}
Expand Down
Loading

0 comments on commit d8dcf61

Please sign in to comment.