From 6ad5e64a4b318154e24b61b749efdcc1700f3c9c Mon Sep 17 00:00:00 2001 From: Gorka Guridi Date: Fri, 3 May 2024 12:17:04 +0100 Subject: [PATCH] Allow loading an external JSON in addition to load vendor list from URL. (#4) --- cmp/cmp_test.json | 17 +++++++++++++++++ cmp/loader.go | 41 +++++++++++++++++++++++++++++++++-------- cmp/loader_test.go | 28 +++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 cmp/cmp_test.json diff --git a/cmp/cmp_test.json b/cmp/cmp_test.json new file mode 100644 index 0000000..c446476 --- /dev/null +++ b/cmp/cmp_test.json @@ -0,0 +1,17 @@ +{ + "lastUpdated": "2024-05-03T00:00:00Z", + "cmps": { + "1": { + "id": 1, + "name": "CMP #1", + "isCommercial": true, + "environments": ["Web"] + }, + "2": { + "id": 2, + "name": "CMP #2", + "isCommercial": false, + "environments": ["Smartphone"] + } + } +} diff --git a/cmp/loader.go b/cmp/loader.go index bdcb4d8..bee59ee 100644 --- a/cmp/loader.go +++ b/cmp/loader.go @@ -2,6 +2,7 @@ package cmp import ( "encoding/json" + "io" "net/http" "golang.org/x/exp/maps" @@ -20,7 +21,8 @@ type Option func(loader *Loader) // Loader is the type that contains the logic to load and parse a CMP JSON list. type Loader struct { - URL string + URL string + JSON string } // CMP contains the structure of the CMP info that comes inside the JSON @@ -38,6 +40,14 @@ func WithURL(url string) Option { } } +// WithJSON allows to pass a JSON string loaded externally so our loader +// will parse the cmp-list JSON format for you. +func WithJSON(json string) Option { + return func(cmp *Loader) { + cmp.JSON = json + } +} + // NewLoader returns a CMP vendor list loader instance. func NewLoader(options ...Option) *Loader { loader := &Loader{ @@ -50,26 +60,41 @@ func NewLoader(options ...Option) *Loader { } // Unmarshal parses the JSON vendor list into a struct so we can use them. -func (loader *Loader) Unmarshal(response *http.Response) ([]CMP, error) { +func (loader *Loader) Unmarshal(data []byte) ([]CMP, error) { type Response struct { CMPS map[string]CMP `json:"cmps"` } - data := Response{} - if err := json.NewDecoder(response.Body).Decode(&data); err != nil { + response := Response{} + if err := json.Unmarshal(data, &response); err != nil { return []CMP{}, err } - return maps.Values(data.CMPS), nil + return maps.Values(response.CMPS), nil } -// Load is used to load the vendor list into a list of CMP information. -func (loader *Loader) Load() ([]CMP, error) { +// LoadHTTP is used to load the vendor list from a HTTP url. +func (loader *Loader) LoadHTTP() ([]CMP, error) { response, err := http.Get(loader.URL) if err == nil { - return loader.Unmarshal(response) + if data, err := io.ReadAll(response.Body); err == nil { + return loader.Unmarshal(data) + } } return []CMP{}, err } +// LoadJSON is used to load the vendor list from a received JSON string. +func (loader *Loader) LoadJSON() ([]CMP, error) { + return loader.Unmarshal([]byte(loader.JSON)) +} + +// Load decides which CMP list we are going to load. +func (loader *Loader) Load() ([]CMP, error) { + if loader.JSON != "" { + return loader.LoadJSON() + } + return loader.LoadHTTP() +} + // LoadIDs loads the list of vendor CMP ids globally so we can reuse it // with subsequent calls. func (loader *Loader) LoadIDs() error { diff --git a/cmp/loader_test.go b/cmp/loader_test.go index f53e57f..e9e209b 100644 --- a/cmp/loader_test.go +++ b/cmp/loader_test.go @@ -1,6 +1,8 @@ package cmp_test import ( + "os" + "github.com/hybridtheory/iab-tcf/cmp" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -27,13 +29,37 @@ var _ = Describe("Loader", func() { BeforeEach(func() { loader = cmp.NewLoader(cmp.WithURL(testURL)) + err = loader.LoadIDs() + }) + + It("triggers an error because the url is not found", func() { + Expect(err).To(HaveOccurred()) }) It("is used to retrieve the JSON", func() { - _, err = loader.Load() Expect(err).Should(MatchError(MatchRegexp("lookup unknown-url"))) }) }) + + Context("with json", func() { + const ( + testJSONFile = "cmp_test.json" + ) + + BeforeEach(func() { + contents, _ := os.ReadFile(testJSONFile) + loader = cmp.NewLoader(cmp.WithJSON(string(contents))) + err = loader.LoadIDs() + }) + + It("does not trigger an error", func() { + Expect(err).ToNot(HaveOccurred()) + }) + + It("is used to parse the JSON", func() { + Expect(cmp.ValidCMPs).Should(Equal([]int{1, 2})) + }) + }) }) Describe("load", func() {