Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit 02072ac

Browse files
authoredSep 9, 2024
Merge pull request #16 from grafana/refactor-catalog-constructors
refactor catalog constructors
2 parents 45e79d2 + 0436454 commit 02072ac

File tree

5 files changed

+137
-119
lines changed

5 files changed

+137
-119
lines changed
 

‎.golangci.yml

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ issues:
2424
- gocognit
2525
- funlen
2626
- lll
27+
- forbidigo
28+
- gosec
2729
- path: js\/modules\/k6\/http\/.*_test\.go
2830
linters:
2931
# k6/http module's tests are quite complex because they often have several nested levels.

‎catalog.go

+52-32
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
package k6catalog
33

44
import (
5+
"bytes"
56
"context"
7+
"encoding/json"
68
"errors"
79
"fmt"
810
"io"
@@ -18,10 +20,13 @@ const (
1820
)
1921

2022
var (
21-
ErrCannotSatisfy = errors.New("cannot satisfy dependency") //nolint:revive
22-
ErrInvalidConstrain = errors.New("invalid constrain") //nolint:revive
23-
ErrUnknownDependency = errors.New("unknown dependency") //nolint:revive
24-
ErrDownload = errors.New("downloading catalog") //nolint:revive
23+
ErrCannotSatisfy = errors.New("cannot satisfy dependency") //nolint:revive
24+
ErrDownload = errors.New("downloading catalog") //nolint:revive
25+
ErrInvalidConstrain = errors.New("invalid constrain") //nolint:revive
26+
ErrInvalidCatalog = fmt.Errorf("invalid catalog") //nolint:revive
27+
ErrOpening = errors.New("opening catalog") //nolint:revive
28+
ErrUnknownDependency = errors.New("unknown dependency") //nolint:revive
29+
ErrDependencyNotFound = fmt.Errorf("dependency not found in registry") //nolint:revive
2530
)
2631

2732
// Dependency defines a Dependency with a version constrain
@@ -45,22 +50,54 @@ type Catalog interface {
4550
Resolve(ctx context.Context, dep Dependency) (Module, error)
4651
}
4752

53+
// entry defines a catalog entry
54+
type entry struct {
55+
Module string `json:"module,omitempty"`
56+
Versions []string `json:"versions,omitempty"`
57+
}
58+
4859
type catalog struct {
49-
registry Registry
60+
dependencies map[string]entry
5061
}
5162

52-
// NewCatalog creates a catalog from a registry
53-
func NewCatalog(registry Registry) Catalog {
54-
return catalog{registry: registry}
63+
// getVersions returns the versions for a given module
64+
func (c catalog) getVersions(_ context.Context, mod string) (entry, error) {
65+
e, found := c.dependencies[mod]
66+
if !found {
67+
return entry{}, fmt.Errorf("%w : %s", ErrDependencyNotFound, mod)
68+
}
69+
70+
return e, nil
5571
}
5672

5773
// NewCatalogFromJSON creates a Catalog from a json file
58-
func NewCatalogFromJSON(catalogFile string) (Catalog, error) {
59-
registry, err := loadRegistryFromJSON(catalogFile)
74+
func NewCatalogFromJSON(stream io.Reader) (Catalog, error) {
75+
buff := &bytes.Buffer{}
76+
_, err := buff.ReadFrom(stream)
77+
if err != nil {
78+
return nil, fmt.Errorf("%w: %w", ErrInvalidCatalog, err)
79+
}
80+
81+
dependencies := map[string]entry{}
82+
err = json.Unmarshal(buff.Bytes(), &dependencies)
6083
if err != nil {
61-
return nil, err
84+
return nil, fmt.Errorf("%w: %w", ErrInvalidCatalog, err)
6285
}
63-
return catalog{registry: registry}, nil
86+
87+
return catalog{
88+
dependencies: dependencies,
89+
}, nil
90+
}
91+
92+
// NewCatalogFromFile creates a Catalog from a json file
93+
func NewCatalogFromFile(catalogFile string) (Catalog, error) {
94+
json, err := os.ReadFile(catalogFile) //nolint:forbidigo,gosec
95+
if err != nil {
96+
return nil, fmt.Errorf("%w: %w", ErrOpening, err)
97+
}
98+
99+
buff := bytes.NewBuffer(json)
100+
return NewCatalogFromJSON(buff)
64101
}
65102

66103
// NewCatalogFromURL creates a Catalog from a URL
@@ -80,24 +117,7 @@ func NewCatalogFromURL(ctx context.Context, catalogURL string) (Catalog, error)
80117
return nil, fmt.Errorf("%w %s", ErrDownload, resp.Status)
81118
}
82119

83-
catalogFile, err := os.CreateTemp("", "catalog*.json") //nolint:forbidigo
84-
if err != nil {
85-
return nil, fmt.Errorf("%w %w", ErrDownload, err)
86-
}
87-
88-
_, err = io.Copy(catalogFile, resp.Body)
89-
if err != nil {
90-
_ = catalogFile.Close()
91-
_ = os.Remove(catalogFile.Name()) //nolint:forbidigo
92-
return nil, fmt.Errorf("%w %w", ErrDownload, err)
93-
}
94-
95-
err = catalogFile.Close()
96-
if err != nil {
97-
return nil, fmt.Errorf("%w %w", ErrDownload, err)
98-
}
99-
100-
catalog, err := NewCatalogFromJSON(catalogFile.Name())
120+
catalog, err := NewCatalogFromJSON(resp.Body)
101121
if err != nil {
102122
return nil, fmt.Errorf("%w %w", ErrDownload, err)
103123
}
@@ -107,11 +127,11 @@ func NewCatalogFromURL(ctx context.Context, catalogURL string) (Catalog, error)
107127

108128
// DefaultCatalog creates a Catalog from the default json file 'catalog.json'
109129
func DefaultCatalog() (Catalog, error) {
110-
return NewCatalogFromJSON(defaultCatalogFile)
130+
return NewCatalogFromFile(defaultCatalogFile)
111131
}
112132

113133
func (c catalog) Resolve(ctx context.Context, dep Dependency) (Module, error) {
114-
entry, err := c.registry.GetVersions(ctx, dep.Name)
134+
entry, err := c.getVersions(ctx, dep.Name)
115135
if err != nil {
116136
return Module{}, err
117137
}

‎catalog_test.go

+82-29
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
11
package k6catalog
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
6-
"fmt"
77
"net/http"
88
"net/http/httptest"
9+
"os"
10+
"path/filepath"
911
"testing"
1012
)
1113

12-
type fakeRegistry struct {
13-
entries map[string]Entry
14-
}
15-
16-
func (r fakeRegistry) GetVersions(_ context.Context, dep string) (Entry, error) {
17-
e, found := r.entries[dep]
18-
if !found {
19-
return Entry{}, fmt.Errorf("entry not found : %s", dep)
20-
}
21-
22-
return Entry{Module: e.Module, Versions: e.Versions}, nil
23-
}
14+
const (
15+
testCatalog = `{ "dep": {"Module": "github.com/dep", "Versions": ["v0.1.0", "v0.2.0"]}}`
16+
invalidCatalog = `{ "dep": {}}`
17+
)
2418

2519
func TestResolve(t *testing.T) {
2620
t.Parallel()
@@ -53,13 +47,11 @@ func TestResolve(t *testing.T) {
5347
},
5448
}
5549

56-
registry := fakeRegistry{
57-
entries: map[string]Entry{
58-
"dep": {Module: "github.com/dep", Versions: []string{"v0.1.0", "v0.2.0"}},
59-
},
50+
json := bytes.NewBuffer([]byte(testCatalog))
51+
catalog, err := NewCatalogFromJSON(json)
52+
if err != nil {
53+
t.Fatalf("test setup %v", err)
6054
}
61-
62-
catalog := NewCatalog(registry)
6355
for _, tc := range testCases {
6456
tc := tc
6557

@@ -78,9 +70,38 @@ func TestResolve(t *testing.T) {
7870
}
7971
}
8072

81-
const testCatalog = `{
82-
"k6/x/output-kafka": {"Module": "github.com/grafana/xk6-output-kafka", "Versions": ["v0.1.0", "v0.2.0"]}
83-
}`
73+
func TestCatalogFromJSON(t *testing.T) {
74+
t.Parallel()
75+
76+
testCases := []struct {
77+
name string
78+
json string
79+
expectErr error
80+
}{
81+
{
82+
name: "load json",
83+
json: testCatalog,
84+
expectErr: nil,
85+
},
86+
{
87+
name: "empty json",
88+
json: "",
89+
expectErr: ErrInvalidCatalog,
90+
},
91+
}
92+
93+
for _, tc := range testCases {
94+
t.Run(tc.name, func(t *testing.T) {
95+
t.Parallel()
96+
97+
json := bytes.NewBuffer([]byte(tc.json))
98+
_, err := NewCatalogFromJSON(json)
99+
if !errors.Is(err, tc.expectErr) {
100+
t.Fatalf("expected %v got %v", tc.expectErr, err)
101+
}
102+
})
103+
}
104+
}
84105

85106
func TestCatalogFromURL(t *testing.T) {
86107
t.Parallel()
@@ -104,13 +125,6 @@ func TestCatalogFromURL(t *testing.T) {
104125
},
105126
expectErr: ErrDownload,
106127
},
107-
{
108-
name: "empty catalog",
109-
handler: func(w http.ResponseWriter, _ *http.Request) {
110-
w.WriteHeader(http.StatusOK)
111-
},
112-
expectErr: ErrInvalidRegistry,
113-
},
114128
}
115129

116130
for _, tc := range testCases {
@@ -127,3 +141,42 @@ func TestCatalogFromURL(t *testing.T) {
127141
})
128142
}
129143
}
144+
145+
func TestCatalogFromFile(t *testing.T) {
146+
t.Parallel()
147+
148+
catalogFile := filepath.Join(t.TempDir(), "catalog.json")
149+
err := os.WriteFile(catalogFile, []byte(testCatalog), 0o644)
150+
if err != nil {
151+
t.Fatalf("test setup: %v", err)
152+
}
153+
154+
testCases := []struct {
155+
name string
156+
file string
157+
expectErr error
158+
}{
159+
{
160+
name: "open catalog",
161+
file: catalogFile,
162+
expectErr: nil,
163+
},
164+
{
165+
name: "catalog not found",
166+
file: "/path/not/found",
167+
expectErr: ErrOpening,
168+
},
169+
}
170+
171+
for _, tc := range testCases {
172+
t.Run(tc.name, func(t *testing.T) {
173+
t.Parallel()
174+
175+
_, err := NewCatalogFromFile(tc.file)
176+
177+
if !errors.Is(err, tc.expectErr) {
178+
t.Fatalf("expected %v got %v", tc.expectErr, err)
179+
}
180+
})
181+
}
182+
}

‎cmd/cmd.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func New() *cobra.Command {
3939
return fmt.Errorf("path to registry must be specified")
4040
}
4141

42-
catalog, err := k6catalog.NewCatalogFromJSON(path)
42+
catalog, err := k6catalog.NewCatalogFromFile(path)
4343
if err != nil {
4444
return err
4545
}

‎registry.go

-57
This file was deleted.

0 commit comments

Comments
 (0)