Skip to content

Commit

Permalink
Add some unit tests for the resource handler
Browse files Browse the repository at this point in the history
This patch adds some unit tests for the resource handler.

Signed-off-by: Juan Hernandez <[email protected]>
  • Loading branch information
jhernand committed Nov 22, 2023
1 parent 1f506f3 commit 08520a6
Show file tree
Hide file tree
Showing 7 changed files with 454 additions and 17 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ require (
github.com/onsi/ginkgo/v2 v2.13.0
github.com/onsi/gomega v1.29.0
go.uber.org/mock v0.3.0
k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf
)

require (
github.com/PaesslerAG/gval v1.0.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/stretchr/testify v1.8.2 // indirect
Expand All @@ -28,6 +30,7 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/itchyny/gojq v0.12.13
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
golang.org/x/net v0.18.0
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down Expand Up @@ -82,3 +86,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf h1:iTzha1p7Fi83476ypNSz8nV9iR9932jIIs26F7gNLsU=
k8s.io/utils v0.0.0-20231121161247-cf03d44ff3cf/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
4 changes: 2 additions & 2 deletions internal/data/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
// Object represents an object containing a list of fields, each with a name and a value.
type Object = map[string]any

// List represents a list of objecs.
type List = []any
// Array represents a list of objecs.
type Array = []any

func GetString(o Object, path string) (result string, err error) {
value, err := jsonpath.Get(path, o)
Expand Down
20 changes: 14 additions & 6 deletions internal/service/deployment_manager_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

. "github.com/onsi/ginkgo/v2/dsl/core"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/ghttp"
. "github.com/onsi/gomega/ghttp"

"github.com/openshift-kni/oran-o2ims/internal/data"
Expand Down Expand Up @@ -112,6 +113,15 @@ var _ = Describe("Deployment manager handler", func() {
backend.Close()
})

// RespondWithList creates a handler that responds with the given search results.
var RespondWithList = func(items ...data.Object) http.HandlerFunc {
return ghttp.RespondWithJSONEncoded(http.StatusOK, data.Object{
"apiVersion": "v1",
"kind": "List",
"items": items,
})
}

Describe("List", func() {
It("Uses the configured token", func() {
// Prepare a backend:
Expand Down Expand Up @@ -146,9 +156,7 @@ var _ = Describe("Deployment manager handler", func() {
It("Translates empty list of results", func() {
// Prepare a backend:
backend.AppendHandlers(
CombineHandlers(
RespondWithList(),
),
RespondWithList(),
)

// Send the request and verify the result:
Expand All @@ -173,7 +181,7 @@ var _ = Describe("Deployment manager handler", func() {
},
},
"spec": data.Object{
"managedClusterClientConfigs": data.List{
"managedClusterClientConfigs": data.Array{
data.Object{
"url": "https://my-cluster:6443",
},
Expand All @@ -188,7 +196,7 @@ var _ = Describe("Deployment manager handler", func() {
},
},
"spec": data.Object{
"managedClusterClientConfigs": data.List{
"managedClusterClientConfigs": data.Array{
data.Object{
"url": "https://your-cluster:6443",
},
Expand Down Expand Up @@ -270,7 +278,7 @@ var _ = Describe("Deployment manager handler", func() {
},
},
"spec": data.Object{
"managedClusterClientConfigs": data.List{
"managedClusterClientConfigs": data.Array{
data.Object{
"url": "https://my-cluster:6443",
},
Expand Down
282 changes: 282 additions & 0 deletions internal/service/resource_pool_handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
/*
Copyright (c) 2023 Red Hat, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing permissions and limitations under the
License.
*/

package service

import (
"context"
"net/http"

. "github.com/onsi/ginkgo/v2/dsl/core"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/ghttp"
"k8s.io/utils/ptr"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/searchapi"
. "github.com/openshift-kni/oran-o2ims/internal/testing"
"github.com/openshift-kni/oran-o2ims/internal/text"
)

var _ = Describe("Resource pool handler", func() {
Describe("Creation", func() {
It("Can't be created without a logger", func() {
handler, err := NewResourcePoolHandler().
SetCloudID("123").
SetBackendURL("https://my-backend:6443").
SetBackendToken("my-token").
Build()
Expect(err).To(HaveOccurred())
Expect(handler).To(BeNil())
msg := err.Error()
Expect(msg).To(ContainSubstring("logger"))
Expect(msg).To(ContainSubstring("mandatory"))
})

It("Can't be created without a cloud identifier", func() {
handler, err := NewResourcePoolHandler().
SetLogger(logger).
SetBackendURL("https://my-backend:6443").
SetBackendToken("my-token").
Build()
Expect(err).To(HaveOccurred())
Expect(handler).To(BeNil())
msg := err.Error()
Expect(msg).To(ContainSubstring("cloud identifier"))
Expect(msg).To(ContainSubstring("mandatory"))
})

It("Can't be created without a backend URL", func() {
handler, err := NewResourcePoolHandler().
SetLogger(logger).
SetCloudID("123").
SetBackendToken("my-token").
Build()
Expect(err).To(HaveOccurred())
Expect(handler).To(BeNil())
msg := err.Error()
Expect(msg).To(ContainSubstring("backend URL"))
Expect(msg).To(ContainSubstring("mandatory"))
})

It("Can't be created without a backend token", func() {
handler, err := NewResourcePoolHandler().
SetLogger(logger).
SetCloudID("123").
SetBackendURL("https://my-backend:6443").
Build()
Expect(err).To(HaveOccurred())
Expect(handler).To(BeNil())
msg := err.Error()
Expect(msg).To(ContainSubstring("backend token"))
Expect(msg).To(ContainSubstring("mandatory"))
})
})

Describe("Behaviour", func() {
var (
ctx context.Context
backend *Server
handler *ResourcePoolHandler
)

BeforeEach(func() {
var err error

// Create a context:
ctx = context.Background()

// Create the backend server:
backend = MakeTCPServer()

// Create the handler:
handler, err = NewResourcePoolHandler().
SetLogger(logger).
SetCloudID("123").
SetBackendURL(backend.URL()).
SetBackendToken("my-token").
SetGraphqlQuery(text.Dedent(`
query ($input: [SearchInput]) {
searchResult: search(input: $input) {
items,
related {
items
},
}
}
`)).
SetGraphqlVars(&searchapi.SearchInput{
Filters: []*searchapi.SearchFilter{
{
Property: "kind",
Values: []*string{
ptr.To("cluster"),
},
},
},
RelatedKinds: []*string{
ptr.To("Node"),
},
}).
Build()
Expect(err).ToNot(HaveOccurred())
Expect(handler).ToNot(BeNil())
})

AfterEach(func() {
backend.Close()
})

// RespondWithItems creates a handler that responds with the given search results.
var RespondWithItems = func(items ...data.Object) http.HandlerFunc {
return RespondWithObject(data.Object{
"data": data.Object{
"searchResult": data.Array{
data.Object{
"items": items,
"related": data.Array{
data.Object{
"items": data.Array{},
},
},
},
},
},
})
}

Describe("List", func() {
It("Uses the configured token", func() {
// Prepare a backend:
backend.AppendHandlers(
CombineHandlers(
VerifyHeaderKV("Authorization", "Bearer my-token"),
RespondWithItems(),
),
)

// Send the request. Note that we ignore the error here because
// all we care about in this test is that it sends the token, no
// matter what is the result.
_, _ = handler.List(ctx, &ListRequest{})
})

It("Translates empty list of results", func() {
// Prepare the backend:
backend.AppendHandlers(
RespondWithItems(),
)

// Send the request and verify the result:
response, err := handler.List(ctx, &ListRequest{})
Expect(err).ToNot(HaveOccurred())
Expect(response).ToNot(BeNil())
items, err := data.Collect(ctx, response.Items)
Expect(err).ToNot(HaveOccurred())
Expect(items).To(BeEmpty())
})

It("Translates non empty list of results", func() {
// Prepare the backend:
backend.AppendHandlers(
RespondWithItems(
data.Object{
"cluster": "0",
"label": "a=b; c=d",
"name": "my-cluster-0",
},
data.Object{
"cluster": "1",
"label": "a=b; c=d",
"name": "my-cluster-1",
},
),
)

// Send the request:
response, err := handler.List(ctx, &ListRequest{})
Expect(err).ToNot(HaveOccurred())
Expect(response).ToNot(BeNil())
items, err := data.Collect(ctx, response.Items)
Expect(err).ToNot(HaveOccurred())
Expect(items).To(HaveLen(2))

// Verify first result:
Expect(items[0]).To(MatchJQ(`.description`, ""))
Expect(items[0]).To(MatchJQ(`.globalLocationID`, ""))
Expect(items[0]).To(MatchJQ(`.location`, ""))
Expect(items[0]).To(MatchJQ(`.name`, "my-cluster-0"))
Expect(items[0]).To(MatchJQ(`.oCloudID`, "123"))
Expect(items[0]).To(MatchJQ(`.resourcePoolID`, "0"))

// Verify second result:
Expect(items[1]).To(MatchJQ(`.description`, ""))
Expect(items[1]).To(MatchJQ(`.globalLocationID`, ""))
Expect(items[1]).To(MatchJQ(`.location`, ""))
Expect(items[1]).To(MatchJQ(`.name`, "my-cluster-1"))
Expect(items[1]).To(MatchJQ(`.oCloudID`, "123"))
Expect(items[1]).To(MatchJQ(`.resourcePoolID`, "1"))
})
})

Describe("Get", func() {
It("Uses the configured token", func() {
// Prepare a backend:
backend.AppendHandlers(
CombineHandlers(
VerifyHeaderKV("Authorization", "Bearer my-token"),
RespondWithItems(),
),
)

// Send the request. Note that we ignore the error here because
// all we care about in this test is that it sends the token, no
// matter what is the response.
_, _ = handler.Get(ctx, &GetRequest{
ID: "123",
})
})

It("Translates result", func() {
// Prepare a backend:
backend.AppendHandlers(
CombineHandlers(
RespondWithItems(
data.Object{
"cluster": "0",
"label": "a=b; c=d",
"name": "my-cluster-0",
},
),
),
)

// Send the request:
response, err := handler.Get(ctx, &GetRequest{
ID: "0",
})
Expect(err).ToNot(HaveOccurred())
Expect(response).ToNot(BeNil())

// Verify the result:
Expect(response.Object).To(MatchJQ(`.description`, ""))
Expect(response.Object).To(MatchJQ(`.globalLocationID`, ""))
Expect(response.Object).To(MatchJQ(`.location`, ""))
Expect(response.Object).To(MatchJQ(`.name`, "my-cluster-0"))
Expect(response.Object).To(MatchJQ(`.oCloudID`, "123"))
Expect(response.Object).To(MatchJQ(`.resourcePoolID`, "0"))
})
})
})
})
Loading

0 comments on commit 08520a6

Please sign in to comment.