From 36ce810d4c4cd68dc100646e8060ec94ae846f52 Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Fri, 20 Sep 2024 08:54:22 +0200 Subject: [PATCH 01/13] replace shared-informers' methods with cached client (#461) --- cmd/main.go | 32 +- go.mod | 11 + go.sum | 776 ++++++++++++++++++ .../service/context/service_context.go | 4 +- .../service/factory/service_factory.go | 14 +- pkg/informers/informers.go | 104 --- pkg/informers/service/informer_service.go | 159 +--- .../service/informer_service_test.go | 578 ++++--------- pkg/kubeclient/client.go | 24 +- pkg/kubeclient/client_test.go | 4 +- pkg/kubeclient/signup.go | 18 +- pkg/proxy/handlers/spacelister_list.go | 9 +- pkg/proxy/proxy_test.go | 4 +- pkg/proxy/service/cluster_service_test.go | 20 +- pkg/server/in_cluster_application.go | 8 +- pkg/signup/service/signup_service_test.go | 56 +- test/fake/proxy.go | 10 +- 17 files changed, 1072 insertions(+), 759 deletions(-) delete mode 100644 pkg/informers/informers.go diff --git a/cmd/main.go b/cmd/main.go index 9713ae4b..b0e7ef96 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -11,7 +11,6 @@ import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/auth" "github.com/codeready-toolchain/registration-service/pkg/configuration" - "github.com/codeready-toolchain/registration-service/pkg/informers" "github.com/codeready-toolchain/registration-service/pkg/log" "github.com/codeready-toolchain/registration-service/pkg/proxy" "github.com/codeready-toolchain/registration-service/pkg/proxy/metrics" @@ -85,12 +84,7 @@ func main() { } } - informer, informerShutdown, err := informers.StartInformer(cfg) - if err != nil { - panic(err.Error()) - } - - app, err := server.NewInClusterApplication(*informer) + app, err := server.NewInClusterApplication(cl) if err != nil { panic(err.Error()) } @@ -121,11 +115,6 @@ func main() { } proxySrv := p.StartProxy(proxy.DefaultPort) - // stop the informer when proxy server shuts down - proxySrv.RegisterOnShutdown(func() { - informerShutdown <- struct{}{} - }) - // --------------------------------------------- // Registration Service // --------------------------------------------- @@ -202,9 +191,22 @@ func newCachedClient(ctx context.Context, cfg *rest.Config) (client.Client, erro // populate the cache backed by shared informers that are initialized lazily on the first call // for the given GVK with all resources we are interested in from the host-operator namespace - objectsToList := []client.ObjectList{&toolchainv1alpha1.ToolchainConfigList{}, &corev1.SecretList{}} - for i := range objectsToList { - if err := hostCluster.GetClient().List(ctx, objectsToList[i], client.InNamespace(configuration.Namespace())); err != nil { + objectsToList := map[string]client.ObjectList{ + "MasterUserRecord": &toolchainv1alpha1.MasterUserRecordList{}, + "Space": &toolchainv1alpha1.SpaceList{}, + "SpaceBinding": &toolchainv1alpha1.SpaceBindingList{}, + "ToolchainStatus": &toolchainv1alpha1.ToolchainStatusList{}, + "UserSignup": &toolchainv1alpha1.UserSignupList{}, + "ProxyPlugin": &toolchainv1alpha1.ProxyPluginList{}, + "NSTemplateTier": &toolchainv1alpha1.NSTemplateTierList{}, + "ToolchainConfig": &toolchainv1alpha1.ToolchainConfigList{}, + "BannedUser": &toolchainv1alpha1.BannedUserList{}, + "Secret": &corev1.SecretList{}} + + for resourceName := range objectsToList { + log.Infof(nil, "Syncing informer cache with %s resources", resourceName) + if err := hostCluster.GetClient().List(ctx, objectsToList[resourceName], client.InNamespace(configuration.Namespace())); err != nil { + log.Errorf(nil, err, "Informer cache sync failed for %s", resourceName) return nil, err } } diff --git a/go.mod b/go.mod index bc6a459e..2df15414 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,10 @@ require ( cloud.google.com/go/auth v0.3.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect + github.com/BurntSushi/toml v0.4.1 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.1.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.11.2 // indirect @@ -67,6 +71,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/gorilla/mux v1.8.0 // indirect + github.com/huandu/xstrings v1.3.1 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect @@ -77,7 +82,12 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/migueleliasweb/go-github-mock v0.0.18 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect + github.com/redhat-cop/operator-utils v1.3.3-0.20220121120056-862ef22b8cdf // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/spf13/cast v1.3.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect @@ -94,6 +104,7 @@ require ( google.golang.org/grpc v1.63.2 // indirect k8s.io/apiextensions-apiserver v0.25.0 // indirect k8s.io/component-base v0.25.0 // indirect + k8s.io/kubectl v0.24.0 // indirect k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect ) diff --git a/go.sum b/go.sum index 9de6f37a..d65f126e 100644 --- a/go.sum +++ b/go.sum @@ -1,30 +1,106 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs= cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/recaptchaenterprise/v2 v2.13.0 h1:+QG02kE63W13vXI+rwAxFF3EhGX6K7gXwFz9OKwKcHw= cloud.google.com/go/recaptchaenterprise/v2 v2.13.0/go.mod h1:jNYyn2ScR4DTg+VNhjhv/vJQdaU8qz+NpmpIzEE7HFQ= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.44.100 h1:7I86bWNQB+HGDT5z/dJy61J7qgbgLoZ7O51C9eL6hrA= github.com/aws/aws-sdk-go v1.44.100/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= @@ -32,8 +108,14 @@ github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A= github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= @@ -43,38 +125,87 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpV github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codeready-toolchain/api v0.0.0-20240815232340-d0c164a83d27 h1:uEH8HAM81QZBccuqQpGKJUoJQe28+DFSYi/mRKZDYrA= github.com/codeready-toolchain/api v0.0.0-20240815232340-d0c164a83d27/go.mod h1:ie9p4LenCCS0LsnbWp6/xwpFDdCWYE0KWzUO6Sk1g0E= github.com/codeready-toolchain/toolchain-common v0.0.0-20240905135929-d55d86fdd41e h1:xTqyuImyon/P2QfV5NIJDsVkEWqb9b6Ax9INsmzpI1Q= github.com/codeready-toolchain/toolchain-common v0.0.0-20240905135929-d55d86fdd41e/go.mod h1:aIbki5CFsykeqZn2/ZwvUb3Krx2f2Tbq58R6MGnk6H8= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.6.0 h1:0Z7D/bVhE6ja07lI8CTjTonp6SB07o8bNuFyRbsBUQg= github.com/gin-contrib/cors v1.6.0/go.mod h1:cI+h6iOAyxKRtUtC6iF/Si1KSFvGm/gK+kshxlCi8ro= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= @@ -87,20 +218,35 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -120,11 +266,17 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -132,14 +284,25 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -147,20 +310,29 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -173,44 +345,119 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7 h1:K8qael4LemsmJCGt+ccI8b0fCNFDttmEu3qtpFt3G0M= github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7/go.mod h1:/Pk5i/SqYdYv1cie5wGwoZ4P6TpgMi+Yf58mtJSHdOw= github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c h1:hnbwWED5rIu+UaMkLR3JtnscMVGqp35lfzQwLuZAAUY= github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c/go.mod h1:pD+iEcdAGVXld5foVN4e24zb/6fnb60tgZPZ3P/3T/I= github.com/kevinburke/twilio-go v0.0.0-20220922200631-8f3f155dfe1f h1:hfNgahMeAII8WXHg8COu6hX/TM/e5FBleh8jyiUMZNM= github.com/kevinburke/twilio-go v0.0.0-20220922200631-8f3f155dfe1f/go.mod h1:PDdDH7RSKjjy9iFyoMzfeChOSmXpXuMEUqmAJSihxx4= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -242,80 +489,202 @@ github.com/lestrrat-go/jwx v1.2.29/go.mod h1:hU8k2l6WF0ncx20uQdOmik/Gjg6E3/wIRtX github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/resync v0.0.0-20161211202428-d39c09a11215 h1:hDa3vAq/Zo5gjfJ46XMsGFbH+hTizpR4fUzQCk2nxgk= github.com/matryer/resync v0.0.0-20161211202428-d39c09a11215/go.mod h1:LH+NgPY9AJpDfqAFtzyer01N9MYNsAKUf3DC9DV1xIY= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/migueleliasweb/go-github-mock v0.0.18 h1:0lWt9MYmZQGnQE2rFtjlft/YtD6hzxuN6JJRFpujzEI= github.com/migueleliasweb/go-github-mock v0.0.18/go.mod h1:CcgXcbMoRnf3rRVHqGssuBquZDIcaplxL2W6G+xs7kM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nyaruka/phonenumbers v1.1.1 h1:fyoZmpLN2VCmAnc51XcrNOUVP2wT1ZzQl348ggIaXII= github.com/nyaruka/phonenumbers v1.1.1/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/openshift/api v0.0.0-20230213134911-7ba313770556 h1:7W2fOhJicyEff24VaF7ASNzPtYvr+iSCVft4SIBAzaE= github.com/openshift/api v0.0.0-20230213134911-7ba313770556/go.mod h1:aQ6LDasvHMvHZXqLHnX2GRmnfTWCF/iIwz8EMTTIE9A= github.com/openshift/library-go v0.0.0-20230301092340-c13b89190a26 h1:vXYT3dX03Fm5FCX1284aTGoa5qBZFp3zMnIVaV9WOdg= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.40.0 h1:Afz7EVRqGg2Mqqf4JuF9vdvp1pi220m55Pi9T2JnO4Q= github.com/prometheus/common v0.40.0/go.mod h1:L65ZJPSmfn/UBWLQIHV7dBrKFidB/wPlF1y5TlSt9OE= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/redhat-cop/operator-utils v1.3.3-0.20220121120056-862ef22b8cdf h1:fsZiv9XuFo8G7IyzFWjG02vqzJG7kSqFvD1Wiq3V/o8= +github.com/redhat-cop/operator-utils v1.3.3-0.20220121120056-862ef22b8cdf/go.mod h1:FfTyeSCu+e2VLgeMh/1RFG8TSkVjKRPEyR6EmDt0RIw= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/scylladb/go-set v1.0.2/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -327,12 +696,16 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4= github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -344,67 +717,179 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -415,35 +900,110 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -456,7 +1016,9 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= @@ -466,9 +1028,13 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -476,18 +1042,73 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -496,24 +1117,108 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.177.0 h1:8a0p/BbPa65GlqGWtUKxot4p0TV8OGOfyTjtmkXNXmk= google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 h1:DTJM0R8LECCgFeUwApvcEJHz85HLagW8uRENYxHh1ww= google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 h1:DujSIu+2tC9Ht0aPNA7jgj23Iq8Ewi5sgkQ++wdvonE= google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -528,9 +1233,11 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -538,14 +1245,26 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/h2non/gock.v1 v1.0.14 h1:fTeu9fcUvSnLNacYvYI54h+1/XEteDyHvrVCZEEEYNM= gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.0 h1:nLzhkFyl5bkblqYBoiWJUt5JkWOzmiaBtCxdJAqJd3U= gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -557,37 +1276,94 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= +k8s.io/api v0.24.0/go.mod h1:5Jl90IUrJHUJYEMANRURMiVvJ0g7Ax7r3R1bqO8zx8I= k8s.io/api v0.25.0 h1:H+Q4ma2U/ww0iGB78ijZx6DRByPz6/733jIuFpX70e0= k8s.io/api v0.25.0/go.mod h1:ttceV1GyV1i1rnmvzT3BST08N6nGt+dudGrquzVQWPk= +k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c= k8s.io/apiextensions-apiserver v0.25.0 h1:CJ9zlyXAbq0FIW8CD7HHyozCMBpDSiH7EdrSTCZcZFY= k8s.io/apiextensions-apiserver v0.25.0/go.mod h1:3pAjZiN4zw7R8aZC5gR0y3/vCkGlAjCazcg1me8iB/E= +k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU= k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400= k8s.io/apiserver v0.25.0 h1:8kl2ifbNffD440MyvHtPaIz1mw4mGKVgWqM0nL+oyu4= k8s.io/apiserver v0.25.0/go.mod h1:BKwsE+PTC+aZK+6OJQDPr0v6uS91/HWxX7evElAH6xo= +k8s.io/cli-runtime v0.22.1/go.mod h1:YqwGrlXeEk15Yn3em2xzr435UGwbrCw5x+COQoTYfoo= +k8s.io/cli-runtime v0.24.0/go.mod h1:9XxoZDsEkRFUThnwqNviqzljtT/LdHtNWvcNFrAXl0A= +k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= +k8s.io/client-go v0.24.0/go.mod h1:VFPQET+cAFpYxh6Bq6f4xyMY80G6jKKktU6G0m00VDw= k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E= k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8= +k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= +k8s.io/code-generator v0.24.0/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= +k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo= +k8s.io/component-base v0.24.0/go.mod h1:Dgazgon0i7KYUsS8krG8muGiMVtUZxG037l1MKyXgrA= k8s.io/component-base v0.25.0 h1:haVKlLkPCFZhkcqB6WCvpVxftrg6+FK5x1ZuaIDaQ5Y= k8s.io/component-base v0.25.0/go.mod h1:F2Sumv9CnbBlqrpdf7rKZTmmd2meJq0HizeyY/yAFxk= +k8s.io/component-helpers v0.22.1/go.mod h1:QvBcDbX+qU5I2tMZABBF5fRwAlQwiv771IGBHK9WYh4= +k8s.io/component-helpers v0.24.0/go.mod h1:Q2SlLm4h6g6lPTC9GMMfzdywfLSvJT2f1hOnnjaWD8c= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/kubectl v0.22.1/go.mod h1:mjAOgEbMNMtZWxnfM6jd+nPjPsaoLqO5xanc78WcSbw= k8s.io/kubectl v0.24.0 h1:nA+WtMLVdXUs4wLogGd1mPTAesnLdBpCVgCmz3I7dXo= +k8s.io/kubectl v0.24.0/go.mod h1:pdXkmCyHiRTqjYfyUJiXtbVNURhv0/Q1TyRhy2d5ic0= +k8s.io/metrics v0.22.1/go.mod h1:i/ZNap89UkV1gLa26dn7fhKAdheJaKy+moOqJbiif7E= +k8s.io/metrics v0.24.0/go.mod h1:jrLlFGdKl3X+szubOXPG0Lf2aVxuV3QJcbsgVRAM6fI= +k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/controller-runtime v0.10.0/go.mod h1:GCdh6kqV6IY4LK0JLwX0Zm6g233RtVGdb/f0+KSfprg= sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ= sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g= +sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI= +sigs.k8s.io/kustomize/cmd/config v0.9.13/go.mod h1:7547FLF8W/lTaDf0BDqFTbZxM9zqwEJqCKN9sSR0xSs= +sigs.k8s.io/kustomize/cmd/config v0.10.6/go.mod h1:/S4A4nUANUa4bZJ/Edt7ZQTyKOY9WCER0uBS1SW2Rco= +sigs.k8s.io/kustomize/kustomize/v4 v4.2.0/go.mod h1:MOkR6fmhwG7hEDRXBYELTi5GSFcLwfqwzTRHW3kv5go= +sigs.k8s.io/kustomize/kustomize/v4 v4.5.4/go.mod h1:Zo/Xc5FKD6sHl0lilbrieeGeZHVYCA4BzxeAaLI05Bg= +sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM= +sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/application/service/context/service_context.go b/pkg/application/service/context/service_context.go index 6bf91f46..3f47b5ed 100644 --- a/pkg/application/service/context/service_context.go +++ b/pkg/application/service/context/service_context.go @@ -2,14 +2,14 @@ package context import ( "github.com/codeready-toolchain/registration-service/pkg/application/service" - "github.com/codeready-toolchain/registration-service/pkg/informers" "github.com/codeready-toolchain/registration-service/pkg/kubeclient" + "sigs.k8s.io/controller-runtime/pkg/client" ) type ServiceContextProducer func() ServiceContext type ServiceContext interface { CRTClient() kubeclient.CRTClient - Informer() informers.Informer + Client() client.Client Services() service.Services } diff --git a/pkg/application/service/factory/service_factory.go b/pkg/application/service/factory/service_factory.go index dd9f5660..b41023ad 100644 --- a/pkg/application/service/factory/service_factory.go +++ b/pkg/application/service/factory/service_factory.go @@ -6,18 +6,18 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/application/service" servicecontext "github.com/codeready-toolchain/registration-service/pkg/application/service/context" "github.com/codeready-toolchain/registration-service/pkg/configuration" - "github.com/codeready-toolchain/registration-service/pkg/informers" informerservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "github.com/codeready-toolchain/registration-service/pkg/log" clusterservice "github.com/codeready-toolchain/registration-service/pkg/proxy/service" signupservice "github.com/codeready-toolchain/registration-service/pkg/signup/service" verificationservice "github.com/codeready-toolchain/registration-service/pkg/verification/service" + "sigs.k8s.io/controller-runtime/pkg/client" ) type serviceContextImpl struct { kubeClient kubeclient.CRTClient - informer informers.Informer + client client.Client services service.Services } @@ -29,14 +29,14 @@ func CRTClientOption(kubeClient kubeclient.CRTClient) ServiceContextOption { } } -func InformerOption(informer informers.Informer) ServiceContextOption { +func InformerOption(client client.Client) ServiceContextOption { return func(ctx *serviceContextImpl) { - ctx.informer = informer + ctx.client = client } } -func (s *serviceContextImpl) Informer() informers.Informer { - return s.informer +func (s *serviceContextImpl) Client() client.Client { + return s.client } func (s *serviceContextImpl) CRTClient() kubeclient.CRTClient { @@ -65,7 +65,7 @@ func (s *ServiceFactory) defaultServiceContextProducer() servicecontext.ServiceC } func (s *ServiceFactory) InformerService() service.InformerService { - return informerservice.NewInformerService(s.getContext()) + return informerservice.NewInformerService(s.getContext().Client(), configuration.Namespace()) } func (s *ServiceFactory) MemberClusterService() service.MemberClusterService { diff --git a/pkg/informers/informers.go b/pkg/informers/informers.go deleted file mode 100644 index 887f18d8..00000000 --- a/pkg/informers/informers.go +++ /dev/null @@ -1,104 +0,0 @@ -package informers - -import ( - "fmt" - - toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/configuration" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" - "github.com/codeready-toolchain/registration-service/pkg/log" - - "k8s.io/apimachinery/pkg/runtime/schema" - - "k8s.io/client-go/dynamic" - "k8s.io/client-go/dynamic/dynamicinformer" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/cache" -) - -type Informer struct { - Masteruserrecord cache.GenericLister - Space cache.GenericLister - SpaceBinding cache.GenericLister - ToolchainStatus cache.GenericLister - UserSignup cache.GenericLister - ProxyPluginConfig cache.GenericLister - NSTemplateTier cache.GenericLister - BannedUsers cache.GenericLister -} - -func StartInformer(cfg *rest.Config) (*Informer, chan struct{}, error) { - group := toolchainv1alpha1.GroupVersion.Group - version := toolchainv1alpha1.GroupVersion.Version - - informer := &Informer{} - dynamicClient, err := dynamic.NewForConfig(cfg) - if err != nil { - return nil, nil, err - } - - factory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynamicClient, 0, configuration.Namespace(), nil) - - // MasterUserRecords - genericMasterUserRecordInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.MurResourcePlural}) - informer.Masteruserrecord = genericMasterUserRecordInformer.Lister() - masterUserRecordInformer := genericMasterUserRecordInformer.Informer() - - // Space - genericSpaceInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.SpaceResourcePlural}) - informer.Space = genericSpaceInformer.Lister() - spaceInformer := genericSpaceInformer.Informer() - - // SpaceBinding - genericSpaceBindingInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.SpaceBindingResourcePlural}) - informer.SpaceBinding = genericSpaceBindingInformer.Lister() - spaceBindingInformer := genericSpaceBindingInformer.Informer() - - // ToolchainStatus - genericToolchainStatusInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.ToolchainStatusPlural}) - informer.ToolchainStatus = genericToolchainStatusInformer.Lister() - toolchainstatusInformer := genericToolchainStatusInformer.Informer() - - // UserSignups - genericUserSignupInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.UserSignupResourcePlural}) - informer.UserSignup = genericUserSignupInformer.Lister() - userSignupInformer := genericUserSignupInformer.Informer() - - // Proxy plugins - proxyPluginInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.ProxyPluginsPlural}) - informer.ProxyPluginConfig = proxyPluginInformer.Lister() - proxyPluginConfigInformer := proxyPluginInformer.Informer() - - // NSTemplateTier plugins - genericNSTemplateTierInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.NSTemplateTierPlural}) - informer.NSTemplateTier = genericNSTemplateTierInformer.Lister() - nsTemplateTierInformer := genericNSTemplateTierInformer.Informer() - - // BannedUsers - genericBannedUsersInformer := factory.ForResource(schema.GroupVersionResource{Group: group, Version: version, Resource: resources.BannedUserResourcePlural}) - informer.BannedUsers = genericBannedUsersInformer.Lister() - bannedUsersInformer := genericBannedUsersInformer.Informer() - - stopper := make(chan struct{}) - - log.Info(nil, "Starting proxy cache informers") - factory.Start(stopper) - - if !cache.WaitForCacheSync(stopper, - masterUserRecordInformer.HasSynced, - spaceInformer.HasSynced, - spaceBindingInformer.HasSynced, - toolchainstatusInformer.HasSynced, - userSignupInformer.HasSynced, - proxyPluginConfigInformer.HasSynced, - nsTemplateTierInformer.HasSynced, - bannedUsersInformer.HasSynced, - ) { - err := fmt.Errorf("timed out waiting for caches to sync") - log.Error(nil, err, "Failed to create informers") - return nil, nil, err - } - log.Info(nil, "Informer caches synced") - - return informer, stopper, nil -} diff --git a/pkg/informers/service/informer_service.go b/pkg/informers/service/informer_service.go index d0d5e8ae..f7729b7d 100644 --- a/pkg/informers/service/informer_service.go +++ b/pkg/informers/service/informer_service.go @@ -1,179 +1,98 @@ package service import ( + "context" + toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service" - "github.com/codeready-toolchain/registration-service/pkg/application/service/base" - servicecontext "github.com/codeready-toolchain/registration-service/pkg/application/service/context" - "github.com/codeready-toolchain/registration-service/pkg/configuration" - "github.com/codeready-toolchain/registration-service/pkg/informers" "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" - "github.com/codeready-toolchain/registration-service/pkg/log" "github.com/codeready-toolchain/toolchain-common/pkg/hash" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" ) type Option func(f *ServiceImpl) // ServiceImpl represents the implementation of the informer service. type ServiceImpl struct { // nolint:revive - base.BaseService - informer informers.Informer + client client.Client + namespace string } -// NewInformerService creates a service object for getting resources via shared informers -func NewInformerService(context servicecontext.ServiceContext, options ...Option) service.InformerService { +// NewInformerService creates a service object for getting resources +func NewInformerService(client client.Client, namespace string) service.InformerService { si := &ServiceImpl{ - BaseService: base.NewBaseService(context), - informer: context.Informer(), - } - for _, o := range options { - o(si) + client: client, + namespace: namespace, } return si } func (s *ServiceImpl) GetProxyPluginConfig(name string) (*toolchainv1alpha1.ProxyPlugin, error) { - obj, err := s.informer.ProxyPluginConfig.ByNamespace(configuration.Namespace()).Get(name) - if err != nil { - return nil, err - } - - unobj := obj.(*unstructured.Unstructured) - config := &toolchainv1alpha1.ProxyPlugin{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), config); err != nil { - log.Errorf(nil, err, "failed to get Proxy Plugin config %q", name) - return nil, err - - } - return config, err + pluginConfig := &toolchainv1alpha1.ProxyPlugin{} + namespacedName := types.NamespacedName{Name: name, Namespace: s.namespace} + err := s.client.Get(context.TODO(), namespacedName, pluginConfig) + return pluginConfig, err } func (s *ServiceImpl) GetMasterUserRecord(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - obj, err := s.informer.Masteruserrecord.ByNamespace(configuration.Namespace()).Get(name) - if err != nil { - return nil, err - } - - unobj := obj.(*unstructured.Unstructured) mur := &toolchainv1alpha1.MasterUserRecord{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), mur); err != nil { - log.Errorf(nil, err, "failed to get MasterUserRecord '%s'", name) - return nil, err - } + namespacedName := types.NamespacedName{Name: name, Namespace: s.namespace} + err := s.client.Get(context.TODO(), namespacedName, mur) return mur, err } func (s *ServiceImpl) GetSpace(name string) (*toolchainv1alpha1.Space, error) { - obj, err := s.informer.Space.ByNamespace(configuration.Namespace()).Get(name) - if err != nil { - return nil, err - } - - unobj := obj.(*unstructured.Unstructured) space := &toolchainv1alpha1.Space{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), space); err != nil { - log.Errorf(nil, err, "failed to get Space '%s'", name) - return nil, err - } + namespacedName := types.NamespacedName{Name: name, Namespace: s.namespace} + err := s.client.Get(context.TODO(), namespacedName, space) return space, err } func (s *ServiceImpl) GetToolchainStatus() (*toolchainv1alpha1.ToolchainStatus, error) { - obj, err := s.informer.ToolchainStatus.ByNamespace(configuration.Namespace()).Get(resources.ToolchainStatusName) - if err != nil { - return nil, err - } - - unobj := obj.(*unstructured.Unstructured) - stat := &toolchainv1alpha1.ToolchainStatus{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), stat); err != nil { - log.Errorf(nil, err, "failed to get ToolchainStatus %s", resources.ToolchainStatusName) - return nil, err - } - return stat, err + status := &toolchainv1alpha1.ToolchainStatus{} + namespacedName := types.NamespacedName{Name: resources.ToolchainStatusName, Namespace: s.namespace} + err := s.client.Get(context.TODO(), namespacedName, status) + return status, err } func (s *ServiceImpl) GetUserSignup(name string) (*toolchainv1alpha1.UserSignup, error) { - obj, err := s.informer.UserSignup.ByNamespace(configuration.Namespace()).Get(name) - if err != nil { - return nil, err - } - - unobj := obj.(*unstructured.Unstructured) - us := &toolchainv1alpha1.UserSignup{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), us); err != nil { - log.Errorf(nil, err, "failed to get UserSignup '%s'", name) - return nil, err - } - return us, err + signup := &toolchainv1alpha1.UserSignup{} + namespacedName := types.NamespacedName{Name: name, Namespace: s.namespace} + err := s.client.Get(context.TODO(), namespacedName, signup) + return signup, err } func (s *ServiceImpl) ListSpaceBindings(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - selector := labels.NewSelector().Add(reqs...) - objs, err := s.informer.SpaceBinding.ByNamespace(configuration.Namespace()).List(selector) - if err != nil { - return nil, err + selector := labels.NewSelector() + for i := range reqs { + selector = selector.Add(reqs[i]) } - sbs := []toolchainv1alpha1.SpaceBinding{} - for _, obj := range objs { - unobj := obj.(*unstructured.Unstructured) - sb := &toolchainv1alpha1.SpaceBinding{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), sb); err != nil { - log.Errorf(nil, err, "failed to list SpaceBindings") - return nil, err - } - sbs = append(sbs, *sb) + bindings := &toolchainv1alpha1.SpaceBindingList{} + if err := s.client.List(context.TODO(), bindings, client.InNamespace(s.namespace), client.MatchingLabelsSelector{Selector: selector}); err != nil { + return nil, err } - return sbs, err + return bindings.Items, nil } func (s *ServiceImpl) GetNSTemplateTier(name string) (*toolchainv1alpha1.NSTemplateTier, error) { - obj, err := s.informer.NSTemplateTier.ByNamespace(configuration.Namespace()).Get(name) - if err != nil { - return nil, err - } - - unobj := obj.(*unstructured.Unstructured) tier := &toolchainv1alpha1.NSTemplateTier{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), tier); err != nil { - log.Errorf(nil, err, "failed to get NSTemplateTier '%s'", name) - return nil, err - } + namespacedName := types.NamespacedName{Name: name, Namespace: s.namespace} + err := s.client.Get(context.TODO(), namespacedName, tier) return tier, err } func (s *ServiceImpl) ListBannedUsersByEmail(email string) ([]toolchainv1alpha1.BannedUser, error) { hashedEmail := hash.EncodeString(email) - r, err := labels.NewRequirement(toolchainv1alpha1.BannedUserEmailHashLabelKey, selection.Equals, []string{hashedEmail}) - if err != nil { - return nil, err - } - ls := labels.NewSelector().Add(*r) - objs, err := s.informer.BannedUsers.ByNamespace(configuration.Namespace()).List(ls) - if err != nil { + bannedUsers := &toolchainv1alpha1.BannedUserList{} + if err := s.client.List(context.TODO(), bannedUsers, client.InNamespace(s.namespace), + client.MatchingLabels{toolchainv1alpha1.BannedUserEmailHashLabelKey: hashedEmail}); err != nil { return nil, err } - bb := []toolchainv1alpha1.BannedUser{} - for _, obj := range objs { - unobj := obj.(*unstructured.Unstructured) - bu := &toolchainv1alpha1.BannedUser{} - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unobj.UnstructuredContent(), bu); err != nil { - log.Errorf(nil, err, "failed to list BannedUsers") - return nil, err - } - - // check in case of hash collision - if bu.Spec.Email == email { - bb = append(bb, *bu) - } - } - return bb, nil + return bannedUsers.Items, nil } diff --git a/pkg/informers/service/informer_service_test.go b/pkg/informers/service/informer_service_test.go index bbb15b5c..c7980470 100644 --- a/pkg/informers/service/informer_service_test.go +++ b/pkg/informers/service/informer_service_test.go @@ -1,541 +1,247 @@ package service_test import ( - "fmt" "testing" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - appservice "github.com/codeready-toolchain/registration-service/pkg/application/service" - "github.com/codeready-toolchain/registration-service/pkg/configuration" - "github.com/codeready-toolchain/registration-service/pkg/informers" "github.com/codeready-toolchain/registration-service/pkg/informers/service" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" - "github.com/codeready-toolchain/registration-service/test" "github.com/codeready-toolchain/toolchain-common/pkg/hash" - + "github.com/codeready-toolchain/toolchain-common/pkg/test" + "github.com/codeready-toolchain/toolchain-common/pkg/test/masteruserrecord" + "github.com/codeready-toolchain/toolchain-common/pkg/test/space" + "github.com/codeready-toolchain/toolchain-common/pkg/test/usersignup" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" ) -func TestRunInformerServiceSuite(t *testing.T) { - suite.Run(t, &TestInformerServiceSuite{test.UnitTestSuite{}}) -} - -type TestInformerServiceSuite struct { - test.UnitTestSuite -} - -// Testing the Informer Service is mainly about ensuring the right types are being returned since informers use -// dynamic clients and if a Lister is setup incorrectly it can lead to bugs where we try to convert the unstructured object -// to the wrong type. This is possible and will not return any errors! -func (s *TestInformerServiceSuite) TestInformerService() { - - s.Run("masteruserrecords", func() { - // given - murLister := fakeLister{ - objs: map[string]*unstructured.Unstructured{ - "johnMur": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{ - "tierName": "deactivate30", - "propagatedClaims": map[string]interface{}{ - "sub": "john-id", - }, - "userAccounts": []map[string]interface{}{ - { - "targetCluster": "member1", - }, - }, - }, - }, - }, - "noise": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{ - "tierName": "deactivate30", - "propagatedClaims": map[string]interface{}{ - "sub": "noise-id", - }, - "userAccounts": []map[string]interface{}{ - { - "targetCluster": "member2", - }, - }, - }, - }, - }, +func TestInformerService(t *testing.T) { + // given + murJohn := masteruserrecord.NewMasterUserRecord(t, "johnMur") + murNoise := masteruserrecord.NewMasterUserRecord(t, "noise") + spaceJohn := space.NewSpace(test.HostOperatorNs, "johnSpace") + spaceNoise := space.NewSpace(test.HostOperatorNs, "noiseSpace") + pluginTekton := &toolchainv1alpha1.ProxyPlugin{ObjectMeta: metav1.ObjectMeta{ + Name: "tekton-results", + Namespace: test.HostOperatorNs, + }} + pluginNoise := &toolchainv1alpha1.ProxyPlugin{ObjectMeta: metav1.ObjectMeta{ + Name: "noise", + Namespace: test.HostOperatorNs, + }} + status := &toolchainv1alpha1.ToolchainStatus{ + ObjectMeta: metav1.ObjectMeta{ + Name: "toolchain-status", + Namespace: test.HostOperatorNs, + }, + Status: toolchainv1alpha1.ToolchainStatusStatus{ + HostOperator: &toolchainv1alpha1.HostOperatorStatus{ + Version: "v1alpha1", }, - } - inf := informers.Informer{ - Masteruserrecord: murLister, - } - - svc := service.NewInformerService(fakeInformerServiceContext{ - Svcs: s.Application, - informer: inf, - }) + }, + } + signupJohn := usersignup.NewUserSignup(usersignup.WithName("johnUserSignup"), + usersignup.WithTargetCluster("member2")) + signupJohn.Spec.IdentityClaims = toolchainv1alpha1.IdentityClaimsEmbedded{ + PropagatedClaims: toolchainv1alpha1.PropagatedClaims{ + Sub: "foo", + OriginalSub: "sub-key", + }, + PreferredUsername: "foo@redhat.com", + GivenName: "Foo", + FamilyName: "Bar", + Company: "Red Hat", + } + signupNoise := usersignup.NewUserSignup(usersignup.WithName("noise")) + bannedAlice := &toolchainv1alpha1.BannedUser{ + ObjectMeta: metav1.ObjectMeta{ + Name: "alice", + Namespace: test.HostOperatorNs, + Labels: map[string]string{ + toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString("alice@redhat.com"), + }, + }, + Spec: toolchainv1alpha1.BannedUserSpec{ + Email: "alice@redhat.com", + }, + } + bannedBob := &toolchainv1alpha1.BannedUser{ + ObjectMeta: metav1.ObjectMeta{ + Name: "bob", + Namespace: test.HostOperatorNs, + Labels: map[string]string{ + toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString("bob@redhat.com"), + }, + }, + Spec: toolchainv1alpha1.BannedUserSpec{ + Email: "bob@redhat.com", + }, + } + bannedBobDup := &toolchainv1alpha1.BannedUser{ + ObjectMeta: metav1.ObjectMeta{ + Name: "bob-dup", + Namespace: test.HostOperatorNs, + Labels: map[string]string{ + toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString("bob@redhat.com"), + }, + }, + Spec: toolchainv1alpha1.BannedUserSpec{ + Email: "bob@redhat.com", + }, + } + + client := test.NewFakeClient(t, murJohn, murNoise, spaceJohn, spaceNoise, pluginTekton, + pluginNoise, status, signupJohn, signupNoise, bannedAlice, bannedBob, bannedBobDup) + svc := service.NewInformerService(client, test.HostOperatorNs) - s.Run("not found", func() { + t.Run("masteruserrecords", func(t *testing.T) { + t.Run("not found", func(t *testing.T) { // when val, err := svc.GetMasterUserRecord("unknown") //then - assert.Nil(s.T(), val) - assert.EqualError(s.T(), err, "not found") + assert.Empty(t, val) + assert.EqualError(t, err, "masteruserrecords.toolchain.dev.openshift.com \"unknown\" not found") }) - s.Run("found", func() { - // given - expected := &toolchainv1alpha1.MasterUserRecord{ - Spec: toolchainv1alpha1.MasterUserRecordSpec{ - TierName: "deactivate30", - UserAccounts: []toolchainv1alpha1.UserAccountEmbedded{ - { - TargetCluster: "member1", - }, - }, - PropagatedClaims: toolchainv1alpha1.PropagatedClaims{ - Sub: "john-id", - }, - }, - } - + t.Run("found", func(t *testing.T) { // when val, err := svc.GetMasterUserRecord("johnMur") // then - require.NotNil(s.T(), val) - require.NoError(s.T(), err) - assert.Equal(s.T(), expected, val) + require.NotNil(t, val) + require.NoError(t, err) + assert.Equal(t, murJohn.Spec, val.Spec) }) }) - s.Run("spaces", func() { - // given - spaceLister := fakeLister{ - objs: map[string]*unstructured.Unstructured{ - "johnSpace": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{ - "targetCluster": "member2", - "tierName": "base1ns", - }, - }, - }, - "noise": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{ - "targetCluster": "member1", - "tierName": "base", - }, - }, - }, - }, - } - - inf := informers.Informer{ - Space: spaceLister, - } - - svc := service.NewInformerService(fakeInformerServiceContext{ - Svcs: s.Application, - informer: inf, - }) - - s.Run("not found", func() { + t.Run("spaces", func(t *testing.T) { + t.Run("not found", func(t *testing.T) { // when val, err := svc.GetSpace("unknown") // then - assert.Nil(s.T(), val) - assert.EqualError(s.T(), err, "not found") + assert.Empty(t, val) + assert.EqualError(t, err, "spaces.toolchain.dev.openshift.com \"unknown\" not found") }) - s.Run("found", func() { - // given - expected := &toolchainv1alpha1.Space{ - Spec: toolchainv1alpha1.SpaceSpec{ - TargetCluster: "member2", - TierName: "base1ns", - }, - } - + t.Run("found", func(t *testing.T) { // when val, err := svc.GetSpace("johnSpace") // then - require.NotNil(s.T(), val) - require.NoError(s.T(), err) - assert.Equal(s.T(), expected, val) + require.NotNil(t, val) + require.NoError(t, err) + assert.Equal(t, spaceJohn.Spec, val.Spec) }) }) - s.Run("proxy configs", func() { - // given - proxyConfigLister := fakeLister{ - objs: map[string]*unstructured.Unstructured{ - "tekton-results": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{ - "openShiftRouteTargetEndpoint": map[string]interface{}{ - "namespace": "tekton-results", - "name": "tekton-results", - }, - }, - }, - }, - "noise": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{}, - }, - }, - }, - } - - inf := informers.Informer{ - ProxyPluginConfig: proxyConfigLister, - } - - svc := service.NewInformerService(fakeInformerServiceContext{ - Svcs: s.Application, - informer: inf, - }) - - s.Run("not found", func() { + t.Run("proxy configs", func(t *testing.T) { + t.Run("not found", func(t *testing.T) { // when val, err := svc.GetProxyPluginConfig("unknown") // then - assert.Nil(s.T(), val) - assert.EqualError(s.T(), err, "not found") + assert.Empty(t, val) + assert.EqualError(t, err, "proxyplugins.toolchain.dev.openshift.com \"unknown\" not found") }) - s.Run("found", func() { - // given - expected := &toolchainv1alpha1.ProxyPlugin{ - Spec: toolchainv1alpha1.ProxyPluginSpec{ - OpenShiftRouteTargetEndpoint: &toolchainv1alpha1.OpenShiftRouteTarget{ - Namespace: "tekton-results", - Name: "tekton-results", - }, - }, - } - + t.Run("found", func(t *testing.T) { // when val, err := svc.GetProxyPluginConfig("tekton-results") // then - require.NotNil(s.T(), val) - require.NoError(s.T(), err) - assert.Equal(s.T(), expected, val) + require.NotNil(t, val) + require.NoError(t, err) + assert.Equal(t, pluginTekton.Spec, val.Spec) }) }) - s.Run("toolchainstatuses", func() { - // given - emptyToolchainStatusLister := fakeLister{ - objs: map[string]*unstructured.Unstructured{}, - } - - toolchainStatusLister := fakeLister{ - objs: map[string]*unstructured.Unstructured{ - "toolchain-status": { - Object: map[string]interface{}{ - "status": map[string]interface{}{ - "hostOperator": map[string]interface{}{ - "version": "v1alpha1", - }, - }, - }, - }, - }, - } - - s.Run("not found", func() { + t.Run("toolchainstatuses", func(t *testing.T) { + t.Run("not found", func(t *testing.T) { // given - inf := informers.Informer{ - ToolchainStatus: emptyToolchainStatusLister, - } - - svc := service.NewInformerService(fakeInformerServiceContext{ - Svcs: s.Application, - informer: inf, - }) + client := test.NewFakeClient(t) + svc := service.NewInformerService(client, test.HostOperatorNs) // when val, err := svc.GetToolchainStatus() // then - assert.Nil(s.T(), val) - assert.EqualError(s.T(), err, "not found") + assert.Empty(t, val) + assert.EqualError(t, err, "toolchainstatuses.toolchain.dev.openshift.com \"toolchain-status\" not found") }) - s.Run("found", func() { - // given - inf := informers.Informer{ - ToolchainStatus: toolchainStatusLister, - } - - svc := service.NewInformerService(fakeInformerServiceContext{ - Svcs: s.Application, - informer: inf, - }) - - expected := &toolchainv1alpha1.ToolchainStatus{ - Status: toolchainv1alpha1.ToolchainStatusStatus{ - HostOperator: &toolchainv1alpha1.HostOperatorStatus{ - Version: "v1alpha1", - }, - }, - } - + t.Run("found", func(t *testing.T) { // when val, err := svc.GetToolchainStatus() // then - require.NotNil(s.T(), val) - require.NoError(s.T(), err) - assert.Equal(s.T(), expected, val) + require.NotNil(t, val) + require.NoError(t, err) + assert.Equal(t, status.Status, val.Status) }) }) - s.Run("usersignups", func() { - // given - userSignupLister := fakeLister{ - objs: map[string]*unstructured.Unstructured{ - "johnUserSignup": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{ - "targetCluster": "member2", - "identityClaims": map[string]interface{}{ - "sub": "foo", - "originalSub": "sub-key", - "preferredUsername": "foo@redhat.com", - "givenName": "Foo", - "familyName": "Bar", - "company": "Red Hat", - }, - }, - }, - }, - "noise": { - Object: map[string]interface{}{ - "spec": map[string]interface{}{ - "targetCluster": "member1", - "identityClaims": map[string]interface{}{ - "sub": "noise", - "originalSub": "noise-key", - "preferredUsername": "noise@redhat.com", - "givenName": "Noise", - "familyName": "Make", - "company": "Noisy", - }, - }, - }, - }, - }, - } - - inf := informers.Informer{ - UserSignup: userSignupLister, - } - - svc := service.NewInformerService(fakeInformerServiceContext{ - Svcs: s.Application, - informer: inf, - }) - - s.Run("not found", func() { + t.Run("usersignups", func(t *testing.T) { + t.Run("not found", func(t *testing.T) { // when val, err := svc.GetUserSignup("unknown") // then - assert.Nil(s.T(), val) - assert.EqualError(s.T(), err, "not found") + assert.Empty(t, val) + assert.EqualError(t, err, "usersignups.toolchain.dev.openshift.com \"unknown\" not found") }) - s.Run("found", func() { - // given - expected := &toolchainv1alpha1.UserSignup{ - Spec: toolchainv1alpha1.UserSignupSpec{ - TargetCluster: "member2", - IdentityClaims: toolchainv1alpha1.IdentityClaimsEmbedded{ - PreferredUsername: "foo@redhat.com", - GivenName: "Foo", - FamilyName: "Bar", - Company: "Red Hat", - PropagatedClaims: toolchainv1alpha1.PropagatedClaims{ - Sub: "foo", - OriginalSub: "sub-key", - }, - }, - }, - } - + t.Run("found", func(t *testing.T) { // when val, err := svc.GetUserSignup("johnUserSignup") // then - require.NotNil(s.T(), val) - require.NoError(s.T(), err) - assert.Equal(s.T(), expected, val) + require.NotNil(t, val) + require.NoError(t, err) + assert.Equal(t, signupJohn.Spec, val.Spec) }) }) - s.Run("bannedusers", func() { - // given - bb := map[string]toolchainv1alpha1.BannedUser{ - "alice": { - ObjectMeta: metav1.ObjectMeta{ - Name: "alice", - Namespace: configuration.Namespace(), - Labels: map[string]string{ - toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString("alice@redhat.com"), - }, - }, - Spec: toolchainv1alpha1.BannedUserSpec{ - Email: "alice@redhat.com", - }, - }, - "bob": { - ObjectMeta: metav1.ObjectMeta{ - Name: "bob", - Namespace: configuration.Namespace(), - Labels: map[string]string{ - toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString("bob@redhat.com"), - }, - }, - Spec: toolchainv1alpha1.BannedUserSpec{ - Email: "bob@redhat.com", - }, - }, - "bob-dup": { - ObjectMeta: metav1.ObjectMeta{ - Name: "bob-dup", - Namespace: configuration.Namespace(), - Labels: map[string]string{ - toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString("bob@redhat.com"), - }, - }, - Spec: toolchainv1alpha1.BannedUserSpec{ - Email: "bob@redhat.com", - }, - }, - } - - // convert to unstructured.Unstructured for fakeLister - bbu := make(map[string]*unstructured.Unstructured, len(bb)) - for k, b := range bb { - bu, err := runtime.DefaultUnstructuredConverter.ToUnstructured(b.DeepCopy()) - require.NoError(s.T(), err) - bbu[k] = &unstructured.Unstructured{Object: bu} - } - - // setup InformerService with fakeLister - inf := informers.Informer{BannedUsers: fakeLister{objs: bbu}} - svc := service.NewInformerService(fakeInformerServiceContext{ - Svcs: s.Application, - informer: inf, - }) - - s.Run("not found", func() { + t.Run("bannedusers", func(t *testing.T) { + t.Run("not found", func(t *testing.T) { // when rbb, err := svc.ListBannedUsersByEmail("unknown@unknown.com") // then - require.NoError(s.T(), err) - require.Empty(s.T(), rbb) + require.NoError(t, err) + require.Empty(t, rbb) }) - s.Run("invalid email", func() { + t.Run("invalid email", func(t *testing.T) { // when rbb, err := svc.ListBannedUsersByEmail("not-an-email") // then - require.NoError(s.T(), err) - require.Empty(s.T(), rbb) + require.NoError(t, err) + require.Empty(t, rbb) }) - s.Run("found one", func() { - // given - expected := bb["alice"] - + t.Run("found one", func(t *testing.T) { // when - rbb, err := svc.ListBannedUsersByEmail(expected.Spec.Email) + rbb, err := svc.ListBannedUsersByEmail(bannedAlice.Spec.Email) // then - require.NotNil(s.T(), rbb) - require.NoError(s.T(), err) - require.Len(s.T(), rbb, 1, "expected 1 result for email %s", expected.Spec.Email) - require.Equal(s.T(), expected, rbb[0]) + require.NotNil(t, rbb) + require.NoError(t, err) + require.Len(t, rbb, 1, "expected 1 result for email %s", bannedAlice.Spec.Email) + require.Equal(t, *bannedAlice, rbb[0]) }) - s.Run("found multiple", func() { - // given - expected := []toolchainv1alpha1.BannedUser{bb["bob"], bb["bob-dup"]} - + t.Run("found multiple", func(t *testing.T) { // when - rbb, err := svc.ListBannedUsersByEmail(expected[0].Spec.Email) + rbb, err := svc.ListBannedUsersByEmail(bannedBob.Spec.Email) // then - require.NotNil(s.T(), rbb) - require.NoError(s.T(), err) - require.Len(s.T(), rbb, 2, "expected 2 results for email %s", expected[0].Spec.Email) - require.Equal(s.T(), expected, rbb) + require.NotNil(t, rbb) + require.NoError(t, err) + require.Len(t, rbb, 2, "expected 2 results for email %s", bannedBob.Spec.Email) + require.ElementsMatch(t, []toolchainv1alpha1.BannedUser{*bannedBob, *bannedBobDup}, rbb) }) }) } - -type fakeInformerServiceContext struct { - Svcs appservice.Services - informer informers.Informer -} - -func (sc fakeInformerServiceContext) CRTClient() kubeclient.CRTClient { - panic("shouldn't need CRTClient") -} - -func (sc fakeInformerServiceContext) Informer() informers.Informer { - return sc.informer -} - -func (sc fakeInformerServiceContext) Services() appservice.Services { - return sc.Svcs -} - -type fakeLister struct { - objs map[string]*unstructured.Unstructured -} - -// List will return all objects across namespaces -func (l fakeLister) List(ls labels.Selector) (ret []runtime.Object, err error) { - objs := []runtime.Object{} - for _, o := range l.objs { - ll := labels.Set(o.GetLabels()) - if ls.Matches(ll) { - objs = append(objs, o) - } - } - return objs, nil -} - -// Get will attempt to retrieve assuming that name==key -func (l fakeLister) Get(name string) (runtime.Object, error) { - obj := l.objs[name] - if obj != nil { - return obj, nil - } - return nil, fmt.Errorf("not found") -} - -// ByNamespace will give you a GenericNamespaceLister for one namespace -func (l fakeLister) ByNamespace(_ string) cache.GenericNamespaceLister { - return l -} diff --git a/pkg/kubeclient/client.go b/pkg/kubeclient/client.go index dd33ddf9..48d47217 100644 --- a/pkg/kubeclient/client.go +++ b/pkg/kubeclient/client.go @@ -2,7 +2,7 @@ package kubeclient import ( crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/informers" + "sigs.k8s.io/controller-runtime/pkg/client" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" @@ -24,7 +24,7 @@ type V1Alpha1 interface { } // NewCRTRESTClient creates a new REST client for managing Codeready Toolchain resources via the Kubernetes API -func NewCRTRESTClient(cfg *rest.Config, informer informers.Informer, namespace string) (CRTClient, error) { +func NewCRTRESTClient(cfg *rest.Config, client client.Client, namespace string) (CRTClient, error) { scheme := runtime.NewScheme() err := crtapi.SchemeBuilder.AddToScheme(scheme) if err != nil { @@ -46,7 +46,7 @@ func NewCRTRESTClient(cfg *rest.Config, informer informers.Informer, namespace s crtRESTClient := &CRTRESTClient{ RestClient: restClient, - Informer: informer, + Client: client, Config: config, NS: namespace, Scheme: scheme, @@ -75,7 +75,7 @@ func getRegisterObject() []runtime.Object { type CRTRESTClient struct { RestClient rest.Interface - Informer informers.Informer + Client client.Client NS string Config rest.Config Scheme *runtime.Scheme @@ -95,7 +95,7 @@ func (c *V1Alpha1REST) UserSignups() UserSignupInterface { return &userSignupClient{ crtClient: crtClient{ restClient: c.client.RestClient, - informer: c.client.Informer, + client: c.client.Client, ns: c.client.NS, cfg: c.client.Config, scheme: c.client.Scheme, @@ -108,7 +108,7 @@ func (c *V1Alpha1REST) MasterUserRecords() MasterUserRecordInterface { return &masterUserRecordClient{ crtClient: crtClient{ restClient: c.client.RestClient, - informer: c.client.Informer, + client: c.client.Client, ns: c.client.NS, cfg: c.client.Config, scheme: c.client.Scheme, @@ -121,7 +121,7 @@ func (c *V1Alpha1REST) BannedUsers() BannedUserInterface { return &bannedUserClient{ crtClient: crtClient{ restClient: c.client.RestClient, - informer: c.client.Informer, + client: c.client.Client, ns: c.client.NS, cfg: c.client.Config, scheme: c.client.Scheme, @@ -134,7 +134,7 @@ func (c *V1Alpha1REST) ToolchainStatuses() ToolchainStatusInterface { return &toolchainStatusClient{ crtClient: crtClient{ restClient: c.client.RestClient, - informer: c.client.Informer, + client: c.client.Client, ns: c.client.NS, cfg: c.client.Config, scheme: c.client.Scheme, @@ -147,7 +147,7 @@ func (c *V1Alpha1REST) SocialEvents() SocialEventInterface { return &socialeventClient{ crtClient: crtClient{ restClient: c.client.RestClient, - informer: c.client.Informer, + client: c.client.Client, ns: c.client.NS, cfg: c.client.Config, scheme: c.client.Scheme, @@ -160,7 +160,7 @@ func (c *V1Alpha1REST) Spaces() SpaceInterface { return &spaceClient{ crtClient: crtClient{ restClient: c.client.RestClient, - informer: c.client.Informer, + client: c.client.Client, ns: c.client.NS, cfg: c.client.Config, scheme: c.client.Scheme, @@ -173,7 +173,7 @@ func (c *V1Alpha1REST) SpaceBindings() SpaceBindingInterface { return &spaceBindingClient{ crtClient: crtClient{ restClient: c.client.RestClient, - informer: c.client.Informer, + client: c.client.Client, ns: c.client.NS, cfg: c.client.Config, scheme: c.client.Scheme, @@ -183,7 +183,7 @@ func (c *V1Alpha1REST) SpaceBindings() SpaceBindingInterface { type crtClient struct { restClient rest.Interface - informer informers.Informer + client client.Client ns string cfg rest.Config scheme *runtime.Scheme diff --git a/pkg/kubeclient/client_test.go b/pkg/kubeclient/client_test.go index f1397af8..26f93765 100644 --- a/pkg/kubeclient/client_test.go +++ b/pkg/kubeclient/client_test.go @@ -3,7 +3,7 @@ package kubeclient_test import ( "testing" - "github.com/codeready-toolchain/registration-service/pkg/informers" + "github.com/codeready-toolchain/toolchain-common/pkg/test" "k8s.io/client-go/rest" "github.com/stretchr/testify/require" @@ -17,7 +17,7 @@ const ( func TestNewClient(t *testing.T) { // Try creating a new client with an empty config - client, err := kubeclient.NewCRTRESTClient(&rest.Config{}, informers.Informer{}, TestNamespace) + client, err := kubeclient.NewCRTRESTClient(&rest.Config{}, test.NewFakeClient(t), TestNamespace) // Check that there are no errors, and the clients are returned require.NoError(t, err) diff --git a/pkg/kubeclient/signup.go b/pkg/kubeclient/signup.go index 315045b0..596f71fe 100644 --- a/pkg/kubeclient/signup.go +++ b/pkg/kubeclient/signup.go @@ -9,6 +9,7 @@ import ( "github.com/codeready-toolchain/toolchain-common/pkg/hash" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" + "sigs.k8s.io/controller-runtime/pkg/client" ) var ( @@ -98,26 +99,29 @@ func (c *userSignupClient) listActiveSignupsByLabelForHashedValue(labelKey, valu // label matching the specified label func (c *userSignupClient) listActiveSignupsByLabel(labelKey, labelValue string) ([]*crtapi.UserSignup, error) { - stateRequirement, err := labels.NewRequirement(crtapi.UserSignupStateLabelKey, selection.NotEquals, []string{crtapi.UserSignupStateLabelValueDeactivated}) + // TODO add unit tests checking that the label selection works as expected. Right now, it's not possible to do that thanks to the great abstraction and multiple level of layers, mocks, and services. + selector := labels.NewSelector() + stateRequirement, err := labels.NewRequirement(crtapi.UserSignupStateLabelKey, selection.NotIn, []string{crtapi.UserSignupStateLabelValueDeactivated, crtapi.UserSignupStateLabelValueNotReady}) if err != nil { return nil, err } + selector = selector.Add(*stateRequirement) labelRequirement, err := labels.NewRequirement(labelKey, selection.Equals, []string{labelValue}) if err != nil { return nil, err } + selector = selector.Add(*labelRequirement) - userSignups, err := c.informer.UserSignup.ByNamespace(c.ns).List(labels.NewSelector().Add(*stateRequirement).Add(*labelRequirement)) + userSignups := &crtapi.UserSignupList{} + err = c.client.List(context.TODO(), userSignups, client.InNamespace(c.ns), client.MatchingLabelsSelector{Selector: selector}) if err != nil { return nil, err } - result := make([]*crtapi.UserSignup, len(userSignups)) + result := make([]*crtapi.UserSignup, len(userSignups.Items)) - for i := range userSignups { - userSignup := &crtapi.UserSignup{} - err = c.crtClient.scheme.Convert(userSignups[i], userSignup, nil) - result[i] = userSignup + for i := range userSignups.Items { + result[i] = &userSignups.Items[i] } return result, err diff --git a/pkg/proxy/handlers/spacelister_list.go b/pkg/proxy/handlers/spacelister_list.go index b0328d0d..afa51985 100644 --- a/pkg/proxy/handlers/spacelister_list.go +++ b/pkg/proxy/handlers/spacelister_list.go @@ -6,17 +6,16 @@ import ( "net/http" "time" + toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" + "github.com/codeready-toolchain/registration-service/pkg/context" + "github.com/codeready-toolchain/registration-service/pkg/proxy/metrics" + "github.com/codeready-toolchain/registration-service/pkg/signup" "github.com/labstack/echo/v4" errs "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" - - toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/context" - "github.com/codeready-toolchain/registration-service/pkg/proxy/metrics" - "github.com/codeready-toolchain/registration-service/pkg/signup" ) func HandleSpaceListRequest(spaceLister *SpaceLister) echo.HandlerFunc { diff --git a/pkg/proxy/proxy_test.go b/pkg/proxy/proxy_test.go index 50f05db4..43902df1 100644 --- a/pkg/proxy/proxy_test.go +++ b/pkg/proxy/proxy_test.go @@ -836,8 +836,8 @@ func (s *TestProxySuite) newMemberClusterServiceWithMembers(serverURL string) ap } return service.NewMemberClusterService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { diff --git a/pkg/proxy/service/cluster_service_test.go b/pkg/proxy/service/cluster_service_test.go index e818da0c..408b94ec 100644 --- a/pkg/proxy/service/cluster_service_test.go +++ b/pkg/proxy/service/cluster_service_test.go @@ -102,8 +102,8 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -203,8 +203,8 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { s.Run("no member clusters", func() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { @@ -232,8 +232,8 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { s.Run("no member cluster with the given URL", func() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { @@ -294,8 +294,8 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { @@ -462,8 +462,8 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { s.Run("get workspace by name", func() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { diff --git a/pkg/server/in_cluster_application.go b/pkg/server/in_cluster_application.go index 979cba2d..067af309 100644 --- a/pkg/server/in_cluster_application.go +++ b/pkg/server/in_cluster_application.go @@ -5,22 +5,22 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/application/service" "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" "github.com/codeready-toolchain/registration-service/pkg/configuration" - "github.com/codeready-toolchain/registration-service/pkg/informers" "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" ) // NewInClusterApplication creates a new in-cluster application with the specified configuration and options. This // application type is intended to run inside a Kubernetes cluster, where it makes use of the rest.InClusterConfig() // function to determine which Kubernetes configuration to use to create the REST client that interacts with the // Kubernetes service endpoints. -func NewInClusterApplication(informer informers.Informer) (application.Application, error) { +func NewInClusterApplication(client client.Client) (application.Application, error) { k8sConfig, err := rest.InClusterConfig() if err != nil { return nil, err } - kubeClient, err := kubeclient.NewCRTRESTClient(k8sConfig, informer, configuration.Namespace()) + kubeClient, err := kubeclient.NewCRTRESTClient(k8sConfig, client, configuration.Namespace()) if err != nil { return nil, err } @@ -28,7 +28,7 @@ func NewInClusterApplication(informer informers.Informer) (application.Applicati return &InClusterApplication{ serviceFactory: factory.NewServiceFactory( factory.WithServiceContextOptions(factory.CRTClientOption(kubeClient), - factory.InformerOption(informer), + factory.InformerOption(client), )), }, nil } diff --git a/pkg/signup/service/signup_service_test.go b/pkg/signup/service/signup_service_test.go index 08e5ead6..dcfe641d 100644 --- a/pkg/signup/service/signup_service_test.go +++ b/pkg/signup/service/signup_service_test.go @@ -273,8 +273,8 @@ func (s *TestSignupServiceSuite) TestGetSignupFailsWithNotFoundThenOtherError() s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -730,8 +730,8 @@ func (s *TestSignupServiceSuite) TestGetUserSignupFails() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -764,8 +764,8 @@ func (s *TestSignupServiceSuite) TestGetSignupNotFound() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -857,8 +857,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -890,8 +890,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { states.SetVerificationRequired(&userSignupNotComplete, false) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) mur := s.newProvisionedMUR("bill") @@ -1048,8 +1048,8 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1109,8 +1109,8 @@ func (s *TestSignupServiceSuite) TestGetSignupDeactivated() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1205,8 +1205,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusOK() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1256,8 +1256,8 @@ func (s *TestSignupServiceSuite) TestGetSignupByUsernameOK() { svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1333,8 +1333,8 @@ func (s *TestSignupServiceSuite) TestGetSignupByUsernameOK() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1450,8 +1450,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusFailGetToolchainStatus() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1506,8 +1506,8 @@ func (s *TestSignupServiceSuite) TestGetSignupMURGetFails() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1636,8 +1636,8 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) @@ -1691,8 +1691,8 @@ func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ - Client: s, - Svcs: s.Application, + CrtClient: s, + Svcs: s.Application, }, ) diff --git a/test/fake/proxy.go b/test/fake/proxy.go index 5dc68736..c3ebacbc 100644 --- a/test/fake/proxy.go +++ b/test/fake/proxy.go @@ -3,11 +3,11 @@ package fake import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service" - "github.com/codeready-toolchain/registration-service/pkg/informers" "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "github.com/codeready-toolchain/registration-service/pkg/proxy/access" "github.com/codeready-toolchain/registration-service/pkg/signup" "github.com/gin-gonic/gin" + "sigs.k8s.io/controller-runtime/pkg/client" ) // This whole service abstraction is such a huge pain. We have to get rid of it!!! @@ -126,15 +126,15 @@ func (m *SignupService) PhoneNumberAlreadyInUse(_, _, _ string) error { } type MemberClusterServiceContext struct { - Client kubeclient.CRTClient - Svcs service.Services + CrtClient kubeclient.CRTClient + Svcs service.Services } func (sc MemberClusterServiceContext) CRTClient() kubeclient.CRTClient { - return sc.Client + return sc.CrtClient } -func (sc MemberClusterServiceContext) Informer() informers.Informer { +func (sc MemberClusterServiceContext) Client() client.Client { panic("shouldn't need informer in mock member cluster service") } From cbd0f40e81eb46406e5f2cd73829dba9220e4c28 Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Fri, 20 Sep 2024 18:10:23 +0200 Subject: [PATCH 02/13] add ToolchainCluster to client cache (#463) --- cmd/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/main.go b/cmd/main.go index b0e7ef96..27abb45a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -201,6 +201,7 @@ func newCachedClient(ctx context.Context, cfg *rest.Config) (client.Client, erro "NSTemplateTier": &toolchainv1alpha1.NSTemplateTierList{}, "ToolchainConfig": &toolchainv1alpha1.ToolchainConfigList{}, "BannedUser": &toolchainv1alpha1.BannedUserList{}, + "ToolchainCluster": &toolchainv1alpha1.ToolchainClusterList{}, "Secret": &corev1.SecretList{}} for resourceName := range objectsToList { From d7ff96d6723c4751057bb5e05b2a73f9729edecd Mon Sep 17 00:00:00 2001 From: Alexey Kazakov Date: Mon, 23 Sep 2024 10:42:03 -0700 Subject: [PATCH 03/13] Add signup URL to authconfig payload (#464) --- pkg/configuration/configuration.go | 2 +- pkg/configuration/configuration_test.go | 2 +- pkg/controller/authconfig.go | 4 ++++ pkg/controller/authconfig_test.go | 9 +++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/configuration/configuration.go b/pkg/configuration/configuration.go index a914eef5..925fea81 100644 --- a/pkg/configuration/configuration.go +++ b/pkg/configuration/configuration.go @@ -136,7 +136,7 @@ func (r RegistrationServiceConfig) LogLevel() string { } func (r RegistrationServiceConfig) RegistrationServiceURL() string { - return commonconfig.GetString(r.cfg.Host.RegistrationService.RegistrationServiceURL, "https://registration.crt-placeholder.com") + return commonconfig.GetString(r.cfg.Host.RegistrationService.RegistrationServiceURL, "") } func (r RegistrationServiceConfig) Verification() VerificationConfig { diff --git a/pkg/configuration/configuration_test.go b/pkg/configuration/configuration_test.go index 409c21cf..294df8f1 100644 --- a/pkg/configuration/configuration_test.go +++ b/pkg/configuration/configuration_test.go @@ -43,7 +43,7 @@ func TestRegistrationService(t *testing.T) { // then assert.Equal(t, "prod", regServiceCfg.Environment()) assert.Equal(t, "info", regServiceCfg.LogLevel()) - assert.Equal(t, "https://registration.crt-placeholder.com", regServiceCfg.RegistrationServiceURL()) + assert.Equal(t, "", regServiceCfg.RegistrationServiceURL()) assert.Empty(t, regServiceCfg.Analytics().SegmentWriteKey()) assert.Empty(t, regServiceCfg.Analytics().DevSpacesSegmentWriteKey()) assert.Equal(t, "https://sso.devsandbox.dev/auth/js/keycloak.js", regServiceCfg.Auth().AuthClientLibraryURL()) diff --git a/pkg/controller/authconfig.go b/pkg/controller/authconfig.go index f03ec4dd..49c8db57 100644 --- a/pkg/controller/authconfig.go +++ b/pkg/controller/authconfig.go @@ -12,6 +12,9 @@ type configResponse struct { // this holds the raw config. Note: this is intentionally a string // not json as this field may also hold non-json configs! AuthClientConfigRaw string `json:"auth-client-config"` + // The signup page URL. After user logs into SSO but has not signed up yet then this URL can be used to redirect the user to + // sign up. If not set then the base URL of the registration service is supposed to be used by the clients. + SignupURL string `json:"signup-url"` } // AuthConfig implements the auth config endpoint, which is invoked to @@ -30,6 +33,7 @@ func (ac *AuthConfig) GetHandler(ctx *gin.Context) { configRespData := configResponse{ AuthClientLibraryURL: cfg.Auth().AuthClientLibraryURL(), AuthClientConfigRaw: cfg.Auth().AuthClientConfigRaw(), + SignupURL: cfg.RegistrationServiceURL(), } ctx.JSON(http.StatusOK, configRespData) } diff --git a/pkg/controller/authconfig_test.go b/pkg/controller/authconfig_test.go index cab44ba9..39a49664 100644 --- a/pkg/controller/authconfig_test.go +++ b/pkg/controller/authconfig_test.go @@ -6,6 +6,8 @@ import ( "net/http/httptest" "testing" + testconfig "github.com/codeready-toolchain/toolchain-common/pkg/test/config" + "github.com/codeready-toolchain/registration-service/pkg/configuration" "github.com/codeready-toolchain/registration-service/test" @@ -31,6 +33,9 @@ func (s *TestAuthConfigSuite) TestAuthClientConfigHandler() { // Check if the config is set to testing mode, so the handler may use this. assert.True(s.T(), configuration.IsTestingMode(), "testing mode not set correctly to true") + s.OverrideApplicationDefault(testconfig.RegistrationService(). + RegistrationServiceURL("https://signup.domain.com")) + defer s.DefaultConfig() cfg := configuration.GetRegistrationServiceConfig() // Create handler instance. @@ -115,5 +120,9 @@ func (s *TestAuthConfigSuite) TestAuthClientConfigHandler() { assert.Equal(s.T(), config["public-client"], valBool, "wrong 'public-client' in authconfig response") }) }) + + s.Run("envelope signup url", func() { + assert.Equal(s.T(), "https://signup.domain.com", dataEnvelope.SignupURL) + }) }) } From e15d7cc1730b9b07523bd5c91d89250634d360cb Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Tue, 24 Sep 2024 08:59:47 +0200 Subject: [PATCH 04/13] replace methods of the CRTRestClient with the cached client (#462) --- pkg/informers/service/informer_service.go | 3 +- pkg/kubeclient/banneduser.go | 32 +----- pkg/kubeclient/client.go | 116 ++++++---------------- pkg/kubeclient/client_test.go | 4 +- pkg/kubeclient/mur.go | 13 +-- pkg/kubeclient/resources/names.go | 13 --- pkg/kubeclient/signup.go | 34 ++----- pkg/kubeclient/socialevent.go | 16 +-- pkg/kubeclient/space.go | 13 +-- pkg/kubeclient/spacebinding.go | 24 +---- pkg/kubeclient/toolchainstatus.go | 12 +-- pkg/server/in_cluster_application.go | 8 +- test/fake/signup_client.go | 1 - 13 files changed, 68 insertions(+), 221 deletions(-) delete mode 100644 pkg/kubeclient/resources/names.go diff --git a/pkg/informers/service/informer_service.go b/pkg/informers/service/informer_service.go index f7729b7d..58f879d6 100644 --- a/pkg/informers/service/informer_service.go +++ b/pkg/informers/service/informer_service.go @@ -5,7 +5,6 @@ import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" "github.com/codeready-toolchain/toolchain-common/pkg/hash" "k8s.io/apimachinery/pkg/labels" @@ -53,7 +52,7 @@ func (s *ServiceImpl) GetSpace(name string) (*toolchainv1alpha1.Space, error) { func (s *ServiceImpl) GetToolchainStatus() (*toolchainv1alpha1.ToolchainStatus, error) { status := &toolchainv1alpha1.ToolchainStatus{} - namespacedName := types.NamespacedName{Name: resources.ToolchainStatusName, Namespace: s.namespace} + namespacedName := types.NamespacedName{Name: "toolchain-status", Namespace: s.namespace} err := s.client.Get(context.TODO(), namespacedName, status) return status, err } diff --git a/pkg/kubeclient/banneduser.go b/pkg/kubeclient/banneduser.go index e7fd105b..e34733c2 100644 --- a/pkg/kubeclient/banneduser.go +++ b/pkg/kubeclient/banneduser.go @@ -2,18 +2,10 @@ package kubeclient import ( "context" - "fmt" crtapi "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/toolchain-common/pkg/hash" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/dynamic" -) - -const ( - bannedUserResourcePlural = "bannedusers" + "sigs.k8s.io/controller-runtime/pkg/client" ) type bannedUserClient struct { @@ -50,24 +42,10 @@ func (c *bannedUserClient) listByLabelForHashedValue(labelKey, valueToHash strin // listByLabel returns a BannedUserList containing any BannedUser resources that have a label matching the specified label func (c *bannedUserClient) listByLabel(labelKey, labelValue string) (*crtapi.BannedUserList, error) { - - intf, err := dynamic.NewForConfig(&c.cfg) - if err != nil { + bannedUsers := &crtapi.BannedUserList{} + if err := c.client.List(context.TODO(), bannedUsers, client.InNamespace(c.ns), + client.MatchingLabels{labelKey: labelValue}); err != nil { return nil, err } - - r := schema.GroupVersionResource{Group: "toolchain.dev.openshift.com", Version: "v1alpha1", Resource: bannedUserResourcePlural} - listOptions := metav1.ListOptions{ - LabelSelector: fmt.Sprintf("%s=%s", labelKey, labelValue), - } - - list, err := intf.Resource(r).Namespace(c.ns).List(context.TODO(), listOptions) - if err != nil { - return nil, err - } - - result := &crtapi.BannedUserList{} - - err = c.crtClient.scheme.Convert(list, result, nil) - return result, err + return bannedUsers, nil } diff --git a/pkg/kubeclient/client.go b/pkg/kubeclient/client.go index 48d47217..eb6f345d 100644 --- a/pkg/kubeclient/client.go +++ b/pkg/kubeclient/client.go @@ -5,8 +5,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/client-go/rest" ) type CRTClient interface { @@ -24,62 +22,28 @@ type V1Alpha1 interface { } // NewCRTRESTClient creates a new REST client for managing Codeready Toolchain resources via the Kubernetes API -func NewCRTRESTClient(cfg *rest.Config, client client.Client, namespace string) (CRTClient, error) { +func NewCRTRESTClient(client client.Client, namespace string) (CRTClient, error) { scheme := runtime.NewScheme() err := crtapi.SchemeBuilder.AddToScheme(scheme) if err != nil { return nil, err } - crtapi.SchemeBuilder.Register(getRegisterObject()...) - - config := *cfg - config.GroupVersion = &crtapi.GroupVersion - config.APIPath = "/apis" - config.ContentType = runtime.ContentTypeJSON - config.NegotiatedSerializer = serializer.WithoutConversionCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)} - config.UserAgent = rest.DefaultKubernetesUserAgent() - - restClient, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } crtRESTClient := &CRTRESTClient{ - RestClient: restClient, - Client: client, - Config: config, - NS: namespace, - Scheme: scheme, + Client: client, + NS: namespace, + Scheme: scheme, } crtRESTClient.v1Alpha1 = &V1Alpha1REST{client: crtRESTClient} return crtRESTClient, nil } -func getRegisterObject() []runtime.Object { - return []runtime.Object{ - &crtapi.UserSignup{}, - &crtapi.UserSignupList{}, - &crtapi.MasterUserRecord{}, - &crtapi.MasterUserRecordList{}, - &crtapi.BannedUser{}, - &crtapi.BannedUserList{}, - &crtapi.ToolchainStatus{}, - &crtapi.ToolchainStatusList{}, - &crtapi.Space{}, - &crtapi.SpaceList{}, - &crtapi.SpaceBinding{}, - &crtapi.SpaceBindingList{}, - } -} - type CRTRESTClient struct { - RestClient rest.Interface - Client client.Client - NS string - Config rest.Config - Scheme *runtime.Scheme - v1Alpha1 *V1Alpha1REST + Client client.Client + NS string + Scheme *runtime.Scheme + v1Alpha1 *V1Alpha1REST } func (c *CRTRESTClient) V1Alpha1() V1Alpha1 { @@ -94,11 +58,9 @@ type V1Alpha1REST struct { func (c *V1Alpha1REST) UserSignups() UserSignupInterface { return &userSignupClient{ crtClient: crtClient{ - restClient: c.client.RestClient, - client: c.client.Client, - ns: c.client.NS, - cfg: c.client.Config, - scheme: c.client.Scheme, + client: c.client.Client, + ns: c.client.NS, + scheme: c.client.Scheme, }, } } @@ -107,11 +69,9 @@ func (c *V1Alpha1REST) UserSignups() UserSignupInterface { func (c *V1Alpha1REST) MasterUserRecords() MasterUserRecordInterface { return &masterUserRecordClient{ crtClient: crtClient{ - restClient: c.client.RestClient, - client: c.client.Client, - ns: c.client.NS, - cfg: c.client.Config, - scheme: c.client.Scheme, + client: c.client.Client, + ns: c.client.NS, + scheme: c.client.Scheme, }, } } @@ -120,11 +80,9 @@ func (c *V1Alpha1REST) MasterUserRecords() MasterUserRecordInterface { func (c *V1Alpha1REST) BannedUsers() BannedUserInterface { return &bannedUserClient{ crtClient: crtClient{ - restClient: c.client.RestClient, - client: c.client.Client, - ns: c.client.NS, - cfg: c.client.Config, - scheme: c.client.Scheme, + client: c.client.Client, + ns: c.client.NS, + scheme: c.client.Scheme, }, } } @@ -133,11 +91,9 @@ func (c *V1Alpha1REST) BannedUsers() BannedUserInterface { func (c *V1Alpha1REST) ToolchainStatuses() ToolchainStatusInterface { return &toolchainStatusClient{ crtClient: crtClient{ - restClient: c.client.RestClient, - client: c.client.Client, - ns: c.client.NS, - cfg: c.client.Config, - scheme: c.client.Scheme, + client: c.client.Client, + ns: c.client.NS, + scheme: c.client.Scheme, }, } } @@ -146,11 +102,9 @@ func (c *V1Alpha1REST) ToolchainStatuses() ToolchainStatusInterface { func (c *V1Alpha1REST) SocialEvents() SocialEventInterface { return &socialeventClient{ crtClient: crtClient{ - restClient: c.client.RestClient, - client: c.client.Client, - ns: c.client.NS, - cfg: c.client.Config, - scheme: c.client.Scheme, + client: c.client.Client, + ns: c.client.NS, + scheme: c.client.Scheme, }, } } @@ -159,11 +113,9 @@ func (c *V1Alpha1REST) SocialEvents() SocialEventInterface { func (c *V1Alpha1REST) Spaces() SpaceInterface { return &spaceClient{ crtClient: crtClient{ - restClient: c.client.RestClient, - client: c.client.Client, - ns: c.client.NS, - cfg: c.client.Config, - scheme: c.client.Scheme, + client: c.client.Client, + ns: c.client.NS, + scheme: c.client.Scheme, }, } } @@ -172,19 +124,15 @@ func (c *V1Alpha1REST) Spaces() SpaceInterface { func (c *V1Alpha1REST) SpaceBindings() SpaceBindingInterface { return &spaceBindingClient{ crtClient: crtClient{ - restClient: c.client.RestClient, - client: c.client.Client, - ns: c.client.NS, - cfg: c.client.Config, - scheme: c.client.Scheme, + client: c.client.Client, + ns: c.client.NS, + scheme: c.client.Scheme, }, } } type crtClient struct { - restClient rest.Interface - client client.Client - ns string - cfg rest.Config - scheme *runtime.Scheme + client client.Client + ns string + scheme *runtime.Scheme } diff --git a/pkg/kubeclient/client_test.go b/pkg/kubeclient/client_test.go index 26f93765..8528e5e3 100644 --- a/pkg/kubeclient/client_test.go +++ b/pkg/kubeclient/client_test.go @@ -4,8 +4,6 @@ import ( "testing" "github.com/codeready-toolchain/toolchain-common/pkg/test" - "k8s.io/client-go/rest" - "github.com/stretchr/testify/require" "github.com/codeready-toolchain/registration-service/pkg/kubeclient" @@ -17,7 +15,7 @@ const ( func TestNewClient(t *testing.T) { // Try creating a new client with an empty config - client, err := kubeclient.NewCRTRESTClient(&rest.Config{}, test.NewFakeClient(t), TestNamespace) + client, err := kubeclient.NewCRTRESTClient(test.NewFakeClient(t), TestNamespace) // Check that there are no errors, and the clients are returned require.NoError(t, err) diff --git a/pkg/kubeclient/mur.go b/pkg/kubeclient/mur.go index 21b34150..098b77af 100644 --- a/pkg/kubeclient/mur.go +++ b/pkg/kubeclient/mur.go @@ -4,7 +4,7 @@ import ( "context" crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" + "k8s.io/apimachinery/pkg/types" ) type masterUserRecordClient struct { @@ -18,11 +18,8 @@ type MasterUserRecordInterface interface { // Get returns the MasterUserRecord with the specified name, or an error if something went wrong while attempting to retrieve it func (c *masterUserRecordClient) Get(name string) (*crtapi.MasterUserRecord, error) { result := &crtapi.MasterUserRecord{} - err := c.restClient.Get(). - Namespace(c.ns). - Resource(resources.MurResourcePlural). - Name(name). - Do(context.TODO()). - Into(result) - return result, err + if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { + return nil, err + } + return result, nil } diff --git a/pkg/kubeclient/resources/names.go b/pkg/kubeclient/resources/names.go deleted file mode 100644 index 7f0f3119..00000000 --- a/pkg/kubeclient/resources/names.go +++ /dev/null @@ -1,13 +0,0 @@ -package resources - -const ( - UserSignupResourcePlural = "usersignups" - MurResourcePlural = "masteruserrecords" - SpaceResourcePlural = "spaces" - SpaceBindingResourcePlural = "spacebindings" - ToolchainStatusPlural = "toolchainstatuses" - ToolchainStatusName = "toolchain-status" - ProxyPluginsPlural = "proxyplugins" - NSTemplateTierPlural = "nstemplatetiers" - BannedUserResourcePlural = "bannedusers" -) diff --git a/pkg/kubeclient/signup.go b/pkg/kubeclient/signup.go index 596f71fe..069f5959 100644 --- a/pkg/kubeclient/signup.go +++ b/pkg/kubeclient/signup.go @@ -5,10 +5,10 @@ import ( "regexp" crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" "github.com/codeready-toolchain/toolchain-common/pkg/hash" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -32,48 +32,28 @@ type UserSignupInterface interface { // If not found then NotFound error returned func (c *userSignupClient) Get(name string) (*crtapi.UserSignup, error) { result := &crtapi.UserSignup{} - err := c.restClient.Get(). - Namespace(c.ns). - Resource(resources.UserSignupResourcePlural). - Name(name). - Do(context.TODO()). - Into(result) - if err != nil { + if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { return nil, err } - return result, err + return result, nil } // Create creates a new UserSignup resource in the cluster, and returns the resulting UserSignup that was created, or // an error if something went wrong func (c *userSignupClient) Create(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) { - result := &crtapi.UserSignup{} - err := c.restClient.Post(). - Namespace(c.ns). - Resource(resources.UserSignupResourcePlural). - Body(obj). - Do(context.TODO()). - Into(result) - if err != nil { + if err := c.client.Create(context.TODO(), obj); err != nil { return nil, err } - return result, err + return obj, nil } // Update will update an existing UserSignup resource in the cluster, returning an error if something went wrong func (c *userSignupClient) Update(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) { - result := &crtapi.UserSignup{} - err := c.restClient.Put(). - Namespace(c.ns). - Resource(resources.UserSignupResourcePlural). - Name(obj.Name). - Body(obj). - Do(context.TODO()). - Into(result) + err := c.client.Update(context.TODO(), obj) if err != nil { return nil, err } - return result, nil + return obj, nil } // ListActiveSignupsByPhoneNumberOrHash will return a list of non-deactivated UserSignups that have a phone number hash diff --git a/pkg/kubeclient/socialevent.go b/pkg/kubeclient/socialevent.go index b0d75e6b..346a04f7 100644 --- a/pkg/kubeclient/socialevent.go +++ b/pkg/kubeclient/socialevent.go @@ -4,10 +4,7 @@ import ( "context" crtapi "github.com/codeready-toolchain/api/api/v1alpha1" -) - -const ( - socialeventResourcePlural = "socialevents" + "k8s.io/apimachinery/pkg/types" ) type socialeventClient struct { @@ -21,11 +18,8 @@ type SocialEventInterface interface { // Get returns the SocialEvent with the specified name, or an error if something went wrong while attempting to retrieve it func (c *socialeventClient) Get(name string) (*crtapi.SocialEvent, error) { result := &crtapi.SocialEvent{} - err := c.restClient.Get(). - Namespace(c.ns). - Resource(socialeventResourcePlural). - Name(name). - Do(context.TODO()). - Into(result) - return result, err + if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { + return nil, err + } + return result, nil } diff --git a/pkg/kubeclient/space.go b/pkg/kubeclient/space.go index 73d420b6..79745a99 100644 --- a/pkg/kubeclient/space.go +++ b/pkg/kubeclient/space.go @@ -4,7 +4,7 @@ import ( "context" crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" + "k8s.io/apimachinery/pkg/types" ) type spaceClient struct { @@ -18,11 +18,8 @@ type SpaceInterface interface { // List returns the Spaces that match for the provided selector, or an error if something went wrong while attempting to retrieve it func (c *spaceClient) Get(name string) (*crtapi.Space, error) { result := &crtapi.Space{} - err := c.restClient.Get(). - Namespace(c.ns). - Resource(resources.SpaceResourcePlural). - Name(name). - Do(context.TODO()). - Into(result) - return result, err + if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { + return nil, err + } + return result, nil } diff --git a/pkg/kubeclient/spacebinding.go b/pkg/kubeclient/spacebinding.go index 5cdc3971..f32b60da 100644 --- a/pkg/kubeclient/spacebinding.go +++ b/pkg/kubeclient/spacebinding.go @@ -4,12 +4,8 @@ import ( "context" crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" - "github.com/codeready-toolchain/registration-service/pkg/log" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/dynamic" + "sigs.k8s.io/controller-runtime/pkg/client" ) type spaceBindingClient struct { @@ -23,25 +19,11 @@ type SpaceBindingInterface interface { // List returns the SpaceBindings that match for the provided selector, or an error if something went wrong while attempting to retrieve it func (c *spaceBindingClient) ListSpaceBindings(reqs ...labels.Requirement) ([]crtapi.SpaceBinding, error) { - intf, err := dynamic.NewForConfig(&c.cfg) - if err != nil { - return nil, err - } - selector := labels.NewSelector().Add(reqs...) - r := schema.GroupVersionResource{Group: "toolchain.dev.openshift.com", Version: "v1alpha1", Resource: resources.SpaceBindingResourcePlural} - log.Infof(nil, "Listing SpaceBindings with selector: %v", selector.String()) - listOptions := metav1.ListOptions{ - LabelSelector: selector.String(), - } - - list, err := intf.Resource(r).Namespace(c.ns).List(context.TODO(), listOptions) - if err != nil { - return nil, err - } result := &crtapi.SpaceBindingList{} + err := c.client.List(context.TODO(), result, client.InNamespace(c.ns), + client.MatchingLabelsSelector{Selector: selector}) - err = c.crtClient.scheme.Convert(list, result, nil) return result.Items, err } diff --git a/pkg/kubeclient/toolchainstatus.go b/pkg/kubeclient/toolchainstatus.go index 8cf003b6..0c591899 100644 --- a/pkg/kubeclient/toolchainstatus.go +++ b/pkg/kubeclient/toolchainstatus.go @@ -4,7 +4,7 @@ import ( "context" crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient/resources" + "k8s.io/apimachinery/pkg/types" ) type toolchainStatusClient struct { @@ -19,14 +19,8 @@ type ToolchainStatusInterface interface { // If not found then NotFound error returned func (c *toolchainStatusClient) Get() (*crtapi.ToolchainStatus, error) { result := &crtapi.ToolchainStatus{} - err := c.restClient.Get(). - Namespace(c.ns). - Resource(resources.ToolchainStatusPlural). - Name(resources.ToolchainStatusName). - Do(context.TODO()). - Into(result) - if err != nil { + if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: "toolchain-status"}, result); err != nil { return nil, err } - return result, err + return result, nil } diff --git a/pkg/server/in_cluster_application.go b/pkg/server/in_cluster_application.go index 067af309..14a60115 100644 --- a/pkg/server/in_cluster_application.go +++ b/pkg/server/in_cluster_application.go @@ -6,7 +6,6 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" "github.com/codeready-toolchain/registration-service/pkg/configuration" "github.com/codeready-toolchain/registration-service/pkg/kubeclient" - "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -15,12 +14,7 @@ import ( // function to determine which Kubernetes configuration to use to create the REST client that interacts with the // Kubernetes service endpoints. func NewInClusterApplication(client client.Client) (application.Application, error) { - k8sConfig, err := rest.InClusterConfig() - if err != nil { - return nil, err - } - - kubeClient, err := kubeclient.NewCRTRESTClient(k8sConfig, client, configuration.Namespace()) + kubeClient, err := kubeclient.NewCRTRESTClient(client, configuration.Namespace()) if err != nil { return nil, err } diff --git a/test/fake/signup_client.go b/test/fake/signup_client.go index 2639a2d2..47d3501d 100644 --- a/test/fake/signup_client.go +++ b/test/fake/signup_client.go @@ -6,7 +6,6 @@ import ( crtapi "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/toolchain-common/pkg/hash" - "github.com/gofrs/uuid" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" From c8280883c8a0a33da1a06a246eacb27c0af0c988 Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Wed, 25 Sep 2024 15:38:43 +0200 Subject: [PATCH 05/13] use FakeClient as the backend for InformersService in unit tests (#466) --- pkg/controller/usernames_test.go | 17 +- pkg/proxy/handlers/spacelister_get_test.go | 302 ++++++++------- pkg/proxy/handlers/spacelister_list_test.go | 93 +++-- pkg/proxy/handlers/spacelister_test.go | 6 +- pkg/proxy/proxy_test.go | 121 +++--- pkg/proxy/service/cluster_service_test.go | 61 ++- pkg/signup/service/signup_service_test.go | 396 ++++++-------------- test/fake/informer.go | 164 +------- 8 files changed, 428 insertions(+), 732 deletions(-) diff --git a/pkg/controller/usernames_test.go b/pkg/controller/usernames_test.go index a7551526..3fe507ff 100644 --- a/pkg/controller/usernames_test.go +++ b/pkg/controller/usernames_test.go @@ -1,21 +1,24 @@ package controller_test import ( + "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" - toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/controller" + "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/codeready-toolchain/registration-service/pkg/username" "github.com/codeready-toolchain/registration-service/test" "github.com/codeready-toolchain/registration-service/test/fake" + commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "sigs.k8s.io/controller-runtime/pkg/client" ) type TestUsernamesSuite struct { @@ -31,13 +34,13 @@ func (s *TestUsernamesSuite) TestUsernamesGetHandler() { req, err := http.NewRequest(http.MethodGet, "/api/v1/usernames", nil) require.NoError(s.T(), err) - fakeClient := fake.InitClient(s.T(), + fakeClient := commontest.NewFakeClient(s.T(), fake.NewMasterUserRecord("johnny"), ) s.Run("success", func() { - fakeInformer := fake.GetInformerService(fakeClient)() + fakeInformer := service.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(fakeInformer) // Create Usernames controller instance. @@ -97,9 +100,11 @@ func (s *TestUsernamesSuite) TestUsernamesGetHandler() { s.Run("error", func() { // force error while retrieving MUR - fakeInformer := fake.GetInformerService(fakeClient, fake.WithGetMurFunc(func(_ string) (*toolchainv1alpha1.MasterUserRecord, error) { - return nil, fmt.Errorf("mock error") - }))() + fakeClient := commontest.NewFakeClient(s.T()) + fakeClient.MockGet = func(_ context.Context, _ client.ObjectKey, _ client.Object, _ ...client.GetOption) error { + return fmt.Errorf("mock error") + } + fakeInformer := service.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(fakeInformer) // Create Usernames controller instance. diff --git a/pkg/proxy/handlers/spacelister_get_test.go b/pkg/proxy/handlers/spacelister_get_test.go index 2328fcb6..762cd3e1 100644 --- a/pkg/proxy/handlers/spacelister_get_test.go +++ b/pkg/proxy/handlers/spacelister_get_test.go @@ -12,6 +12,7 @@ import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service" rcontext "github.com/codeready-toolchain/registration-service/pkg/context" + infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/codeready-toolchain/registration-service/pkg/proxy/handlers" "github.com/codeready-toolchain/registration-service/pkg/proxy/metrics" proxytest "github.com/codeready-toolchain/registration-service/pkg/proxy/test" @@ -20,14 +21,12 @@ import ( commoncluster "github.com/codeready-toolchain/toolchain-common/pkg/cluster" commonproxy "github.com/codeready-toolchain/toolchain-common/pkg/proxy" "github.com/codeready-toolchain/toolchain-common/pkg/test" - spacetest "github.com/codeready-toolchain/toolchain-common/pkg/test/space" spacebindingrequesttest "github.com/codeready-toolchain/toolchain-common/pkg/test/spacebindingrequest" "github.com/gin-gonic/gin" "github.com/labstack/echo/v4" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/labels" runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -47,9 +46,8 @@ func TestSpaceListerGet(t *testing.T) { } func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { - fakeSignupService, fakeClient := buildSpaceListerFakes(t) - memberFakeClient := fake.InitClient(t, + memberFakeClient := test.NewFakeClient(t, // spacebinding requests spacebindingrequesttest.NewSpaceBindingRequest("animelover-sbr", "dancelover-dev", spacebindingrequesttest.WithSpaceRole("viewer"), @@ -63,7 +61,7 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { ), ) - memberClientErrorList := fake.InitClient(t) + memberClientErrorList := test.NewFakeClient(t) memberClientErrorList.MockList = func(ctx context.Context, list runtimeclient.ObjectList, opts ...runtimeclient.ListOption) error { if _, ok := list.(*toolchainv1alpha1.SpaceBindingRequestList); ok { return fmt.Errorf("mock list error") @@ -75,19 +73,19 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { // given tests := map[string]struct { username string - expectedWs []toolchainv1alpha1.Workspace + expectedWs func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace expectedErr string expectedErrCode int expectedWorkspace string overrideSignupFunc func(ctx *gin.Context, userID, username string, checkUserSignupComplete bool) (*signup.Signup, error) - overrideInformerFunc func() service.InformerService + mockFakeClient func(fakeClient *test.FakeClient) overrideGetMembersFunc func(conditions ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster overrideMemberClient *test.FakeClient }{ "dancelover gets dancelover space": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "dancelover", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "dancelover", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }, @@ -117,15 +115,15 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { }, }, }), - ), + )} }, expectedErr: "", expectedWorkspace: "dancelover", }, "dancelover gets movielover space": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "movielover", "other", false, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "movielover", "other", false, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -150,15 +148,15 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string(nil), // this is system generated so no actions for the user }, }), - ), + )} }, expectedErr: "", expectedWorkspace: "movielover", }, "dancelover gets foodlover space": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "foodlover", "admin", false, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "foodlover", "admin", false, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -174,15 +172,15 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string{"override"}, // since the binding is inherited from parent space, then it can only be overridden }, }), - ), + )} }, expectedErr: "", expectedWorkspace: "foodlover", }, "movielover gets movielover space": { username: "movie.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "movielover", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "movielover", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -208,22 +206,22 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string(nil), // this is system generated so no actions for the user }, }), - ), + )} }, expectedErr: "", expectedWorkspace: "movielover", }, "movielover cannot get dancelover space": { username: "movie.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "\"workspaces.toolchain.dev.openshift.com \\\"dancelover\\\" not found\"", expectedWorkspace: "dancelover", expectedErrCode: 404, }, "signup not ready yet": { username: "movie.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "movielover", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "movielover", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -248,27 +246,29 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string(nil), // this is system generated so no actions for the user }, }), - ), + )} }, expectedErr: "", expectedWorkspace: "movielover", }, "get nstemplatetier error": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "nstemplatetier error", expectedErrCode: 500, - overrideInformerFunc: func() service.InformerService { - informerFunc := fake.GetInformerService(fakeClient, fake.WithGetNSTemplateTierFunc(func(_ string) (*toolchainv1alpha1.NSTemplateTier, error) { - return nil, fmt.Errorf("nstemplatetier error") - })) - return informerFunc() + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockGet = func(ctx context.Context, key runtimeclient.ObjectKey, obj runtimeclient.Object, opts ...runtimeclient.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.NSTemplateTier); ok && key.Name == "base1ns" { + return fmt.Errorf("nstemplatetier error") + } + return fakeClient.Client.Get(ctx, key, obj, opts...) + } }, expectedWorkspace: "dancelover", }, "get signup error": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "signup error", expectedErrCode: 500, overrideSignupFunc: func(_ *gin.Context, _, _ string, _ bool) (*signup.Signup, error) { @@ -278,63 +278,64 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { }, "signup has no compliant username set": { username: "racing.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "\"workspaces.toolchain.dev.openshift.com \\\"racinglover\\\" not found\"", expectedErrCode: 404, expectedWorkspace: "racinglover", }, "list spacebindings error": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "list spacebindings error", expectedErrCode: 500, - overrideInformerFunc: func() service.InformerService { - listSpaceBindingFunc := func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return nil, fmt.Errorf("list spacebindings error") + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockList = func(ctx context.Context, list runtimeclient.ObjectList, opts ...runtimeclient.ListOption) error { + if _, ok := list.(*toolchainv1alpha1.SpaceBindingList); ok { + return fmt.Errorf("list spacebindings error") + } + return fakeClient.Client.List(ctx, list, opts...) } - return fake.GetInformerService(fakeClient, fake.WithListSpaceBindingFunc(listSpaceBindingFunc))() }, expectedWorkspace: "dancelover", }, "unable to get space": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "\"workspaces.toolchain.dev.openshift.com \\\"dancelover\\\" not found\"", expectedErrCode: 404, - overrideInformerFunc: func() service.InformerService { - getSpaceFunc := func(_ string) (*toolchainv1alpha1.Space, error) { - return nil, fmt.Errorf("no space") + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockGet = func(ctx context.Context, key runtimeclient.ObjectKey, obj runtimeclient.Object, opts ...runtimeclient.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.Space); ok && key.Name == "dancelover" { + return fmt.Errorf("no space") + } + return fakeClient.Client.Get(ctx, key, obj, opts...) } - return fake.GetInformerService(fakeClient, fake.WithGetSpaceFunc(getSpaceFunc))() }, expectedWorkspace: "dancelover", }, "unable to get parent-space": { username: "food.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "Internal error occurred: unable to get parent-space: parent-space error", expectedErrCode: 500, - overrideInformerFunc: func() service.InformerService { - getSpaceFunc := func(name string) (*toolchainv1alpha1.Space, error) { - if name == "dancelover" { - // return the error only when trying to get the parent space - return nil, fmt.Errorf("parent-space error") + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockGet = func(ctx context.Context, key runtimeclient.ObjectKey, obj runtimeclient.Object, opts ...runtimeclient.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.Space); ok && key.Name == "dancelover" { + return fmt.Errorf("parent-space error") } - // return the foodlover space - return fake.NewSpace("foodlover", "member-2", "foodlover", spacetest.WithSpecParentSpace("dancelover")), nil + return fakeClient.Client.Get(ctx, key, obj, opts...) } - return fake.GetInformerService(fakeClient, fake.WithGetSpaceFunc(getSpaceFunc))() }, expectedWorkspace: "foodlover", }, "error spaceBinding request has no name": { username: "anime.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "animelover", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "animelover", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), - ), + )} }, expectedErr: "Internal error occurred: SpaceBindingRequest name not found on binding: carlover-sb-from-sbr", expectedErrCode: 500, @@ -342,12 +343,12 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { }, "error spaceBinding request has no namespace set": { username: "car.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "carlover", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "carlover", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), - ), + )} }, expectedErr: "Internal error occurred: SpaceBindingRequest namespace not found on binding: animelover-sb-from-sbr", expectedErrCode: 500, @@ -355,8 +356,8 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { }, "parent can list parentspace": { username: "parent.space", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "parentspace", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "parentspace", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -367,14 +368,14 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string(nil), // this is system generated so no actions for the user }, }), - ), + )} }, expectedWorkspace: "parentspace", }, "parent can list childspace": { username: "parent.space", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "childspace", "admin", false, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "childspace", "admin", false, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -390,14 +391,14 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string{"override"}, }, }), - ), + )} }, expectedWorkspace: "childspace", }, "parent can list grandchildspace": { username: "parent.space", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "grandchildspace", "admin", false, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "grandchildspace", "admin", false, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -418,13 +419,13 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string{"override"}, }, }), - ), + )} }, expectedWorkspace: "grandchildspace", }, "child cannot list parentspace": { username: "child.space", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "\"workspaces.toolchain.dev.openshift.com \\\"parentspace\\\" not found\"", expectedErrCode: 404, expectedWorkspace: "parentspace", @@ -432,8 +433,8 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { "child can list childspace": { username: "child.space", expectedWorkspace: "childspace", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "childspace", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "childspace", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -449,14 +450,14 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string{"override"}, }, }), - ), + )} }, }, "child can list grandchildspace": { username: "child.space", expectedWorkspace: "grandchildspace", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "grandchildspace", "admin", false, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "grandchildspace", "admin", false, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -477,13 +478,13 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string{"override"}, }, }), - ), + )} }, }, "grandchild can list grandchildspace": { username: "grandchild.space", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "grandchildspace", "admin", true, + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{workspaceFor(t, fakeClient, "grandchildspace", "admin", true, commonproxy.WithAvailableRoles([]string{ "admin", "viewer", }), @@ -504,7 +505,7 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { AvailableActions: []string{"override"}, }, }), - ), + )} }, expectedWorkspace: "grandchildspace", }, @@ -513,14 +514,14 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { expectedWorkspace: "parentspace", expectedErr: "\"workspaces.toolchain.dev.openshift.com \\\"parentspace\\\" not found\"", expectedErrCode: 404, - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, }, "grandchild cannot list childspace": { username: "grandchild.space", expectedWorkspace: "childspace", expectedErr: "\"workspaces.toolchain.dev.openshift.com \\\"childspace\\\" not found\"", expectedErrCode: 404, - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, }, "no member clusters found": { username: "movie.lover", @@ -543,22 +544,24 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { for k, tc := range tests { t.Run(k, func(t *testing.T) { // given + fakeSignupService, fakeClient := buildSpaceListerFakes(t) + if tc.mockFakeClient != nil { + tc.mockFakeClient(fakeClient) + } + signupProvider := fakeSignupService.GetSignupFromInformer if tc.overrideSignupFunc != nil { signupProvider = tc.overrideSignupFunc } - informerFunc := fake.GetInformerService(fakeClient) - if tc.overrideInformerFunc != nil { - informerFunc = tc.overrideInformerFunc - } - proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) s := &handlers.SpaceLister{ - GetSignupFunc: signupProvider, - GetInformerServiceFunc: informerFunc, - ProxyMetrics: proxyMetrics, + GetSignupFunc: signupProvider, + GetInformerServiceFunc: func() service.InformerService { + return infservice.NewInformerService(fakeClient, test.HostOperatorNs) + }, + ProxyMetrics: proxyMetrics, } e := echo.New() @@ -592,10 +595,14 @@ func testSpaceListerGet(t *testing.T, publicViewerEnabled bool) { // get workspace case workspace, decodeErr := decodeResponseToWorkspace(rec.Body.Bytes()) require.NoError(t, decodeErr) - require.Len(t, tc.expectedWs, 1, "test case should have exactly one expected item since it's a get request") - for i := range tc.expectedWs { - assert.Equal(t, tc.expectedWs[i].Name, workspace.Name) - assert.Equal(t, tc.expectedWs[i].Status, workspace.Status) + var expectedWorkspaces []toolchainv1alpha1.Workspace + if tc.expectedWs != nil { + expectedWorkspaces = tc.expectedWs(t, fakeClient) + } + require.Len(t, expectedWorkspaces, 1, "test case should have exactly one expected item since it's a get request") + for i := range expectedWorkspaces { + assert.Equal(t, expectedWorkspaces[i].Name, workspace.Name) + assert.Equal(t, expectedWorkspaces[i].Status, workspace.Status) } } }) @@ -610,32 +617,20 @@ func TestGetUserWorkspace(t *testing.T) { newSignup("robin", "robin.space", true), ) - fakeClient := fake.InitClient(t, - // space - fake.NewSpace("batman", "member-1", "batman"), - fake.NewSpace("robin", "member-1", "robin"), - - fake.NewSpaceBinding("robin-1", "robin", "robin", "admin"), - // 2 spacebindings to force the error - fake.NewSpaceBinding("batman-1", "batman", "batman", "admin"), - fake.NewSpaceBinding("batman-2", "batman", "batman", "maintainer"), - fake.NewSpaceBinding("community-robin", toolchainv1alpha1.KubesawAuthenticatedUsername, "robin", "viewer"), - ) - - robinWS := workspaceFor(t, fakeClient, "robin", "admin", true) - tests := map[string]struct { - username string - expectedErr string - workspaceRequest string - expectedWorkspace *toolchainv1alpha1.Workspace - overrideInformerFunc func() service.InformerService - overrideSignupFunc func(ctx *gin.Context, userID, username string, checkUserSignupComplete bool) (*signup.Signup, error) + username string + expectedErr string + workspaceRequest string + expectedWorkspace func(t *testing.T, fakeClient *test.FakeClient) toolchainv1alpha1.Workspace + mockFakeClient func(fakeClient *test.FakeClient) + overrideSignupFunc func(ctx *gin.Context, userID, username string, checkUserSignupComplete bool) (*signup.Signup, error) }{ "get robin workspace": { - username: "robin.space", - workspaceRequest: "robin", - expectedWorkspace: &robinWS, + username: "robin.space", + workspaceRequest: "robin", + expectedWorkspace: func(t *testing.T, fakeClient *test.FakeClient) toolchainv1alpha1.Workspace { + return workspaceFor(t, fakeClient, "robin", "admin", true) + }, }, "invalid number of spacebindings": { username: "batman.space", @@ -654,22 +649,26 @@ func TestGetUserWorkspace(t *testing.T) { "space not found": { username: "invalid.user", workspaceRequest: "batman", - overrideInformerFunc: func() service.InformerService { - getSpaceFunc := func(_ string) (*toolchainv1alpha1.Space, error) { - return nil, fmt.Errorf("no space") + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockGet = func(ctx context.Context, key runtimeclient.ObjectKey, obj runtimeclient.Object, opts ...runtimeclient.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.Space); ok { + return fmt.Errorf("no space") + } + return fakeClient.Client.Get(ctx, key, obj, opts...) } - return fake.GetInformerService(fakeClient, fake.WithGetSpaceFunc(getSpaceFunc))() }, expectedWorkspace: nil, // user is not authorized }, "error getting usersignup": { username: "invalid.user", workspaceRequest: "batman", - overrideInformerFunc: func() service.InformerService { - getSpaceFunc := func(_ string) (*toolchainv1alpha1.Space, error) { - return nil, fmt.Errorf("no space") + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockGet = func(ctx context.Context, key runtimeclient.ObjectKey, obj runtimeclient.Object, opts ...runtimeclient.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.Space); ok { + return fmt.Errorf("no space") + } + return fakeClient.Client.Get(ctx, key, obj, opts...) } - return fake.GetInformerService(fakeClient, fake.WithGetSpaceFunc(getSpaceFunc))() }, expectedWorkspace: nil, // user is not authorized }, @@ -686,11 +685,13 @@ func TestGetUserWorkspace(t *testing.T) { username: "robin.space", workspaceRequest: "robin", expectedErr: "list spacebindings error", - overrideInformerFunc: func() service.InformerService { - listSpaceBindingFunc := func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return nil, fmt.Errorf("list spacebindings error") + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockList = func(ctx context.Context, list runtimeclient.ObjectList, opts ...runtimeclient.ListOption) error { + if _, ok := list.(*toolchainv1alpha1.SpaceBindingList); ok { + return fmt.Errorf("list spacebindings error") + } + return fakeClient.Client.List(ctx, list, opts...) } - return fake.GetInformerService(fakeClient, fake.WithListSpaceBindingFunc(listSpaceBindingFunc))() }, expectedWorkspace: nil, }, @@ -711,20 +712,33 @@ func TestGetUserWorkspace(t *testing.T) { for k, tc := range tests { t.Run(k, func(t *testing.T) { // given + fakeClient := test.NewFakeClient(t, + // space + fake.NewSpace("batman", "member-1", "batman"), + fake.NewSpace("robin", "member-1", "robin"), + + fake.NewSpaceBinding("robin-1", "robin", "robin", "admin"), + // 2 spacebindings to force the error + fake.NewSpaceBinding("batman-1", "batman", "batman", "admin"), + fake.NewSpaceBinding("batman-2", "batman", "batman", "maintainer"), + fake.NewSpaceBinding("community-robin", toolchainv1alpha1.KubesawAuthenticatedUsername, "robin", "viewer"), + ) + if tc.mockFakeClient != nil { + tc.mockFakeClient(fakeClient) + } + signupProvider := fakeSignupService.GetSignupFromInformer if tc.overrideSignupFunc != nil { signupProvider = tc.overrideSignupFunc } - informerFunc := fake.GetInformerService(fakeClient) - if tc.overrideInformerFunc != nil { - informerFunc = tc.overrideInformerFunc - } proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) s := &handlers.SpaceLister{ - GetSignupFunc: signupProvider, - GetInformerServiceFunc: informerFunc, - ProxyMetrics: proxyMetrics, + GetSignupFunc: signupProvider, + GetInformerServiceFunc: func() service.InformerService { + return infservice.NewInformerService(fakeClient, test.HostOperatorNs) + }, + ProxyMetrics: proxyMetrics, } e := echo.New() @@ -748,7 +762,7 @@ func TestGetUserWorkspace(t *testing.T) { } if tc.expectedWorkspace != nil { - require.Equal(t, tc.expectedWorkspace, wrk) + require.Equal(t, tc.expectedWorkspace(t, fakeClient), *wrk) } else { require.Nil(t, wrk) // user is not authorized to get this workspace } @@ -764,7 +778,7 @@ func TestSpaceListerGetPublicViewerEnabled(t *testing.T) { newSignup("gordon", "gordon.no-space", false), ) - fakeClient := fake.InitClient(t, + fakeClient := test.NewFakeClient(t, // space fake.NewSpace("robin", "member-1", "robin"), fake.NewSpace("batman", "member-1", "batman"), @@ -826,13 +840,14 @@ func TestSpaceListerGetPublicViewerEnabled(t *testing.T) { t.Run(k, func(t *testing.T) { // given signupProvider := fakeSignupService.GetSignupFromInformer - informerFunc := fake.GetInformerService(fakeClient) proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) s := &handlers.SpaceLister{ - GetSignupFunc: signupProvider, - GetInformerServiceFunc: informerFunc, - ProxyMetrics: proxyMetrics, + GetSignupFunc: signupProvider, + GetInformerServiceFunc: func() service.InformerService { + return infservice.NewInformerService(fakeClient, test.HostOperatorNs) + }, + ProxyMetrics: proxyMetrics, } e := echo.New() @@ -868,7 +883,7 @@ func TestGetUserWorkspaceWithBindingsWithPublicViewerEnabled(t *testing.T) { newSignup("gordon", "gordon.no-space", false), ) - fakeClient := fake.InitClient(t, + fakeClient := test.NewFakeClient(t, // NSTemplateTiers fake.NewBase1NSTemplateTier(), @@ -962,13 +977,14 @@ func TestGetUserWorkspaceWithBindingsWithPublicViewerEnabled(t *testing.T) { t.Run(k, func(t *testing.T) { // given signupProvider := fakeSignupService.GetSignupFromInformer - informerFunc := fake.GetInformerService(fakeClient) proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) s := &handlers.SpaceLister{ - GetSignupFunc: signupProvider, - GetInformerServiceFunc: informerFunc, - ProxyMetrics: proxyMetrics, + GetSignupFunc: signupProvider, + GetInformerServiceFunc: func() service.InformerService { + return infservice.NewInformerService(fakeClient, test.HostOperatorNs) + }, + ProxyMetrics: proxyMetrics, } e := echo.New() @@ -984,7 +1000,7 @@ func TestGetUserWorkspaceWithBindingsWithPublicViewerEnabled(t *testing.T) { getMembersFuncMock := func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { return []*commoncluster.CachedToolchainCluster{ { - Client: fake.InitClient(t), + Client: test.NewFakeClient(t), Config: &commoncluster.Config{ Name: "not-me", }, diff --git a/pkg/proxy/handlers/spacelister_list_test.go b/pkg/proxy/handlers/spacelister_list_test.go index 1402f367..7ca5eff4 100644 --- a/pkg/proxy/handlers/spacelister_list_test.go +++ b/pkg/proxy/handlers/spacelister_list_test.go @@ -1,6 +1,7 @@ package handlers_test import ( + "context" "fmt" "net/http" "net/http/httptest" @@ -8,13 +9,14 @@ import ( "testing" "time" + infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/gin-gonic/gin" "github.com/labstack/echo/v4" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service" @@ -71,14 +73,15 @@ func TestListUserWorkspaces(t *testing.T) { t.Run(k, func(t *testing.T) { // given signupProvider := fakeSignupService.GetSignupFromInformer - informerFunc := fake.GetInformerService(fakeClient) proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) s := &handlers.SpaceLister{ - GetSignupFunc: signupProvider, - GetInformerServiceFunc: informerFunc, - ProxyMetrics: proxyMetrics, + GetSignupFunc: signupProvider, + GetInformerServiceFunc: func() service.InformerService { + return infservice.NewInformerService(fakeClient, test.HostOperatorNs) + }, + ProxyMetrics: proxyMetrics, } e := echo.New() @@ -114,68 +117,72 @@ func TestHandleSpaceListRequest(t *testing.T) { } for k, rtc := range tt { - fakeSignupService, fakeClient := buildSpaceListerFakes(t) t.Run(k, func(t *testing.T) { // given tests := map[string]struct { - username string - expectedWs []toolchainv1alpha1.Workspace - expectedErr string - expectedErrCode int - expectedWorkspace string - overrideSignupFunc func(ctx *gin.Context, userID, username string, checkUserSignupComplete bool) (*signup.Signup, error) - overrideInformerFunc func() service.InformerService + username string + expectedWs func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace + expectedErr string + expectedErrCode int + expectedWorkspace string + overrideSignupFunc func(ctx *gin.Context, userID, username string, checkUserSignupComplete bool) (*signup.Signup, error) + mockFakeClient func(fakeClient *test.FakeClient) }{ "dancelover lists spaces": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "dancelover", "admin", true), - workspaceFor(t, fakeClient, "movielover", "other", false), + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{ + workspaceFor(t, fakeClient, "dancelover", "admin", true), + workspaceFor(t, fakeClient, "movielover", "other", false), + } }, expectedErr: "", }, "movielover lists spaces": { username: "movie.lover", - expectedWs: []toolchainv1alpha1.Workspace{ - workspaceFor(t, fakeClient, "movielover", "admin", true), + expectedWs: func(t *testing.T, fakeClient *test.FakeClient) []toolchainv1alpha1.Workspace { + return []toolchainv1alpha1.Workspace{ + workspaceFor(t, fakeClient, "movielover", "admin", true), + } }, expectedErr: "", }, "signup has no compliant username set": { username: "racing.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "", expectedErrCode: 200, }, "space not initialized yet": { username: "panda.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "", expectedErrCode: 200, }, "no spaces found": { username: "user.nospace", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "", expectedErrCode: 200, }, "informer error": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "list spacebindings error", expectedErrCode: 500, - overrideInformerFunc: func() service.InformerService { - inf := fake.NewFakeInformer() - inf.ListSpaceBindingFunc = func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return nil, fmt.Errorf("list spacebindings error") + mockFakeClient: func(fakeClient *test.FakeClient) { + fakeClient.MockList = func(ctx context.Context, list runtimeclient.ObjectList, opts ...runtimeclient.ListOption) error { + if _, ok := list.(*toolchainv1alpha1.SpaceBindingList); ok { + return fmt.Errorf("list spacebindings error") + } + return fakeClient.Client.List(ctx, list, opts...) } - return inf }, }, "get signup error": { username: "dance.lover", - expectedWs: []toolchainv1alpha1.Workspace{}, + expectedWs: nil, expectedErr: "signup error", expectedErrCode: 500, overrideSignupFunc: func(_ *gin.Context, _, _ string, _ bool) (*signup.Signup, error) { @@ -187,22 +194,24 @@ func TestHandleSpaceListRequest(t *testing.T) { for k, tc := range tests { t.Run(k, func(t *testing.T) { // given + fakeSignupService, fakeClient := buildSpaceListerFakes(t) + if tc.mockFakeClient != nil { + tc.mockFakeClient(fakeClient) + } + signupProvider := fakeSignupService.GetSignupFromInformer if tc.overrideSignupFunc != nil { signupProvider = tc.overrideSignupFunc } - informerFunc := fake.GetInformerService(fakeClient) - if tc.overrideInformerFunc != nil { - informerFunc = tc.overrideInformerFunc - } - proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) s := &handlers.SpaceLister{ - GetSignupFunc: signupProvider, - GetInformerServiceFunc: informerFunc, - ProxyMetrics: proxyMetrics, + GetSignupFunc: signupProvider, + GetInformerServiceFunc: func() service.InformerService { + return infservice.NewInformerService(fakeClient, test.HostOperatorNs) + }, + ProxyMetrics: proxyMetrics, } e := echo.New() @@ -226,10 +235,14 @@ func TestHandleSpaceListRequest(t *testing.T) { // list workspace case workspaceList, decodeErr := decodeResponseToWorkspaceList(rec.Body.Bytes()) require.NoError(t, decodeErr) - require.Equal(t, len(tc.expectedWs), len(workspaceList.Items)) - for i := range tc.expectedWs { - assert.Equal(t, tc.expectedWs[i].Name, workspaceList.Items[i].Name) - assert.Equal(t, tc.expectedWs[i].Status, workspaceList.Items[i].Status) + var expectedWorkspaces []toolchainv1alpha1.Workspace + if tc.expectedWs != nil { + expectedWorkspaces = tc.expectedWs(t, fakeClient) + } + require.Equal(t, len(expectedWorkspaces), len(workspaceList.Items)) + for i := range expectedWorkspaces { + assert.Equal(t, expectedWorkspaces[i].Name, workspaceList.Items[i].Name) + assert.Equal(t, expectedWorkspaces[i].Status, workspaceList.Items[i].Status) } } }) diff --git a/pkg/proxy/handlers/spacelister_test.go b/pkg/proxy/handlers/spacelister_test.go index f03b465d..240914f9 100644 --- a/pkg/proxy/handlers/spacelister_test.go +++ b/pkg/proxy/handlers/spacelister_test.go @@ -13,7 +13,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/configuration" "github.com/codeready-toolchain/registration-service/pkg/signup" "github.com/codeready-toolchain/registration-service/test/fake" commonproxy "github.com/codeready-toolchain/toolchain-common/pkg/proxy" @@ -100,9 +99,8 @@ func buildSpaceListerFakesWithResources(t *testing.T, signups []fake.SignupDef, //nstemplatetier fake.NewBase1NSTemplateTier(), ) - fakeClient := fake.InitClient(t, oo...) - return fakeSignupService, fakeClient + return fakeSignupService, test.NewFakeClient(t, oo...) } func newSignup(signupName, username string, ready bool) fake.SignupDef { @@ -146,7 +144,7 @@ func decodeResponseToWorkspaceList(data []byte) (*toolchainv1alpha1.WorkspaceLis func workspaceFor(t *testing.T, fakeClient client.Client, name, role string, isHomeWorkspace bool, additionalWSOptions ...commonproxy.WorkspaceOption) toolchainv1alpha1.Workspace { // get the space for the user space := &toolchainv1alpha1.Space{} - err := fakeClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: configuration.Namespace()}, space) + err := fakeClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: test.HostOperatorNs}, space) require.NoError(t, err) // create the workspace based on the space diff --git a/pkg/proxy/proxy_test.go b/pkg/proxy/proxy_test.go index 43902df1..6bd9ad6c 100644 --- a/pkg/proxy/proxy_test.go +++ b/pkg/proxy/proxy_test.go @@ -19,7 +19,7 @@ import ( appservice "github.com/codeready-toolchain/registration-service/pkg/application/service" "github.com/codeready-toolchain/registration-service/pkg/auth" - "github.com/codeready-toolchain/registration-service/pkg/configuration" + infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/codeready-toolchain/registration-service/pkg/proxy/access" "github.com/codeready-toolchain/registration-service/pkg/proxy/handlers" "github.com/codeready-toolchain/registration-service/pkg/proxy/metrics" @@ -29,6 +29,7 @@ import ( "github.com/codeready-toolchain/registration-service/test" "github.com/codeready-toolchain/registration-service/test/fake" "github.com/prometheus/client_golang/prometheus" + "k8s.io/client-go/kubernetes/scheme" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" commoncluster "github.com/codeready-toolchain/toolchain-common/pkg/cluster" @@ -43,7 +44,6 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -61,7 +61,7 @@ var ( bannedUser = toolchainv1alpha1.BannedUser{ ObjectMeta: metav1.ObjectMeta{ Name: "alice", - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString("alice@redhat.com"), }, @@ -91,24 +91,24 @@ func (s *TestProxySuite) TestProxy() { s.SetConfig(testconfig.RegistrationService(). Environment(string(environment))) - inf := fake.GetInformerService( - fake.InitClient(s.T()), - fake.WithGetBannedUsersByEmailFunc(func(email string) ([]toolchainv1alpha1.BannedUser, error) { - switch email { - case bannedUser.Spec.Email: - return []toolchainv1alpha1.BannedUser{bannedUser}, nil - case bannedUserListErrorEmailValue: - return nil, fmt.Errorf("list banned user error") - default: - return nil, nil - } - }))() + fakeClient := commontest.NewFakeClient(s.T(), &bannedUser) + fakeClient.MockList = func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { + listOptions := &client.ListOptions{} + for _, opt := range opts { + opt.ApplyToList(listOptions) + } + if strings.Contains(listOptions.LabelSelector.String(), hash.EncodeString(bannedUserListErrorEmailValue)) { + return fmt.Errorf("list banned user error") + } + return fakeClient.Client.List(ctx, list, opts...) + } + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) fakeApp := &fake.ProxyFakeApp{ InformerServiceMock: inf, } proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) - p, err := newProxyWithClusterClient(fakeApp, nil, proxyMetrics, proxytest.NewGetMembersFunc(fake.InitClient(s.T()))) + p, err := newProxyWithClusterClient(fakeApp, nil, proxyMetrics, proxytest.NewGetMembersFunc(commontest.NewFakeClient(s.T()))) require.NoError(s.T(), err) server := p.StartProxy(DefaultPort) @@ -724,49 +724,28 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { }), ) s.Application.MockSignupService(fakeApp.SignupServiceMock) - inf := fake.NewFakeInformer() - inf.GetSpaceFunc = func(name string) (*toolchainv1alpha1.Space, error) { - switch name { - case "mycoolworkspace": - return fake.NewSpace("mycoolworkspace", "member-2", "smith2"), nil - } - return nil, fmt.Errorf("space not found error") - } - inf.ListSpaceBindingFunc = func(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - // always return a spacebinding for the purposes of the proxy tests, actual testing of the space lister is covered in the space lister tests - spaceBindings := []toolchainv1alpha1.SpaceBinding{} - for _, req := range reqs { - if req.Values().List()[0] == "smith2" || req.Values().List()[0] == "mycoolworkspace" { - spaceBindings = []toolchainv1alpha1.SpaceBinding{*fake.NewSpaceBinding("mycoolworkspace-smith2", "smith2", "mycoolworkspace", "admin")} - } - } - return spaceBindings, nil - } - inf.GetProxyPluginConfigFunc = func(name string) (*toolchainv1alpha1.ProxyPlugin, error) { - switch name { - case "myplugin": - return &toolchainv1alpha1.ProxyPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: metav1.NamespaceDefault, - Name: "myplugin", - }, - Spec: toolchainv1alpha1.ProxyPluginSpec{ - OpenShiftRouteTargetEndpoint: &toolchainv1alpha1.OpenShiftRouteTarget{ - Namespace: metav1.NamespaceDefault, - Name: metav1.NamespaceDefault, - }, - }, - Status: toolchainv1alpha1.ProxyPluginStatus{}, - }, nil - } - return nil, fmt.Errorf("proxy plugin not found") - } - inf.GetNSTemplateTierFunc = func(_ string) (*toolchainv1alpha1.NSTemplateTier, error) { - return fake.NewBase1NSTemplateTier(), nil - } - inf.ListBannedUsersByEmailFunc = func(_ string) ([]toolchainv1alpha1.BannedUser, error) { - return nil, nil + + proxyPlugin := &toolchainv1alpha1.ProxyPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: commontest.HostOperatorNs, + Name: "myplugin", + }, + Spec: toolchainv1alpha1.ProxyPluginSpec{ + OpenShiftRouteTargetEndpoint: &toolchainv1alpha1.OpenShiftRouteTarget{ + Namespace: commontest.HostOperatorNs, + Name: "proxy-plugin", + }, + }, + Status: toolchainv1alpha1.ProxyPluginStatus{}, } + require.NoError(s.T(), routev1.Install(scheme.Scheme)) + fakeClient := commontest.NewFakeClient(s.T(), + fake.NewSpace("mycoolworkspace", "member-2", "smith2"), + fake.NewSpaceBinding("mycoolworkspace-smith2", "smith2", "mycoolworkspace", "admin"), + proxyPlugin, + fake.NewBase1NSTemplateTier()) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) + s.Application.MockInformerService(inf) fakeApp.MemberClusterServiceMock = s.newMemberClusterServiceWithMembers(testServer.URL) @@ -811,7 +790,6 @@ type headerToAdd struct { } func (s *TestProxySuite) newMemberClusterServiceWithMembers(serverURL string) appservice.MemberClusterService { - fakeClient := commontest.NewFakeClient(s.T()) serverHost := serverURL switch { case strings.HasPrefix(serverURL, "http://"): @@ -819,21 +797,24 @@ func (s *TestProxySuite) newMemberClusterServiceWithMembers(serverURL string) ap case strings.HasPrefix(serverURL, "https://"): serverHost = strings.TrimPrefix(serverURL, "https://") } - fakeClient.MockGet = func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - route, ok := obj.(*routev1.Route) - if ok && key.Namespace == metav1.NamespaceDefault && key.Name == metav1.NamespaceDefault { - route.Namespace = key.Namespace - route.Name = key.Name - route.Spec.Port = &routev1.RoutePort{TargetPort: intstr.FromString("http")} - route.Status.Ingress = []routev1.RouteIngress{ + + route := &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: commontest.HostOperatorNs, + Name: "proxy-plugin", + }, + Spec: routev1.RouteSpec{ + Port: &routev1.RoutePort{TargetPort: intstr.FromString("http")}, + }, + Status: routev1.RouteStatus{ + Ingress: []routev1.RouteIngress{ { Host: serverHost, }, - } - return nil - } - return fakeClient.Client.Get(ctx, key, obj, opts...) + }, + }, } + fakeClient := commontest.NewFakeClient(s.T(), route) return service.NewMemberClusterService( fake.MemberClusterServiceContext{ CrtClient: s, diff --git a/pkg/proxy/service/cluster_service_test.go b/pkg/proxy/service/cluster_service_test.go index 408b94ec..3379f0b2 100644 --- a/pkg/proxy/service/cluster_service_test.go +++ b/pkg/proxy/service/cluster_service_test.go @@ -7,6 +7,7 @@ import ( "net/url" "testing" + infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/codeready-toolchain/registration-service/pkg/proxy/access" "github.com/codeready-toolchain/registration-service/pkg/proxy/service" "github.com/codeready-toolchain/registration-service/pkg/signup" @@ -69,35 +70,25 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { })) s.Application.MockSignupService(sc) - inf := fake.NewFakeInformer() - inf.GetSpaceFunc = func(name string) (*toolchainv1alpha1.Space, error) { - switch name { - case "noise1", "teamspace": - return fake.NewSpace(name, "member-1", name), nil - case "smith2": - return fake.NewSpace(name, "member-2", name), nil - case "unknown-cluster": - return fake.NewSpace(name, "unknown-cluster", name), nil - } - return nil, fmt.Errorf("space not found error") - } - inf.GetProxyPluginConfigFunc = func(name string) (*toolchainv1alpha1.ProxyPlugin, error) { - if name != "tekton-results" { - return nil, errors.New("not found") - } - pp := &toolchainv1alpha1.ProxyPlugin{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: toolchainv1alpha1.ProxyPluginSpec{ - OpenShiftRouteTargetEndpoint: &toolchainv1alpha1.OpenShiftRouteTarget{ - Namespace: "tekton-results", - Name: "tekton-results", - }, + pp := &toolchainv1alpha1.ProxyPlugin{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tekton-results", + Namespace: commontest.HostOperatorNs, + }, + Spec: toolchainv1alpha1.ProxyPluginSpec{ + OpenShiftRouteTargetEndpoint: &toolchainv1alpha1.OpenShiftRouteTarget{ + Namespace: "tekton-results", + Name: "tekton-results", }, - } - return pp, nil + }, } + fakeClient := commontest.NewFakeClient(s.T(), + fake.NewSpace("noise1", "member-1", "noise1"), + fake.NewSpace("teamspace", "member-1", "teamspace"), + fake.NewSpace("smith2", "member-2", "smith2"), + fake.NewSpace("unknown-cluster", "unknown-cluster", "unknown-cluster"), + pp) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewMemberClusterService( @@ -172,14 +163,16 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { s.Run("unable to get space", func() { s.Run("informer service returns error", func() { - original := inf.GetSpaceFunc - defer func() { // restore original GetSpaceFunc after test - inf.GetSpaceFunc = original - s.Application.MockInformerService(inf) - }() - inf.GetSpaceFunc = func(_ string) (*toolchainv1alpha1.Space, error) { // informer error - return nil, fmt.Errorf("oopsi woopsi") + fakeClient.MockGet = func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.Space); ok && key.Name == "smith2" { + return fmt.Errorf("oopsi woopsi") + } + return fakeClient.Client.Get(ctx, key, obj, opts...) } + defer func() { + fakeClient.MockGet = nil + }() + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) // when diff --git a/pkg/signup/service/signup_service_test.go b/pkg/signup/service/signup_service_test.go index dcfe641d..c39f5658 100644 --- a/pkg/signup/service/signup_service_test.go +++ b/pkg/signup/service/signup_service_test.go @@ -2,6 +2,7 @@ package service_test import ( "bytes" + gocontext "context" "errors" "fmt" "hash/crc32" @@ -15,15 +16,17 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/configuration" "github.com/codeready-toolchain/registration-service/pkg/context" errors2 "github.com/codeready-toolchain/registration-service/pkg/errors" + infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/codeready-toolchain/registration-service/pkg/signup/service" "github.com/codeready-toolchain/registration-service/pkg/util" "github.com/codeready-toolchain/registration-service/test" "github.com/codeready-toolchain/registration-service/test/fake" + "sigs.k8s.io/controller-runtime/pkg/client" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" commonconfig "github.com/codeready-toolchain/toolchain-common/pkg/configuration" "github.com/codeready-toolchain/toolchain-common/pkg/states" - test2 "github.com/codeready-toolchain/toolchain-common/pkg/test" + commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" testconfig "github.com/codeready-toolchain/toolchain-common/pkg/test/config" recaptchapb "cloud.google.com/go/recaptchaenterprise/v2/apiv1/recaptchaenterprisepb" @@ -36,7 +39,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" ) @@ -52,7 +54,7 @@ func TestRunSignupServiceSuite(t *testing.T) { func (s *TestSignupServiceSuite) ServiceConfiguration(namespace string, verificationEnabled bool, excludedDomains string, verificationCodeExpiresInMin int) { - test2.SetEnvVarAndRestore(s.T(), commonconfig.WatchNamespaceEnvVar, namespace) + commontest.SetEnvVarAndRestore(s.T(), commonconfig.WatchNamespaceEnvVar, namespace) s.OverrideApplicationDefault( testconfig.RegistrationService(). @@ -62,7 +64,7 @@ func (s *TestSignupServiceSuite) ServiceConfiguration(namespace string, verifica } func (s *TestSignupServiceSuite) TestSignup() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) // given userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -74,7 +76,7 @@ func (s *TestSignupServiceSuite) TestSignup() { require.NoError(s.T(), err) gvr, _ := meta.UnsafeGuessKindToResource(gvk) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, configuration.Namespace()) + values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) require.NoError(s.T(), err) userSignups := values.(*toolchainv1alpha1.UserSignupList) @@ -82,7 +84,7 @@ func (s *TestSignupServiceSuite) TestSignup() { require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] - require.Equal(s.T(), configuration.Namespace(), val.Namespace) + require.Equal(s.T(), commontest.HostOperatorNs, val.Namespace) require.Equal(s.T(), username, val.Name) require.True(s.T(), states.VerificationRequired(&val)) require.Equal(s.T(), "a7b1b413c1cbddbcd19a51222ef8e20a", val.Labels[toolchainv1alpha1.UserSignupUserEmailHashLabelKey]) @@ -132,7 +134,7 @@ func (s *TestSignupServiceSuite) TestSignup() { deactivatedUS.Annotations[toolchainv1alpha1.UserSignupLastTargetClusterAnnotationKey] = "member-3" // assume the user was targeted to member-3 states.SetDeactivated(deactivatedUS, true) deactivatedUS.Status.Conditions = deactivated() - err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, configuration.Namespace()) + err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, commontest.HostOperatorNs) require.NoError(s.T(), err) // when @@ -154,7 +156,7 @@ func (s *TestSignupServiceSuite) TestSignup() { // also, alter the activation counter annotation delete(deactivatedUS.Annotations, toolchainv1alpha1.UserSignupActivationCounterAnnotationKey) delete(deactivatedUS.Annotations, toolchainv1alpha1.UserSignupLastTargetClusterAnnotationKey) - err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, configuration.Namespace()) + err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, commontest.HostOperatorNs) require.NoError(s.T(), err) // when @@ -173,7 +175,7 @@ func (s *TestSignupServiceSuite) TestSignup() { deactivatedUS := existing.DeepCopy() states.SetDeactivated(deactivatedUS, true) deactivatedUS.Status.Conditions = deactivated() - err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, configuration.Namespace()) + err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, commontest.HostOperatorNs) require.NoError(s.T(), err) s.FakeUserSignupClient.MockUpdate = func(signup *toolchainv1alpha1.UserSignup) (*toolchainv1alpha1.UserSignup, error) { if signup.Name == "jsmith" { @@ -262,14 +264,15 @@ func (s *TestSignupServiceSuite) TestGetSignupFailsWithNotFoundThenOtherError() s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == "000" { - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) + fakeClient := commontest.NewFakeClient(t) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok && key.Name != "000" { + return errors2.NewInternalError(errors.New("something quite unfortunate happened"), "something bad") } - return nil, errors2.NewInternalError(errors.New("something quite unfortunate happened"), "something bad") + return fakeClient.Client.Get(ctx, key, obj, opts...) } + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -287,7 +290,7 @@ func (s *TestSignupServiceSuite) TestGetSignupFailsWithNotFoundThenOtherError() } func (s *TestSignupServiceSuite) TestSignupNoSpaces() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) // given userID, err := uuid.NewV4() @@ -315,7 +318,7 @@ func (s *TestSignupServiceSuite) TestSignupNoSpaces() { require.NoError(s.T(), err) gvr, _ := meta.UnsafeGuessKindToResource(gvk) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, configuration.Namespace()) + values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) require.NoError(s.T(), err) userSignups := values.(*toolchainv1alpha1.UserSignupList) @@ -327,7 +330,7 @@ func (s *TestSignupServiceSuite) TestSignupNoSpaces() { } func (s *TestSignupServiceSuite) TestSignupWithCaptchaEnabled() { - test2.SetEnvVarAndRestore(s.T(), commonconfig.WatchNamespaceEnvVar, configuration.Namespace()) + commontest.SetEnvVarAndRestore(s.T(), commonconfig.WatchNamespaceEnvVar, commontest.HostOperatorNs) // captcha is enabled serviceOption := func(svc *service.ServiceImpl) { @@ -373,7 +376,7 @@ func (s *TestSignupServiceSuite) TestSignupWithCaptchaEnabled() { require.NoError(s.T(), err) gvr, _ := meta.UnsafeGuessKindToResource(gvk) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, configuration.Namespace()) + values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) require.NoError(s.T(), err) userSignups := values.(*toolchainv1alpha1.UserSignupList) @@ -385,7 +388,7 @@ func (s *TestSignupServiceSuite) TestSignupWithCaptchaEnabled() { } func (s *TestSignupServiceSuite) TestUserSignupWithInvalidSubjectPrefix() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) // given userID, err := uuid.NewV4() @@ -412,7 +415,7 @@ func (s *TestSignupServiceSuite) TestUserSignupWithInvalidSubjectPrefix() { require.NoError(s.T(), err) gvr, _ := meta.UnsafeGuessKindToResource(gvk) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, configuration.Namespace()) + values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) require.NoError(s.T(), err) userSignups := values.(*toolchainv1alpha1.UserSignupList) @@ -462,7 +465,7 @@ func (s *TestSignupServiceSuite) TestEncodeUserID() { } func (s *TestSignupServiceSuite) TestUserWithExcludedDomainEmailSignsUp() { - s.ServiceConfiguration(configuration.Namespace(), true, "redhat.com", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "redhat.com", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -484,7 +487,7 @@ func (s *TestSignupServiceSuite) TestUserWithExcludedDomainEmailSignsUp() { require.NoError(s.T(), err) gvr, _ := meta.UnsafeGuessKindToResource(gvk) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, configuration.Namespace()) + values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) require.NoError(s.T(), err) userSignups := values.(*toolchainv1alpha1.UserSignupList) @@ -496,7 +499,7 @@ func (s *TestSignupServiceSuite) TestUserWithExcludedDomainEmailSignsUp() { } func (s *TestSignupServiceSuite) TestCRTAdminUserSignup() { - s.ServiceConfiguration(configuration.Namespace(), true, "redhat.com", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "redhat.com", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -516,7 +519,7 @@ func (s *TestSignupServiceSuite) TestCRTAdminUserSignup() { } func (s *TestSignupServiceSuite) TestFailsIfUserSignupNameAlreadyExists() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -524,7 +527,7 @@ func (s *TestSignupServiceSuite) TestFailsIfUserSignupNameAlreadyExists() { TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, }, Spec: toolchainv1alpha1.UserSignupSpec{}, }) @@ -541,7 +544,7 @@ func (s *TestSignupServiceSuite) TestFailsIfUserSignupNameAlreadyExists() { } func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) // given userID, err := uuid.NewV4() @@ -554,7 +557,7 @@ func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: bannedUserID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.BannedUserEmailHashLabelKey: "a7b1b413c1cbddbcd19a51222ef8e20a", }, @@ -584,7 +587,7 @@ func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { } func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseBannedUser() { - s.ServiceConfiguration(configuration.Namespace(), true, "redhat.com", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "redhat.com", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -596,7 +599,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseBannedUser() { TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: bannedUserID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.BannedUserEmailHashLabelKey: "a7b1b413c1cbddbcd19a51222ef8e20a", toolchainv1alpha1.BannedUserPhoneNumberHashLabelKey: "fd276563a8232d16620da8ec85d0575f", @@ -618,7 +621,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseBannedUser() { } func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseUserSignup() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -627,7 +630,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseUserSignup() { TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.UserSignupUserEmailHashLabelKey: "a7b1b413c1cbddbcd19a51222ef8e20a", toolchainv1alpha1.UserSignupUserPhoneHashLabelKey: "fd276563a8232d16620da8ec85d0575f", @@ -649,7 +652,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseUserSignup() { } func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -661,7 +664,7 @@ func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: bannedUserID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.BannedUserEmailHashLabelKey: "1df66fbb427ff7e64ac46af29cc74b71", }, @@ -685,7 +688,7 @@ func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { require.NoError(s.T(), err) gvr, _ := meta.UnsafeGuessKindToResource(gvk) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, configuration.Namespace()) + values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) require.NoError(s.T(), err) userSignups := values.(*toolchainv1alpha1.UserSignupList) @@ -693,7 +696,7 @@ func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] - require.Equal(s.T(), configuration.Namespace(), val.Namespace) + require.Equal(s.T(), commontest.HostOperatorNs, val.Namespace) require.Equal(s.T(), "jsmith", val.Name) require.False(s.T(), states.ApprovedManually(&val)) require.Equal(s.T(), "a7b1b413c1cbddbcd19a51222ef8e20a", val.Labels[toolchainv1alpha1.UserSignupUserEmailHashLabelKey]) @@ -719,14 +722,15 @@ func (s *TestSignupServiceSuite) TestGetUserSignupFails() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == username { - return nil, errors.New("an error occurred") + fakeClient := commontest.NewFakeClient(t) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if key.Name != username { + return errors.New("an error occurred") } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) + return fakeClient.Client.Get(ctx, key, obj, opts...) } + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -755,12 +759,8 @@ func (s *TestSignupServiceSuite) TestGetSignupNotFound() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - + fakeClient := commontest.NewFakeClient(t) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -780,18 +780,18 @@ func (s *TestSignupServiceSuite) TestGetSignupNotFound() { func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) c, _ := gin.CreateTestContext(httptest.NewRecorder()) - userSignupNotComplete := toolchainv1alpha1.UserSignup{ + userSignupNotComplete := &toolchainv1alpha1.UserSignup{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, }, Spec: toolchainv1alpha1.UserSignupSpec{ IdentityClaims: toolchainv1alpha1.IdentityClaimsEmbedded{ @@ -815,9 +815,9 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { }, }, } - states.SetVerificationRequired(&userSignupNotComplete, true) + states.SetVerificationRequired(userSignupNotComplete, true) - err = s.FakeUserSignupClient.Tracker.Add(&userSignupNotComplete) + err = s.FakeUserSignupClient.Tracker.Add(userSignupNotComplete) require.NoError(s.T(), err) // when @@ -846,14 +846,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { s.T().Run("informer - with check for usersignup complete condition", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == userID.String() { - return &userSignupNotComplete, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - + fakeClient := commontest.NewFakeClient(t, userSignupNotComplete) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -887,7 +881,7 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { s.T().Run("informer - with no check for UserSignup complete condition", func(t *testing.T) { // given - states.SetVerificationRequired(&userSignupNotComplete, false) + states.SetVerificationRequired(userSignupNotComplete, false) svc := service.NewSignupService( fake.MemberClusterServiceContext{ CrtClient: s, @@ -910,28 +904,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { err = s.FakeToolchainStatusClient.Tracker.Add(toolchainStatus) require.NoError(t, err) - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == userID.String() { - return &userSignupNotComplete, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetMurFunc = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if name == mur.Name { - return mur, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetSpaceFunc = func(_ string) (*toolchainv1alpha1.Space, error) { - return space, nil - } - inf.ListSpaceBindingFunc = func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return []toolchainv1alpha1.SpaceBinding{*spacebinding}, nil - } - inf.GetToolchainStatusFunc = func() (*toolchainv1alpha1.ToolchainStatus, error) { - return toolchainStatus, nil - } + fakeClient := commontest.NewFakeClient(t, userSignupNotComplete, mur, space, spacebinding, toolchainStatus) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) // when @@ -961,7 +935,7 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) noCondition := toolchainv1alpha1.UserSignupStatus{} pendingApproval := toolchainv1alpha1.UserSignupStatus{ @@ -994,11 +968,11 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { c, _ := gin.CreateTestContext(httptest.NewRecorder()) - userSignup := toolchainv1alpha1.UserSignup{ + userSignup := &toolchainv1alpha1.UserSignup{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, }, Spec: toolchainv1alpha1.UserSignupSpec{ IdentityClaims: toolchainv1alpha1.IdentityClaimsEmbedded{ @@ -1008,9 +982,9 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { Status: status, } - states.SetVerificationRequired(&userSignup, true) + states.SetVerificationRequired(userSignup, true) - err = s.FakeUserSignupClient.Tracker.Add(&userSignup) + err = s.FakeUserSignupClient.Tracker.Add(userSignup) require.NoError(s.T(), err) // when @@ -1037,14 +1011,8 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == userID.String() { - return &userSignup, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - + fakeClient := commontest.NewFakeClient(t, userSignup) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1080,7 +1048,7 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { func (s *TestSignupServiceSuite) TestGetSignupDeactivated() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) us := s.newUserSignupComplete() us.Status.Conditions = deactivated() @@ -1098,14 +1066,8 @@ func (s *TestSignupServiceSuite) TestGetSignupDeactivated() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == us.Name { - return us, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - + fakeClient := commontest.NewFakeClient(t, us) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1128,7 +1090,7 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusOK() { for _, appsSubDomain := range []string{".apps.", ".apps-"} { s.SetupTest() s.T().Run("for apps subdomain: "+appsSubDomain, func(t *testing.T) { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) us := s.newUserSignupComplete() err := s.FakeUserSignupClient.Tracker.Add(us) @@ -1179,29 +1141,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusOK() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == us.Name { - return us, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetMurFunc = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if name == mur.Name { - return mur, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetToolchainStatusFunc = func() (*toolchainv1alpha1.ToolchainStatus, error) { - return toolchainStatus, nil - } - inf.GetSpaceFunc = func(_ string) (*toolchainv1alpha1.Space, error) { - return space, nil - } - inf.ListSpaceBindingFunc = func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return []toolchainv1alpha1.SpaceBinding{*spacebinding}, nil - } - + fakeClient := commontest.NewFakeClient(t, us, mur, toolchainStatus, space, spacebinding) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1237,7 +1178,7 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusOK() { func (s *TestSignupServiceSuite) TestGetSignupByUsernameOK() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) us := s.newUserSignupComplete() us.Name = service.EncodeUserIdentifier(us.Spec.IdentityClaims.PreferredUsername) @@ -1307,29 +1248,8 @@ func (s *TestSignupServiceSuite) TestGetSignupByUsernameOK() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == us.Name { - return us, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetMurFunc = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if name == mur.Name { - return mur, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetToolchainStatusFunc = func() (*toolchainv1alpha1.ToolchainStatus, error) { - return toolchainStatus, nil - } - inf.GetSpaceFunc = func(_ string) (*toolchainv1alpha1.Space, error) { - return space, nil - } - inf.ListSpaceBindingFunc = func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return []toolchainv1alpha1.SpaceBinding{*spacebinding}, nil - } - + fakeClient := commontest.NewFakeClient(t, us, mur, toolchainStatus, space, spacebinding) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1367,7 +1287,7 @@ func (s *TestSignupServiceSuite) newToolchainStatus(appsSubDomain string) *toolc TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: "toolchain-status", - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, }, Status: toolchainv1alpha1.ToolchainStatusStatus{ Members: []toolchainv1alpha1.Member{ @@ -1402,7 +1322,7 @@ func (s *TestSignupServiceSuite) newToolchainStatus(appsSubDomain string) *toolc func (s *TestSignupServiceSuite) TestGetSignupStatusFailGetToolchainStatus() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) c, _ := gin.CreateTestContext(httptest.NewRecorder()) @@ -1424,29 +1344,8 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusFailGetToolchainStatus() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == us.Name { - return us, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetMurFunc = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if name == mur.Name { - return mur, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetSpaceFunc = func(name string) (*toolchainv1alpha1.Space, error) { - if name == space.Name { - return space, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetToolchainStatusFunc = func() (*toolchainv1alpha1.ToolchainStatus, error) { - return nil, apierrors.NewNotFound(schema.GroupResource{}, "toolchain-status") - } - + fakeClient := commontest.NewFakeClient(t, us, mur, space) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1459,13 +1358,13 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusFailGetToolchainStatus() { _, err := svc.GetSignupFromInformer(c, us.Name, "", true) // then - require.EqualError(t, err, fmt.Sprintf("error when retrieving ToolchainStatus to set Che Dashboard for completed UserSignup %s: \"toolchain-status\" not found", us.Name)) + require.EqualError(t, err, fmt.Sprintf("error when retrieving ToolchainStatus to set Che Dashboard for completed UserSignup %s: toolchainstatuses.toolchain.dev.openshift.com \"toolchain-status\" not found", us.Name)) }) } func (s *TestSignupServiceSuite) TestGetSignupMURGetFails() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) us := s.newUserSignupComplete() err := s.FakeUserSignupClient.Tracker.Add(us) @@ -1489,20 +1388,14 @@ func (s *TestSignupServiceSuite) TestGetSignupMURGetFails() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == us.Name { - return us, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetMurFunc = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if name == us.Status.CompliantUsername { - return nil, returnedErr + fakeClient := commontest.NewFakeClient(t, us) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.MasterUserRecord); ok && key.Name == us.Status.CompliantUsername { + return returnedErr } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) + return fakeClient.Client.Get(ctx, key, obj, opts...) } - + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1521,7 +1414,7 @@ func (s *TestSignupServiceSuite) TestGetSignupMURGetFails() { func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) us := s.newUserSignupComplete() err := s.FakeUserSignupClient.Tracker.Add(us) @@ -1533,7 +1426,7 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: "ted", - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, }, } @@ -1610,29 +1503,8 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { // informer case // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == us.Name { - return us, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetMurFunc = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if name == mur.Name { - return mur, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetSpaceFunc = func(name string) (*toolchainv1alpha1.Space, error) { - if name == space.Name { - return space, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - inf.GetToolchainStatusFunc = func() (*toolchainv1alpha1.ToolchainStatus, error) { - return toolchainStatus, nil - } - + fakeClient := commontest.NewFakeClient(t, us, mur, toolchainStatus, space) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1657,7 +1529,7 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) us := s.newBannedUserSignup() err := s.FakeUserSignupClient.Tracker.Add(us) @@ -1680,14 +1552,8 @@ func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetUserSignupFunc = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == us.Name { - return us, nil - } - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - + fakeClient := commontest.NewFakeClient(t, us) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) s.Application.MockInformerService(inf) svc := service.NewSignupService( fake.MemberClusterServiceContext{ @@ -1709,7 +1575,7 @@ func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { func (s *TestSignupServiceSuite) TestGetDefaultUserNamespace() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) space := s.newSpace("dave") err := s.FakeSpaceClient.Tracker.Add(space) @@ -1724,10 +1590,8 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespace() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetSpaceFunc = func(_ string) (*toolchainv1alpha1.Space, error) { - return space, nil - } + fakeClient := commontest.NewFakeClient(t, space) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "dave", "dave") @@ -1742,7 +1606,7 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespace() { // This is valuable when user doesn't have default home space created, but has access to some shared spaces func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFromFirstUnownedSpace() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) // space created for userA space := s.newSpace("userA") err := s.FakeSpaceClient.Tracker.Add(space) @@ -1772,13 +1636,8 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFromFirstUnownedSpac s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetSpaceFunc = func(_ string) (*toolchainv1alpha1.Space, error) { - return space, nil - } - inf.ListSpaceBindingFunc = func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return []toolchainv1alpha1.SpaceBinding{*spacebindingB, *spaceCindingC}, nil - } + fakeClient := commontest.NewFakeClient(t, space, spacebindingB, spaceCindingC) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "", "userB") @@ -1792,7 +1651,7 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFromFirstUnownedSpac // TestGetDefaultUserNamespaceMultiSpace tests that the home Space created for the user is prioritized when there are multiple spaces func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceMultiSpace() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) // space1 created by userA space1 := s.newSpace("userA") @@ -1824,20 +1683,8 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceMultiSpace() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetSpaceFunc = func(name string) (*toolchainv1alpha1.Space, error) { - switch name { - case space1.Name: - return space1, nil - case space2.Name: - return space2, nil - default: - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } - } - inf.ListSpaceBindingFunc = func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return []toolchainv1alpha1.SpaceBinding{*spacebinding1, *spacebinding2}, nil - } + fakeClient := commontest.NewFakeClient(t, space1, space2, spacebinding1, spacebinding2) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "userB", "userB") @@ -1850,7 +1697,7 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceMultiSpace() { func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpaceBinding() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) space := s.newSpace("dave") err := s.FakeSpaceClient.Tracker.Add(space) @@ -1865,13 +1712,14 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpa s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetSpaceFunc = func(_ string) (*toolchainv1alpha1.Space, error) { - return space, nil - } - inf.ListSpaceBindingFunc = func(_ ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return nil, apierrors.NewInternalError(fmt.Errorf("something went wrong")) + fakeClient := commontest.NewFakeClient(t, space) + fakeClient.MockList = func(ctx gocontext.Context, list client.ObjectList, opts ...client.ListOption) error { + if _, ok := list.(*toolchainv1alpha1.SpaceBindingList); ok { + return apierrors.NewInternalError(fmt.Errorf("something went wrong")) + } + return fakeClient.Client.List(ctx, list, opts...) } + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "", "dave") @@ -1884,7 +1732,7 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpa func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoSpace() { // given - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) // when targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(s, "dave", "dave") @@ -1895,10 +1743,8 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoSpace() { s.T().Run("informer", func(t *testing.T) { // given - inf := fake.NewFakeInformer() - inf.GetSpaceFunc = func(name string) (*toolchainv1alpha1.Space, error) { - return nil, apierrors.NewNotFound(schema.GroupResource{}, name) - } + fakeClient := commontest.NewFakeClient(t) + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "dave", "dave") @@ -1910,7 +1756,7 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoSpace() { } func (s *TestSignupServiceSuite) TestGetUserSignup() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) s.Run("getusersignup ok", func() { us := s.newUserSignupComplete() @@ -1942,7 +1788,7 @@ func (s *TestSignupServiceSuite) TestGetUserSignup() { } func (s *TestSignupServiceSuite) TestUpdateUserSignup() { - s.ServiceConfiguration(configuration.Namespace(), true, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) us := s.newUserSignupComplete() err := s.FakeUserSignupClient.Tracker.Add(us) @@ -1975,7 +1821,7 @@ func (s *TestSignupServiceSuite) TestUpdateUserSignup() { } func (s *TestSignupServiceSuite) TestIsPhoneVerificationRequired() { - test2.SetEnvVarAndRestore(s.T(), commonconfig.WatchNamespaceEnvVar, configuration.Namespace()) + commontest.SetEnvVarAndRestore(s.T(), commonconfig.WatchNamespaceEnvVar, commontest.HostOperatorNs) s.Run("phone verification is required", func() { s.Run("captcha verification is disabled", func() { @@ -2094,7 +1940,7 @@ func (s *TestSignupServiceSuite) TestIsPhoneVerificationRequired() { func (s *TestSignupServiceSuite) TestGetSignupUpdatesUserSignupIdentityClaims() { - s.ServiceConfiguration(configuration.Namespace(), false, "", 5) + s.ServiceConfiguration(commontest.HostOperatorNs, false, "", 5) // Create a new UserSignup, set its UserID and AccountID annotations userSignup := s.newUserSignupComplete() @@ -2106,7 +1952,7 @@ func (s *TestSignupServiceSuite) TestGetSignupUpdatesUserSignupIdentityClaims() TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userSignup.Status.CompliantUsername, - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, }, Spec: toolchainv1alpha1.MasterUserRecordSpec{ UserAccounts: []toolchainv1alpha1.UserAccountEmbedded{{TargetCluster: "member-123"}}, @@ -2235,7 +2081,7 @@ func (s *TestSignupServiceSuite) newUserSignupCompleteWithReason(reason string) TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Annotations: map[string]string{ toolchainv1alpha1.UserSignupUserEmailHashLabelKey: "90cb861692508c36933b85dfe43f5369", }, @@ -2282,7 +2128,7 @@ func (s *TestSignupServiceSuite) newBannedUserSignup() *toolchainv1alpha1.UserSi TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Annotations: map[string]string{ toolchainv1alpha1.UserSignupUserEmailHashLabelKey: "a7b1b413c1cbddbcd19a51222ef8e20a", }, @@ -2325,7 +2171,7 @@ func (s *TestSignupServiceSuite) newProvisionedMUR(name string) *toolchainv1alph TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: name, - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, }, Spec: toolchainv1alpha1.MasterUserRecordSpec{ UserAccounts: []toolchainv1alpha1.UserAccountEmbedded{{TargetCluster: "member-123"}}, @@ -2352,7 +2198,7 @@ func (s *TestSignupServiceSuite) newSpace(name string) *toolchainv1alpha1.Space TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: name, - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.SpaceCreatorLabelKey: name, }, @@ -2382,7 +2228,7 @@ func (s *TestSignupServiceSuite) newSpaceBinding(murName, spaceName string) *too TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: name.String(), - Namespace: configuration.Namespace(), + Namespace: commontest.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.SpaceBindingSpaceLabelKey: spaceName, toolchainv1alpha1.SpaceBindingMasterUserRecordLabelKey: murName, diff --git a/test/fake/informer.go b/test/fake/informer.go index c51e297c..dbbb1fa6 100644 --- a/test/fake/informer.go +++ b/test/fake/informer.go @@ -1,94 +1,13 @@ package fake import ( - "context" - "testing" - toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/application/service" "github.com/codeready-toolchain/registration-service/pkg/configuration" "github.com/codeready-toolchain/toolchain-common/pkg/test" spacetest "github.com/codeready-toolchain/toolchain-common/pkg/test/space" - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" ) -func NewFakeInformer() Informer { - return Informer{} -} - -type Informer struct { - GetMurFunc func(name string) (*toolchainv1alpha1.MasterUserRecord, error) - GetSpaceFunc func(name string) (*toolchainv1alpha1.Space, error) - GetToolchainStatusFunc func() (*toolchainv1alpha1.ToolchainStatus, error) - GetUserSignupFunc func(name string) (*toolchainv1alpha1.UserSignup, error) - ListSpaceBindingFunc func(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) - GetProxyPluginConfigFunc func(name string) (*toolchainv1alpha1.ProxyPlugin, error) - GetNSTemplateTierFunc func(name string) (*toolchainv1alpha1.NSTemplateTier, error) - ListBannedUsersByEmailFunc func(email string) ([]toolchainv1alpha1.BannedUser, error) -} - -func (f Informer) GetProxyPluginConfig(name string) (*toolchainv1alpha1.ProxyPlugin, error) { - if f.GetProxyPluginConfigFunc != nil { - return f.GetProxyPluginConfigFunc(name) - } - panic("not supposed to call GetProxyPluginConfig") -} - -func (f Informer) GetMasterUserRecord(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if f.GetMurFunc != nil { - return f.GetMurFunc(name) - } - panic("not supposed to call GetMasterUserRecord") -} - -func (f Informer) GetSpace(name string) (*toolchainv1alpha1.Space, error) { - if f.GetSpaceFunc != nil { - return f.GetSpaceFunc(name) - } - panic("not supposed to call GetSpace") -} - -func (f Informer) GetToolchainStatus() (*toolchainv1alpha1.ToolchainStatus, error) { - if f.GetToolchainStatusFunc != nil { - return f.GetToolchainStatusFunc() - } - panic("not supposed to call GetToolchainStatus") -} - -func (f Informer) GetUserSignup(name string) (*toolchainv1alpha1.UserSignup, error) { - if f.GetUserSignupFunc != nil { - return f.GetUserSignupFunc(name) - } - panic("not supposed to call GetUserSignup") -} - -func (f Informer) ListSpaceBindings(req ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - if f.ListSpaceBindingFunc != nil { - return f.ListSpaceBindingFunc(req...) - } - panic("not supposed to call ListSpaceBindings") -} - -func (f Informer) GetNSTemplateTier(tier string) (*toolchainv1alpha1.NSTemplateTier, error) { - if f.GetNSTemplateTierFunc != nil { - return f.GetNSTemplateTierFunc(tier) - } - panic("not supposed to call GetNSTemplateTierFunc") -} - -func (f Informer) ListBannedUsersByEmail(email string) ([]toolchainv1alpha1.BannedUser, error) { - if f.ListBannedUsersByEmailFunc != nil { - return f.ListBannedUsersByEmailFunc(email) - } - panic("not supposed to call BannedUsersByEmail") -} - func NewSpace(name, targetCluster, compliantUserName string, spaceTestOptions ...spacetest.Option) *toolchainv1alpha1.Space { spaceTestOptions = append(spaceTestOptions, @@ -108,7 +27,7 @@ func NewSpace(name, targetCluster, compliantUserName string, spaceTestOptions .. }, ), ) - return spacetest.NewSpace(configuration.Namespace(), name, + return spacetest.NewSpace(test.HostOperatorNs, name, spaceTestOptions..., ) } @@ -116,7 +35,8 @@ func NewSpace(name, targetCluster, compliantUserName string, spaceTestOptions .. func NewSpaceBinding(name, murLabelValue, spaceLabelValue, role string) *toolchainv1alpha1.SpaceBinding { return &toolchainv1alpha1.SpaceBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: name, + Name: name, + Namespace: test.HostOperatorNs, Labels: map[string]string{ toolchainv1alpha1.SpaceBindingMasterUserRecordLabelKey: murLabelValue, toolchainv1alpha1.SpaceBindingSpaceLabelKey: spaceLabelValue, @@ -133,7 +53,7 @@ func NewSpaceBinding(name, murLabelValue, spaceLabelValue, role string) *toolcha func NewBase1NSTemplateTier() *toolchainv1alpha1.NSTemplateTier { return &toolchainv1alpha1.NSTemplateTier{ ObjectMeta: metav1.ObjectMeta{ - Namespace: configuration.Namespace(), + Namespace: test.HostOperatorNs, Name: "base1ns", }, Spec: toolchainv1alpha1.NSTemplateTierSpec{ @@ -180,79 +100,3 @@ func NewMasterUserRecord(name string) *toolchainv1alpha1.MasterUserRecord { }, } } - -type InformerServiceOptions func(informer *Informer) - -func WithGetNSTemplateTierFunc(getNsTemplateTierFunc func(tier string) (*toolchainv1alpha1.NSTemplateTier, error)) InformerServiceOptions { - return func(informer *Informer) { - informer.GetNSTemplateTierFunc = getNsTemplateTierFunc - } -} - -func WithListSpaceBindingFunc(listSpaceBindingFunc func(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error)) InformerServiceOptions { - return func(informer *Informer) { - informer.ListSpaceBindingFunc = listSpaceBindingFunc - } -} - -func WithGetSpaceFunc(getSpaceFunc func(name string) (*toolchainv1alpha1.Space, error)) InformerServiceOptions { - return func(informer *Informer) { - informer.GetSpaceFunc = getSpaceFunc - } -} - -func WithGetMurFunc(getMurFunc func(name string) (*toolchainv1alpha1.MasterUserRecord, error)) InformerServiceOptions { - return func(informer *Informer) { - informer.GetMurFunc = getMurFunc - } -} - -func WithGetBannedUsersByEmailFunc(bannedUsersByEmail func(ermail string) ([]toolchainv1alpha1.BannedUser, error)) InformerServiceOptions { - return func(informer *Informer) { - informer.ListBannedUsersByEmailFunc = bannedUsersByEmail - } -} - -func GetInformerService(fakeClient client.Client, options ...InformerServiceOptions) func() service.InformerService { - return func() service.InformerService { - - inf := NewFakeInformer() - inf.GetSpaceFunc = func(name string) (*toolchainv1alpha1.Space, error) { - space := &toolchainv1alpha1.Space{} - err := fakeClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: configuration.Namespace()}, space) - return space, err - } - inf.ListSpaceBindingFunc = func(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - sbList := &toolchainv1alpha1.SpaceBindingList{} - err := fakeClient.List(context.TODO(), sbList, &client.ListOptions{LabelSelector: labels.NewSelector().Add(reqs...)}) - return sbList.Items, err - } - inf.GetNSTemplateTierFunc = func(tier string) (*toolchainv1alpha1.NSTemplateTier, error) { - nsTemplateTier := &toolchainv1alpha1.NSTemplateTier{} - err := fakeClient.Get(context.TODO(), types.NamespacedName{Name: tier, Namespace: configuration.Namespace()}, nsTemplateTier) - return nsTemplateTier, err - } - inf.GetMurFunc = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - mur := &toolchainv1alpha1.MasterUserRecord{} - err := fakeClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: configuration.Namespace()}, mur) - return mur, err - } - - for _, modify := range options { - modify(&inf) - } - - return inf - } -} - -func InitClient(t *testing.T, initObjs ...runtime.Object) *test.FakeClient { - scheme := runtime.NewScheme() - var AddToSchemes runtime.SchemeBuilder - addToSchemes := append(AddToSchemes, - toolchainv1alpha1.AddToScheme) - err := addToSchemes.AddToScheme(scheme) - require.NoError(t, err) - cl := test.NewFakeClient(t, initObjs...) - return cl -} From 283ead386168dcd62dacee56893299407da283ba Mon Sep 17 00:00:00 2001 From: Francesco Ilario Date: Thu, 26 Sep 2024 18:42:12 +0200 Subject: [PATCH 06/13] feat: add Public-Viewer support (#443) This commit adds the notion of Public-Viewer to the Proxy as described in [JIRA ASC-532](https://issues.redhat.com/browse/ASC-532). --------- Signed-off-by: Francesco Ilario Co-authored-by: Alexey Kazakov Co-authored-by: Francisc Munteanu --- pkg/proxy/proxy.go | 244 +++++++++++++++-- pkg/proxy/proxy_community_test.go | 422 ++++++++++++++++++++++++++++++ pkg/proxy/proxy_test.go | 209 +++++++++++---- test/fake/informer.go | 16 ++ 4 files changed, 816 insertions(+), 75 deletions(-) create mode 100644 pkg/proxy/proxy_community_test.go diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go index 2b7e469b..08ded564 100644 --- a/pkg/proxy/proxy.go +++ b/pkg/proxy/proxy.go @@ -26,6 +26,7 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/proxy/access" "github.com/codeready-toolchain/registration-service/pkg/proxy/handlers" "github.com/codeready-toolchain/registration-service/pkg/proxy/metrics" + "github.com/codeready-toolchain/registration-service/pkg/signup" commoncluster "github.com/codeready-toolchain/toolchain-common/pkg/cluster" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" @@ -119,6 +120,7 @@ func (p *Proxy) StartProxy(port string) *http.Server { } }, p.ensureUserIsNotBanned(), + p.addPublicViewerContext(), ) // middleware after routing @@ -142,6 +144,7 @@ func (p *Proxy) StartProxy(port string) *http.Server { // Space lister routes wg.GET("/:workspace", handlers.HandleSpaceGetRequest(p.spaceLister, p.getMembersFunc)) wg.GET("", handlers.HandleSpaceListRequest(p.spaceLister)) + router.GET(proxyHealthEndpoint, p.health) // SSO routes. Used by web login (oc login -w). // Here is the expected flow for the "oc login -w" command: @@ -269,6 +272,7 @@ func (p *Proxy) health(ctx echo.Context) error { } func (p *Proxy) processRequest(ctx echo.Context) (string, *access.ClusterAccess, error) { + // retrieve required information from the HTTP request userID, _ := ctx.Get(context.SubKey).(string) username, _ := ctx.Get(context.UsernameKey).(string) proxyPluginName, workspaceName, err := getWorkspaceContext(ctx.Request()) @@ -276,40 +280,203 @@ func (p *Proxy) processRequest(ctx echo.Context) (string, *access.ClusterAccess, return "", nil, crterrors.NewBadRequest("unable to get workspace context", err.Error()) } - ctx.Set(context.WorkspaceKey, workspaceName) // set workspace context for logging - cluster, err := p.app.MemberClusterService().GetClusterAccess(userID, username, workspaceName, proxyPluginName, false) - if err != nil { - return "", nil, crterrors.NewInternalError(errs.New("unable to get target cluster"), err.Error()) - } + // set workspace context for logging + ctx.Set(context.WorkspaceKey, workspaceName) - // before proxying the request, verify that the user has a spacebinding for the workspace and that the namespace (if any) belongs to the workspace - var workspaces []toolchainv1alpha1.Workspace - if workspaceName != "" { - // when a workspace name was provided - // validate that the user has access to the workspace by getting all spacebindings recursively, starting from this workspace and going up to the parent workspaces till the "root" of the workspace tree. - workspace, err := handlers.GetUserWorkspace(ctx, p.spaceLister, workspaceName) + // if the target workspace is NOT explicitly declared in the HTTP request, + // process the request against the user's home workspace + if workspaceName == "" { + cluster, err := p.processHomeWorkspaceRequest(ctx, userID, username, proxyPluginName) if err != nil { - return "", nil, crterrors.NewInternalError(errs.New("unable to retrieve user workspaces"), err.Error()) - } - if workspace == nil { - // not found - return "", nil, crterrors.NewForbiddenError("invalid workspace request", fmt.Sprintf("access to workspace '%s' is forbidden", workspaceName)) - } - // workspace was found means we can forward the request - workspaces = []toolchainv1alpha1.Workspace{*workspace} - } else { - // list all workspaces - workspaces, err = handlers.ListUserWorkspaces(ctx, p.spaceLister) - if err != nil { - return "", nil, crterrors.NewInternalError(errs.New("unable to retrieve user workspaces"), err.Error()) + return "", nil, err } + return proxyPluginName, cluster, nil + } + + // if the target workspace is explicitly declared in the HTTP request, + // process the request against the declared workspace + cluster, err := p.processWorkspaceRequest(ctx, userID, username, workspaceName, proxyPluginName) + if err != nil { + return "", nil, err + } + return proxyPluginName, cluster, nil +} + +// processHomeWorkspaceRequest process an HTTP Request targeting the user's home workspace. +func (p *Proxy) processHomeWorkspaceRequest(ctx echo.Context, userID, username, proxyPluginName string) (*access.ClusterAccess, error) { + // retrieves the ClusterAccess for the user and their home workspace + cluster, err := p.app.MemberClusterService().GetClusterAccess(userID, username, "", proxyPluginName, false) + if err != nil { + return nil, crterrors.NewInternalError(errs.New("unable to get target cluster"), err.Error()) } + + // list all workspaces the user has access to + workspaces, err := handlers.ListUserWorkspaces(ctx, p.spaceLister) + if err != nil { + return nil, crterrors.NewInternalError(errs.New("unable to retrieve user workspaces"), err.Error()) + } + + // check whether the user has access to the home workspace + // and whether the requestedNamespace -if any- exists in the workspace. requestedNamespace := namespaceFromCtx(ctx) - if err := validateWorkspaceRequest(workspaceName, requestedNamespace, workspaces); err != nil { - return "", nil, crterrors.NewForbiddenError("invalid workspace request", err.Error()) + if err := validateWorkspaceRequest("", requestedNamespace, workspaces...); err != nil { + return nil, crterrors.NewForbiddenError("invalid workspace request", err.Error()) } - return proxyPluginName, cluster, nil + // return the cluster access + return cluster, nil +} + +// processWorkspaceRequest process an HTTP Request targeting a specific workspace. +func (p *Proxy) processWorkspaceRequest(ctx echo.Context, userID, username, workspaceName, proxyPluginName string) (*access.ClusterAccess, error) { + // check that the user is provisioned and the space exists. + // if the PublicViewer support is enabled, user check is skipped. + if err := p.checkUserIsProvisionedAndSpaceExists(ctx, userID, username, workspaceName); err != nil { + return nil, err + } + + // retrieve the requested Workspace with SpaceBindings + workspace, err := p.getUserWorkspaceWithBindings(ctx, workspaceName) + if err != nil { + return nil, err + } + + // check whether the user has access to the workspace + // and whether the requestedNamespace -if any- exists in the workspace. + requestedNamespace := namespaceFromCtx(ctx) + if err := validateWorkspaceRequest(workspaceName, requestedNamespace, *workspace); err != nil { + return nil, crterrors.NewForbiddenError("invalid workspace request", err.Error()) + } + + // retrieve the ClusterAccess for the user and the target workspace + return p.getClusterAccess(ctx, userID, username, proxyPluginName, workspace) +} + +// checkUserIsProvisionedAndSpaceExists checks that the user is provisioned and the Space exists. +// If the PublicViewer support is enabled, User check is skipped. +func (p *Proxy) checkUserIsProvisionedAndSpaceExists(ctx echo.Context, userID, username, workspaceName string) error { + if err := p.checkUserIsProvisioned(ctx, userID, username); err != nil { + return crterrors.NewInternalError(errs.New("unable to get target cluster"), err.Error()) + } + if err := p.checkSpaceExists(workspaceName); err != nil { + return crterrors.NewInternalError(errs.New("unable to get target cluster"), err.Error()) + } + return nil +} + +// checkSpaceExists checks whether the Space exists. +func (p *Proxy) checkSpaceExists(workspaceName string) error { + if _, err := p.app.InformerService().GetSpace(workspaceName); err != nil { + // log the actual error but do not return it so that it doesn't reveal information about a space that may not belong to the requestor + log.Errorf(nil, err, "requested space '%s' does not exist", workspaceName) + return fmt.Errorf("access to workspace '%s' is forbidden", workspaceName) + } + return nil +} + +// checkUserIsProvisioned checks whether the user is Approved, if they are not an error is returned. +// If public-viewer is enabled, user validation is skipped. +func (p *Proxy) checkUserIsProvisioned(ctx echo.Context, userID, username string) error { + // skip if public-viewer is enabled: read-only operations on community workspaces are always permitted. + if context.IsPublicViewerEnabled(ctx) { + return nil + } + + // retrieve the UserSignup for the requesting user. + // + // UserSignup complete status is not checked, since it might cause the proxy blocking the request + // and returning an error when quick transitions from ready to provisioning are happening. + userSignup, err := p.app.SignupService().GetSignupFromInformer(nil, userID, username, false) + if err != nil { + return err + } + + // if the UserSignup is nil or has NOT the CompliantUsername set, + // it means that MUR was NOT created and useraccount is NOT provisioned yet + if userSignup == nil || userSignup.CompliantUsername == "" { + cause := errs.New("user is not provisioned (yet)") + log.Error(nil, cause, fmt.Sprintf("signup object: %+v", userSignup)) + return cause + } + return nil +} + +// getClusterAccess retrieves the access to the cluster hosting the requested workspace, +// if the user has access to it. +// Access can be either direct (a SpaceBinding linking the user to the workspace exists) +// or community (a SpaceBinding linking the PublicViewer user to the workspace exists). +func (p *Proxy) getClusterAccess(ctx echo.Context, userID, username, proxyPluginName string, workspace *toolchainv1alpha1.Workspace) (*access.ClusterAccess, error) { + // retrieve cluster access as requesting user or PublicViewer + cluster, err := p.getClusterAccessAsUserOrPublicViewer(ctx, userID, username, proxyPluginName, workspace) + if err != nil { + return nil, crterrors.NewInternalError(errs.New("unable to get target cluster"), err.Error()) + } + return cluster, nil +} + +// getClusterAccessAsUserOrPublicViewer if the requesting user exists and has direct access to the workspace, +// this function returns the ClusterAccess impersonating the requesting user. +// If PublicViewer support is enabled and PublicViewer user has access to the workspace, +// this function returns the ClusterAccess impersonating the PublicViewer user. +// If requesting user does not exists and PublicViewer is disabled or does not have access to the workspace, +// this function returns an error. +func (p *Proxy) getClusterAccessAsUserOrPublicViewer(ctx echo.Context, userID, username, proxyPluginName string, workspace *toolchainv1alpha1.Workspace) (*access.ClusterAccess, error) { + // retrieve the requesting user's UserSignup + userSignup, err := p.app.SignupService().GetSignupFromInformer(nil, userID, username, false) + if err != nil { + log.Error(nil, err, fmt.Sprintf("error retrieving user signup for userID '%s' and username '%s'", userID, username)) + return nil, crterrors.NewInternalError(errs.New("unable to get user info"), "error retrieving user") + } + + // proceed as PublicViewer if the feature is enabled and userSignup is nil + publicViewerEnabled := context.IsPublicViewerEnabled(ctx) + if publicViewerEnabled && !userHasDirectAccess(userSignup, workspace) { + return p.app.MemberClusterService().GetClusterAccess( + toolchainv1alpha1.KubesawAuthenticatedUsername, + toolchainv1alpha1.KubesawAuthenticatedUsername, + workspace.Name, + proxyPluginName, + publicViewerEnabled) + } + + // otherwise retrieve the ClusterAccess for the cluster hosting the workspace and the given user. + return p.app.MemberClusterService().GetClusterAccess(userID, username, workspace.Name, proxyPluginName, publicViewerEnabled) +} + +// userHasDirectAccess checks if an UserSignup has access to a workspace. +// Workspace's bindings are obtained from its `status.bindings` property. +func userHasDirectAccess(signup *signup.Signup, workspace *toolchainv1alpha1.Workspace) bool { + if signup == nil { + return false + } + + return userHasBinding(signup.CompliantUsername, workspace) +} + +func userHasBinding(username string, workspace *toolchainv1alpha1.Workspace) bool { + for _, b := range workspace.Status.Bindings { + if b.MasterUserRecord == username { + return true + } + } + return false + +} + +// getUserWorkspaceWithBindings retrieves the workspace with the SpaceBindings if the requesting user has access to it. +// User access to the Workspace is checked by getting all spacebindings recursively, +// starting from this workspace and going up to the parent workspaces till the "root" of the workspace tree. +func (p *Proxy) getUserWorkspaceWithBindings(ctx echo.Context, workspaceName string) (*toolchainv1alpha1.Workspace, error) { + workspace, err := handlers.GetUserWorkspaceWithBindings(ctx, p.spaceLister, workspaceName, p.getMembersFunc) + if err != nil { + return nil, crterrors.NewInternalError(errs.New("unable to retrieve user workspaces"), err.Error()) + } + if workspace == nil { + // not found + return nil, crterrors.NewForbiddenError("invalid workspace request", fmt.Sprintf("access to workspace '%s' is forbidden", workspaceName)) + } + // workspace was found means we can forward the request + return workspace, nil } func (p *Proxy) handleRequestAndRedirect(ctx echo.Context) error { @@ -409,6 +576,18 @@ func (p *Proxy) addUserContext() echo.MiddlewareFunc { } } +// addPublicViewerContext updates echo.Context with the configuration's PublicViewerEnabled value. +func (p *Proxy) addPublicViewerContext() echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(ctx echo.Context) error { + publicViewerEnabled := configuration.GetRegistrationServiceConfig().PublicViewerEnabled() + ctx.Set(context.PublicViewerEnabled, publicViewerEnabled) + + return next(ctx) + } + } +} + // ensureUserIsNotBanned rejects the request if the user is banned. // This Middleware requires the context to contain the email of the user, // so it needs to be executed after the `addUserContext` Middleware. @@ -503,11 +682,17 @@ func extractUserToken(req *http.Request) (string, error) { func (p *Proxy) newReverseProxy(ctx echo.Context, target *access.ClusterAccess, isPlugin bool) *httputil.ReverseProxy { req := ctx.Request() targetQuery := target.APIURL().RawQuery + username, _ := ctx.Get(context.UsernameKey).(string) + // set username in context for logging purposes + ctx.Set(context.ImpersonateUser, target.Username()) + director := func(req *http.Request) { origin := req.URL.String() req.URL.Scheme = target.APIURL().Scheme req.URL.Host = target.APIURL().Host req.URL.Path = singleJoiningSlash(target.APIURL().Path, req.URL.Path) + req.Header.Set("X-SSO-User", username) + if isPlugin { // for non k8s clients testing, like vanilla http clients accessing plugin proxy flows, testing has proven that the request // host needs to be updated in addition to the URL in order to have the reverse proxy contact the openshift @@ -671,7 +856,10 @@ func replaceTokenInWebsocketRequest(req *http.Request, newToken string) { req.Header.Set(ph, strings.Join(protocols, ",")) } -func validateWorkspaceRequest(requestedWorkspace, requestedNamespace string, workspaces []toolchainv1alpha1.Workspace) error { +// validateWorkspaceRequest checks whether the requested workspace is in the list of workspaces the user has visibility on (retrieved via the spaceLister). +// If `requestedWorkspace` is zero, this function looks for the home workspace (the one with `status.Type` set to `home`). +// If `requestedNamespace` is NOT zero, this function checks if the namespace exists in the workspace. +func validateWorkspaceRequest(requestedWorkspace, requestedNamespace string, workspaces ...toolchainv1alpha1.Workspace) error { // check workspace access isHomeWSRequested := requestedWorkspace == "" diff --git a/pkg/proxy/proxy_community_test.go b/pkg/proxy/proxy_community_test.go new file mode 100644 index 00000000..5274bd75 --- /dev/null +++ b/pkg/proxy/proxy_community_test.go @@ -0,0 +1,422 @@ +package proxy + +import ( + "fmt" + "net/http" + "net/http/httptest" + "time" + + appservice "github.com/codeready-toolchain/registration-service/pkg/application/service" + "github.com/codeready-toolchain/registration-service/pkg/auth" + infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" + "github.com/codeready-toolchain/registration-service/pkg/proxy/handlers" + "github.com/codeready-toolchain/registration-service/pkg/signup" + "github.com/codeready-toolchain/registration-service/test/fake" + commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" + authsupport "github.com/codeready-toolchain/toolchain-common/pkg/test/auth" + "github.com/google/uuid" + "go.uber.org/atomic" + + toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" + testconfig "github.com/codeready-toolchain/toolchain-common/pkg/test/config" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func (s *TestProxySuite) TestProxyCommunityEnabled() { + // given + + port := "30456" + + env := s.DefaultConfig().Environment() + defer s.SetConfig(testconfig.RegistrationService(). + Environment(env)) + s.SetConfig(testconfig.RegistrationService(). + Environment(string(testconfig.E2E))) // We use e2e-test environment just to be able to re-use token generation + _, err := auth.InitializeDefaultTokenParser() + require.NoError(s.T(), err) + + for _, environment := range []testconfig.EnvName{testconfig.E2E, testconfig.Dev, testconfig.Prod} { + s.Run("for environment "+string(environment), func() { + // spin up proxy + s.SetConfig( + testconfig.RegistrationService().Environment(string(environment)), + testconfig.PublicViewerConfig(true), + ) + fakeApp := &fake.ProxyFakeApp{} + p, server := s.spinUpProxy(fakeApp, port) + defer func() { + _ = server.Close() + }() + + // wait for proxy to be alive + s.Run("is alive", func() { + s.waitForProxyToBeAlive(port) + }) + s.Run("health check ok", func() { + s.checkProxyIsHealthy(port) + }) + + // run community tests + s.checkProxyCommunityOK(fakeApp, p, port) + }) + } +} + +func (s *TestProxySuite) checkProxyCommunityOK(fakeApp *fake.ProxyFakeApp, p *Proxy, port string) { + podsRequestURL := func(workspace string) string { + return fmt.Sprintf("http://localhost:%s/workspaces/%s/api/pods", port, workspace) + } + + podsInNamespaceRequestURL := func(workspace string, namespace string) string { + return fmt.Sprintf("http://localhost:%s/workspaces/%s/api/namespaces/%s/pods", port, workspace, namespace) + } + + s.Run("successfully proxy", func() { + // user with public workspace + smith := uuid.New() + // user with private workspace + alice := uuid.New() + // unsigned user + bob := uuid.New() + // not ready + john := uuid.New() + // banned user + eve, eveEmail := uuid.New(), "eve@somecorp.com" + + // Start the member-2 API Server + httpTestServerResponse := "my response" + testServer := httptest.NewServer(nil) + defer testServer.Close() + + // initialize SignupService + signupService := fake.NewSignupService( + fake.Signup(smith.String(), &signup.Signup{ + Name: "smith", + APIEndpoint: testServer.URL, + ClusterName: "member-2", + CompliantUsername: "smith", + Username: "smith@", + Status: signup.Status{ + Ready: true, + }, + }), + fake.Signup(alice.String(), &signup.Signup{ + Name: "alice", + APIEndpoint: testServer.URL, + ClusterName: "member-2", + CompliantUsername: "alice", + Username: "alice@", + Status: signup.Status{ + Ready: true, + }, + }), + fake.Signup(john.String(), &signup.Signup{ + Name: "john", + CompliantUsername: "john", + Username: "john@", + Status: signup.Status{ + Ready: false, + }, + }), + fake.Signup(eve.String(), &signup.Signup{ + Name: "eve", + CompliantUsername: "eve", + Username: "eve@", + Status: signup.Status{ + Ready: false, + Reason: toolchainv1alpha1.UserSignupUserBannedReason, + }, + }), + ) + + // init fakeClient + cli := commontest.NewFakeClient(s.T(), + fake.NewSpace("smith-community", "member-2", "smith"), + fake.NewSpace("alice-private", "member-2", "alice"), + fake.NewSpaceBinding("smith-community-smith", "smith", "smith-community", "admin"), + fake.NewSpaceBinding("smith-community-publicviewer", toolchainv1alpha1.KubesawAuthenticatedUsername, "smith-community", "viewer"), + fake.NewSpaceBinding("alice-default", "alice", "alice-private", "admin"), + fake.NewBannedUser("eve", eveEmail), + fake.NewBase1NSTemplateTier(), + ) + + // configure informer + inf := infservice.NewInformerService(cli, commontest.HostOperatorNs) + + // configure Application + fakeApp.Err = nil + fakeApp.InformerServiceMock = inf + fakeApp.MemberClusterServiceMock = s.newMemberClusterServiceWithMembers(testServer.URL) + fakeApp.SignupServiceMock = signupService + + s.Application.MockSignupService(signupService) + s.Application.MockInformerService(inf) + + // configure proxy + p.spaceLister = &handlers.SpaceLister{ + GetSignupFunc: fakeApp.SignupServiceMock.GetSignupFromInformer, + GetInformerServiceFunc: func() appservice.InformerService { return inf }, + ProxyMetrics: p.metrics, + } + + // run test cases + tests := map[string]struct { + ProxyRequestMethod string + ProxyRequestHeaders http.Header + ExpectedAPIServerRequestHeaders http.Header + ExpectedProxyResponseStatus int + RequestPath string + ExpectedResponse string + }{ + // Given smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // When smith requests the list of pods in workspace smith-community + // Then the request is forwarded from the proxy + // And the request impersonates smith + // And the request's X-SSO-User Header is set to smith's ID + // And the request is successful + "plain http actual request as community space owner": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(smith)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + "Impersonate-User": {"smith"}, + "X-SSO-User": {"username-" + smith.String()}, + }, + ExpectedProxyResponseStatus: http.StatusOK, + RequestPath: podsRequestURL("smith-community"), + ExpectedResponse: httpTestServerResponse, + }, + // Given The not ready user john exists + // When john requests the list of pods in workspace smith-community + // Then the request is forwarded from the proxy + // And the request impersonates john + // And the request's X-SSO-User Header is set to john's ID + // And the request is successful + "plain http actual request as notReadyUser": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(john)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + "Impersonate-User": {toolchainv1alpha1.KubesawAuthenticatedUsername}, + "X-SSO-User": {"username-" + john.String()}, + }, + ExpectedProxyResponseStatus: http.StatusOK, + RequestPath: podsRequestURL("smith-community"), + ExpectedResponse: httpTestServerResponse, + }, + // Given The not signed up user bob exists + // When bob requests the list of pods in workspace smith-community + // Then the request is forwarded from the proxy + // And the request impersonates bob + // And the request's X-SSO-User Header is set to bob's ID + // And the request is successful + "plain http actual request as not signed up user": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(bob)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + "Impersonate-User": {toolchainv1alpha1.KubesawAuthenticatedUsername}, + "X-SSO-User": {"username-" + bob.String()}, + }, + ExpectedProxyResponseStatus: http.StatusOK, + RequestPath: podsRequestURL("smith-community"), + ExpectedResponse: httpTestServerResponse, + }, + // Given smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // And a user named alice exists + // And smith's smith-community is not directly shared with alice + // When alice requests the list of pods in workspace smith-community + // Then the request is forwarded from the proxy + // And the request impersonates the PublicViewer + // And the request's X-SSO-User Header is set to alice's ID + // And the request is successful + "plain http actual request as community user": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(alice)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + "Impersonate-User": {toolchainv1alpha1.KubesawAuthenticatedUsername}, + "X-SSO-User": {"username-" + alice.String()}, + }, + ExpectedProxyResponseStatus: http.StatusOK, + RequestPath: podsRequestURL("smith-community"), + ExpectedResponse: httpTestServerResponse, + }, + // Given user alice exists + // And alice owns a private workspace + // When smith requests the list of pods in alice's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http actual request as non-owner to private workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(smith)}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsRequestURL("alice-private"), + ExpectedResponse: "invalid workspace request: access to workspace 'alice-private' is forbidden", + }, + // Given banned user eve exists + // And user smith exists + // And smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // When eve requests the list of pods in smith's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http actual request as banned user to community workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(eve, authsupport.WithEmailClaim(eveEmail))}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsRequestURL("smith-community"), + ExpectedResponse: "user access is forbidden: user access is forbidden", + }, + // Given banned user eve exist + // And user alice exists + // And alice owns a private workspace + // When eve requests the list of pods in alice's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http actual request as banned user to private workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(eve, authsupport.WithEmailClaim(eveEmail))}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsRequestURL("alice-private"), + ExpectedResponse: "user access is forbidden: user access is forbidden", + }, + // Given user alice exists + // And alice owns a private workspace + // When alice requests the list of pods in a non existing namespace in alice's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http request as owner to not existing namespace in private workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(alice)}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsInNamespaceRequestURL("alice-private", "not-existing"), + ExpectedResponse: "invalid workspace request: access to namespace 'not-existing' in workspace 'alice-private' is forbidden", + }, + // Given smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // When smith requests the list of pods in a non existing namespace in workspace smith-community + // Then the request is forwarded from the proxy + // And the request impersonates smith + // And the request's X-SSO-User Header is set to smith's ID + // And the request is successful + "plain http request as owner to not existing namespace in community workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(smith)}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsInNamespaceRequestURL("smith-community", "not-existing"), + ExpectedResponse: "invalid workspace request: access to namespace 'not-existing' in workspace 'smith-community' is forbidden", + }, + // Given smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // And user alice exists + // When alice requests the list of pods in a non existing namespace in smith's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http request as community user to not existing namespace in community workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(alice)}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsInNamespaceRequestURL("smith-community", "not-existing"), + ExpectedResponse: "invalid workspace request: access to namespace 'not-existing' in workspace 'smith-community' is forbidden", + }, + // Given smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // When bob requests the list of pods in a non existing namespace in smith's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http request as unsigned user to not existing namespace in community workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(bob)}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsInNamespaceRequestURL("smith-community", "not-existing"), + ExpectedResponse: "invalid workspace request: access to namespace 'not-existing' in workspace 'smith-community' is forbidden", + }, + // Given smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // And not ready user john exists + // When john requests the list of pods in a non existing namespace in smith's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http request as notReadyUser to not existing namespace in community workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(john)}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsInNamespaceRequestURL("smith-community", "not-existing"), + ExpectedResponse: "invalid workspace request: access to namespace 'not-existing' in workspace 'smith-community' is forbidden", + }, + // Given banned user eve exists + // And user smith exists + // And smith owns a workspace named smith-community + // And smith-community is publicly visible (shared with PublicViewer) + // When eve requests the list of pods in a non existing namespace smith's workspace + // Then the proxy does NOT forward the request + // And the proxy rejects the call with 403 Forbidden + "plain http actual request as banned user to not existing namespace community workspace": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(eve, authsupport.WithEmailClaim(eveEmail))}}, + ExpectedProxyResponseStatus: http.StatusForbidden, + RequestPath: podsInNamespaceRequestURL("smith-community", "not-existing"), + ExpectedResponse: "user access is forbidden: user access is forbidden", + }, + } + + for k, tc := range tests { + s.Run(k, func() { + testServerInvoked := atomic.NewBool(false) + + // given + testServer.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + v := testServerInvoked.Swap(true) + require.False(s.T(), v, "expected handler to be invoked just one time") + + w.Header().Set("Content-Type", "application/json") + // Set the Access-Control-Allow-Origin header to make sure it's overridden by the proxy response modifier + w.Header().Set("Access-Control-Allow-Origin", "dummy") + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte(httpTestServerResponse)) + require.NoError(s.T(), err) + for hk, hv := range tc.ExpectedAPIServerRequestHeaders { + require.Len(s.T(), r.Header.Values(hk), len(hv)) + for i := range hv { + assert.Equal(s.T(), hv[i], r.Header.Values(hk)[i], "header %s", hk) + } + } + }) + + // prepare request + req, err := http.NewRequest(tc.ProxyRequestMethod, tc.RequestPath, nil) + require.NoError(s.T(), err) + require.NotNil(s.T(), req) + + for hk, hv := range tc.ProxyRequestHeaders { + for _, v := range hv { + req.Header.Add(hk, v) + } + } + + // when + client := http.Client{Timeout: 3 * time.Second} + resp, err := client.Do(req) + + // then + require.NoError(s.T(), err) + require.NotNil(s.T(), resp) + defer resp.Body.Close() + assert.Equal(s.T(), tc.ExpectedProxyResponseStatus, resp.StatusCode) + s.assertResponseBody(resp, tc.ExpectedResponse) + + forwardExpected := len(tc.ExpectedAPIServerRequestHeaders) > 0 + requestForwarded := testServerInvoked.Load() + require.Equal(s.T(), + forwardExpected, requestForwarded, + "expecting call forward to be %v, got %v", forwardExpected, requestForwarded, + ) + }) + } + }) +} diff --git a/pkg/proxy/proxy_test.go b/pkg/proxy/proxy_test.go index 6bd9ad6c..cb1aa373 100644 --- a/pkg/proxy/proxy_test.go +++ b/pkg/proxy/proxy_test.go @@ -28,6 +28,8 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/signup" "github.com/codeready-toolchain/registration-service/test" "github.com/codeready-toolchain/registration-service/test/fake" + "github.com/gin-gonic/gin" + "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "k8s.io/client-go/kubernetes/scheme" @@ -38,7 +40,6 @@ import ( authsupport "github.com/codeready-toolchain/toolchain-common/pkg/test/auth" testconfig "github.com/codeready-toolchain/toolchain-common/pkg/test/config" - "github.com/google/uuid" routev1 "github.com/openshift/api/route/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -117,46 +118,11 @@ func (s *TestProxySuite) TestProxy() { _ = server.Close() }() - // Wait up to N seconds for the Proxy server to start - ready := false - sec := 10 - for i := 0; i < sec; i++ { - log.Println("Checking if Proxy is started...") - req, err := http.NewRequest("GET", "http://localhost:8081/api/mycoolworkspace/pods", nil) - require.NoError(s.T(), err) - require.NotNil(s.T(), req) - resp, err := http.DefaultClient.Do(req) - if err != nil { - time.Sleep(time.Second) - continue - } - _, _ = io.Copy(io.Discard, resp.Body) - _ = resp.Body.Close() - if resp.StatusCode != http.StatusUnauthorized { - // The server may be running but still not fully ready to accept requests - time.Sleep(time.Second) - continue - } - // Server is up and running! - ready = true - break - } - require.True(s.T(), ready, "Proxy is not ready after %d seconds", sec) - + s.Run("is alive", func() { + s.waitForProxyToBeAlive(DefaultPort) + }) s.Run("health check ok", func() { - req, err := http.NewRequest("GET", "http://localhost:8081/proxyhealth", nil) - require.NoError(s.T(), err) - require.NotNil(s.T(), req) - - // when - resp, err := http.DefaultClient.Do(req) - - // then - require.NoError(s.T(), err) - require.NotNil(s.T(), resp) - defer resp.Body.Close() - assert.Equal(s.T(), http.StatusOK, resp.StatusCode) - s.assertResponseBody(resp, `{"alive": true}`) + s.checkProxyIsHealthy(DefaultPort) }) s.checkPlainHTTPErrors(fakeApp) @@ -167,6 +133,62 @@ func (s *TestProxySuite) TestProxy() { } } +func (s *TestProxySuite) spinUpProxy(fakeApp *fake.ProxyFakeApp, port string) (*Proxy, *http.Server) { + proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) + p, err := newProxyWithClusterClient( + fakeApp, nil, proxyMetrics, proxytest.NewGetMembersFunc(commontest.NewFakeClient(s.T()))) + require.NoError(s.T(), err) + + server := p.StartProxy(port) + require.NotNil(s.T(), server) + + return p, server +} + +func (s *TestProxySuite) waitForProxyToBeAlive(port string) { + // Wait up to N seconds for the Proxy server to start + ready := false + sec := 10 + for i := 0; i < sec; i++ { + log.Println("Checking if Proxy is started...") + req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%s/api/mycoolworkspace/pods", port), nil) + require.NoError(s.T(), err) + require.NotNil(s.T(), req) + resp, err := http.DefaultClient.Do(req) + if err != nil { + time.Sleep(time.Second) + continue + } + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + if resp.StatusCode != http.StatusUnauthorized { + // The server may be running but still not fully ready to accept requests + time.Sleep(time.Second) + continue + } + // Server is up and running! + ready = true + break + } + require.True(s.T(), ready, "Proxy is not ready after %d seconds", sec) +} + +func (s *TestProxySuite) checkProxyIsHealthy(port string) { + req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%s/proxyhealth", port), nil) + require.NoError(s.T(), err) + require.NotNil(s.T(), req) + + // when + resp, err := http.DefaultClient.Do(req) + + // then + require.NoError(s.T(), err) + require.NotNil(s.T(), resp) + defer resp.Body.Close() + assert.Equal(s.T(), http.StatusOK, resp.StatusCode) + s.assertResponseBody(resp, `{"alive": true}`) +} + func (s *TestProxySuite) checkPlainHTTPErrors(fakeApp *fake.ProxyFakeApp) { s.Run("plain http error", func() { s.Run("unauthorized if no token present", func() { @@ -218,6 +240,23 @@ func (s *TestProxySuite) checkPlainHTTPErrors(fakeApp *fake.ProxyFakeApp) { s.assertResponseBody(resp, "invalid bearer token: unable to extract userID from token: token does not comply to expected claims: subject missing") }) + s.Run("unauthorized if can't extract email from a valid token", func() { + // when + req, err := http.NewRequest("GET", "http://localhost:8081/api/mycoolworkspace/pods", nil) + require.NoError(s.T(), err) + require.NotNil(s.T(), req) + userID := uuid.New() + req.Header.Set("Authorization", "Bearer "+s.token(userID, authsupport.WithEmailClaim(""))) + resp, err := http.DefaultClient.Do(req) + + // then + require.NoError(s.T(), err) + require.NotNil(s.T(), resp) + defer resp.Body.Close() + assert.Equal(s.T(), http.StatusUnauthorized, resp.StatusCode) + s.assertResponseBody(resp, "invalid bearer token: unable to extract userID from token: token does not comply to expected claims: email missing") + }) + s.Run("unauthorized if workspace context is invalid", func() { // when req := s.request() @@ -476,11 +515,15 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { tests := map[string]struct { ProxyRequestMethod string + ProxyRequestPaths map[string]string ProxyRequestHeaders http.Header ExpectedAPIServerRequestHeaders http.Header ExpectedProxyResponseHeaders http.Header ExpectedProxyResponseStatus int Standalone bool // If true then the request is not expected to be forwarded to the kube api server + + OverrideGetSignupFunc func(ctx *gin.Context, userID, username string, checkUserSignupCompleted bool) (*signup.Signup, error) + ExpectedResponse *string }{ "plain http cors preflight request with no request method": { ProxyRequestMethod: "OPTIONS", @@ -569,6 +612,16 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { }, ExpectedProxyResponseStatus: http.StatusOK, }, + "proxy plain http actual request as not provisioned user": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(uuid.New())}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + "Impersonate-User": {"smith3"}, + }, + ExpectedResponse: ptr("unable to get target cluster: user is not provisioned (yet)"), + ExpectedProxyResponseStatus: http.StatusInternalServerError, + }, "proxy plain http actual request": { ProxyRequestMethod: "GET", ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(userID)}}, @@ -627,6 +680,54 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { }, ExpectedProxyResponseStatus: http.StatusOK, }, + "error retrieving user workspaces": { + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(userID)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + }, + ExpectedProxyResponseStatus: http.StatusInternalServerError, + OverrideGetSignupFunc: func(_ *gin.Context, _, _ string, _ bool) (*signup.Signup, error) { + return nil, fmt.Errorf("test error") + }, + ExpectedResponse: ptr("unable to retrieve user workspaces: test error"), + }, + "unauthorized if workspace not exists": { + ProxyRequestPaths: map[string]string{ + "not existing workspace namespace": "http://localhost:8081/workspaces/not-existing-workspace/api/namespaces/not-existing-namespace/pods", + }, + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(userID)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + }, + ExpectedResponse: ptr("unable to get target cluster: access to workspace 'not-existing-workspace' is forbidden"), + ExpectedProxyResponseStatus: http.StatusInternalServerError, + }, + "unauthorized if namespace does not exist in implicit workspace": { + ProxyRequestPaths: map[string]string{ + "not existing namespace": "http://localhost:8081/api/namespaces/not-existing-namespace/pods", + }, + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(userID)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + }, + ExpectedResponse: ptr("invalid workspace request: access to namespace 'not-existing-namespace' in workspace 'mycoolworkspace' is forbidden"), + ExpectedProxyResponseStatus: http.StatusForbidden, + }, + "unauthorized if namespace does not exist in explicit workspace": { + ProxyRequestPaths: map[string]string{ + "not existing namespace": "http://localhost:8081/workspaces/mycoolworkspace/api/namespaces/not-existing-namespace/pods", + }, + ProxyRequestMethod: "GET", + ProxyRequestHeaders: map[string][]string{"Authorization": {"Bearer " + s.token(userID)}}, + ExpectedAPIServerRequestHeaders: map[string][]string{ + "Authorization": {"Bearer clusterSAToken"}, + }, + ExpectedResponse: ptr("invalid workspace request: access to namespace 'not-existing-namespace' in workspace 'mycoolworkspace' is forbidden"), + ExpectedProxyResponseStatus: http.StatusForbidden, + }, } rejectedHeaders := []headerToAdd{ @@ -645,6 +746,14 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { for k, tc := range tests { s.Run(k, func() { + paths := tc.ProxyRequestPaths + if len(paths) == 0 { + paths = map[string]string{ + "default workspace": "http://localhost:8081/api/mycoolworkspace/pods", + "workspace context": "http://localhost:8081/workspaces/mycoolworkspace/api/mycoolworkspace/pods", + "proxy plugin context": "http://localhost:8081/plugins/myplugin/workspaces/mycoolworkspace/api/mycoolworkspace/pods", + } + } for _, firstHeader := range rejectedHeaders { rejectedHeadersToAdd := []headerToAdd{firstHeader} @@ -653,11 +762,7 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { // Test each request using both the default workspace URL and a URL that uses the // workspace context. Both should yield the same results. - for workspaceContext, reqPath := range map[string]string{ - "default workspace": "http://localhost:8081/api/mycoolworkspace/pods", - "workspace context": "http://localhost:8081/workspaces/mycoolworkspace/api/mycoolworkspace/pods", - "proxy plugin context": "http://localhost:8081/plugins/myplugin/workspaces/mycoolworkspace/api/mycoolworkspace/pods", - } { + for workspaceContext, reqPath := range paths { s.Run(workspaceContext, func() { // given req, err := http.NewRequest(tc.ProxyRequestMethod, reqPath, nil) @@ -748,6 +853,7 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { s.Application.MockInformerService(inf) fakeApp.MemberClusterServiceMock = s.newMemberClusterServiceWithMembers(testServer.URL) + fakeApp.InformerServiceMock = inf p.spaceLister = &handlers.SpaceLister{ GetSignupFunc: fakeApp.SignupServiceMock.GetSignupFromInformer, @@ -756,6 +862,9 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { }, ProxyMetrics: p.metrics, } + if tc.OverrideGetSignupFunc != nil { + p.spaceLister.GetSignupFunc = tc.OverrideGetSignupFunc + } } // when @@ -767,7 +876,9 @@ func (s *TestProxySuite) checkProxyOK(fakeApp *fake.ProxyFakeApp, p *Proxy) { require.NotNil(s.T(), resp) defer resp.Body.Close() assert.Equal(s.T(), tc.ExpectedProxyResponseStatus, resp.StatusCode) - if !tc.Standalone { + if tc.ExpectedResponse != nil { + s.assertResponseBody(resp, *tc.ExpectedResponse) + } else if !tc.Standalone { s.assertResponseBody(resp, "my response") } for hk, hv := range tc.ExpectedProxyResponseHeaders { @@ -855,6 +966,10 @@ var noCORSHeaders = map[string][]string{ "Vary": {}, } +func ptr[T any](t T) *T { + return &t +} + func upgradeToWebsocket(req *http.Request) { req.Header.Set("Connection", "upgrade") req.Header.Set("Upgrade", "websocket") @@ -1100,7 +1215,7 @@ func (s *TestProxySuite) TestValidateWorkspaceRequest() { for k, tc := range tests { s.T().Run(k, func(t *testing.T) { - err := validateWorkspaceRequest(tc.requestedWorkspace, tc.requestedNamespace, tc.workspaces) + err := validateWorkspaceRequest(tc.requestedWorkspace, tc.requestedNamespace, tc.workspaces...) if tc.expectedErr == "" { require.NoError(t, err) } else { diff --git a/test/fake/informer.go b/test/fake/informer.go index dbbb1fa6..241f1cf4 100644 --- a/test/fake/informer.go +++ b/test/fake/informer.go @@ -3,6 +3,7 @@ package fake import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/configuration" + "github.com/codeready-toolchain/toolchain-common/pkg/hash" "github.com/codeready-toolchain/toolchain-common/pkg/test" spacetest "github.com/codeready-toolchain/toolchain-common/pkg/test/space" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -100,3 +101,18 @@ func NewMasterUserRecord(name string) *toolchainv1alpha1.MasterUserRecord { }, } } + +func NewBannedUser(name, email string) *toolchainv1alpha1.BannedUser { + return &toolchainv1alpha1.BannedUser{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: configuration.Namespace(), + Labels: map[string]string{ + toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString(email), + }, + }, + Spec: toolchainv1alpha1.BannedUserSpec{ + Email: email, + }, + } +} From 4e4213a0c75f87bba4f7ecc4ca6979bc2c0729a4 Mon Sep 17 00:00:00 2001 From: Feny Mehta Date: Mon, 30 Sep 2024 14:29:09 +0530 Subject: [PATCH 07/13] KUBESAW-192: Introduce a make command for pre-requisite of verify-replace script (#465) Signed-off-by: Feny Mehta --- make/go.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/go.mk b/make/go.mk index 83bb4dda..dc402849 100644 --- a/make/go.mk +++ b/make/go.mk @@ -45,3 +45,6 @@ tidy: vet: go vet ./... +.PHONY: pre-verify +pre-verify: + echo "No Pre-requisite needed" \ No newline at end of file From a657f363c63584a402cdf7713298e349306856ef Mon Sep 17 00:00:00 2001 From: Francisc Munteanu Date: Mon, 30 Sep 2024 13:51:30 +0200 Subject: [PATCH 08/13] bump api (#467) Co-authored-by: Devtools --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 2df15414..4cd6d610 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/aws/aws-sdk-go v1.44.100 - github.com/codeready-toolchain/api v0.0.0-20240815232340-d0c164a83d27 + github.com/codeready-toolchain/api v0.0.0-20240927104325-b5bfcb3cb1b0 github.com/codeready-toolchain/toolchain-common v0.0.0-20240905135929-d55d86fdd41e github.com/go-logr/logr v1.4.1 github.com/gofrs/uuid v4.2.0+incompatible @@ -149,7 +149,7 @@ require ( github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect github.com/ttacon/libphonenumber v1.2.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - go.uber.org/atomic v1.10.0 // indirect + go.uber.org/atomic v1.10.0 go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/net v0.24.0 // indirect diff --git a/go.sum b/go.sum index d65f126e..7f85215c 100644 --- a/go.sum +++ b/go.sum @@ -139,8 +139,8 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/codeready-toolchain/api v0.0.0-20240815232340-d0c164a83d27 h1:uEH8HAM81QZBccuqQpGKJUoJQe28+DFSYi/mRKZDYrA= -github.com/codeready-toolchain/api v0.0.0-20240815232340-d0c164a83d27/go.mod h1:ie9p4LenCCS0LsnbWp6/xwpFDdCWYE0KWzUO6Sk1g0E= +github.com/codeready-toolchain/api v0.0.0-20240927104325-b5bfcb3cb1b0 h1:7cXHlRpoi1Owo8fYawl80PUsVWz+9AtMge6OJ4DjvWU= +github.com/codeready-toolchain/api v0.0.0-20240927104325-b5bfcb3cb1b0/go.mod h1:ie9p4LenCCS0LsnbWp6/xwpFDdCWYE0KWzUO6Sk1g0E= github.com/codeready-toolchain/toolchain-common v0.0.0-20240905135929-d55d86fdd41e h1:xTqyuImyon/P2QfV5NIJDsVkEWqb9b6Ax9INsmzpI1Q= github.com/codeready-toolchain/toolchain-common v0.0.0-20240905135929-d55d86fdd41e/go.mod h1:aIbki5CFsykeqZn2/ZwvUb3Krx2f2Tbq58R6MGnk6H8= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= From bc6b76d7968fed0a20a1ad1e1c26b08541409b26 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Mon, 30 Sep 2024 19:46:27 +0200 Subject: [PATCH 09/13] chore: remove Shane from CODEOWNERS (#468) Shane left the team Signed-off-by: Xavier Coulon --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 629180bd..b6e88321 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @MatousJobanek @xcoulon @alexeykazakov @rajivnathan @ranakan19 @sbryzak @mfrancisc +* @MatousJobanek @xcoulon @alexeykazakov @rajivnathan @ranakan19 @mfrancisc From 503d23290aa697a144c48b915f8bb3df6eec7c48 Mon Sep 17 00:00:00 2001 From: Francisc Munteanu Date: Tue, 1 Oct 2024 08:52:23 +0200 Subject: [PATCH 10/13] fix: log errors inside VerifyPhoneCode (#470) * log errors inside VerifyPhoneCode --- pkg/controller/signup.go | 1 - pkg/verification/service/verification_service.go | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/controller/signup.go b/pkg/controller/signup.go index f26deea3..f9bacd80 100644 --- a/pkg/controller/signup.go +++ b/pkg/controller/signup.go @@ -139,7 +139,6 @@ func (s *Signup) VerifyPhoneCodeHandler(ctx *gin.Context) { err := s.app.VerificationService().VerifyPhoneCode(ctx, userID, username, code) if err != nil { - log.Error(ctx, err, "error validating user verification phone code") e := &crterrors.Error{} switch { case errors.As(err, &e): diff --git a/pkg/verification/service/verification_service.go b/pkg/verification/service/verification_service.go index 11862511..84bb1952 100644 --- a/pkg/verification/service/verification_service.go +++ b/pkg/verification/service/verification_service.go @@ -321,6 +321,7 @@ func (s *ServiceImpl) VerifyPhoneCode(ctx *gin.Context, userID, username, code s doUpdate := func() error { signup, err := s.Services().SignupService().GetUserSignupFromIdentifier(userID, username) if err != nil { + log.Error(ctx, err, fmt.Sprintf("error getting signup from identifier. user_id: %s | username: %s", userID, username)) return err } @@ -342,6 +343,7 @@ func (s *ServiceImpl) VerifyPhoneCode(ctx *gin.Context, userID, username, code s _, err = s.Services().SignupService().UpdateUserSignup(signup) if err != nil { + log.Error(ctx, err, fmt.Sprintf("error updating usersignup: %s", signup.Name)) return err } From 6d3e72060d28c48c810247db716315fbe8182cf7 Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Tue, 1 Oct 2024 11:59:43 +0200 Subject: [PATCH 11/13] use FakeClient as backend for RESTClient based unit tests (#469) Co-authored-by: Alexey Kazakov Co-authored-by: Francisc Munteanu --- cmd/main.go | 2 +- .../service/factory/service_factory.go | 12 +- pkg/controller/signup_test.go | 181 ++--- pkg/proxy/proxy_test.go | 3 +- pkg/proxy/service/cluster_service_test.go | 15 +- pkg/server/in_cluster_application.go | 9 +- pkg/signup/service/resource_provider.go | 24 +- pkg/signup/service/signup_service.go | 2 +- pkg/signup/service/signup_service_test.go | 658 +++++++----------- .../service/verification_service_test.go | 384 +++++----- test/fake/banneduser_client.go | 84 --- test/fake/fake.go | 18 - test/fake/masteruserrecord_client.go | 117 ---- test/fake/mockable_application.go | 8 - test/fake/signup_client.go | 162 ----- test/fake/socialevent_client.go | 75 -- test/fake/space_client.go | 71 -- test/fake/spacebinding_client.go | 68 -- test/fake/toolchainstatus_client.go | 67 -- test/testsuite.go | 102 +-- test/util/application.go | 24 + test/util/service_context.go | 23 + 22 files changed, 573 insertions(+), 1536 deletions(-) delete mode 100644 test/fake/banneduser_client.go delete mode 100644 test/fake/fake.go delete mode 100644 test/fake/masteruserrecord_client.go delete mode 100644 test/fake/signup_client.go delete mode 100644 test/fake/socialevent_client.go delete mode 100644 test/fake/space_client.go delete mode 100644 test/fake/spacebinding_client.go delete mode 100644 test/fake/toolchainstatus_client.go create mode 100644 test/util/application.go create mode 100644 test/util/service_context.go diff --git a/cmd/main.go b/cmd/main.go index 27abb45a..534f163e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -84,7 +84,7 @@ func main() { } } - app, err := server.NewInClusterApplication(cl) + app, err := server.NewInClusterApplication(cl, configuration.Namespace()) if err != nil { panic(err.Error()) } diff --git a/pkg/application/service/factory/service_factory.go b/pkg/application/service/factory/service_factory.go index b41023ad..ccf6947b 100644 --- a/pkg/application/service/factory/service_factory.go +++ b/pkg/application/service/factory/service_factory.go @@ -88,6 +88,12 @@ func (s *ServiceFactory) WithVerificationServiceOption(opt verificationservice.V s.verificationServiceOptions = append(s.verificationServiceOptions, opt) } +func (s *ServiceFactory) WithSignupService(signupService service.SignupService) { + s.signupServiceFunc = func(_ ...signupservice.SignupServiceOption) service.SignupService { + return signupService + } +} + // Option an option to configure the Service Factory type Option func(f *ServiceFactory) @@ -115,8 +121,10 @@ func NewServiceFactory(options ...Option) *ServiceFactory { return verificationservice.NewVerificationService(f.getContext(), f.verificationServiceOptions...) } - f.signupServiceFunc = func(_ ...signupservice.SignupServiceOption) service.SignupService { - return signupservice.NewSignupService(f.getContext(), f.signupServiceOptions...) + if f.signupServiceFunc == nil { + f.signupServiceFunc = func(_ ...signupservice.SignupServiceOption) service.SignupService { + return signupservice.NewSignupService(f.getContext(), f.signupServiceOptions...) + } } return f diff --git a/pkg/controller/signup_test.go b/pkg/controller/signup_test.go index 2400bf56..de5de249 100644 --- a/pkg/controller/signup_test.go +++ b/pkg/controller/signup_test.go @@ -2,6 +2,7 @@ package controller_test import ( "bytes" + gocontext "context" "encoding/json" "errors" "fmt" @@ -21,11 +22,13 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/verification/service" verification_service "github.com/codeready-toolchain/registration-service/pkg/verification/service" "github.com/codeready-toolchain/registration-service/test" + testutil "github.com/codeready-toolchain/registration-service/test/util" "github.com/codeready-toolchain/toolchain-common/pkg/states" commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" testconfig "github.com/codeready-toolchain/toolchain-common/pkg/test/config" testsocialevent "github.com/codeready-toolchain/toolchain-common/pkg/test/socialevent" testusersignup "github.com/codeready-toolchain/toolchain-common/pkg/test/usersignup" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/gin-gonic/gin" "github.com/gofrs/uuid" @@ -36,10 +39,7 @@ import ( apiv1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" ) type TestSignupSuite struct { @@ -51,19 +51,19 @@ func TestRunSignupSuite(t *testing.T) { suite.Run(t, &TestSignupSuite{test.UnitTestSuite{}, nil}) } -func (s *TestSignupSuite) SetHTTPClientFactoryOption() { - s.httpClient = &http.Client{Transport: &http.Transport{}} - gock.InterceptClient(s.httpClient) +func httpClientFactoryOption() func(serviceFactory *factory.ServiceFactory) { + httpClient := &http.Client{Transport: &http.Transport{}} + gock.InterceptClient(httpClient) serviceOption := func(svc *verification_service.ServiceImpl) { - svc.HTTPClient = s.httpClient + svc.HTTPClient = httpClient } opt := func(serviceFactory *factory.ServiceFactory) { serviceFactory.WithVerificationServiceOption(serviceOption) } - s.WithFactoryOption(opt) + return opt } func (s *TestSignupSuite) TestSignupPostHandler() { @@ -73,13 +73,16 @@ func (s *TestSignupSuite) TestSignupPostHandler() { require.NoError(s.T(), err) svc := &FakeSignupService{} - s.Application.MockSignupService(svc) + + _, application := testutil.PrepareInClusterAppWithOption(s.T(), func(serviceFactory *factory.ServiceFactory) { + serviceFactory.WithSignupService(svc) + }) // Check if the config is set to testing mode, so the handler may use this. assert.True(s.T(), configuration.IsTestingMode(), "testing mode not set correctly to true") // Create signup instance. - signupCtrl := controller.NewSignup(s.Application) + signupCtrl := controller.NewSignup(application) handler := gin.HandlerFunc(signupCtrl.PostHandler) userID, err := uuid.NewV4() @@ -172,7 +175,9 @@ func (s *TestSignupSuite) TestSignupGetHandler() { // Create a mock SignupService svc := &FakeSignupService{} - s.Application.MockSignupService(svc) + _, application := testutil.PrepareInClusterAppWithOption(s.T(), func(serviceFactory *factory.ServiceFactory) { + serviceFactory.WithSignupService(svc) + }) // Create UserSignup ob, err := uuid.NewV4() @@ -180,7 +185,7 @@ func (s *TestSignupSuite) TestSignupGetHandler() { userID := ob.String() // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.GetHandler) s.Run("signups found", func() { @@ -258,11 +263,6 @@ func (s *TestSignupSuite) TestSignupGetHandler() { } func (s *TestSignupSuite) TestInitVerificationHandler() { - // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() - - defer gock.Off() - // call override config to ensure the factory option takes effect s.OverrideApplicationDefault() @@ -287,11 +287,11 @@ func (s *TestSignupSuite) TestInitVerificationHandler() { } states.SetVerificationRequired(userSignup, true) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) + defer gock.Off() // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.InitVerificationHandler) assertInitVerificationSuccess := func(phoneNumber, expectedHash string, expectedCounter int) { @@ -303,7 +303,8 @@ func (s *TestSignupSuite) TestInitVerificationHandler() { rr := initPhoneVerification(s.T(), handler, gin.Param{}, data, userID, "", http.MethodPut, "/api/v1/signup/verification") require.Equal(s.T(), http.StatusNoContent, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) require.NotEmpty(s.T(), updatedUserSignup.Annotations[crtapi.UserSignupVerificationCodeAnnotationKey]) @@ -395,11 +396,10 @@ func (s *TestSignupSuite) TestInitVerificationHandler() { } states.SetVerificationRequired(userSignup, false) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) + _, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.InitVerificationHandler) data := []byte(`{"phone_number": "2268213044", "country_code": "1"}`) @@ -447,10 +447,12 @@ func (s *TestSignupSuite) TestInitVerificationHandler() { }, } - s.Application.MockSignupService(svc) + _, application := testutil.PrepareInClusterAppWithOption(s.T(), func(serviceFactory *factory.ServiceFactory) { + serviceFactory.WithSignupService(svc) + }, userSignup) // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.InitVerificationHandler) // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. @@ -483,12 +485,10 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { Status: crtapi.UserSignupStatus{}, } - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) - s.Run("verification successful", func() { // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyPhoneCodeHandler) param := gin.Param{ @@ -500,7 +500,8 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { // Check the status code is what we expect. require.Equal(s.T(), http.StatusOK, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) // Check that the correct UserSignup is passed into the FakeSignupService for update @@ -512,13 +513,13 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { s.Run("getsignup returns error", func() { // Simulate returning an error - s.FakeUserSignupClient.MockGet = func(string) (userSignup *crtapi.UserSignup, e error) { - return nil, errors.New("no user") + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) + fakeClient.MockGet = func(_ gocontext.Context, _ client.ObjectKey, _ client.Object, _ ...client.GetOption) error { + return errors.New("no user") } - defer func() { s.FakeUserSignupClient.MockGet = nil }() // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyPhoneCodeHandler) param := gin.Param{ @@ -541,14 +542,10 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { }) s.Run("getsignup returns nil", func() { - - s.FakeUserSignupClient.MockGet = func(userID string) (userSignup *crtapi.UserSignup, e error) { - return nil, apierrors.NewNotFound(schema.GroupResource{}, userID) - } - defer func() { s.FakeUserSignupClient.MockGet = nil }() + _, application := testutil.PrepareInClusterApp(s.T()) // Create Signup controller instance and handle the verification request - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyPhoneCodeHandler) param := gin.Param{ @@ -566,18 +563,17 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { require.Equal(s.T(), "Not Found", bodyParams["status"]) require.InDelta(s.T(), float64(404), bodyParams["code"], 0.01) - require.Equal(s.T(), " \"jsmith\" not found: user not found", bodyParams["message"]) + require.Equal(s.T(), "usersignups.toolchain.dev.openshift.com \"jsmith\" not found: user not found", bodyParams["message"]) require.Equal(s.T(), "error while verifying phone code", bodyParams["details"]) }) s.Run("update usersignup returns error", func() { - s.FakeUserSignupClient.MockUpdate = func(*crtapi.UserSignup) (*crtapi.UserSignup, error) { - return nil, apierrors.NewServiceUnavailable("service unavailable") + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) + fakeClient.MockUpdate = func(_ gocontext.Context, _ client.Object, _ ...client.UpdateOption) error { + return apierrors.NewServiceUnavailable("service unavailable") } - defer func() { s.FakeUserSignupClient.MockUpdate = nil }() - // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyPhoneCodeHandler) param := gin.Param{ @@ -608,13 +604,10 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { userSignup.Annotations[crtapi.UserVerificationExpiryAnnotationKey] = time.Now().Add(10 * time.Second).Format(service.TimestampLayout) userSignup.Annotations[crtapi.UserSignupVerificationTimestampAnnotationKey] = time.Now().Format(service.TimestampLayout) - err := s.FakeUserSignupClient.Delete(userSignup.Name, nil) - require.NoError(s.T(), err) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) + _, application := testutil.PrepareInClusterApp(s.T(), userSignup) // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyPhoneCodeHandler) param := gin.Param{ @@ -638,7 +631,8 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { s.Run("no code provided", func() { // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + _, application := testutil.PrepareInClusterApp(s.T(), userSignup) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyPhoneCodeHandler) param := gin.Param{ @@ -677,11 +671,10 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { Status: crtapi.UserSignupStatus{}, } - err = s.FakeUserSignupClient.Tracker.Add(otherUserSignup) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), otherUserSignup, userSignup) // Create Signup controller instance. - ctrl := controller.NewSignup(s.Application) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyPhoneCodeHandler) param := gin.Param{ @@ -693,7 +686,8 @@ func (s *TestSignupSuite) TestVerifyPhoneCodeHandler() { // Check the status code is what we expect. require.Equal(s.T(), http.StatusOK, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(otherUserSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(otherUserSignup), updatedUserSignup) require.NoError(s.T(), err) // Check that the correct UserSignup is passed into the FakeSignupService for update @@ -726,9 +720,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event") - err := s.setupFakeClients(userSignup, event) - require.NoError(s.T(), err) - ctrl := controller.NewSignup(s.Application) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyActivationCodeHandler) // when @@ -736,7 +729,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // then require.Equal(s.T(), http.StatusOK, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err := fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) require.False(s.T(), states.VerificationRequired(updatedUserSignup)) require.Empty(s.T(), updatedUserSignup.Annotations[crtapi.UserVerificationAttemptsAnnotationKey]) @@ -751,9 +745,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { testusersignup.VerificationRequired(time.Second), // just signed up testusersignup.WithVerificationAttempts(configuration.GetRegistrationServiceConfig().Verification().AttemptsAllowed()), // already reached max attempts ) - err := s.setupFakeClients(userSignup) - require.NoError(s.T(), err) - ctrl := controller.NewSignup(s.Application) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyActivationCodeHandler) // when @@ -761,7 +754,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // then require.Equal(s.T(), http.StatusTooManyRequests, rr.Code) // should be `Forbidden` as in other cases? - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err := fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) require.True(s.T(), states.VerificationRequired(updatedUserSignup)) require.Equal(s.T(), "3", updatedUserSignup.Annotations[crtapi.UserVerificationAttemptsAnnotationKey]) @@ -770,9 +764,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { s.Run("invalid code", func() { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up - err := s.setupFakeClients(userSignup) - require.NoError(s.T(), err) - ctrl := controller.NewSignup(s.Application) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyActivationCodeHandler) // when @@ -780,7 +773,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // then require.Equal(s.T(), http.StatusForbidden, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err := fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) require.True(s.T(), states.VerificationRequired(updatedUserSignup)) require.Equal(s.T(), "1", updatedUserSignup.Annotations[crtapi.UserVerificationAttemptsAnnotationKey]) @@ -790,9 +784,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithStartTime(time.Now().Add(60*time.Minute))) - err := s.setupFakeClients(userSignup, event) - require.NoError(s.T(), err) - ctrl := controller.NewSignup(s.Application) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyActivationCodeHandler) // when @@ -801,7 +794,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // then // Check the status code is what we expect. require.Equal(s.T(), http.StatusForbidden, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err := fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) // Check that the correct UserSignup is passed into the FakeSignupService for update require.True(s.T(), states.VerificationRequired(updatedUserSignup)) @@ -812,9 +806,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithEndTime(time.Now().Add(-1*time.Minute))) - err := s.setupFakeClients(userSignup, event) - require.NoError(s.T(), err) - ctrl := controller.NewSignup(s.Application) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyActivationCodeHandler) // when @@ -823,7 +816,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // then // Check the status code is what we expect. require.Equal(s.T(), http.StatusForbidden, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err := fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) // Check that the correct UserSignup is passed into the FakeSignupService for update require.True(s.T(), states.VerificationRequired(updatedUserSignup)) @@ -834,9 +828,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithActivationCount(10)) // same as `spec.MaxAttendees` - err := s.setupFakeClients(userSignup, event) - require.NoError(s.T(), err) - ctrl := controller.NewSignup(s.Application) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) + ctrl := controller.NewSignup(application) handler := gin.HandlerFunc(ctrl.VerifyActivationCodeHandler) // when @@ -845,7 +838,8 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { // then // Check the status code is what we expect. require.Equal(s.T(), http.StatusForbidden, rr.Code) - updatedUserSignup, err := s.FakeUserSignupClient.Get(userSignup.Name) + updatedUserSignup := &crtapi.UserSignup{} + err := fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), updatedUserSignup) require.NoError(s.T(), err) // Check that the correct UserSignup is passed into the FakeSignupService for update require.True(s.T(), states.VerificationRequired(updatedUserSignup)) @@ -854,31 +848,6 @@ func (s *TestSignupSuite) TestVerifyActivationCodeHandler() { }) } -func (s *TestSignupSuite) setupFakeClients(objects ...runtime.Object) error { - clientScheme := runtime.NewScheme() - if err := crtapi.SchemeBuilder.AddToScheme(clientScheme); err != nil { - return err - } - s.FakeUserSignupClient.Tracker = kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - s.FakeSocialEventClient.Tracker = kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - - for _, obj := range objects { - switch obj := obj.(type) { - case *crtapi.UserSignup: - if err := s.FakeUserSignupClient.Tracker.Add(obj); err != nil { - return err - } - case *crtapi.SocialEvent: - if err := s.FakeSocialEventClient.Tracker.Add(obj); err != nil { - return err - } - default: - return fmt.Errorf("unexpected type of object: %T", obj) - } - } - return nil -} - func initActivationCodeVerification(t *testing.T, handler gin.HandlerFunc, username, code string) *httptest.ResponseRecorder { // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. rr := httptest.NewRecorder() diff --git a/pkg/proxy/proxy_test.go b/pkg/proxy/proxy_test.go index cb1aa373..52dcba0a 100644 --- a/pkg/proxy/proxy_test.go +++ b/pkg/proxy/proxy_test.go @@ -928,8 +928,7 @@ func (s *TestProxySuite) newMemberClusterServiceWithMembers(serverURL string) ap fakeClient := commontest.NewFakeClient(s.T(), route) return service.NewMemberClusterService( fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { diff --git a/pkg/proxy/service/cluster_service_test.go b/pkg/proxy/service/cluster_service_test.go index 3379f0b2..aa50a7f7 100644 --- a/pkg/proxy/service/cluster_service_test.go +++ b/pkg/proxy/service/cluster_service_test.go @@ -93,8 +93,7 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, + Svcs: s.Application, }, ) @@ -196,8 +195,7 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { s.Run("no member clusters", func() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { @@ -225,8 +223,7 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { s.Run("no member cluster with the given URL", func() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { @@ -287,8 +284,7 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { @@ -455,8 +451,7 @@ func (s *TestClusterServiceSuite) TestGetClusterAccess() { s.Run("get workspace by name", func() { svc := service.NewMemberClusterService( fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, + Svcs: s.Application, }, func(si *service.ServiceImpl) { si.GetMembersFunc = func(_ ...commoncluster.Condition) []*commoncluster.CachedToolchainCluster { diff --git a/pkg/server/in_cluster_application.go b/pkg/server/in_cluster_application.go index 14a60115..903a973d 100644 --- a/pkg/server/in_cluster_application.go +++ b/pkg/server/in_cluster_application.go @@ -4,7 +4,6 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/application" "github.com/codeready-toolchain/registration-service/pkg/application/service" "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" - "github.com/codeready-toolchain/registration-service/pkg/configuration" "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -13,17 +12,17 @@ import ( // application type is intended to run inside a Kubernetes cluster, where it makes use of the rest.InClusterConfig() // function to determine which Kubernetes configuration to use to create the REST client that interacts with the // Kubernetes service endpoints. -func NewInClusterApplication(client client.Client) (application.Application, error) { - kubeClient, err := kubeclient.NewCRTRESTClient(client, configuration.Namespace()) +func NewInClusterApplication(client client.Client, namespace string, options ...factory.Option) (application.Application, error) { + kubeClient, err := kubeclient.NewCRTRESTClient(client, namespace) if err != nil { return nil, err } return &InClusterApplication{ - serviceFactory: factory.NewServiceFactory( + serviceFactory: factory.NewServiceFactory(append(options, factory.WithServiceContextOptions(factory.CRTClientOption(kubeClient), factory.InformerOption(client), - )), + ))...), }, nil } diff --git a/pkg/signup/service/resource_provider.go b/pkg/signup/service/resource_provider.go index af4b1d40..21f12f75 100644 --- a/pkg/signup/service/resource_provider.go +++ b/pkg/signup/service/resource_provider.go @@ -14,26 +14,26 @@ type ResourceProvider interface { ListSpaceBindings(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) } -type crtClientProvider struct { - cl kubeclient.CRTClient +type CrtClientProvider struct { + Cl kubeclient.CRTClient } -func (p crtClientProvider) GetMasterUserRecord(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - return p.cl.V1Alpha1().MasterUserRecords().Get(name) +func (p CrtClientProvider) GetMasterUserRecord(name string) (*toolchainv1alpha1.MasterUserRecord, error) { + return p.Cl.V1Alpha1().MasterUserRecords().Get(name) } -func (p crtClientProvider) GetToolchainStatus() (*toolchainv1alpha1.ToolchainStatus, error) { - return p.cl.V1Alpha1().ToolchainStatuses().Get() +func (p CrtClientProvider) GetToolchainStatus() (*toolchainv1alpha1.ToolchainStatus, error) { + return p.Cl.V1Alpha1().ToolchainStatuses().Get() } -func (p crtClientProvider) GetUserSignup(name string) (*toolchainv1alpha1.UserSignup, error) { - return p.cl.V1Alpha1().UserSignups().Get(name) +func (p CrtClientProvider) GetUserSignup(name string) (*toolchainv1alpha1.UserSignup, error) { + return p.Cl.V1Alpha1().UserSignups().Get(name) } -func (p crtClientProvider) GetSpace(name string) (*toolchainv1alpha1.Space, error) { - return p.cl.V1Alpha1().Spaces().Get(name) +func (p CrtClientProvider) GetSpace(name string) (*toolchainv1alpha1.Space, error) { + return p.Cl.V1Alpha1().Spaces().Get(name) } -func (p crtClientProvider) ListSpaceBindings(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return p.cl.V1Alpha1().SpaceBindings().ListSpaceBindings(reqs...) +func (p CrtClientProvider) ListSpaceBindings(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { + return p.Cl.V1Alpha1().SpaceBindings().ListSpaceBindings(reqs...) } diff --git a/pkg/signup/service/signup_service.go b/pkg/signup/service/signup_service.go index 463a3feb..98370c08 100644 --- a/pkg/signup/service/signup_service.go +++ b/pkg/signup/service/signup_service.go @@ -57,7 +57,7 @@ func NewSignupService(context servicecontext.ServiceContext, opts ...SignupServi s := &ServiceImpl{ BaseService: base.NewBaseService(context), - defaultProvider: crtClientProvider{context.CRTClient()}, + defaultProvider: CrtClientProvider{context.CRTClient()}, CaptchaChecker: captcha.Helper{}, } diff --git a/pkg/signup/service/signup_service_test.go b/pkg/signup/service/signup_service_test.go index c39f5658..a568cd28 100644 --- a/pkg/signup/service/signup_service_test.go +++ b/pkg/signup/service/signup_service_test.go @@ -17,10 +17,11 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/context" errors2 "github.com/codeready-toolchain/registration-service/pkg/errors" infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" + "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "github.com/codeready-toolchain/registration-service/pkg/signup/service" "github.com/codeready-toolchain/registration-service/pkg/util" "github.com/codeready-toolchain/registration-service/test" - "github.com/codeready-toolchain/registration-service/test/fake" + testutil "github.com/codeready-toolchain/registration-service/test/util" "sigs.k8s.io/controller-runtime/pkg/client" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" @@ -37,10 +38,7 @@ import ( "github.com/stretchr/testify/suite" apiv1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" ) type TestSignupServiceSuite struct { @@ -51,11 +49,9 @@ func TestRunSignupServiceSuite(t *testing.T) { suite.Run(t, &TestSignupServiceSuite{test.UnitTestSuite{}}) } -func (s *TestSignupServiceSuite) ServiceConfiguration(namespace string, verificationEnabled bool, +func (s *TestSignupServiceSuite) ServiceConfiguration(verificationEnabled bool, excludedDomains string, verificationCodeExpiresInMin int) { - commontest.SetEnvVarAndRestore(s.T(), commonconfig.WatchNamespaceEnvVar, namespace) - s.OverrideApplicationDefault( testconfig.RegistrationService(). Verification().Enabled(verificationEnabled). @@ -64,23 +60,16 @@ func (s *TestSignupServiceSuite) ServiceConfiguration(namespace string, verifica } func (s *TestSignupServiceSuite) TestSignup() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) // given userID, err := uuid.NewV4() require.NoError(s.T(), err) - assertUserSignupExists := func(userSignup *toolchainv1alpha1.UserSignup, username string) (schema.GroupVersionResource, toolchainv1alpha1.UserSignup) { - require.NotNil(s.T(), userSignup) - - gvk, err := apiutil.GVKForObject(userSignup, s.FakeUserSignupClient.Scheme) - require.NoError(s.T(), err) - gvr, _ := meta.UnsafeGuessKindToResource(gvk) + assertUserSignupExists := func(cl client.Client, username string) toolchainv1alpha1.UserSignup { - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) + userSignups := &toolchainv1alpha1.UserSignupList{} + err := cl.List(gocontext.TODO(), userSignups, client.InNamespace(commontest.HostOperatorNs)) require.NoError(s.T(), err) - - userSignups := values.(*toolchainv1alpha1.UserSignupList) - require.NotEmpty(s.T(), userSignups.Items) require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] @@ -101,7 +90,7 @@ func (s *TestSignupServiceSuite) TestSignup() { require.Equal(s.T(), "original-sub-value", val.Spec.IdentityClaims.OriginalSub) require.Equal(s.T(), "jsmith@gmail.com", val.Spec.IdentityClaims.Email) - return gvr, val + return val } rr := httptest.NewRecorder() @@ -116,8 +105,10 @@ func (s *TestSignupServiceSuite) TestSignup() { ctx.Set(context.UserIDKey, "13349822") ctx.Set(context.AccountIDKey, "45983711") + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + // when - userSignup, err := s.Application.SignupService().Signup(ctx) + userSignup, err := application.SignupService().Signup(ctx) // then require.NoError(s.T(), err) @@ -125,7 +116,7 @@ func (s *TestSignupServiceSuite) TestSignup() { assert.Empty(s.T(), userSignup.Annotations[toolchainv1alpha1.UserSignupLastTargetClusterAnnotationKey]) // at this point, the last target cluster annotation is not set require.Equal(s.T(), "original-sub-value", userSignup.Spec.IdentityClaims.OriginalSub) - gvr, existing := assertUserSignupExists(userSignup, "jsmith") + existing := assertUserSignupExists(fakeClient, "jsmith") s.Run("deactivate and reactivate again", func() { // given @@ -134,16 +125,14 @@ func (s *TestSignupServiceSuite) TestSignup() { deactivatedUS.Annotations[toolchainv1alpha1.UserSignupLastTargetClusterAnnotationKey] = "member-3" // assume the user was targeted to member-3 states.SetDeactivated(deactivatedUS, true) deactivatedUS.Status.Conditions = deactivated() - err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, commontest.HostOperatorNs) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), deactivatedUS) // when - deactivatedUS, err = s.Application.SignupService().Signup(ctx) + deactivatedUS, err = application.SignupService().Signup(ctx) // then require.NoError(s.T(), err) - assertUserSignupExists(deactivatedUS, "jsmith") - assert.NotEmpty(s.T(), deactivatedUS.ResourceVersion) + assertUserSignupExists(fakeClient, "jsmith") assert.Equal(s.T(), "2", deactivatedUS.Annotations[toolchainv1alpha1.UserSignupActivationCounterAnnotationKey]) // value was preserved assert.Equal(s.T(), "member-3", deactivatedUS.Annotations[toolchainv1alpha1.UserSignupLastTargetClusterAnnotationKey]) // value was preserved }) @@ -156,16 +145,14 @@ func (s *TestSignupServiceSuite) TestSignup() { // also, alter the activation counter annotation delete(deactivatedUS.Annotations, toolchainv1alpha1.UserSignupActivationCounterAnnotationKey) delete(deactivatedUS.Annotations, toolchainv1alpha1.UserSignupLastTargetClusterAnnotationKey) - err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, commontest.HostOperatorNs) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), deactivatedUS) // when - userSignup, err := s.Application.SignupService().Signup(ctx) + userSignup, err := application.SignupService().Signup(ctx) // then require.NoError(s.T(), err) - assertUserSignupExists(userSignup, "jsmith") - assert.NotEmpty(s.T(), userSignup.ResourceVersion) + assertUserSignupExists(fakeClient, "jsmith") assert.Empty(s.T(), userSignup.Annotations[toolchainv1alpha1.UserSignupActivationCounterAnnotationKey]) // was initially missing, and was not set assert.Empty(s.T(), userSignup.Annotations[toolchainv1alpha1.UserSignupLastTargetClusterAnnotationKey]) // was initially missing, and was not set }) @@ -175,17 +162,16 @@ func (s *TestSignupServiceSuite) TestSignup() { deactivatedUS := existing.DeepCopy() states.SetDeactivated(deactivatedUS, true) deactivatedUS.Status.Conditions = deactivated() - err := s.FakeUserSignupClient.Tracker.Update(gvr, deactivatedUS, commontest.HostOperatorNs) - require.NoError(s.T(), err) - s.FakeUserSignupClient.MockUpdate = func(signup *toolchainv1alpha1.UserSignup) (*toolchainv1alpha1.UserSignup, error) { - if signup.Name == "jsmith" { - return nil, errors.New("an error occurred") + fakeClient, application := testutil.PrepareInClusterApp(s.T(), deactivatedUS) + fakeClient.MockUpdate = func(ctx gocontext.Context, obj client.Object, opts ...client.UpdateOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok && obj.GetName() == "jsmith" { + return errors.New("an error occurred") } - return &toolchainv1alpha1.UserSignup{}, nil + return fakeClient.Client.Update(ctx, obj, opts...) } // when - _, err = s.Application.SignupService().Signup(ctx) + _, err = application.SignupService().Signup(ctx) // then require.EqualError(s.T(), err, "an error occurred") @@ -207,12 +193,13 @@ func (s *TestSignupServiceSuite) TestSignupFailsWhenClientReturnsError() { ctx.Set(context.FamilyNameKey, "abernathy") ctx.Set(context.CompanyKey, "red hat") - s.FakeUserSignupClient.MockGet = func(_ string) (*toolchainv1alpha1.UserSignup, error) { - return nil, errors2.NewInternalError(errors.New("an internal error"), "an internal error happened") + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + fakeClient.MockGet = func(_ gocontext.Context, _ client.ObjectKey, _ client.Object, _ ...client.GetOption) error { + return errors2.NewInternalError(errors.New("an internal error"), "an internal error happened") } // when - _, err = s.Application.SignupService().Signup(ctx) + _, err = application.SignupService().Signup(ctx) require.EqualError(s.T(), err, "an internal error: an internal error happened") } @@ -232,32 +219,33 @@ func (s *TestSignupServiceSuite) TestSignupFailsWithNotFoundThenOtherError() { ctx.Set(context.FamilyNameKey, "smith") ctx.Set(context.CompanyKey, "red hat") - s.FakeUserSignupClient.MockGet = func(id string) (*toolchainv1alpha1.UserSignup, error) { - if id == userID.String() { - return nil, apierrors.NewNotFound(schema.GroupResource{}, id) + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok && key.Name != userID.String() { + return errors2.NewInternalError(errors.New("something bad happened"), "something very bad happened") } - return nil, errors2.NewInternalError(errors.New("something bad happened"), "something very bad happened") + return fakeClient.Client.Get(ctx, key, obj, opts...) } // when - _, err = s.Application.SignupService().Signup(ctx) + _, err = application.SignupService().Signup(ctx) require.EqualError(s.T(), err, "something bad happened: something very bad happened") } func (s *TestSignupServiceSuite) TestGetSignupFailsWithNotFoundThenOtherError() { - // given - s.FakeUserSignupClient.MockGet = func(id string) (*toolchainv1alpha1.UserSignup, error) { - if id == "000" { - return nil, apierrors.NewNotFound(schema.GroupResource{}, id) + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok && key.Name != "000" { + return errors2.NewInternalError(errors.New("something quite unfortunate happened"), "something bad") } - return nil, errors2.NewInternalError(errors.New("something quite unfortunate happened"), "something bad") + return fakeClient.Client.Get(ctx, key, obj, opts...) } c, _ := gin.CreateTestContext(httptest.NewRecorder()) // when - _, err := s.Application.SignupService().GetSignup(c, "000", "abc") + _, err := application.SignupService().GetSignup(c, "000", "abc") // then require.EqualError(s.T(), err, "something quite unfortunate happened: something bad") @@ -271,18 +259,10 @@ func (s *TestSignupServiceSuite) TestGetSignupFailsWithNotFoundThenOtherError() } return fakeClient.Client.Get(ctx, key, obj, opts...) } - - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when - _, err := svc.GetSignupFromInformer(c, "000", "abc", true) + _, err = svc.GetSignupFromInformer(c, "000", "abc", true) // then require.EqualError(t, err, "something quite unfortunate happened: something bad") @@ -290,7 +270,7 @@ func (s *TestSignupServiceSuite) TestGetSignupFailsWithNotFoundThenOtherError() } func (s *TestSignupServiceSuite) TestSignupNoSpaces() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) // given userID, err := uuid.NewV4() @@ -307,22 +287,18 @@ func (s *TestSignupServiceSuite) TestSignupNoSpaces() { ctx.Set(context.CompanyKey, "red hat") ctx.Request, _ = http.NewRequest("POST", "/?no-space=true", bytes.NewBufferString("")) + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + // when - userSignup, err := s.Application.SignupService().Signup(ctx) + userSignup, err := application.SignupService().Signup(ctx) // then require.NoError(s.T(), err) require.NotNil(s.T(), userSignup) - gvk, err := apiutil.GVKForObject(userSignup, s.FakeUserSignupClient.Scheme) + userSignups := &toolchainv1alpha1.UserSignupList{} + err = fakeClient.List(gocontext.TODO(), userSignups, client.InNamespace(commontest.HostOperatorNs)) require.NoError(s.T(), err) - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) - require.NoError(s.T(), err) - - userSignups := values.(*toolchainv1alpha1.UserSignupList) - require.NotEmpty(s.T(), userSignups.Items) require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] @@ -341,8 +317,6 @@ func (s *TestSignupServiceSuite) TestSignupWithCaptchaEnabled() { serviceFactory.WithSignupServiceOption(serviceOption) } - s.WithFactoryOption(opt) - s.OverrideApplicationDefault( testconfig.RegistrationService(). Verification().Enabled(true). @@ -365,22 +339,18 @@ func (s *TestSignupServiceSuite) TestSignupWithCaptchaEnabled() { ctx.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("")) ctx.Request.Header.Set("Recaptcha-Token", "abc") + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), opt) + // when - userSignup, err := s.Application.SignupService().Signup(ctx) + userSignup, err := application.SignupService().Signup(ctx) // then require.NoError(s.T(), err) require.NotNil(s.T(), userSignup) - gvk, err := apiutil.GVKForObject(userSignup, s.FakeUserSignupClient.Scheme) + userSignups := &toolchainv1alpha1.UserSignupList{} + err = fakeClient.List(gocontext.TODO(), userSignups, client.InNamespace(commontest.HostOperatorNs)) require.NoError(s.T(), err) - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) - require.NoError(s.T(), err) - - userSignups := values.(*toolchainv1alpha1.UserSignupList) - require.NotEmpty(s.T(), userSignups.Items) require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] @@ -388,7 +358,7 @@ func (s *TestSignupServiceSuite) TestSignupWithCaptchaEnabled() { } func (s *TestSignupServiceSuite) TestUserSignupWithInvalidSubjectPrefix() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) // given userID, err := uuid.NewV4() @@ -405,21 +375,18 @@ func (s *TestSignupServiceSuite) TestUserSignupWithInvalidSubjectPrefix() { ctx.Set(context.FamilyNameKey, "jones") ctx.Set(context.CompanyKey, "red hat") + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + // when - userSignup, err := s.Application.SignupService().Signup(ctx) + userSignup, err := application.SignupService().Signup(ctx) // then require.NoError(s.T(), err) + require.NotNil(s.T(), userSignup) - gvk, err := apiutil.GVKForObject(userSignup, s.FakeUserSignupClient.Scheme) - require.NoError(s.T(), err) - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) + userSignups := &toolchainv1alpha1.UserSignupList{} + err = fakeClient.List(gocontext.TODO(), userSignups, client.InNamespace(commontest.HostOperatorNs)) require.NoError(s.T(), err) - - userSignups := values.(*toolchainv1alpha1.UserSignupList) - require.NotEmpty(s.T(), userSignups.Items) require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] @@ -465,7 +432,7 @@ func (s *TestSignupServiceSuite) TestEncodeUserID() { } func (s *TestSignupServiceSuite) TestUserWithExcludedDomainEmailSignsUp() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "redhat.com", 5) + s.ServiceConfiguration(true, "redhat.com", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -479,19 +446,18 @@ func (s *TestSignupServiceSuite) TestUserWithExcludedDomainEmailSignsUp() { ctx.Set(context.FamilyNameKey, "smith") ctx.Set(context.CompanyKey, "red hat") - userSignup, err := s.Application.SignupService().Signup(ctx) - require.NoError(s.T(), err) - require.NotNil(s.T(), userSignup) + fakeClient, application := testutil.PrepareInClusterApp(s.T()) - gvk, err := apiutil.GVKForObject(userSignup, s.FakeUserSignupClient.Scheme) - require.NoError(s.T(), err) - gvr, _ := meta.UnsafeGuessKindToResource(gvk) + // when + userSignup, err := application.SignupService().Signup(ctx) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) + // then require.NoError(s.T(), err) + require.NotNil(s.T(), userSignup) - userSignups := values.(*toolchainv1alpha1.UserSignupList) - require.NotEmpty(s.T(), userSignups.Items) + userSignups := &toolchainv1alpha1.UserSignupList{} + err = fakeClient.List(gocontext.TODO(), userSignups, client.InNamespace(commontest.HostOperatorNs)) + require.NoError(s.T(), err) require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] @@ -499,7 +465,7 @@ func (s *TestSignupServiceSuite) TestUserWithExcludedDomainEmailSignsUp() { } func (s *TestSignupServiceSuite) TestCRTAdminUserSignup() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "redhat.com", 5) + s.ServiceConfiguration(true, "redhat.com", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -512,25 +478,29 @@ func (s *TestSignupServiceSuite) TestCRTAdminUserSignup() { ctx.Set(context.GivenNameKey, "jane") ctx.Set(context.FamilyNameKey, "smith") ctx.Set(context.CompanyKey, "red hat") + _, application := testutil.PrepareInClusterApp(s.T()) + + // when + userSignup, err := application.SignupService().Signup(ctx) - userSignup, err := s.Application.SignupService().Signup(ctx) + // then require.EqualError(s.T(), err, "forbidden: failed to create usersignup for jsmith-crtadmin") require.Nil(s.T(), userSignup) } func (s *TestSignupServiceSuite) TestFailsIfUserSignupNameAlreadyExists() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) - err = s.FakeUserSignupClient.Tracker.Add(&toolchainv1alpha1.UserSignup{ + signup := &toolchainv1alpha1.UserSignup{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), Namespace: commontest.HostOperatorNs, }, Spec: toolchainv1alpha1.UserSignupSpec{}, - }) + } require.NoError(s.T(), err) rr := httptest.NewRecorder() @@ -538,13 +508,18 @@ func (s *TestSignupServiceSuite) TestFailsIfUserSignupNameAlreadyExists() { ctx.Set(context.UsernameKey, "jsmith") ctx.Set(context.SubKey, userID.String()) ctx.Set(context.EmailKey, "jsmith@gmail.com") - _, err = s.Application.SignupService().Signup(ctx) + _, application := testutil.PrepareInClusterApp(s.T(), signup) + + // when + _, err = application.SignupService().Signup(ctx) + + // then require.EqualError(s.T(), err, fmt.Sprintf("Operation cannot be fulfilled on \"\": UserSignup [id: %s; username: jsmith]. Unable to create UserSignup because there is already an active UserSignup with such ID", userID.String())) } func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) // given userID, err := uuid.NewV4() @@ -553,7 +528,7 @@ func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { bannedUserID, err := uuid.NewV4() require.NoError(s.T(), err) - err = s.FakeBannedUserClient.Tracker.Add(&toolchainv1alpha1.BannedUser{ + bannedUser := &toolchainv1alpha1.BannedUser{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: bannedUserID.String(), @@ -565,7 +540,7 @@ func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { Spec: toolchainv1alpha1.BannedUserSpec{ Email: "jsmith@gmail.com", }, - }) + } require.NoError(s.T(), err) rr := httptest.NewRecorder() @@ -574,8 +549,10 @@ func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { ctx.Set(context.SubKey, userID.String()) ctx.Set(context.EmailKey, "jsmith@gmail.com") + _, application := testutil.PrepareInClusterApp(s.T(), bannedUser) + // when - _, err = s.Application.SignupService().Signup(ctx) + _, err = application.SignupService().Signup(ctx) // then require.Error(s.T(), err) @@ -587,7 +564,7 @@ func (s *TestSignupServiceSuite) TestFailsIfUserBanned() { } func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseBannedUser() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "redhat.com", 5) + s.ServiceConfiguration(true, "redhat.com", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -595,7 +572,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseBannedUser() { bannedUserID, err := uuid.NewV4() require.NoError(s.T(), err) - err = s.FakeBannedUserClient.Tracker.Add(&toolchainv1alpha1.BannedUser{ + bannedUser := &toolchainv1alpha1.BannedUser{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: bannedUserID.String(), @@ -608,7 +585,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseBannedUser() { Spec: toolchainv1alpha1.BannedUserSpec{ Email: "jane.doe@gmail.com", }, - }) + } require.NoError(s.T(), err) rr := httptest.NewRecorder() @@ -616,17 +593,23 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseBannedUser() { ctx.Set(context.UsernameKey, "jsmith") ctx.Set(context.SubKey, userID.String()) ctx.Set(context.EmailKey, "jsmith@gmail.com") - err = s.Application.SignupService().PhoneNumberAlreadyInUse(bannedUserID.String(), "jsmith", "+12268213044") + + _, application := testutil.PrepareInClusterApp(s.T(), bannedUser) + + // when + err = application.SignupService().PhoneNumberAlreadyInUse(bannedUserID.String(), "jsmith", "+12268213044") + + // then require.EqualError(s.T(), err, "cannot re-register with phone number: phone number already in use") } func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseUserSignup() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) - err = s.FakeUserSignupClient.Tracker.Add(&toolchainv1alpha1.UserSignup{ + signup := &toolchainv1alpha1.UserSignup{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: userID.String(), @@ -636,7 +619,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseUserSignup() { toolchainv1alpha1.UserSignupUserPhoneHashLabelKey: "fd276563a8232d16620da8ec85d0575f", }, }, - }) + } require.NoError(s.T(), err) rr := httptest.NewRecorder() @@ -647,12 +630,18 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseUserSignup() { newUserID, err := uuid.NewV4() require.NoError(s.T(), err) - err = s.Application.SignupService().PhoneNumberAlreadyInUse(newUserID.String(), "jsmith", "+12268213044") + + _, application := testutil.PrepareInClusterApp(s.T(), signup) + + // when + err = application.SignupService().PhoneNumberAlreadyInUse(newUserID.String(), "jsmith", "+12268213044") + + // then require.EqualError(s.T(), err, "cannot re-register with phone number: phone number already in use") } func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -660,7 +649,7 @@ func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { bannedUserID, err := uuid.NewV4() require.NoError(s.T(), err) - err = s.FakeBannedUserClient.Tracker.Add(&toolchainv1alpha1.BannedUser{ + bannedUser := &toolchainv1alpha1.BannedUser{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ Name: bannedUserID.String(), @@ -672,7 +661,7 @@ func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { Spec: toolchainv1alpha1.BannedUserSpec{ Email: "jane.doe@gmail.com", }, - }) + } require.NoError(s.T(), err) rr := httptest.NewRecorder() @@ -680,19 +669,19 @@ func (s *TestSignupServiceSuite) TestOKIfOtherUserBanned() { ctx.Set(context.UsernameKey, "jsmith") ctx.Set(context.SubKey, userID.String()) ctx.Set(context.EmailKey, "jsmith@gmail.com") - userSignup, err := s.Application.SignupService().Signup(ctx) - require.NoError(s.T(), err) - require.NotNil(s.T(), userSignup) - gvk, err := apiutil.GVKForObject(userSignup, s.FakeUserSignupClient.Scheme) - require.NoError(s.T(), err) - gvr, _ := meta.UnsafeGuessKindToResource(gvk) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), bannedUser) - values, err := s.FakeUserSignupClient.Tracker.List(gvr, gvk, commontest.HostOperatorNs) + // when + userSignup, err := application.SignupService().Signup(ctx) + + // then require.NoError(s.T(), err) + require.NotNil(s.T(), userSignup) - userSignups := values.(*toolchainv1alpha1.UserSignupList) - require.NotEmpty(s.T(), userSignups.Items) + userSignups := &toolchainv1alpha1.UserSignupList{} + err = fakeClient.List(gocontext.TODO(), userSignups, client.InNamespace(commontest.HostOperatorNs)) + require.NoError(s.T(), err) require.Len(s.T(), userSignups.Items, 1) val := userSignups.Items[0] @@ -707,15 +696,16 @@ func (s *TestSignupServiceSuite) TestGetUserSignupFails() { username := "johnsmith" c, _ := gin.CreateTestContext(httptest.NewRecorder()) - s.FakeUserSignupClient.MockGet = func(name string) (*toolchainv1alpha1.UserSignup, error) { - if name == username { - return nil, errors.New("an error occurred") + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok && key.Name != username { + return errors.New("an error occurred") } - return &toolchainv1alpha1.UserSignup{}, nil + return fakeClient.Client.Get(ctx, key, obj, opts...) } // when - _, err := s.Application.SignupService().GetSignup(c, "", username) + _, err := application.SignupService().GetSignup(c, "", username) // then require.EqualError(s.T(), err, "an error occurred") @@ -730,17 +720,10 @@ func (s *TestSignupServiceSuite) TestGetUserSignupFails() { return fakeClient.Client.Get(ctx, key, obj, opts...) } - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when - _, err := svc.GetSignupFromInformer(c, "johnsmith", "abc", true) + _, err = svc.GetSignupFromInformer(c, "johnsmith", "abc", true) // then require.EqualError(t, err, "an error occurred") @@ -752,22 +735,19 @@ func (s *TestSignupServiceSuite) TestGetSignupNotFound() { require.NoError(s.T(), err) c, _ := gin.CreateTestContext(httptest.NewRecorder()) + _, application := testutil.PrepareInClusterApp(s.T()) + + // when + signup, err := application.SignupService().GetSignup(c, userID.String(), "") - signup, err := s.Application.SignupService().GetSignup(c, userID.String(), "") + // then require.Nil(s.T(), signup) require.NoError(s.T(), err) s.T().Run("informer", func(t *testing.T) { // given fakeClient := commontest.NewFakeClient(t) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when signup, err := svc.GetSignupFromInformer(c, userID.String(), "", true) @@ -780,7 +760,7 @@ func (s *TestSignupServiceSuite) TestGetSignupNotFound() { func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) userID, err := uuid.NewV4() require.NoError(s.T(), err) @@ -817,11 +797,10 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { } states.SetVerificationRequired(userSignupNotComplete, true) - err = s.FakeUserSignupClient.Tracker.Add(userSignupNotComplete) - require.NoError(s.T(), err) + _, application := testutil.PrepareInClusterApp(s.T(), userSignupNotComplete) // when - response, err := s.Application.SignupService().GetSignup(c, userID.String(), "") + response, err := application.SignupService().GetSignup(c, userID.String(), "") // then require.NoError(s.T(), err) @@ -847,14 +826,7 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { s.T().Run("informer - with check for usersignup complete condition", func(t *testing.T) { // given fakeClient := commontest.NewFakeClient(t, userSignupNotComplete) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when response, err := svc.GetSignupFromInformer(c, userID.String(), "", true) @@ -882,31 +854,13 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { s.T().Run("informer - with no check for UserSignup complete condition", func(t *testing.T) { // given states.SetVerificationRequired(userSignupNotComplete, false) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) mur := s.newProvisionedMUR("bill") - err = s.FakeMasterUserRecordClient.Tracker.Add(mur) - require.NoError(t, err) - space := s.newSpace(mur.Name) - err = s.FakeSpaceClient.Tracker.Add(space) - require.NoError(t, err) - spacebinding := s.newSpaceBinding(mur.Name, space.Name) - err = s.FakeSpaceBindingClient.Tracker.Add(spacebinding) - require.NoError(t, err) - toolchainStatus := s.newToolchainStatus(".apps.") - err = s.FakeToolchainStatusClient.Tracker.Add(toolchainStatus) - require.NoError(t, err) fakeClient := commontest.NewFakeClient(t, userSignupNotComplete, mur, space, spacebinding, toolchainStatus) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when // we set checkUserSignupCompleted to false @@ -935,7 +889,7 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusNotComplete() { func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) noCondition := toolchainv1alpha1.UserSignupStatus{} pendingApproval := toolchainv1alpha1.UserSignupStatus{ @@ -984,11 +938,10 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { states.SetVerificationRequired(userSignup, true) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) + _, application := testutil.PrepareInClusterApp(s.T(), userSignup) // when - response, err := s.Application.SignupService().GetSignup(c, userID.String(), "bill") + response, err := application.SignupService().GetSignup(c, userID.String(), "bill") // then require.NoError(s.T(), err) @@ -1012,14 +965,7 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { s.T().Run("informer", func(t *testing.T) { // given fakeClient := commontest.NewFakeClient(t, userSignup) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when response, err := svc.GetSignupFromInformer(c, userID.String(), "", true) @@ -1048,17 +994,17 @@ func (s *TestSignupServiceSuite) TestGetSignupNoStatusNotCompleteCondition() { func (s *TestSignupServiceSuite) TestGetSignupDeactivated() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) us := s.newUserSignupComplete() us.Status.Conditions = deactivated() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) + + fakeClient, application := testutil.PrepareInClusterApp(s.T(), us) c, _ := gin.CreateTestContext(httptest.NewRecorder()) // when - signup, err := s.Application.SignupService().GetSignup(c, us.Name, "") + signup, err := application.SignupService().GetSignup(c, us.Name, "") // then require.Nil(s.T(), signup) @@ -1066,15 +1012,7 @@ func (s *TestSignupServiceSuite) TestGetSignupDeactivated() { s.T().Run("informer", func(t *testing.T) { // given - fakeClient := commontest.NewFakeClient(t, us) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when signup, err := svc.GetSignupFromInformer(c, us.Name, "", true) @@ -1090,32 +1028,20 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusOK() { for _, appsSubDomain := range []string{".apps.", ".apps-"} { s.SetupTest() s.T().Run("for apps subdomain: "+appsSubDomain, func(t *testing.T) { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) us := s.newUserSignupComplete() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(t, err) - mur := s.newProvisionedMUR("ted") - err = s.FakeMasterUserRecordClient.Tracker.Add(mur) - require.NoError(t, err) - - c, _ := gin.CreateTestContext(httptest.NewRecorder()) - toolchainStatus := s.newToolchainStatus(appsSubDomain) - err = s.FakeToolchainStatusClient.Tracker.Add(toolchainStatus) - require.NoError(t, err) - space := s.newSpace(mur.Name) - err = s.FakeSpaceClient.Tracker.Add(space) - require.NoError(t, err) - spacebinding := s.newSpaceBinding(mur.Name, space.Name) - err = s.FakeSpaceBindingClient.Tracker.Add(spacebinding) - require.NoError(t, err) + + _, application := testutil.PrepareInClusterApp(s.T(), us, mur, toolchainStatus, space, spacebinding) + + c, _ := gin.CreateTestContext(httptest.NewRecorder()) // when - response, err := s.Application.SignupService().GetSignup(c, us.Name, "") + response, err := application.SignupService().GetSignup(c, us.Name, "") // then require.NoError(t, err) @@ -1142,14 +1068,7 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusOK() { s.T().Run("informer", func(t *testing.T) { // given fakeClient := commontest.NewFakeClient(t, us, mur, toolchainStatus, space, spacebinding) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when response, err := svc.GetSignupFromInformer(c, us.Name, "", true) @@ -1178,43 +1097,27 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusOK() { func (s *TestSignupServiceSuite) TestGetSignupByUsernameOK() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) us := s.newUserSignupComplete() us.Name = service.EncodeUserIdentifier(us.Spec.IdentityClaims.PreferredUsername) // Set the scheduled deactivation timestamp 1 day in the future deactivationTimestamp := time.Now().Add(time.Hour * 24).Round(time.Second).UTC() us.Status.ScheduledDeactivationTimestamp = util.Ptr(v1.NewTime(deactivationTimestamp)) - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) mur := s.newProvisionedMUR("ted") // Set the provisioned time 29 days in the past provisionedTime := time.Now().Add(-time.Hour * 24 * 29).Round(time.Second) mur.Status.ProvisionedTime = util.Ptr(v1.NewTime(provisionedTime)) - err = s.FakeMasterUserRecordClient.Tracker.Add(mur) - require.NoError(s.T(), err) - - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) - - c, _ := gin.CreateTestContext(httptest.NewRecorder()) space := s.newSpace(mur.Name) - err = s.FakeSpaceClient.Tracker.Add(space) - require.NoError(s.T(), err) - spacebinding := s.newSpaceBinding(mur.Name, space.Name) - err = s.FakeSpaceBindingClient.Tracker.Add(spacebinding) - require.NoError(s.T(), err) - toolchainStatus := s.newToolchainStatus(".apps.") - err = s.FakeToolchainStatusClient.Tracker.Add(toolchainStatus) - require.NoError(s.T(), err) + + fakeClient := commontest.NewFakeClient(s.T(), us, mur, space, spacebinding, toolchainStatus) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(s.T(), fakeClient)) + + c, _ := gin.CreateTestContext(httptest.NewRecorder()) // when response, err := svc.GetSignup(c, "foo", us.Spec.IdentityClaims.PreferredUsername) @@ -1249,14 +1152,7 @@ func (s *TestSignupServiceSuite) TestGetSignupByUsernameOK() { s.T().Run("informer", func(t *testing.T) { // given fakeClient := commontest.NewFakeClient(t, us, mur, toolchainStatus, space, spacebinding) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when response, err := svc.GetSignupFromInformer(c, "foo", us.Spec.IdentityClaims.PreferredUsername, true) @@ -1322,22 +1218,18 @@ func (s *TestSignupServiceSuite) newToolchainStatus(appsSubDomain string) *toolc func (s *TestSignupServiceSuite) TestGetSignupStatusFailGetToolchainStatus() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) c, _ := gin.CreateTestContext(httptest.NewRecorder()) us := s.newUserSignupComplete() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) - mur := s.newProvisionedMUR("ted") - err = s.FakeMasterUserRecordClient.Tracker.Add(mur) - require.NoError(s.T(), err) space := s.newSpace("ted") - require.NoError(s.T(), s.FakeSpaceClient.Tracker.Add(space)) + + _, application := testutil.PrepareInClusterApp(s.T(), us, mur, space) // when - _, err = s.Application.SignupService().GetSignup(c, us.Name, "") + _, err := application.SignupService().GetSignup(c, us.Name, "") // then require.EqualError(s.T(), err, fmt.Sprintf("error when retrieving ToolchainStatus to set Che Dashboard for completed UserSignup %s: toolchainstatuses.toolchain.dev.openshift.com \"toolchain-status\" not found", us.Name)) @@ -1345,17 +1237,10 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusFailGetToolchainStatus() { s.T().Run("informer", func(t *testing.T) { // given fakeClient := commontest.NewFakeClient(t, us, mur, space) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when - _, err := svc.GetSignupFromInformer(c, us.Name, "", true) + _, err = svc.GetSignupFromInformer(c, us.Name, "", true) // then require.EqualError(t, err, fmt.Sprintf("error when retrieving ToolchainStatus to set Che Dashboard for completed UserSignup %s: toolchainstatuses.toolchain.dev.openshift.com \"toolchain-status\" not found", us.Name)) @@ -1364,24 +1249,23 @@ func (s *TestSignupServiceSuite) TestGetSignupStatusFailGetToolchainStatus() { func (s *TestSignupServiceSuite) TestGetSignupMURGetFails() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) us := s.newUserSignupComplete() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) c, _ := gin.CreateTestContext(httptest.NewRecorder()) returnedErr := errors.New("an error occurred") - s.FakeMasterUserRecordClient.MockGet = func(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - if name == us.Status.CompliantUsername { - return nil, returnedErr + fakeClient, application := testutil.PrepareInClusterApp(s.T(), us) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.MasterUserRecord); ok && key.Name == us.Status.CompliantUsername { + return returnedErr } - return &toolchainv1alpha1.MasterUserRecord{}, nil + return fakeClient.Client.Get(ctx, key, obj, opts...) } // when - _, err = s.Application.SignupService().GetSignup(c, us.Name, "") + _, err := application.SignupService().GetSignup(c, us.Name, "") // then require.EqualError(s.T(), err, fmt.Sprintf("error when retrieving MasterUserRecord for completed UserSignup %s: an error occurred", us.Name)) @@ -1395,17 +1279,10 @@ func (s *TestSignupServiceSuite) TestGetSignupMURGetFails() { } return fakeClient.Client.Get(ctx, key, obj, opts...) } - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when - _, err := svc.GetSignupFromInformer(c, us.Name, "", true) + _, err = svc.GetSignupFromInformer(c, us.Name, "", true) // then require.EqualError(t, err, fmt.Sprintf("error when retrieving MasterUserRecord for completed UserSignup %s: an error occurred", us.Name)) @@ -1414,11 +1291,9 @@ func (s *TestSignupServiceSuite) TestGetSignupMURGetFails() { func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) us := s.newUserSignupComplete() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) c, _ := gin.CreateTestContext(httptest.NewRecorder()) @@ -1431,9 +1306,7 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { } space := s.newSpace("ted") - require.NoError(s.T(), s.FakeSpaceClient.Tracker.Add(space)) toolchainStatus := s.newToolchainStatus(".apps.") - require.NoError(s.T(), s.FakeToolchainStatusClient.Tracker.Add(toolchainStatus)) tests := map[string]struct { condition toolchainv1alpha1.Condition @@ -1489,11 +1362,10 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { tc.condition, }, } - err = s.FakeMasterUserRecordClient.Tracker.Add(mur) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), us, mur, space, toolchainStatus) // when - response, err := s.Application.SignupService().GetSignup(c, us.Name, "") + response, err := application.SignupService().GetSignup(c, us.Name, "") // then require.NoError(t, err) @@ -1503,15 +1375,7 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { // informer case // given - fakeClient := commontest.NewFakeClient(t, us, mur, toolchainStatus, space) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when _, err = svc.GetSignupFromInformer(c, us.Name, "", true) @@ -1521,19 +1385,16 @@ func (s *TestSignupServiceSuite) TestGetSignupReadyConditionStatus() { require.Equal(t, tc.expectedConditionReady, response.Status.Ready) require.Equal(t, tc.condition.Reason, response.Status.Reason) require.Equal(t, tc.condition.Message, response.Status.Message) - err = s.FakeMasterUserRecordClient.Delete(mur.Name, nil) - require.NoError(t, err) }) } } func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) us := s.newBannedUserSignup() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), us) rr := httptest.NewRecorder() ctx, _ := gin.CreateTestContext(rr) @@ -1542,7 +1403,7 @@ func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { ctx.Set(context.EmailKey, "jsmith@gmail.com") // when - response, err := s.Application.SignupService().GetSignup(ctx, us.Name, "") + response, err := application.SignupService().GetSignup(ctx, us.Name, "") // then // return not found signup @@ -1552,15 +1413,7 @@ func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { s.T().Run("informer", func(t *testing.T) { // given - fakeClient := commontest.NewFakeClient(t, us) - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - s.Application.MockInformerService(inf) - svc := service.NewSignupService( - fake.MemberClusterServiceContext{ - CrtClient: s, - Svcs: s.Application, - }, - ) + svc := service.NewSignupService(testutil.NewMemberClusterServiceContext(t, fakeClient)) // when response, err := svc.GetSignupFromInformer(ctx, us.Name, "", true) @@ -1575,14 +1428,16 @@ func (s *TestSignupServiceSuite) TestGetSignupBannedUserEmail() { func (s *TestSignupServiceSuite) TestGetDefaultUserNamespace() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) space := s.newSpace("dave") - err := s.FakeSpaceClient.Tracker.Add(space) + fakeClient := commontest.NewFakeClient(s.T(), space) + crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) require.NoError(s.T(), err) + crtClientProvider := service.CrtClientProvider{Cl: crtClient} // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(s, "dave", "dave") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "dave", "dave") // then assert.Equal(s.T(), "dave-dev", defaultUserNamespace) @@ -1590,7 +1445,6 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespace() { s.T().Run("informer", func(t *testing.T) { // given - fakeClient := commontest.NewFakeClient(t, space) inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when @@ -1606,29 +1460,23 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespace() { // This is valuable when user doesn't have default home space created, but has access to some shared spaces func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFromFirstUnownedSpace() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) // space created for userA space := s.newSpace("userA") - err := s.FakeSpaceClient.Tracker.Add(space) - require.NoError(s.T(), err) - // space shared with userB spacebindingB := s.newSpaceBinding("userB", space.Name) - err = s.FakeSpaceBindingClient.Tracker.Add(spacebindingB) - require.NoError(s.T(), err) - // space created for userC spaceC := s.newSpace("userC") - err = s.FakeSpaceClient.Tracker.Add(spaceC) - require.NoError(s.T(), err) - // spaceC shared with userB spaceCindingC := s.newSpaceBinding("userB", spaceC.Name) - err = s.FakeSpaceBindingClient.Tracker.Add(spaceCindingC) + + fakeClient := commontest.NewFakeClient(s.T(), space, spacebindingB, spaceC, spaceCindingC) + crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) require.NoError(s.T(), err) + crtClientProvider := service.CrtClientProvider{Cl: crtClient} // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(s, "", "userB") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "", "userB") // then assert.Equal(s.T(), "userA-dev", defaultUserNamespace) @@ -1636,7 +1484,6 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFromFirstUnownedSpac s.T().Run("informer", func(t *testing.T) { // given - fakeClient := commontest.NewFakeClient(t, space, spacebindingB, spaceCindingC) inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when @@ -1651,31 +1498,25 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFromFirstUnownedSpac // TestGetDefaultUserNamespaceMultiSpace tests that the home Space created for the user is prioritized when there are multiple spaces func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceMultiSpace() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) // space1 created by userA space1 := s.newSpace("userA") - err := s.FakeSpaceClient.Tracker.Add(space1) - require.NoError(s.T(), err) - // space1 shared with userB spacebinding1 := s.newSpaceBinding("userB", space1.Name) - err = s.FakeSpaceBindingClient.Tracker.Add(spacebinding1) - require.NoError(s.T(), err) - // space2 created by userB space2 := s.newSpace("userB") - err = s.FakeSpaceClient.Tracker.Add(space2) - require.NoError(s.T(), err) - // space2 shared with userB spacebinding2 := s.newSpaceBinding("userB", space2.Name) - err = s.FakeSpaceBindingClient.Tracker.Add(spacebinding2) + + fakeClient := commontest.NewFakeClient(s.T(), space1, space2, spacebinding1, spacebinding2) + crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) require.NoError(s.T(), err) + crtClientProvider := service.CrtClientProvider{Cl: crtClient} // when // get default namespace for userB - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(s, "userB", "userB") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "userB", "userB") // then assert.Equal(s.T(), "userB-dev", defaultUserNamespace) // space2 is prioritized over space1 because it was created by the userB @@ -1683,7 +1524,6 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceMultiSpace() { s.T().Run("informer", func(t *testing.T) { // given - fakeClient := commontest.NewFakeClient(t, space1, space2, spacebinding1, spacebinding2) inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when @@ -1697,14 +1537,16 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceMultiSpace() { func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpaceBinding() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) space := s.newSpace("dave") - err := s.FakeSpaceClient.Tracker.Add(space) + fakeClient := commontest.NewFakeClient(s.T(), space) + crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) require.NoError(s.T(), err) + crtClientProvider := service.CrtClientProvider{Cl: crtClient} // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(s, "", "dave") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "", "dave") // then assert.Empty(s.T(), defaultUserNamespace) @@ -1712,7 +1554,6 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpa s.T().Run("informer", func(t *testing.T) { // given - fakeClient := commontest.NewFakeClient(t, space) fakeClient.MockList = func(ctx gocontext.Context, list client.ObjectList, opts ...client.ListOption) error { if _, ok := list.(*toolchainv1alpha1.SpaceBindingList); ok { return apierrors.NewInternalError(fmt.Errorf("something went wrong")) @@ -1732,10 +1573,14 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpa func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoSpace() { // given - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) + fakeClient := commontest.NewFakeClient(s.T()) + crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) + require.NoError(s.T(), err) + crtClientProvider := service.CrtClientProvider{Cl: crtClient} // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(s, "dave", "dave") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "dave", "dave") // then assert.Empty(s.T(), defaultUserNamespace) @@ -1743,7 +1588,6 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoSpace() { s.T().Run("informer", func(t *testing.T) { // given - fakeClient := commontest.NewFakeClient(t) inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when @@ -1756,65 +1600,73 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoSpace() { } func (s *TestSignupServiceSuite) TestGetUserSignup() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) s.Run("getusersignup ok", func() { us := s.newUserSignupComplete() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) + _, application := testutil.PrepareInClusterApp(s.T(), us) - val, err := s.Application.SignupService().GetUserSignupFromIdentifier(us.Name, "") + val, err := application.SignupService().GetUserSignupFromIdentifier(us.Name, "") require.NoError(s.T(), err) require.Equal(s.T(), us.Name, val.Name) }) s.Run("getusersignup returns error", func() { - s.FakeUserSignupClient.MockGet = func(_ string) (userSignup *toolchainv1alpha1.UserSignup, e error) { - return nil, errors.New("get failed") + fakeClient, application := testutil.PrepareInClusterApp(s.T()) + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok { + return errors.New("get failed") + } + return fakeClient.Client.Get(ctx, key, obj, opts...) } - val, err := s.Application.SignupService().GetUserSignupFromIdentifier("foo", "") + val, err := application.SignupService().GetUserSignupFromIdentifier("foo", "") require.EqualError(s.T(), err, "get failed") require.Nil(s.T(), val) }) s.Run("getusersignup with unknown user", func() { - s.FakeUserSignupClient.MockGet = nil + _, application := testutil.PrepareInClusterApp(s.T()) - val, err := s.Application.SignupService().GetUserSignupFromIdentifier("unknown", "") + val, err := application.SignupService().GetUserSignupFromIdentifier("unknown", "") require.True(s.T(), apierrors.IsNotFound(err)) require.Nil(s.T(), val) }) } func (s *TestSignupServiceSuite) TestUpdateUserSignup() { - s.ServiceConfiguration(commontest.HostOperatorNs, true, "", 5) + s.ServiceConfiguration(true, "", 5) us := s.newUserSignupComplete() - err := s.FakeUserSignupClient.Tracker.Add(us) - require.NoError(s.T(), err) s.Run("updateusersignup ok", func() { - val, err := s.Application.SignupService().GetUserSignupFromIdentifier(us.Name, "") + _, application := testutil.PrepareInClusterApp(s.T(), us) + + val, err := application.SignupService().GetUserSignupFromIdentifier(us.Name, "") require.NoError(s.T(), err) val.Spec.IdentityClaims.FamilyName = "Johnson" - updated, err := s.Application.SignupService().UpdateUserSignup(val) + updated, err := application.SignupService().UpdateUserSignup(val) require.NoError(s.T(), err) require.Equal(s.T(), val.Spec.IdentityClaims.FamilyName, updated.Spec.IdentityClaims.FamilyName) }) s.Run("updateusersignup returns error", func() { - s.FakeUserSignupClient.MockUpdate = func(_ *toolchainv1alpha1.UserSignup) (userSignup *toolchainv1alpha1.UserSignup, e error) { - return nil, errors.New("update failed") + fakeClient, application := testutil.PrepareInClusterApp(s.T(), us) + + fakeClient.MockUpdate = func(ctx gocontext.Context, obj client.Object, opts ...client.UpdateOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok { + return errors.New("update failed") + } + return fakeClient.Client.Update(ctx, obj, opts...) } - val, err := s.Application.SignupService().GetUserSignupFromIdentifier(us.Name, "") + val, err := application.SignupService().GetUserSignupFromIdentifier(us.Name, "") require.NoError(s.T(), err) - updated, err := s.Application.SignupService().UpdateUserSignup(val) + updated, err := application.SignupService().UpdateUserSignup(val) require.EqualError(s.T(), err, "update failed") require.Nil(s.T(), updated) }) @@ -1940,14 +1792,11 @@ func (s *TestSignupServiceSuite) TestIsPhoneVerificationRequired() { func (s *TestSignupServiceSuite) TestGetSignupUpdatesUserSignupIdentityClaims() { - s.ServiceConfiguration(commontest.HostOperatorNs, false, "", 5) + s.ServiceConfiguration(false, "", 5) // Create a new UserSignup, set its UserID and AccountID annotations userSignup := s.newUserSignupComplete() - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) - mur := &toolchainv1alpha1.MasterUserRecord{ TypeMeta: v1.TypeMeta{}, ObjectMeta: v1.ObjectMeta{ @@ -1966,17 +1815,17 @@ func (s *TestSignupServiceSuite) TestGetSignupUpdatesUserSignupIdentityClaims() }, }, } - err = s.FakeMasterUserRecordClient.Tracker.Add(mur) - require.NoError(s.T(), err) s.Run("PreferredUsername property updated when set in context", func() { c, _ := gin.CreateTestContext(httptest.NewRecorder()) c.Set(context.UsernameKey, "cocochanel") + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, mur) - _, err := s.Application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) + _, err := application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) require.NoError(s.T(), err) - modified, err := s.FakeUserSignupClient.Get(userSignup.Name) + modified := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), modified) require.NoError(s.T(), err) require.Equal(s.T(), "cocochanel", modified.Spec.IdentityClaims.PreferredUsername) @@ -1995,10 +1844,11 @@ func (s *TestSignupServiceSuite) TestGetSignupUpdatesUserSignupIdentityClaims() c, _ := gin.CreateTestContext(httptest.NewRecorder()) c.Set(context.GivenNameKey, "Jonathan") - _, err := s.Application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) + _, err := application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) require.NoError(s.T(), err) - modified, err := s.FakeUserSignupClient.Get(userSignup.Name) + modified := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), modified) require.NoError(s.T(), err) require.Equal(s.T(), "Jonathan", modified.Spec.IdentityClaims.GivenName) @@ -2020,10 +1870,11 @@ func (s *TestSignupServiceSuite) TestGetSignupUpdatesUserSignupIdentityClaims() c.Set(context.FamilyNameKey, "Smythe") c.Set(context.CompanyKey, "Red Hat") - _, err := s.Application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) + _, err := application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) require.NoError(s.T(), err) - modified, err := s.FakeUserSignupClient.Get(userSignup.Name) + modified := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), modified) require.NoError(s.T(), err) require.Equal(s.T(), "Smythe", modified.Spec.IdentityClaims.FamilyName) @@ -2047,10 +1898,11 @@ func (s *TestSignupServiceSuite) TestGetSignupUpdatesUserSignupIdentityClaims() c.Set(context.OriginalSubKey, "jsmythe-original-sub") c.Set(context.EmailKey, "jsmythe@redhat.com") - _, err := s.Application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) + _, err := application.SignupService().GetSignup(c, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername) require.NoError(s.T(), err) - modified, err := s.FakeUserSignupClient.Get(userSignup.Name) + modified := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), modified) require.NoError(s.T(), err) require.Equal(s.T(), "987654321", modified.Spec.IdentityClaims.Sub) diff --git a/pkg/verification/service/verification_service_test.go b/pkg/verification/service/verification_service_test.go index f9df198b..65bd524f 100644 --- a/pkg/verification/service/verification_service_test.go +++ b/pkg/verification/service/verification_service_test.go @@ -2,6 +2,7 @@ package service_test import ( "bytes" + gocontext "context" "errors" "fmt" "io" @@ -13,6 +14,8 @@ import ( "time" senderpkg "github.com/codeready-toolchain/registration-service/pkg/verification/sender" + testutil "github.com/codeready-toolchain/registration-service/test/util" + "sigs.k8s.io/controller-runtime/pkg/client" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" @@ -35,9 +38,6 @@ import ( "gopkg.in/h2non/gock.v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" ) const ( @@ -101,25 +101,23 @@ func (s *TestVerificationServiceSuite) ServiceConfiguration(accountSID, authToke s.SetSecret(secret) } -func (s *TestVerificationServiceSuite) SetHTTPClientFactoryOption() { +func httpClientFactoryOption() func(serviceFactory *factory.ServiceFactory) { - s.httpClient = &http.Client{Transport: &http.Transport{}} - gock.InterceptClient(s.httpClient) + httpClient := &http.Client{Transport: &http.Transport{}} + gock.InterceptClient(httpClient) serviceOption := func(svc *verificationservice.ServiceImpl) { - svc.HTTPClient = s.httpClient + svc.HTTPClient = httpClient } opt := func(serviceFactory *factory.ServiceFactory) { serviceFactory.WithVerificationServiceOption(serviceOption) } - s.WithFactoryOption(opt) + return opt } func (s *TestVerificationServiceSuite) TestInitVerification() { - // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() s.ServiceConfiguration("xxx", "yyy", "CodeReady") defer gock.Off() @@ -175,22 +173,19 @@ func (s *TestVerificationServiceSuite) TestInitVerification() { states.SetVerificationRequired(userSignup2, true) // Add both UserSignups to the fake client - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) - - err = s.FakeUserSignupClient.Tracker.Add(userSignup2) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup, userSignup2) // Test the init verification for the first UserSignup ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") + err := application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") require.NoError(s.T(), err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) require.NoError(s.T(), err) // Ensure the verification code is set - require.NotEmpty(s.T(), userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) + require.NotEmpty(s.T(), signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) buf := new(bytes.Buffer) _, err = buf.ReadFrom(reqBody) @@ -200,7 +195,7 @@ func (s *TestVerificationServiceSuite) TestInitVerification() { params, err := url.ParseQuery(reqValue) require.NoError(s.T(), err) require.Equal(s.T(), fmt.Sprintf("Developer Sandbox for Red Hat OpenShift: Your verification code is %s", - userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), + signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), params.Get("Body")) require.Equal(s.T(), "CodeReady", params.Get("From")) require.Equal(s.T(), "+1NUMBER", params.Get("To")) @@ -218,14 +213,15 @@ func (s *TestVerificationServiceSuite) TestInitVerification() { ctx, _ = gin.CreateTestContext(httptest.NewRecorder()) // This time we won't pass in the UserID, just the username yet still expect the UserSignup to be found - err = s.Application.VerificationService().InitVerification(ctx, "", userSignup2.Spec.IdentityClaims.PreferredUsername, "+61NUMBER", "1") + err = application.VerificationService().InitVerification(ctx, "", userSignup2.Spec.IdentityClaims.PreferredUsername, "+61NUMBER", "1") require.NoError(s.T(), err) - userSignup2, err = s.FakeUserSignupClient.Get(userSignup2.Name) + signup2 := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup2), signup2) require.NoError(s.T(), err) // Ensure the verification code is set - require.NotEmpty(s.T(), userSignup2.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) + require.NotEmpty(s.T(), signup2.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) buf = new(bytes.Buffer) _, err = buf.ReadFrom(reqBody) @@ -235,7 +231,7 @@ func (s *TestVerificationServiceSuite) TestInitVerification() { params, err = url.ParseQuery(reqValue) require.NoError(s.T(), err) require.Equal(s.T(), fmt.Sprintf("Developer Sandbox for Red Hat OpenShift: Your verification code is %s", - userSignup2.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), + signup2.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), params.Get("Body")) require.Equal(s.T(), "CodeReady", params.Get("From")) require.Equal(s.T(), "+61NUMBER", params.Get("To")) @@ -258,8 +254,6 @@ func (s *TestVerificationServiceSuite) TestNotificationSender() { } func (s *TestVerificationServiceSuite) TestInitVerificationClientFailure() { - // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() s.ServiceConfiguration("xxx", "yyy", "CodeReady") defer gock.Off() @@ -294,60 +288,60 @@ func (s *TestVerificationServiceSuite) TestInitVerificationClientFailure() { states.SetVerificationRequired(userSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) - s.T().Run("when client GET call fails should return error", func(t *testing.T) { + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) // Cause the client GET call to fail - s.FakeUserSignupClient.MockGet = func(_ string) (*toolchainv1alpha1.UserSignup, error) { - return nil, errors.New("get failed") + fakeClient.MockGet = func(ctx gocontext.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok { + return errors.New("get failed") + } + return fakeClient.Client.Get(ctx, key, obj, opts...) } - defer func() { s.FakeUserSignupClient.MockGet = nil }() ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") + err := application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") require.EqualError(t, err, "get failed: error retrieving usersignup: 123", err.Error()) }) s.T().Run("when client UPDATE call fails indefinitely should return error", func(t *testing.T) { - - // Cause the client UPDATE call to fail always - s.FakeUserSignupClient.MockUpdate = func(_ *toolchainv1alpha1.UserSignup) (*toolchainv1alpha1.UserSignup, error) { - return nil, errors.New("there was an error while updating your account - please wait a moment before trying again. If this error persists, please contact the Developer Sandbox team at devsandbox@redhat.com \"+\n\t\t\t\"for assistance: error while verifying phone code") + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) + fakeClient.MockUpdate = func(ctx gocontext.Context, obj client.Object, opts ...client.UpdateOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok { + return errors.New("there was an error while updating your account - please wait a moment before trying again. If this error persists, please contact the Developer Sandbox team at devsandbox@redhat.com \"+\n\t\t\t\"for assistance: error while verifying phone code") + } + return fakeClient.Client.Update(ctx, obj, opts...) } - defer func() { s.FakeUserSignupClient.MockUpdate = nil }() ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") + err := application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") require.EqualError(t, err, "there was an error while updating your account - please wait a moment before "+ "trying again. If this error persists, please contact the Developer Sandbox team at devsandbox@redhat.com "+ "for assistance: error while verifying phone code") }) s.T().Run("when client UPDATE call fails twice should return ok", func(t *testing.T) { + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) failCount := 0 - // Cause the client UPDATE call to fail just twice - s.FakeUserSignupClient.MockUpdate = func(userSignup *toolchainv1alpha1.UserSignup) (*toolchainv1alpha1.UserSignup, error) { - if failCount < 2 { + fakeClient.MockUpdate = func(ctx gocontext.Context, obj client.Object, opts ...client.UpdateOption) error { + if _, ok := obj.(*toolchainv1alpha1.UserSignup); ok && failCount < 2 { failCount++ - return nil, errors.New("update failed") + return errors.New("update failed") } - s.FakeUserSignupClient.MockUpdate = nil - return s.FakeUserSignupClient.Update(userSignup) + return fakeClient.Client.Update(ctx, obj, opts...) } - defer func() { s.FakeUserSignupClient.MockUpdate = nil }() ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") + err := application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") require.NoError(t, err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) - require.NotEmpty(t, userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) + require.NotEmpty(t, signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) buf := new(bytes.Buffer) _, err = buf.ReadFrom(reqBody) @@ -357,7 +351,7 @@ func (s *TestVerificationServiceSuite) TestInitVerificationClientFailure() { params, err := url.ParseQuery(reqValue) require.NoError(t, err) require.Equal(t, fmt.Sprintf("Developer Sandbox for Red Hat OpenShift: Your verification code is %s", - userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), + signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), params.Get("Body")) require.Equal(t, "CodeReady", params.Get("From")) require.Equal(t, "+1NUMBER", params.Get("To")) @@ -366,7 +360,6 @@ func (s *TestVerificationServiceSuite) TestInitVerificationClientFailure() { func (s *TestVerificationServiceSuite) TestInitVerificationPassesWhenMaxCountReachedAndTimestampElapsed() { // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() gock.New("https://api.twilio.com"). Reply(http.StatusNoContent). BodyString("") @@ -404,17 +397,17 @@ func (s *TestVerificationServiceSuite) TestInitVerificationPassesWhenMaxCountRea } states.SetVerificationRequired(userSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") + err := application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") require.NoError(s.T(), err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) require.NoError(s.T(), err) - require.NotEmpty(s.T(), userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) + require.NotEmpty(s.T(), signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) buf := new(bytes.Buffer) _, err = buf.ReadFrom(reqBody) @@ -424,17 +417,14 @@ func (s *TestVerificationServiceSuite) TestInitVerificationPassesWhenMaxCountRea params, err := url.ParseQuery(reqValue) require.NoError(s.T(), err) require.Equal(s.T(), fmt.Sprintf("Developer Sandbox for Red Hat OpenShift: Your verification code is %s", - userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), + signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), params.Get("Body")) require.Equal(s.T(), "CodeReady", params.Get("From")) require.Equal(s.T(), "+1NUMBER", params.Get("To")) - require.Equal(s.T(), "1", userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCounterAnnotationKey]) + require.Equal(s.T(), "1", signup.Annotations[toolchainv1alpha1.UserSignupVerificationCounterAnnotationKey]) } func (s *TestVerificationServiceSuite) TestInitVerificationFailsWhenCountContainsInvalidValue() { - // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() - defer gock.Off() // call override config to ensure the factory option takes effect s.OverrideApplicationDefault() @@ -462,18 +452,15 @@ func (s *TestVerificationServiceSuite) TestInitVerificationFailsWhenCountContain } states.SetVerificationRequired(userSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) + _, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") + err := application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") require.EqualError(s.T(), err, "daily limit exceeded: cannot generate new verification code") } func (s *TestVerificationServiceSuite) TestInitVerificationFailsDailyCounterExceeded() { // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() - gock.New("https://api.twilio.com"). Reply(http.StatusNoContent). BodyString("") @@ -505,19 +492,16 @@ func (s *TestVerificationServiceSuite) TestInitVerificationFailsDailyCounterExce } states.SetVerificationRequired(userSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(s.T(), err) + _, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") + err := application.VerificationService().InitVerification(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "+1NUMBER", "1") require.EqualError(s.T(), err, "daily limit exceeded: cannot generate new verification code", err.Error()) require.Empty(s.T(), userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) } func (s *TestVerificationServiceSuite) TestInitVerificationFailsWhenPhoneNumberInUse() { // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() - gock.New("https://api.twilio.com"). Reply(http.StatusNoContent). BodyString("") @@ -547,9 +531,6 @@ func (s *TestVerificationServiceSuite) TestInitVerificationFailsWhenPhoneNumberI } states.SetApprovedManually(alphaUserSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(alphaUserSignup) - require.NoError(s.T(), err) - bravoUserSignup := &toolchainv1alpha1.UserSignup{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ @@ -565,25 +546,23 @@ func (s *TestVerificationServiceSuite) TestInitVerificationFailsWhenPhoneNumberI } states.SetVerificationRequired(bravoUserSignup, true) - err = s.FakeUserSignupClient.Tracker.Add(bravoUserSignup) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), alphaUserSignup, bravoUserSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, bravoUserSignup.Name, bravoUserSignup.Spec.IdentityClaims.PreferredUsername, e164PhoneNumber, "1") + err := application.VerificationService().InitVerification(ctx, bravoUserSignup.Name, bravoUserSignup.Spec.IdentityClaims.PreferredUsername, e164PhoneNumber, "1") require.Error(s.T(), err) require.Equal(s.T(), "phone number already in use: cannot register using phone number: +19875551122", err.Error()) // Reload bravoUserSignup - bravoUserSignup, err = s.FakeUserSignupClient.Get(bravoUserSignup.Name) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(bravoUserSignup), signup) require.NoError(s.T(), err) - require.Empty(s.T(), bravoUserSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) + require.Empty(s.T(), signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) } func (s *TestVerificationServiceSuite) TestInitVerificationOKWhenPhoneNumberInUseByDeactivatedUserSignup() { // Setup gock to intercept calls made to the Twilio API - s.SetHTTPClientFactoryOption() - gock.New("https://api.twilio.com"). Reply(http.StatusNoContent). BodyString("") @@ -615,9 +594,6 @@ func (s *TestVerificationServiceSuite) TestInitVerificationOKWhenPhoneNumberInUs states.SetApprovedManually(alphaUserSignup, true) states.SetDeactivated(alphaUserSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(alphaUserSignup) - require.NoError(s.T(), err) - bravoUserSignup := &toolchainv1alpha1.UserSignup{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ @@ -633,19 +609,19 @@ func (s *TestVerificationServiceSuite) TestInitVerificationOKWhenPhoneNumberInUs } states.SetVerificationRequired(bravoUserSignup, true) - err = s.FakeUserSignupClient.Tracker.Add(bravoUserSignup) - require.NoError(s.T(), err) + fakeClient, application := testutil.PrepareInClusterAppWithOption(s.T(), httpClientFactoryOption(), alphaUserSignup, bravoUserSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().InitVerification(ctx, bravoUserSignup.Name, bravoUserSignup.Spec.IdentityClaims.PreferredUsername, e164PhoneNumber, "1") + err := application.VerificationService().InitVerification(ctx, bravoUserSignup.Name, bravoUserSignup.Spec.IdentityClaims.PreferredUsername, e164PhoneNumber, "1") require.NoError(s.T(), err) // Reload bravoUserSignup - bravoUserSignup, err = s.FakeUserSignupClient.Get(bravoUserSignup.Name) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(bravoUserSignup), signup) require.NoError(s.T(), err) // Just confirm that verification has been initialized by testing whether a verification code has been set - require.NotEmpty(s.T(), bravoUserSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) + require.NotEmpty(s.T(), signup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) } func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { @@ -676,17 +652,17 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { } states.SetVerificationRequired(userSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") + err := application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") require.NoError(t, err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) - require.False(t, states.VerificationRequired(userSignup)) + require.False(t, states.VerificationRequired(signup)) }) s.T().Run("verification ok for usersignup with username identifier", func(t *testing.T) { @@ -713,17 +689,17 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { } states.SetVerificationRequired(userSignup, true) - err := s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, "", "employee085", "654321") + err := application.VerificationService().VerifyPhoneCode(ctx, "", "employee085", "654321") require.NoError(t, err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) - require.False(t, states.VerificationRequired(userSignup)) + require.False(t, states.VerificationRequired(signup)) }) s.T().Run("when verification code is invalid", func(t *testing.T) { @@ -748,14 +724,10 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { }, } - err := s.FakeUserSignupClient.Delete(userSignup.Name, nil) - require.NoError(t, err) - - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + _, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") + err := application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") require.Error(t, err) e := &crterrors.Error{} require.ErrorAs(t, err, &e) @@ -785,13 +757,10 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { }, } - err := s.FakeUserSignupClient.Delete(userSignup.Name, nil) - require.NoError(t, err) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + _, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") + err := application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") e := &crterrors.Error{} require.ErrorAs(t, err, &e) require.Equal(t, "expired: verification code expired", e.Error()) @@ -820,13 +789,10 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { }, } - err := s.FakeUserSignupClient.Delete(userSignup.Name, nil) - require.NoError(t, err) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + _, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") + err := application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") require.EqualError(t, err, "too many verification attempts", err.Error()) }) @@ -852,19 +818,17 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { }, } - err := s.FakeUserSignupClient.Delete(userSignup.Name, nil) - require.NoError(t, err) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") + err := application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") require.EqualError(t, err, "too many verification attempts", err.Error()) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) - require.Equal(t, "3", userSignup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) + require.Equal(t, "3", signup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) }) s.T().Run("when verifications expiry is corrupt", func(t *testing.T) { @@ -889,13 +853,10 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { }, } - err := s.FakeUserSignupClient.Delete(userSignup.Name, nil) - require.NoError(t, err) - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + _, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") + err := application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") require.EqualError(t, err, "parsing time \"ABC\" as \"2006-01-02T15:04:05.000Z07:00\": cannot parse \"ABC\" as \"2006\": error parsing expiry timestamp", err.Error()) }) @@ -1003,29 +964,19 @@ func (s *TestVerificationServiceSuite) TestVerifyPhoneCode() { } states.SetVerificationRequired(userSignup, true) - _, err := s.FakeUserSignupClient.Get(userSignup.Name) - if err == nil { - // delete the usersignup, if exists, before adding the new one - err = s.FakeUserSignupClient.Delete(userSignup.Name, nil) - require.NoError(t, err) - } - - err = s.FakeUserSignupClient.Tracker.Add(userSignup) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - err = s.Application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") + err := application.VerificationService().VerifyPhoneCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "123456") // then + signup := &toolchainv1alpha1.UserSignup{} + require.NoError(s.T(), fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup)) if tc.expectedErr != "" { require.EqualError(t, err, tc.expectedErr) - _, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) } else { require.NoError(t, err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.False(t, states.VerificationRequired(userSignup)) + require.False(t, states.VerificationRequired(signup)) } }) } @@ -1047,36 +998,36 @@ func (s *TestVerificationServiceSuite) testVerifyActivationCode(targetCluster st // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithTargetCluster(targetCluster)) - err := s.setupFakeClients(userSignup, event) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) // then require.NoError(t, err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.False(t, states.VerificationRequired(userSignup)) - assert.Equal(t, targetCluster, userSignup.Spec.TargetCluster) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.False(t, states.VerificationRequired(signup)) + assert.Equal(t, targetCluster, signup.Spec.TargetCluster) }) s.T().Run("last user to signup", func(t *testing.T) { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithActivationCount(9), testsocialevent.WithTargetCluster(targetCluster)) // one seat left - err := s.setupFakeClients(userSignup, event) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) // then require.NoError(t, err) - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.False(t, states.VerificationRequired(userSignup)) - assert.Equal(t, targetCluster, userSignup.Spec.TargetCluster) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.False(t, states.VerificationRequired(signup)) + assert.Equal(t, targetCluster, signup.Spec.TargetCluster) }) s.T().Run("when too many attempts made", func(t *testing.T) { @@ -1085,18 +1036,18 @@ func (s *TestVerificationServiceSuite) testVerifyActivationCode(targetCluster st testusersignup.VerificationRequired(time.Second), // just signed up testusersignup.WithVerificationAttempts(cfg.Verification().AttemptsAllowed())) event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithTargetCluster(targetCluster)) - err := s.setupFakeClients(userSignup, event) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) // then require.EqualError(t, err, "too many verification attempts: 3") - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.True(t, states.VerificationRequired(userSignup)) // unchanged - assert.Empty(t, userSignup.Spec.TargetCluster) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.True(t, states.VerificationRequired(signup)) // unchanged + assert.Empty(t, signup.Spec.TargetCluster) }) s.T().Run("when invalid code", func(t *testing.T) { @@ -1104,18 +1055,18 @@ func (s *TestVerificationServiceSuite) testVerifyActivationCode(targetCluster st t.Run("first attempt", func(t *testing.T) { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up - err := s.setupFakeClients(userSignup) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "invalid") + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "invalid") // then require.EqualError(t, err, "invalid code: the provided code is invalid") - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.True(t, states.VerificationRequired(userSignup)) // unchanged - assert.Equal(t, "1", userSignup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.True(t, states.VerificationRequired(signup)) // unchanged + assert.Equal(t, "1", signup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented }) t.Run("second attempt", func(t *testing.T) { @@ -1123,18 +1074,18 @@ func (s *TestVerificationServiceSuite) testVerifyActivationCode(targetCluster st userSignup := testusersignup.NewUserSignup( testusersignup.VerificationRequired(time.Second), // just signed up testusersignup.WithVerificationAttempts(2)) // already tried twice before - err := s.setupFakeClients(userSignup) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "invalid") + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, "invalid") // then require.EqualError(t, err, "invalid code: the provided code is invalid") - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.True(t, states.VerificationRequired(userSignup)) // unchanged - assert.Equal(t, "3", userSignup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.True(t, states.VerificationRequired(signup)) // unchanged + assert.Equal(t, "3", signup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented }) }) @@ -1142,81 +1093,56 @@ func (s *TestVerificationServiceSuite) testVerifyActivationCode(targetCluster st // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithActivationCount(10), testsocialevent.WithTargetCluster(targetCluster)) // same as default `spec.MaxAttendees` - err := s.setupFakeClients(userSignup, event) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) // then require.EqualError(t, err, "invalid code: the event is full") - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.True(t, states.VerificationRequired(userSignup)) - assert.Equal(t, "1", userSignup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented - assert.Empty(t, userSignup.Spec.TargetCluster) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.True(t, states.VerificationRequired(signup)) + assert.Equal(t, "1", signup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented + assert.Empty(t, signup.Spec.TargetCluster) }) s.T().Run("when event not open yet", func(t *testing.T) { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithStartTime(time.Now().Add(time.Hour)), testsocialevent.WithTargetCluster(targetCluster)) // starting in 1hr - err := s.setupFakeClients(userSignup, event) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) // then require.EqualError(t, err, "invalid code: the provided code is invalid") - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.True(t, states.VerificationRequired(userSignup)) - assert.Equal(t, "1", userSignup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented - assert.Empty(t, userSignup.Spec.TargetCluster) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.True(t, states.VerificationRequired(signup)) + assert.Equal(t, "1", signup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented + assert.Empty(t, signup.Spec.TargetCluster) }) s.T().Run("when event already closed", func(t *testing.T) { // given userSignup := testusersignup.NewUserSignup(testusersignup.VerificationRequired(time.Second)) // just signed up event := testsocialevent.NewSocialEvent(commontest.HostOperatorNs, "event", testsocialevent.WithEndTime(time.Now().Add(-time.Hour)), testsocialevent.WithTargetCluster(targetCluster)) // ended 1hr ago - err := s.setupFakeClients(userSignup, event) - require.NoError(t, err) + fakeClient, application := testutil.PrepareInClusterApp(s.T(), userSignup, event) // when - err = s.Application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) + err := application.VerificationService().VerifyActivationCode(ctx, userSignup.Name, userSignup.Spec.IdentityClaims.PreferredUsername, event.Name) // then require.EqualError(t, err, "invalid code: the provided code is invalid") - userSignup, err = s.FakeUserSignupClient.Get(userSignup.Name) - require.NoError(t, err) - require.True(t, states.VerificationRequired(userSignup)) - assert.Equal(t, "1", userSignup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented - assert.Empty(t, userSignup.Spec.TargetCluster) + signup := &toolchainv1alpha1.UserSignup{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKeyFromObject(userSignup), signup) + require.NoError(s.T(), err) + require.True(t, states.VerificationRequired(signup)) + assert.Equal(t, "1", signup.Annotations[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey]) // incremented + assert.Empty(t, signup.Spec.TargetCluster) }) } - -func (s *TestVerificationServiceSuite) setupFakeClients(objects ...runtime.Object) error { - clientScheme := runtime.NewScheme() - if err := toolchainv1alpha1.SchemeBuilder.AddToScheme(clientScheme); err != nil { - return err - } - s.FakeUserSignupClient.Tracker = kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - s.FakeSocialEventClient.Tracker = kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - - for _, obj := range objects { - switch obj := obj.(type) { - case *toolchainv1alpha1.UserSignup: - if err := s.FakeUserSignupClient.Tracker.Add(obj); err != nil { - return err - } - case *toolchainv1alpha1.SocialEvent: - if err := s.FakeSocialEventClient.Tracker.Add(obj); err != nil { - return err - } - default: - return fmt.Errorf("unexpected type of object: %T", obj) - } - } - return nil -} diff --git a/test/fake/banneduser_client.go b/test/fake/banneduser_client.go deleted file mode 100644 index 65038cea..00000000 --- a/test/fake/banneduser_client.go +++ /dev/null @@ -1,84 +0,0 @@ -package fake - -import ( - "testing" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/toolchain-common/pkg/hash" - - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" -) - -type FakeBannedUserClient struct { // nolint:revive - Tracker kubetesting.ObjectTracker - Scheme *runtime.Scheme - namespace string - MockListByHashedLabel func(labelKey, labelValue string) (*crtapi.BannedUserList, error) -} - -func NewFakeBannedUserClient(t *testing.T, namespace string, initObjs ...runtime.Object) *FakeBannedUserClient { - clientScheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(clientScheme) - require.NoError(t, err, "Error adding to scheme") - crtapi.SchemeBuilder.Register(&crtapi.BannedUser{}, &crtapi.BannedUserList{}) - - tracker := kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - for _, obj := range initObjs { - err := tracker.Add(obj) - require.NoError(t, err, "failed to add object %v to fake banneduser client", obj) - } - return &FakeBannedUserClient{ - Tracker: tracker, - Scheme: clientScheme, - namespace: namespace, - } -} - -func (c *FakeBannedUserClient) ListByEmail(email string) (*crtapi.BannedUserList, error) { - return c.listByHashedLabel(crtapi.BannedUserEmailHashLabelKey, email) -} -func (c *FakeBannedUserClient) ListByPhoneNumberOrHash(phone string) (*crtapi.BannedUserList, error) { - return c.listByHashedLabel(crtapi.BannedUserPhoneNumberHashLabelKey, phone) -} - -func (c *FakeBannedUserClient) listByHashedLabel(labelKey, labelValue string) (*crtapi.BannedUserList, error) { - hash := hash.EncodeString(labelValue) - - if c.MockListByHashedLabel != nil { - return c.MockListByHashedLabel(labelKey, labelValue) - } - - obj := &crtapi.BannedUser{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - gvk, err := apiutil.GVKForObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.List(gvr, gvk, c.namespace) - if err != nil { - return nil, err - } - list := o.(*crtapi.BannedUserList) - - objs := []crtapi.BannedUser{} - - for _, bu := range list.Items { - if bu.Labels[labelKey] == hash { - objs = append(objs, bu) - } - } - - return &crtapi.BannedUserList{ - Items: objs, - }, - nil -} diff --git a/test/fake/fake.go b/test/fake/fake.go deleted file mode 100644 index f89024b4..00000000 --- a/test/fake/fake.go +++ /dev/null @@ -1,18 +0,0 @@ -package fake - -import ( - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" -) - -// getGVRFromObject returns the GroupVersionResource for the specified object and scheme -func getGVRFromObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionResource, error) { - gvk, err := apiutil.GVKForObject(obj, scheme) - if err != nil { - return schema.GroupVersionResource{}, err - } - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - return gvr, nil -} diff --git a/test/fake/masteruserrecord_client.go b/test/fake/masteruserrecord_client.go deleted file mode 100644 index 4220a439..00000000 --- a/test/fake/masteruserrecord_client.go +++ /dev/null @@ -1,117 +0,0 @@ -package fake - -import ( - "encoding/json" - "testing" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" -) - -type FakeMasterUserRecordClient struct { // nolint:revive - Tracker kubetesting.ObjectTracker - Scheme *runtime.Scheme - namespace string - MockGet func(string) (*crtapi.MasterUserRecord, error) - MockCreate func(*crtapi.MasterUserRecord) (*crtapi.MasterUserRecord, error) - MockUpdate func(*crtapi.MasterUserRecord) (*crtapi.MasterUserRecord, error) - MockDelete func(name string, options *metav1.DeleteOptions) error -} - -func NewFakeMasterUserRecordClient(t *testing.T, namespace string, initObjs ...runtime.Object) *FakeMasterUserRecordClient { - clientScheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(clientScheme) - require.NoError(t, err, "Error adding to scheme") - crtapi.SchemeBuilder.Register(&crtapi.MasterUserRecord{}, &crtapi.MasterUserRecordList{}) - - tracker := kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - for _, obj := range initObjs { - err := tracker.Add(obj) - require.NoError(t, err, "failed to add object %v to fake MUR client", obj) - } - return &FakeMasterUserRecordClient{ - Tracker: tracker, - Scheme: clientScheme, - namespace: namespace, - } -} - -func (c *FakeMasterUserRecordClient) Get(name string) (*crtapi.MasterUserRecord, error) { - if c.MockGet != nil { - return c.MockGet(name) - } - - obj := &crtapi.MasterUserRecord{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.Get(gvr, c.namespace, name) - if err != nil { - return nil, err - } - - j, err := json.Marshal(o) - if err != nil { - return nil, err - } - - decoder := scheme.Codecs.UniversalDecoder() - _, _, err = decoder.Decode(j, nil, obj) - if err != nil { - return nil, err - } - return obj, nil -} - -func (c *FakeMasterUserRecordClient) Create(obj *crtapi.MasterUserRecord) (*crtapi.MasterUserRecord, error) { - if c.MockCreate != nil { - return c.MockCreate(obj) - } - - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - err = c.Tracker.Create(gvr, obj, obj.GetNamespace()) - if err != nil { - return nil, err - } - - return obj, nil -} - -func (c *FakeMasterUserRecordClient) Update(obj *crtapi.MasterUserRecord) (*crtapi.MasterUserRecord, error) { - if c.MockUpdate != nil { - return c.MockUpdate(obj) - } - - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - err = c.Tracker.Update(gvr, obj, obj.GetNamespace()) - if err != nil { - return nil, err - } - return obj, nil -} - -func (c *FakeMasterUserRecordClient) Delete(name string, options *metav1.DeleteOptions) error { - if c.MockDelete != nil { - return c.MockDelete(name, options) - } - - gvr, err := getGVRFromObject(&crtapi.MasterUserRecord{}, c.Scheme) - if err != nil { - return err - } - return c.Tracker.Delete(gvr, c.namespace, name) -} diff --git a/test/fake/mockable_application.go b/test/fake/mockable_application.go index 7a82b7d6..d1ddf1d9 100644 --- a/test/fake/mockable_application.go +++ b/test/fake/mockable_application.go @@ -40,10 +40,6 @@ func (m *MockableApplication) VerificationService() service.VerificationService return m.serviceFactory.VerificationService() } -func (m *MockableApplication) MockVerificationService(svc service.VerificationService) { - m.mockVerificationService = svc -} - func (m *MockableApplication) MemberClusterService() service.MemberClusterService { if m.mockMemberClusterService != nil { return m.mockMemberClusterService @@ -51,10 +47,6 @@ func (m *MockableApplication) MemberClusterService() service.MemberClusterServic return m.serviceFactory.MemberClusterService() } -func (m *MockableApplication) MockMemberClusterService(svc service.MemberClusterService) { - m.mockMemberClusterService = svc -} - func (m *MockableApplication) InformerService() service.InformerService { if m.mockInformerService != nil { return m.mockInformerService diff --git a/test/fake/signup_client.go b/test/fake/signup_client.go deleted file mode 100644 index 47d3501d..00000000 --- a/test/fake/signup_client.go +++ /dev/null @@ -1,162 +0,0 @@ -package fake - -import ( - "encoding/json" - "testing" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/toolchain-common/pkg/hash" - "github.com/gofrs/uuid" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" -) - -type FakeUserSignupClient struct { // nolint:revive - Tracker kubetesting.ObjectTracker - Scheme *runtime.Scheme - namespace string - MockGet func(string) (*crtapi.UserSignup, error) - MockCreate func(*crtapi.UserSignup) (*crtapi.UserSignup, error) - MockUpdate func(*crtapi.UserSignup) (*crtapi.UserSignup, error) - MockDelete func(name string, options *metav1.DeleteOptions) error - MockListByHashedLabel func(labelKey, labelValue string) ([]*crtapi.UserSignup, error) -} - -func NewFakeUserSignupClient(t *testing.T, namespace string, initObjs ...runtime.Object) *FakeUserSignupClient { - clientScheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(clientScheme) - require.NoError(t, err, "Error adding to scheme") - crtapi.SchemeBuilder.Register(&crtapi.UserSignup{}, &crtapi.UserSignupList{}) - - tracker := kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - for _, obj := range initObjs { - err := tracker.Add(obj) - require.NoError(t, err, "failed to add object %v to fake usersignup client", obj) - } - return &FakeUserSignupClient{ - Tracker: tracker, - Scheme: clientScheme, - namespace: namespace, - } -} - -func (c *FakeUserSignupClient) Get(name string) (*crtapi.UserSignup, error) { - if c.MockGet != nil { - return c.MockGet(name) - } - - obj := &crtapi.UserSignup{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.Get(gvr, c.namespace, name) - if err != nil { - return nil, err - } - - j, err := json.Marshal(o) - if err != nil { - return nil, err - } - - decoder := scheme.Codecs.UniversalDecoder() - _, _, err = decoder.Decode(j, nil, obj) - if err != nil { - return nil, err - } - return obj, nil -} - -func (c *FakeUserSignupClient) Create(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) { - if obj != nil { - obj.ResourceVersion = uuid.Must(uuid.NewV4()).String() - } - if c.MockCreate != nil { - return c.MockCreate(obj) - } - - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - err = c.Tracker.Create(gvr, obj, obj.GetNamespace()) - if err != nil { - return nil, err - } - - return obj, nil -} - -func (c *FakeUserSignupClient) Update(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) { - if c.MockUpdate != nil { - return c.MockUpdate(obj) - } - - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - err = c.Tracker.Update(gvr, obj, obj.GetNamespace()) - if err != nil { - return nil, err - } - return obj, nil -} - -func (c *FakeUserSignupClient) Delete(name string, options *metav1.DeleteOptions) error { - if c.MockDelete != nil { - return c.MockDelete(name, options) - } - - gvr, err := getGVRFromObject(&crtapi.UserSignup{}, c.Scheme) - if err != nil { - return err - } - return c.Tracker.Delete(gvr, c.namespace, name) -} - -func (c *FakeUserSignupClient) ListActiveSignupsByPhoneNumberOrHash(phone string) ([]*crtapi.UserSignup, error) { - return c.listByHashedLabel(crtapi.UserSignupUserPhoneHashLabelKey, phone) -} - -func (c *FakeUserSignupClient) listByHashedLabel(labelKey, labelValue string) ([]*crtapi.UserSignup, error) { - hash := hash.EncodeString(labelValue) - - if c.MockListByHashedLabel != nil { - return c.MockListByHashedLabel(labelValue, labelKey) - } - - obj := &crtapi.UserSignup{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - gvk, err := apiutil.GVKForObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.List(gvr, gvk, c.namespace) - if err != nil { - return nil, err - } - list := o.(*crtapi.UserSignupList) - - objs := []*crtapi.UserSignup{} - - for i, bu := range list.Items { - if bu.Labels[labelKey] == hash { - objs = append(objs, &list.Items[i]) - } - } - - return objs, nil -} diff --git a/test/fake/socialevent_client.go b/test/fake/socialevent_client.go deleted file mode 100644 index 9af39b11..00000000 --- a/test/fake/socialevent_client.go +++ /dev/null @@ -1,75 +0,0 @@ -package fake - -import ( - "encoding/json" - "testing" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" -) - -type FakeSocialEventClient struct { // nolint:revive - Tracker kubetesting.ObjectTracker - Scheme *runtime.Scheme - namespace string - MockGet func(string) (*crtapi.SocialEvent, error) - MockCreate func(*crtapi.SocialEvent) (*crtapi.SocialEvent, error) - MockUpdate func(*crtapi.SocialEvent) (*crtapi.SocialEvent, error) - MockDelete func(name string, options *metav1.DeleteOptions) error - MockListByHashedLabel func(labelKey, labelValue string) (*crtapi.SocialEventList, error) -} - -var _ kubeclient.SocialEventInterface = &FakeSocialEventClient{} - -func NewFakeSocialEventClient(t *testing.T, namespace string, initObjs ...runtime.Object) *FakeSocialEventClient { - clientScheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(clientScheme) - require.NoError(t, err, "Error adding to scheme") - crtapi.SchemeBuilder.Register(&crtapi.SocialEvent{}, &crtapi.SocialEventList{}) - - tracker := kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - for _, obj := range initObjs { - err := tracker.Add(obj) - require.NoError(t, err, "failed to add object %v to fake socialevent client", obj) - } - return &FakeSocialEventClient{ - Tracker: tracker, - Scheme: clientScheme, - namespace: namespace, - } -} - -func (c *FakeSocialEventClient) Get(name string) (*crtapi.SocialEvent, error) { - if c.MockGet != nil { - return c.MockGet(name) - } - - obj := &crtapi.SocialEvent{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.Get(gvr, c.namespace, name) - if err != nil { - return nil, err - } - - j, err := json.Marshal(o) - if err != nil { - return nil, err - } - - decoder := scheme.Codecs.UniversalDecoder() - _, _, err = decoder.Decode(j, nil, obj) - if err != nil { - return nil, err - } - return obj, nil -} diff --git a/test/fake/space_client.go b/test/fake/space_client.go deleted file mode 100644 index 60fab247..00000000 --- a/test/fake/space_client.go +++ /dev/null @@ -1,71 +0,0 @@ -package fake - -import ( - "encoding/json" - "testing" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" - - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" -) - -type FakeSpaceClient struct { // nolint:revive - Tracker kubetesting.ObjectTracker - Scheme *runtime.Scheme - namespace string - MockGet func(name string) (*crtapi.Space, error) -} - -var _ kubeclient.SpaceInterface = &FakeSpaceClient{} - -func NewFakeSpaceClient(t *testing.T, namespace string, initObjs ...runtime.Object) *FakeSpaceClient { - clientScheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(clientScheme) - require.NoError(t, err, "Error adding to scheme") - crtapi.SchemeBuilder.Register(&crtapi.Space{}, &crtapi.SpaceList{}) - - tracker := kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - for _, obj := range initObjs { - err := tracker.Add(obj) - require.NoError(t, err, "failed to add object %v to fake spacebinding client", obj) - } - return &FakeSpaceClient{ - Tracker: tracker, - Scheme: clientScheme, - namespace: namespace, - } -} - -func (c *FakeSpaceClient) Get(name string) (*crtapi.Space, error) { - - if c.MockGet != nil { - return c.MockGet(name) - } - - obj := &crtapi.Space{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.Get(gvr, c.namespace, name) - if err != nil { - return nil, err - } - - j, err := json.Marshal(o) - if err != nil { - return nil, err - } - - decoder := scheme.Codecs.UniversalDecoder() - _, _, err = decoder.Decode(j, nil, obj) - if err != nil { - return nil, err - } - return obj, nil -} diff --git a/test/fake/spacebinding_client.go b/test/fake/spacebinding_client.go deleted file mode 100644 index f78f84ce..00000000 --- a/test/fake/spacebinding_client.go +++ /dev/null @@ -1,68 +0,0 @@ -package fake - -import ( - "testing" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" -) - -type FakeSpaceBindingClient struct { // nolint:revive - Tracker kubetesting.ObjectTracker - Scheme *runtime.Scheme - namespace string - MockList func(reqs ...labels.Requirement) ([]crtapi.SpaceBinding, error) -} - -var _ kubeclient.SpaceBindingInterface = &FakeSpaceBindingClient{} - -func NewFakeSpaceBindingClient(t *testing.T, namespace string, initObjs ...runtime.Object) *FakeSpaceBindingClient { - clientScheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(clientScheme) - require.NoError(t, err, "Error adding to scheme") - crtapi.SchemeBuilder.Register(&crtapi.SpaceBinding{}, &crtapi.SpaceBindingList{}) - - tracker := kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - for _, obj := range initObjs { - err := tracker.Add(obj) - require.NoError(t, err, "failed to add object %v to fake spacebinding client", obj) - } - return &FakeSpaceBindingClient{ - Tracker: tracker, - Scheme: clientScheme, - namespace: namespace, - } -} - -func (c *FakeSpaceBindingClient) ListSpaceBindings(reqs ...labels.Requirement) ([]crtapi.SpaceBinding, error) { - - if c.MockList != nil { - return c.MockList(reqs...) - } - - obj := &crtapi.SpaceBinding{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - gvk, err := apiutil.GVKForObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.List(gvr, gvk, c.namespace) - if err != nil { - return nil, err - } - list := o.(*crtapi.SpaceBindingList) - - return list.Items, nil -} diff --git a/test/fake/toolchainstatus_client.go b/test/fake/toolchainstatus_client.go deleted file mode 100644 index e857cce6..00000000 --- a/test/fake/toolchainstatus_client.go +++ /dev/null @@ -1,67 +0,0 @@ -package fake - -import ( - "encoding/json" - "testing" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - - "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - kubetesting "k8s.io/client-go/testing" -) - -type FakeToolchainStatusClient struct { // nolint:revive - Tracker kubetesting.ObjectTracker - Scheme *runtime.Scheme - namespace string - MockGet func() (*crtapi.ToolchainStatus, error) -} - -func NewFakeToolchainStatusClient(t *testing.T, namespace string, initObjs ...runtime.Object) *FakeToolchainStatusClient { - clientScheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(clientScheme) - require.NoError(t, err, "Error adding to scheme") - crtapi.SchemeBuilder.Register(&crtapi.ToolchainStatus{}, &crtapi.ToolchainStatusList{}) - - tracker := kubetesting.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder()) - for _, obj := range initObjs { - err := tracker.Add(obj) - require.NoError(t, err, "failed to add object %v to fake toolchainstatus client", obj) - } - return &FakeToolchainStatusClient{ - Tracker: tracker, - Scheme: clientScheme, - namespace: namespace, - } -} - -func (c *FakeToolchainStatusClient) Get() (*crtapi.ToolchainStatus, error) { - if c.MockGet != nil { - return c.MockGet() - } - - obj := &crtapi.ToolchainStatus{} - gvr, err := getGVRFromObject(obj, c.Scheme) - if err != nil { - return nil, err - } - - o, err := c.Tracker.Get(gvr, c.namespace, "toolchain-status") - if err != nil { - return nil, err - } - - j, err := json.Marshal(o) - if err != nil { - return nil, err - } - - decoder := scheme.Codecs.UniversalDecoder() - _, _, err = decoder.Decode(j, nil, obj) - if err != nil { - return nil, err - } - return obj, nil -} diff --git a/test/testsuite.go b/test/testsuite.go index 8907c2ce..9f6a35bb 100644 --- a/test/testsuite.go +++ b/test/testsuite.go @@ -2,15 +2,12 @@ package test import ( "context" - "os" + toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" "github.com/codeready-toolchain/registration-service/pkg/configuration" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "github.com/codeready-toolchain/registration-service/pkg/log" "github.com/codeready-toolchain/registration-service/test/fake" - - toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" commonconfig "github.com/codeready-toolchain/toolchain-common/pkg/configuration" "github.com/codeready-toolchain/toolchain-common/pkg/test" testconfig "github.com/codeready-toolchain/toolchain-common/pkg/test/config" @@ -20,23 +17,15 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" ) // UnitTestSuite is the base test suite for unit tests. type UnitTestSuite struct { suite.Suite - Application *fake.MockableApplication - ConfigClient *test.FakeClient - FakeUserSignupClient *fake.FakeUserSignupClient - FakeMasterUserRecordClient *fake.FakeMasterUserRecordClient - FakeBannedUserClient *fake.FakeBannedUserClient - FakeToolchainStatusClient *fake.FakeToolchainStatusClient - FakeSocialEventClient *fake.FakeSocialEventClient - FakeSpaceClient *fake.FakeSpaceClient - FakeSpaceBindingClient *fake.FakeSpaceBindingClient - factoryOptions []factory.Option + Application *fake.MockableApplication + ConfigClient *test.FakeClient + factoryOptions []factory.Option } // SetupSuite sets the suite up and sets testmode. @@ -54,33 +43,18 @@ func (s *UnitTestSuite) SetupTest() { func (s *UnitTestSuite) SetupDefaultApplication() { // initialize the toolchainconfig cache s.DefaultConfig() - s.FakeUserSignupClient = fake.NewFakeUserSignupClient(s.T(), configuration.Namespace()) - s.FakeMasterUserRecordClient = fake.NewFakeMasterUserRecordClient(s.T(), configuration.Namespace()) - s.FakeBannedUserClient = fake.NewFakeBannedUserClient(s.T(), configuration.Namespace()) - s.FakeToolchainStatusClient = fake.NewFakeToolchainStatusClient(s.T(), configuration.Namespace()) - s.FakeSocialEventClient = fake.NewFakeSocialEventClient(s.T(), configuration.Namespace()) - s.FakeSpaceClient = fake.NewFakeSpaceClient(s.T(), configuration.Namespace()) - s.FakeSpaceBindingClient = fake.NewFakeSpaceBindingClient(s.T(), configuration.Namespace()) - s.Application = fake.NewMockableApplication(s, s.factoryOptions...) + s.Application = fake.NewMockableApplication(nil, s.factoryOptions...) } func (s *UnitTestSuite) OverrideApplicationDefault(opts ...testconfig.ToolchainConfigOption) { s.SetConfig(opts...) - s.FakeUserSignupClient = fake.NewFakeUserSignupClient(s.T(), configuration.Namespace()) - s.FakeMasterUserRecordClient = fake.NewFakeMasterUserRecordClient(s.T(), configuration.Namespace()) - s.FakeBannedUserClient = fake.NewFakeBannedUserClient(s.T(), configuration.Namespace()) - s.FakeToolchainStatusClient = fake.NewFakeToolchainStatusClient(s.T(), configuration.Namespace()) - s.FakeSpaceBindingClient = fake.NewFakeSpaceBindingClient(s.T(), configuration.Namespace()) - s.Application = fake.NewMockableApplication(s, s.factoryOptions...) + s.Application = fake.NewMockableApplication(nil, s.factoryOptions...) } func (s *UnitTestSuite) SetConfig(opts ...testconfig.ToolchainConfigOption) configuration.RegistrationServiceConfig { - namespace, found := os.LookupEnv(commonconfig.WatchNamespaceEnvVar) - require.Truef(s.T(), found, "%s env var is not", commonconfig.WatchNamespaceEnvVar) - current := &toolchainv1alpha1.ToolchainConfig{} - err := s.ConfigClient.Get(context.TODO(), types.NamespacedName{Name: "config", Namespace: namespace}, current) + err := s.ConfigClient.Get(context.TODO(), types.NamespacedName{Name: "config", Namespace: test.HostOperatorNs}, current) if err == nil { err = s.ConfigClient.Delete(context.TODO(), current) @@ -127,71 +101,9 @@ func (s *UnitTestSuite) DefaultConfig() configuration.RegistrationServiceConfig return configuration.GetRegistrationServiceConfig() } -func (s *UnitTestSuite) WithFactoryOption(opt factory.Option) { - s.factoryOptions = append(s.factoryOptions, opt) -} - // TearDownSuite tears down the test suite. func (s *UnitTestSuite) TearDownSuite() { // summon the GC! commonconfig.ResetCache() s.Application = nil - s.FakeUserSignupClient = nil - s.FakeMasterUserRecordClient = nil - s.FakeBannedUserClient = nil - s.FakeToolchainStatusClient = nil - s.FakeSpaceClient = nil - s.FakeSpaceBindingClient = nil -} - -func (s *UnitTestSuite) V1Alpha1() kubeclient.V1Alpha1 { - return s -} - -func (s *UnitTestSuite) UserSignups() kubeclient.UserSignupInterface { - return s.FakeUserSignupClient -} - -func (s *UnitTestSuite) MasterUserRecords() kubeclient.MasterUserRecordInterface { - return s.FakeMasterUserRecordClient -} - -func (s *UnitTestSuite) BannedUsers() kubeclient.BannedUserInterface { - return s.FakeBannedUserClient -} - -func (s *UnitTestSuite) ToolchainStatuses() kubeclient.ToolchainStatusInterface { - return s.FakeToolchainStatusClient -} - -func (s *UnitTestSuite) SocialEvents() kubeclient.SocialEventInterface { - return s.FakeSocialEventClient -} - -func (s *UnitTestSuite) Spaces() kubeclient.SpaceInterface { - return s.FakeSpaceClient -} - -func (s *UnitTestSuite) SpaceBindings() kubeclient.SpaceBindingInterface { - return s.FakeSpaceBindingClient -} - -func (s *UnitTestSuite) GetMasterUserRecord(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - return s.MasterUserRecords().Get(name) -} - -func (s *UnitTestSuite) GetToolchainStatus() (*toolchainv1alpha1.ToolchainStatus, error) { - return s.ToolchainStatuses().Get() -} - -func (s *UnitTestSuite) GetUserSignup(name string) (*toolchainv1alpha1.UserSignup, error) { - return s.UserSignups().Get(name) -} - -func (s *UnitTestSuite) GetSpace(name string) (*toolchainv1alpha1.Space, error) { - return s.Spaces().Get(name) -} - -func (s *UnitTestSuite) ListSpaceBindings(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return s.SpaceBindings().ListSpaceBindings(reqs...) } diff --git a/test/util/application.go b/test/util/application.go new file mode 100644 index 00000000..2ffdf116 --- /dev/null +++ b/test/util/application.go @@ -0,0 +1,24 @@ +package util + +import ( + "testing" + + "github.com/codeready-toolchain/registration-service/pkg/application" + "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" + "github.com/codeready-toolchain/registration-service/pkg/server" + commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/runtime" +) + +func PrepareInClusterApp(t *testing.T, objects ...runtime.Object) (*commontest.FakeClient, application.Application) { + return PrepareInClusterAppWithOption(t, func(_ *factory.ServiceFactory) { + }, objects...) +} + +func PrepareInClusterAppWithOption(t *testing.T, option factory.Option, objects ...runtime.Object) (*commontest.FakeClient, application.Application) { + fakeClient := commontest.NewFakeClient(t, objects...) + app, err := server.NewInClusterApplication(fakeClient, commontest.HostOperatorNs, option) + require.NoError(t, err) + return fakeClient, app +} diff --git a/test/util/service_context.go b/test/util/service_context.go new file mode 100644 index 00000000..41135a61 --- /dev/null +++ b/test/util/service_context.go @@ -0,0 +1,23 @@ +package util + +import ( + "testing" + + "github.com/codeready-toolchain/registration-service/pkg/kubeclient" + "github.com/codeready-toolchain/registration-service/pkg/server" + "github.com/codeready-toolchain/registration-service/test/fake" + commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" + "github.com/stretchr/testify/require" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func NewMemberClusterServiceContext(t *testing.T, cl client.Client) fake.MemberClusterServiceContext { + crtClient, err := kubeclient.NewCRTRESTClient(cl, commontest.HostOperatorNs) + require.NoError(t, err) + application, err := server.NewInClusterApplication(cl, commontest.HostOperatorNs) + require.NoError(t, err) + return fake.MemberClusterServiceContext{ + CrtClient: crtClient, + Svcs: application, + } +} From d0b1f7d7cf17046cf299549223e6d6dd75ab6b6f Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Thu, 3 Oct 2024 10:06:46 +0200 Subject: [PATCH 12/13] drop newProxyWithClusterClient function and related unnecessary client creation (#472) --- pkg/proxy/proxy.go | 37 ------------------------------------- pkg/proxy/proxy_test.go | 6 +++--- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go index 08ded564..e9425456 100644 --- a/pkg/proxy/proxy.go +++ b/pkg/proxy/proxy.go @@ -32,13 +32,9 @@ import ( "github.com/labstack/echo/v4/middleware" glog "github.com/labstack/gommon/log" errs "github.com/pkg/errors" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/httpstream" "k8s.io/apiserver/pkg/util/wsstream" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -65,7 +61,6 @@ func authorizationEndpointTarget() string { type Proxy struct { app application.Application - cl client.Client tokenParser *auth.TokenParser spaceLister *handlers.SpaceLister metrics *metrics.ProxyMetrics @@ -73,14 +68,6 @@ type Proxy struct { } func NewProxy(app application.Application, proxyMetrics *metrics.ProxyMetrics, getMembersFunc commoncluster.GetMemberClustersFunc) (*Proxy, error) { - cl, err := newClusterClient() - if err != nil { - return nil, err - } - return newProxyWithClusterClient(app, cl, proxyMetrics, getMembersFunc) -} - -func newProxyWithClusterClient(app application.Application, cln client.Client, proxyMetrics *metrics.ProxyMetrics, getMembersFunc commoncluster.GetMemberClustersFunc) (*Proxy, error) { tokenParser, err := auth.DefaultTokenParser() if err != nil { return nil, err @@ -90,7 +77,6 @@ func newProxyWithClusterClient(app application.Application, cln client.Client, p spaceLister := handlers.NewSpaceLister(app, proxyMetrics) return &Proxy{ app: app, - cl: cln, tokenParser: tokenParser, spaceLister: spaceLister, metrics: proxyMetrics, @@ -780,29 +766,6 @@ func singleJoiningSlash(a, b string) string { return a + b } -func newClusterClient() (client.Client, error) { - scheme := runtime.NewScheme() - if err := v1.AddToScheme(scheme); err != nil { - return nil, err - } - if err := toolchainv1alpha1.AddToScheme(scheme); err != nil { - return nil, err - } - - k8sConfig, err := rest.InClusterConfig() - if err != nil { - return nil, err - } - - cl, err := client.New(k8sConfig, client.Options{ - Scheme: scheme, - }) - if err != nil { - return nil, errs.Wrap(err, "cannot create ToolchainCluster client") - } - return cl, nil -} - var ph = textproto.CanonicalMIMEHeaderKey("Sec-WebSocket-Protocol") func extractTokenFromWebsocketRequest(req *http.Request) (string, error) { diff --git a/pkg/proxy/proxy_test.go b/pkg/proxy/proxy_test.go index 52dcba0a..46d8fe13 100644 --- a/pkg/proxy/proxy_test.go +++ b/pkg/proxy/proxy_test.go @@ -109,7 +109,7 @@ func (s *TestProxySuite) TestProxy() { InformerServiceMock: inf, } proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) - p, err := newProxyWithClusterClient(fakeApp, nil, proxyMetrics, proxytest.NewGetMembersFunc(commontest.NewFakeClient(s.T()))) + p, err := NewProxy(fakeApp, proxyMetrics, proxytest.NewGetMembersFunc(commontest.NewFakeClient(s.T()))) require.NoError(s.T(), err) server := p.StartProxy(DefaultPort) @@ -135,8 +135,8 @@ func (s *TestProxySuite) TestProxy() { func (s *TestProxySuite) spinUpProxy(fakeApp *fake.ProxyFakeApp, port string) (*Proxy, *http.Server) { proxyMetrics := metrics.NewProxyMetrics(prometheus.NewRegistry()) - p, err := newProxyWithClusterClient( - fakeApp, nil, proxyMetrics, proxytest.NewGetMembersFunc(commontest.NewFakeClient(s.T()))) + p, err := NewProxy( + fakeApp, proxyMetrics, proxytest.NewGetMembersFunc(commontest.NewFakeClient(s.T()))) require.NoError(s.T(), err) server := p.StartProxy(port) From c11f3a834280d3fa418637c99ce0f4a01ca9c912 Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Thu, 3 Oct 2024 13:23:51 +0200 Subject: [PATCH 13/13] drop CRTClient abstraction (#473) --- cmd/main.go | 5 +- .../service/context/service_context.go | 6 +- .../service/factory/service_factory.go | 22 +-- pkg/kubeclient/banneduser.go | 51 ------- pkg/kubeclient/client.go | 138 ------------------ pkg/kubeclient/client_test.go | 28 ---- pkg/kubeclient/mur.go | 25 ---- pkg/kubeclient/signup.go | 108 -------------- pkg/kubeclient/socialevent.go | 25 ---- pkg/kubeclient/space.go | 25 ---- pkg/kubeclient/spacebinding.go | 29 ---- pkg/kubeclient/toolchainstatus.go | 26 ---- pkg/middleware/jwt_middleware_test.go | 2 +- pkg/middleware/promhttp_middleware_test.go | 2 +- pkg/namespaced/client.go | 22 +++ pkg/server/in_cluster_application.go | 16 +- pkg/server/server_test.go | 2 +- pkg/signup/service/resource_provider.go | 25 ---- pkg/signup/service/signup_service.go | 58 +++++--- pkg/signup/service/signup_service_test.go | 98 ++----------- .../service/verification_service.go | 9 +- .../service/verification_service_test.go | 1 + test/fake/mockable_application.go | 5 +- test/fake/proxy.go | 15 +- test/testsuite.go | 4 +- test/util/application.go | 4 +- test/util/service_context.go | 13 +- 27 files changed, 109 insertions(+), 655 deletions(-) delete mode 100644 pkg/kubeclient/banneduser.go delete mode 100644 pkg/kubeclient/client.go delete mode 100644 pkg/kubeclient/client_test.go delete mode 100644 pkg/kubeclient/mur.go delete mode 100644 pkg/kubeclient/signup.go delete mode 100644 pkg/kubeclient/socialevent.go delete mode 100644 pkg/kubeclient/space.go delete mode 100644 pkg/kubeclient/spacebinding.go delete mode 100644 pkg/kubeclient/toolchainstatus.go create mode 100644 pkg/namespaced/client.go diff --git a/cmd/main.go b/cmd/main.go index 534f163e..202273b5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -84,10 +84,7 @@ func main() { } } - app, err := server.NewInClusterApplication(cl, configuration.Namespace()) - if err != nil { - panic(err.Error()) - } + app := server.NewInClusterApplication(cl, configuration.Namespace()) // Initialize toolchain cluster cache service // let's cache the member clusters before we start the services, // this will speed up the first request diff --git a/pkg/application/service/context/service_context.go b/pkg/application/service/context/service_context.go index 3f47b5ed..cf1929c3 100644 --- a/pkg/application/service/context/service_context.go +++ b/pkg/application/service/context/service_context.go @@ -2,14 +2,12 @@ package context import ( "github.com/codeready-toolchain/registration-service/pkg/application/service" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" - "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/codeready-toolchain/registration-service/pkg/namespaced" ) type ServiceContextProducer func() ServiceContext type ServiceContext interface { - CRTClient() kubeclient.CRTClient - Client() client.Client + Client() namespaced.Client Services() service.Services } diff --git a/pkg/application/service/factory/service_factory.go b/pkg/application/service/factory/service_factory.go index ccf6947b..6860b9c1 100644 --- a/pkg/application/service/factory/service_factory.go +++ b/pkg/application/service/factory/service_factory.go @@ -7,42 +7,30 @@ import ( servicecontext "github.com/codeready-toolchain/registration-service/pkg/application/service/context" "github.com/codeready-toolchain/registration-service/pkg/configuration" informerservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "github.com/codeready-toolchain/registration-service/pkg/log" + "github.com/codeready-toolchain/registration-service/pkg/namespaced" clusterservice "github.com/codeready-toolchain/registration-service/pkg/proxy/service" signupservice "github.com/codeready-toolchain/registration-service/pkg/signup/service" verificationservice "github.com/codeready-toolchain/registration-service/pkg/verification/service" - "sigs.k8s.io/controller-runtime/pkg/client" ) type serviceContextImpl struct { - kubeClient kubeclient.CRTClient - client client.Client - services service.Services + client namespaced.Client + services service.Services } type ServiceContextOption = func(ctx *serviceContextImpl) -func CRTClientOption(kubeClient kubeclient.CRTClient) ServiceContextOption { - return func(ctx *serviceContextImpl) { - ctx.kubeClient = kubeClient - } -} - -func InformerOption(client client.Client) ServiceContextOption { +func NamespacedClientOption(client namespaced.Client) ServiceContextOption { return func(ctx *serviceContextImpl) { ctx.client = client } } -func (s *serviceContextImpl) Client() client.Client { +func (s *serviceContextImpl) Client() namespaced.Client { return s.client } -func (s *serviceContextImpl) CRTClient() kubeclient.CRTClient { - return s.kubeClient -} - func (s *serviceContextImpl) Services() service.Services { return s.services } diff --git a/pkg/kubeclient/banneduser.go b/pkg/kubeclient/banneduser.go deleted file mode 100644 index e34733c2..00000000 --- a/pkg/kubeclient/banneduser.go +++ /dev/null @@ -1,51 +0,0 @@ -package kubeclient - -import ( - "context" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/toolchain-common/pkg/hash" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type bannedUserClient struct { - crtClient -} - -type BannedUserInterface interface { - ListByEmail(email string) (*crtapi.BannedUserList, error) - ListByPhoneNumberOrHash(phoneNumberOrHash string) (*crtapi.BannedUserList, error) -} - -func (c *bannedUserClient) ListByEmail(email string) (*crtapi.BannedUserList, error) { - return c.listByLabelForHashedValue(crtapi.BannedUserEmailHashLabelKey, email) -} - -// ListByPhoneNumberOrHash will return a list of BannedUsers that have a phone number hash label value matching -// the provided value. If the value provided is an actual phone number, then the hash will be calculated and then -// used to query the BannedUsers, otherwise if the hash value has been provided, then that value will be used -// directly for the query. -func (c *bannedUserClient) ListByPhoneNumberOrHash(phoneNumberOrHash string) (*crtapi.BannedUserList, error) { - if md5Matcher.Match([]byte(phoneNumberOrHash)) { - return c.listByLabel(crtapi.BannedUserPhoneNumberHashLabelKey, phoneNumberOrHash) - } - - // Default to searching for a hash of the specified value - return c.listByLabelForHashedValue(crtapi.BannedUserPhoneNumberHashLabelKey, phoneNumberOrHash) -} - -// listByLabelForHashedValue returns a BannedUserList containing any BannedUser resources that have a label matching -// the hash of the specified value -func (c *bannedUserClient) listByLabelForHashedValue(labelKey, valueToHash string) (*crtapi.BannedUserList, error) { - return c.listByLabel(labelKey, hash.EncodeString(valueToHash)) -} - -// listByLabel returns a BannedUserList containing any BannedUser resources that have a label matching the specified label -func (c *bannedUserClient) listByLabel(labelKey, labelValue string) (*crtapi.BannedUserList, error) { - bannedUsers := &crtapi.BannedUserList{} - if err := c.client.List(context.TODO(), bannedUsers, client.InNamespace(c.ns), - client.MatchingLabels{labelKey: labelValue}); err != nil { - return nil, err - } - return bannedUsers, nil -} diff --git a/pkg/kubeclient/client.go b/pkg/kubeclient/client.go deleted file mode 100644 index eb6f345d..00000000 --- a/pkg/kubeclient/client.go +++ /dev/null @@ -1,138 +0,0 @@ -package kubeclient - -import ( - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "k8s.io/apimachinery/pkg/runtime" -) - -type CRTClient interface { - V1Alpha1() V1Alpha1 -} - -type V1Alpha1 interface { - UserSignups() UserSignupInterface - MasterUserRecords() MasterUserRecordInterface - BannedUsers() BannedUserInterface - ToolchainStatuses() ToolchainStatusInterface - SocialEvents() SocialEventInterface - Spaces() SpaceInterface - SpaceBindings() SpaceBindingInterface -} - -// NewCRTRESTClient creates a new REST client for managing Codeready Toolchain resources via the Kubernetes API -func NewCRTRESTClient(client client.Client, namespace string) (CRTClient, error) { - scheme := runtime.NewScheme() - err := crtapi.SchemeBuilder.AddToScheme(scheme) - if err != nil { - return nil, err - } - - crtRESTClient := &CRTRESTClient{ - Client: client, - NS: namespace, - Scheme: scheme, - } - - crtRESTClient.v1Alpha1 = &V1Alpha1REST{client: crtRESTClient} - return crtRESTClient, nil -} - -type CRTRESTClient struct { - Client client.Client - NS string - Scheme *runtime.Scheme - v1Alpha1 *V1Alpha1REST -} - -func (c *CRTRESTClient) V1Alpha1() V1Alpha1 { - return c.v1Alpha1 -} - -type V1Alpha1REST struct { - client *CRTRESTClient -} - -// UserSignups returns an interface which may be used to perform CRUD operations for UserSignup resources -func (c *V1Alpha1REST) UserSignups() UserSignupInterface { - return &userSignupClient{ - crtClient: crtClient{ - client: c.client.Client, - ns: c.client.NS, - scheme: c.client.Scheme, - }, - } -} - -// MasterUserRecords returns an interface which may be used to perform CRUD operations for MasterUserRecord resources -func (c *V1Alpha1REST) MasterUserRecords() MasterUserRecordInterface { - return &masterUserRecordClient{ - crtClient: crtClient{ - client: c.client.Client, - ns: c.client.NS, - scheme: c.client.Scheme, - }, - } -} - -// BannedUsers returns an interface which may be used to perform query operations on BannedUser resources -func (c *V1Alpha1REST) BannedUsers() BannedUserInterface { - return &bannedUserClient{ - crtClient: crtClient{ - client: c.client.Client, - ns: c.client.NS, - scheme: c.client.Scheme, - }, - } -} - -// ToolchainStatuses returns an interface which may be used to perform query operations on ToolchainStatus resources -func (c *V1Alpha1REST) ToolchainStatuses() ToolchainStatusInterface { - return &toolchainStatusClient{ - crtClient: crtClient{ - client: c.client.Client, - ns: c.client.NS, - scheme: c.client.Scheme, - }, - } -} - -// SocialEvents returns an interface which may be used to perform CRUD operations for SocialEvent resources -func (c *V1Alpha1REST) SocialEvents() SocialEventInterface { - return &socialeventClient{ - crtClient: crtClient{ - client: c.client.Client, - ns: c.client.NS, - scheme: c.client.Scheme, - }, - } -} - -// Spaces returns an interface which may be used to perform CRUD operations for Space resources -func (c *V1Alpha1REST) Spaces() SpaceInterface { - return &spaceClient{ - crtClient: crtClient{ - client: c.client.Client, - ns: c.client.NS, - scheme: c.client.Scheme, - }, - } -} - -// SpaceBindings returns an interface which may be used to perform CRUD operations for SpaceBinding resources -func (c *V1Alpha1REST) SpaceBindings() SpaceBindingInterface { - return &spaceBindingClient{ - crtClient: crtClient{ - client: c.client.Client, - ns: c.client.NS, - scheme: c.client.Scheme, - }, - } -} - -type crtClient struct { - client client.Client - ns string - scheme *runtime.Scheme -} diff --git a/pkg/kubeclient/client_test.go b/pkg/kubeclient/client_test.go deleted file mode 100644 index 8528e5e3..00000000 --- a/pkg/kubeclient/client_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package kubeclient_test - -import ( - "testing" - - "github.com/codeready-toolchain/toolchain-common/pkg/test" - "github.com/stretchr/testify/require" - - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" -) - -const ( - TestNamespace = "test-namespace-name" -) - -func TestNewClient(t *testing.T) { - // Try creating a new client with an empty config - client, err := kubeclient.NewCRTRESTClient(test.NewFakeClient(t), TestNamespace) - - // Check that there are no errors, and the clients are returned - require.NoError(t, err) - require.NotNil(t, client) - require.NotNil(t, client.V1Alpha1()) - require.NotNil(t, client.V1Alpha1().UserSignups()) - require.NotNil(t, client.V1Alpha1().MasterUserRecords()) - require.NotNil(t, client.V1Alpha1().BannedUsers()) - require.NotNil(t, client.V1Alpha1().ToolchainStatuses()) -} diff --git a/pkg/kubeclient/mur.go b/pkg/kubeclient/mur.go deleted file mode 100644 index 098b77af..00000000 --- a/pkg/kubeclient/mur.go +++ /dev/null @@ -1,25 +0,0 @@ -package kubeclient - -import ( - "context" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "k8s.io/apimachinery/pkg/types" -) - -type masterUserRecordClient struct { - crtClient -} - -type MasterUserRecordInterface interface { - Get(name string) (*crtapi.MasterUserRecord, error) -} - -// Get returns the MasterUserRecord with the specified name, or an error if something went wrong while attempting to retrieve it -func (c *masterUserRecordClient) Get(name string) (*crtapi.MasterUserRecord, error) { - result := &crtapi.MasterUserRecord{} - if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/kubeclient/signup.go b/pkg/kubeclient/signup.go deleted file mode 100644 index 069f5959..00000000 --- a/pkg/kubeclient/signup.go +++ /dev/null @@ -1,108 +0,0 @@ -package kubeclient - -import ( - "context" - "regexp" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/toolchain-common/pkg/hash" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var ( - md5Matcher = regexp.MustCompile("(?i)[a-f0-9]{32}$") -) - -type userSignupClient struct { - crtClient -} - -// UserSignupInterface is the interface for user signup. -type UserSignupInterface interface { - Get(name string) (*crtapi.UserSignup, error) - Create(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) - Update(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) - ListActiveSignupsByPhoneNumberOrHash(phoneNumberOrHash string) ([]*crtapi.UserSignup, error) -} - -// Get returns the UserSignup with the specified name, or an error if something went wrong while attempting to retrieve it -// If not found then NotFound error returned -func (c *userSignupClient) Get(name string) (*crtapi.UserSignup, error) { - result := &crtapi.UserSignup{} - if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { - return nil, err - } - return result, nil -} - -// Create creates a new UserSignup resource in the cluster, and returns the resulting UserSignup that was created, or -// an error if something went wrong -func (c *userSignupClient) Create(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) { - if err := c.client.Create(context.TODO(), obj); err != nil { - return nil, err - } - return obj, nil -} - -// Update will update an existing UserSignup resource in the cluster, returning an error if something went wrong -func (c *userSignupClient) Update(obj *crtapi.UserSignup) (*crtapi.UserSignup, error) { - err := c.client.Update(context.TODO(), obj) - if err != nil { - return nil, err - } - return obj, nil -} - -// ListActiveSignupsByPhoneNumberOrHash will return a list of non-deactivated UserSignups that have a phone number hash -// label value matching the provided value. If the value provided is an actual phone number, then the hash will be -// calculated and then used to query the UserSignups, otherwise if the hash value has been provided, then that value -// will be used directly for the query. -func (c *userSignupClient) ListActiveSignupsByPhoneNumberOrHash(phoneNumberOrHash string) ([]*crtapi.UserSignup, error) { - if md5Matcher.Match([]byte(phoneNumberOrHash)) { - return c.listActiveSignupsByLabel(crtapi.BannedUserPhoneNumberHashLabelKey, phoneNumberOrHash) - } - - // Default to searching for a hash of the specified value - return c.listActiveSignupsByLabelForHashedValue(crtapi.BannedUserPhoneNumberHashLabelKey, phoneNumberOrHash) -} - -// listActiveSignupsByLabelForHashedValue returns an array of UserSignups containing any non-deactivated UserSignup resources -// that have a label matching the md5 hash of the specified value -func (c *userSignupClient) listActiveSignupsByLabelForHashedValue(labelKey, valueToHash string) ([]*crtapi.UserSignup, error) { - return c.listActiveSignupsByLabel(labelKey, hash.EncodeString(valueToHash)) -} - -// listActiveSignupsByLabel returns an array of UserSignups containing any non-deactivated UserSignup resources that have a -// label matching the specified label -func (c *userSignupClient) listActiveSignupsByLabel(labelKey, labelValue string) ([]*crtapi.UserSignup, error) { - - // TODO add unit tests checking that the label selection works as expected. Right now, it's not possible to do that thanks to the great abstraction and multiple level of layers, mocks, and services. - selector := labels.NewSelector() - stateRequirement, err := labels.NewRequirement(crtapi.UserSignupStateLabelKey, selection.NotIn, []string{crtapi.UserSignupStateLabelValueDeactivated, crtapi.UserSignupStateLabelValueNotReady}) - if err != nil { - return nil, err - } - selector = selector.Add(*stateRequirement) - labelRequirement, err := labels.NewRequirement(labelKey, selection.Equals, []string{labelValue}) - if err != nil { - return nil, err - } - selector = selector.Add(*labelRequirement) - - userSignups := &crtapi.UserSignupList{} - err = c.client.List(context.TODO(), userSignups, client.InNamespace(c.ns), client.MatchingLabelsSelector{Selector: selector}) - if err != nil { - return nil, err - } - - result := make([]*crtapi.UserSignup, len(userSignups.Items)) - - for i := range userSignups.Items { - result[i] = &userSignups.Items[i] - } - - return result, err -} diff --git a/pkg/kubeclient/socialevent.go b/pkg/kubeclient/socialevent.go deleted file mode 100644 index 346a04f7..00000000 --- a/pkg/kubeclient/socialevent.go +++ /dev/null @@ -1,25 +0,0 @@ -package kubeclient - -import ( - "context" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "k8s.io/apimachinery/pkg/types" -) - -type socialeventClient struct { - crtClient -} - -type SocialEventInterface interface { - Get(name string) (*crtapi.SocialEvent, error) -} - -// Get returns the SocialEvent with the specified name, or an error if something went wrong while attempting to retrieve it -func (c *socialeventClient) Get(name string) (*crtapi.SocialEvent, error) { - result := &crtapi.SocialEvent{} - if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/kubeclient/space.go b/pkg/kubeclient/space.go deleted file mode 100644 index 79745a99..00000000 --- a/pkg/kubeclient/space.go +++ /dev/null @@ -1,25 +0,0 @@ -package kubeclient - -import ( - "context" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "k8s.io/apimachinery/pkg/types" -) - -type spaceClient struct { - crtClient -} - -type SpaceInterface interface { - Get(name string) (*crtapi.Space, error) -} - -// List returns the Spaces that match for the provided selector, or an error if something went wrong while attempting to retrieve it -func (c *spaceClient) Get(name string) (*crtapi.Space, error) { - result := &crtapi.Space{} - if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: name}, result); err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/kubeclient/spacebinding.go b/pkg/kubeclient/spacebinding.go deleted file mode 100644 index f32b60da..00000000 --- a/pkg/kubeclient/spacebinding.go +++ /dev/null @@ -1,29 +0,0 @@ -package kubeclient - -import ( - "context" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "k8s.io/apimachinery/pkg/labels" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -type spaceBindingClient struct { - crtClient -} - -type SpaceBindingInterface interface { - ListSpaceBindings(reqs ...labels.Requirement) ([]crtapi.SpaceBinding, error) -} - -// List returns the SpaceBindings that match for the provided selector, or an error if something went wrong while attempting to retrieve it -func (c *spaceBindingClient) ListSpaceBindings(reqs ...labels.Requirement) ([]crtapi.SpaceBinding, error) { - - selector := labels.NewSelector().Add(reqs...) - - result := &crtapi.SpaceBindingList{} - err := c.client.List(context.TODO(), result, client.InNamespace(c.ns), - client.MatchingLabelsSelector{Selector: selector}) - - return result.Items, err -} diff --git a/pkg/kubeclient/toolchainstatus.go b/pkg/kubeclient/toolchainstatus.go deleted file mode 100644 index 0c591899..00000000 --- a/pkg/kubeclient/toolchainstatus.go +++ /dev/null @@ -1,26 +0,0 @@ -package kubeclient - -import ( - "context" - - crtapi "github.com/codeready-toolchain/api/api/v1alpha1" - "k8s.io/apimachinery/pkg/types" -) - -type toolchainStatusClient struct { - crtClient -} - -type ToolchainStatusInterface interface { - Get() (*crtapi.ToolchainStatus, error) -} - -// Get returns the ToolchainStatus with the "toolchain-status" name, or an error if something went wrong while attempting to retrieve it -// If not found then NotFound error returned -func (c *toolchainStatusClient) Get() (*crtapi.ToolchainStatus, error) { - result := &crtapi.ToolchainStatus{} - if err := c.client.Get(context.TODO(), types.NamespacedName{Namespace: c.ns, Name: "toolchain-status"}, result); err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/middleware/jwt_middleware_test.go b/pkg/middleware/jwt_middleware_test.go index 15290bf8..98d6262c 100644 --- a/pkg/middleware/jwt_middleware_test.go +++ b/pkg/middleware/jwt_middleware_test.go @@ -75,7 +75,7 @@ func (s *TestAuthMiddlewareSuite) TestAuthMiddlewareService() { keysEndpointURL := tokengenerator.NewKeyServer().URL // create server - srv := server.New(fake.NewMockableApplication(nil)) + srv := server.New(fake.NewMockableApplication()) // set the key service url in the config s.SetConfig(testconfig.RegistrationService(). diff --git a/pkg/middleware/promhttp_middleware_test.go b/pkg/middleware/promhttp_middleware_test.go index f94b3813..fd716caa 100644 --- a/pkg/middleware/promhttp_middleware_test.go +++ b/pkg/middleware/promhttp_middleware_test.go @@ -33,7 +33,7 @@ func TestPromHTTPMiddlewareSuite(t *testing.T) { func (s *PromHTTPMiddlewareSuite) TestPromHTTPMiddleware() { // given tokengenerator := authsupport.NewTokenManager() - srv := server.New(fake.NewMockableApplication(nil)) + srv := server.New(fake.NewMockableApplication()) keysEndpointURL := tokengenerator.NewKeyServer().URL s.SetConfig(testconfig.RegistrationService(). Environment(configuration.UnitTestsEnvironment). diff --git a/pkg/namespaced/client.go b/pkg/namespaced/client.go new file mode 100644 index 00000000..659140fe --- /dev/null +++ b/pkg/namespaced/client.go @@ -0,0 +1,22 @@ +package namespaced + +import ( + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func NewClient(client client.Client, namespace string) Client { + return Client{Client: client, Namespace: namespace} +} + +type Client struct { + client.Client + Namespace string +} + +func (c Client) NamespacedName(name string) types.NamespacedName { + return types.NamespacedName{ + Namespace: c.Namespace, + Name: name, + } +} diff --git a/pkg/server/in_cluster_application.go b/pkg/server/in_cluster_application.go index 903a973d..60ba20c8 100644 --- a/pkg/server/in_cluster_application.go +++ b/pkg/server/in_cluster_application.go @@ -4,7 +4,7 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/application" "github.com/codeready-toolchain/registration-service/pkg/application/service" "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" + "github.com/codeready-toolchain/registration-service/pkg/namespaced" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -12,18 +12,12 @@ import ( // application type is intended to run inside a Kubernetes cluster, where it makes use of the rest.InClusterConfig() // function to determine which Kubernetes configuration to use to create the REST client that interacts with the // Kubernetes service endpoints. -func NewInClusterApplication(client client.Client, namespace string, options ...factory.Option) (application.Application, error) { - kubeClient, err := kubeclient.NewCRTRESTClient(client, namespace) - if err != nil { - return nil, err - } - +func NewInClusterApplication(client client.Client, namespace string, options ...factory.Option) application.Application { return &InClusterApplication{ serviceFactory: factory.NewServiceFactory(append(options, - factory.WithServiceContextOptions(factory.CRTClientOption(kubeClient), - factory.InformerOption(client), - ))...), - }, nil + factory.WithServiceContextOptions( + factory.NamespacedClientOption(namespaced.NewClient(client, namespace))))...), + } } type InClusterApplication struct { diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index 8ab5559e..dc12f33a 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -34,7 +34,7 @@ const ( func (s *TestServerSuite) TestServer() { // We're using the example config for the configuration here as the // specific config params do not matter for testing the routes setup. - srv := server.New(fake.NewMockableApplication(nil)) + srv := server.New(fake.NewMockableApplication()) fake.MockKeycloakCertsCall(s.T()) // Setting up the routes. diff --git a/pkg/signup/service/resource_provider.go b/pkg/signup/service/resource_provider.go index 21f12f75..f33963e7 100644 --- a/pkg/signup/service/resource_provider.go +++ b/pkg/signup/service/resource_provider.go @@ -2,7 +2,6 @@ package service import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "k8s.io/apimachinery/pkg/labels" ) @@ -13,27 +12,3 @@ type ResourceProvider interface { GetSpace(name string) (*toolchainv1alpha1.Space, error) ListSpaceBindings(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) } - -type CrtClientProvider struct { - Cl kubeclient.CRTClient -} - -func (p CrtClientProvider) GetMasterUserRecord(name string) (*toolchainv1alpha1.MasterUserRecord, error) { - return p.Cl.V1Alpha1().MasterUserRecords().Get(name) -} - -func (p CrtClientProvider) GetToolchainStatus() (*toolchainv1alpha1.ToolchainStatus, error) { - return p.Cl.V1Alpha1().ToolchainStatuses().Get() -} - -func (p CrtClientProvider) GetUserSignup(name string) (*toolchainv1alpha1.UserSignup, error) { - return p.Cl.V1Alpha1().UserSignups().Get(name) -} - -func (p CrtClientProvider) GetSpace(name string) (*toolchainv1alpha1.Space, error) { - return p.Cl.V1Alpha1().Spaces().Get(name) -} - -func (p CrtClientProvider) ListSpaceBindings(reqs ...labels.Requirement) ([]toolchainv1alpha1.SpaceBinding, error) { - return p.Cl.V1Alpha1().SpaceBindings().ListSpaceBindings(reqs...) -} diff --git a/pkg/signup/service/signup_service.go b/pkg/signup/service/signup_service.go index 98370c08..d2a4e249 100644 --- a/pkg/signup/service/signup_service.go +++ b/pkg/signup/service/signup_service.go @@ -1,6 +1,7 @@ package service import ( + gocontext "context" "fmt" "hash/crc32" "regexp" @@ -15,7 +16,9 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/configuration" "github.com/codeready-toolchain/registration-service/pkg/context" "github.com/codeready-toolchain/registration-service/pkg/errors" + infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" "github.com/codeready-toolchain/registration-service/pkg/log" + "github.com/codeready-toolchain/registration-service/pkg/namespaced" "github.com/codeready-toolchain/registration-service/pkg/signup" "github.com/codeready-toolchain/registration-service/pkg/verification/captcha" "github.com/codeready-toolchain/toolchain-common/pkg/condition" @@ -29,6 +32,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/selection" + "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -46,6 +50,7 @@ var annotationsToRetain = []string{ // ServiceImpl represents the implementation of the signup service. type ServiceImpl struct { // nolint:revive base.BaseService + namespaced.Client defaultProvider ResourceProvider CaptchaChecker captcha.Assessor } @@ -57,8 +62,9 @@ func NewSignupService(context servicecontext.ServiceContext, opts ...SignupServi s := &ServiceImpl{ BaseService: base.NewBaseService(context), - defaultProvider: CrtClientProvider{context.CRTClient()}, + defaultProvider: infservice.NewInformerService(context.Client().Client, context.Client().Namespace), CaptchaChecker: captcha.Helper{}, + Client: context.Client(), } for _, opt := range opts { @@ -90,8 +96,9 @@ func (s *ServiceImpl) newUserSignup(ctx *gin.Context) (*toolchainv1alpha1.UserSi emailHash := hash.EncodeString(userEmail) // Query BannedUsers to check the user has not been banned - bannedUsers, err := s.CRTClient().V1Alpha1().BannedUsers().ListByEmail(userEmail) - if err != nil { + bannedUsers := &toolchainv1alpha1.BannedUserList{} + if err := s.List(gocontext.TODO(), bannedUsers, client.InNamespace(s.Namespace), + client.MatchingLabels{toolchainv1alpha1.BannedUserEmailHashLabelKey: hash.EncodeString(userEmail)}); err != nil { return nil, err } @@ -285,13 +292,12 @@ func (s *ServiceImpl) Signup(ctx *gin.Context) (*toolchainv1alpha1.UserSignup, e encodedUserID := EncodeUserIdentifier(ctx.GetString(context.SubKey)) // Retrieve UserSignup resource from the host cluster - userSignup, err := s.CRTClient().V1Alpha1().UserSignups().Get(encodedUserID) - if err != nil { + userSignup := &toolchainv1alpha1.UserSignup{} + if err := s.Get(gocontext.TODO(), s.NamespacedName(encodedUserID), userSignup); err != nil { if apierrors.IsNotFound(err) { // The UserSignup could not be located by its encoded UserID, attempt to load it using its encoded PreferredUsername instead encodedUsername := EncodeUserIdentifier(ctx.GetString(context.UsernameKey)) - userSignup, err = s.CRTClient().V1Alpha1().UserSignups().Get(encodedUsername) - if err != nil { + if err := s.Get(gocontext.TODO(), s.NamespacedName(encodedUsername), userSignup); err != nil { if apierrors.IsNotFound(err) { // New Signup log.WithValues(map[string]interface{}{"encoded_user_id": encodedUserID}).Info(ctx, "user not found, creating a new one") @@ -323,7 +329,7 @@ func (s *ServiceImpl) createUserSignup(ctx *gin.Context) (*toolchainv1alpha1.Use return nil, err } - return s.CRTClient().V1Alpha1().UserSignups().Create(userSignup) + return userSignup, s.Create(gocontext.TODO(), userSignup) } // reactivateUserSignup reactivates the deactivated UserSignup resource with the specified username and userID @@ -349,7 +355,7 @@ func (s *ServiceImpl) reactivateUserSignup(ctx *gin.Context, existing *toolchain existing.Labels = newUserSignup.Labels existing.Spec = newUserSignup.Spec - return s.CRTClient().V1Alpha1().UserSignups().Update(existing) + return existing, s.Update(gocontext.TODO(), existing) } // GetSignup returns Signup resource which represents the corresponding K8s UserSignup @@ -589,33 +595,49 @@ func (s *ServiceImpl) DoGetUserSignupFromIdentifier(provider ResourceProvider, u // UpdateUserSignup is used to update the provided UserSignup resource, and returning the updated resource func (s *ServiceImpl) UpdateUserSignup(userSignup *toolchainv1alpha1.UserSignup) (*toolchainv1alpha1.UserSignup, error) { - userSignup, err := s.CRTClient().V1Alpha1().UserSignups().Update(userSignup) - if err != nil { + if err := s.Update(gocontext.TODO(), userSignup); err != nil { return nil, err } return userSignup, nil } +var ( + md5Matcher = regexp.MustCompile("(?i)[a-f0-9]{32}$") +) + // PhoneNumberAlreadyInUse checks if the phone number has been banned. If so, return -// an internal server error. If not, check if an active (non-deactivated) UserSignup with a different userID and username +// an internal server error. If not, check if an approved UserSignup with a different userID and username // and email address exists. If so, return an internal server error. Otherwise, return without error. // Either the actual phone number, or the md5 hash of the phone number may be provided here. func (s *ServiceImpl) PhoneNumberAlreadyInUse(userID, username, phoneNumberOrHash string) error { - bannedUserList, err := s.CRTClient().V1Alpha1().BannedUsers().ListByPhoneNumberOrHash(phoneNumberOrHash) - if err != nil { + labelValue := hash.EncodeString(phoneNumberOrHash) + if md5Matcher.Match([]byte(phoneNumberOrHash)) { + labelValue = phoneNumberOrHash + } + + bannedUserList := &toolchainv1alpha1.BannedUserList{} + if err := s.List(gocontext.TODO(), bannedUserList, client.InNamespace(s.Namespace), + client.MatchingLabels{toolchainv1alpha1.BannedUserPhoneNumberHashLabelKey: labelValue}); err != nil { return errors.NewInternalError(err, "failed listing banned users") } + if len(bannedUserList.Items) > 0 { return errors.NewForbiddenError("cannot re-register with phone number", "phone number already in use") } - userSignups, err := s.CRTClient().V1Alpha1().UserSignups().ListActiveSignupsByPhoneNumberOrHash(phoneNumberOrHash) - if err != nil { + labelSelector := client.MatchingLabels{ + toolchainv1alpha1.UserSignupStateLabelKey: toolchainv1alpha1.UserSignupStateLabelValueApproved, + toolchainv1alpha1.BannedUserPhoneNumberHashLabelKey: labelValue, + } + userSignups := &toolchainv1alpha1.UserSignupList{} + if err := s.List(gocontext.TODO(), userSignups, client.InNamespace(s.Namespace), labelSelector); err != nil { return errors.NewInternalError(err, "failed listing userSignups") } - for _, signup := range userSignups { - if signup.Spec.IdentityClaims.Sub != userID && signup.Spec.IdentityClaims.PreferredUsername != username && !states.Deactivated(signup) { // nolint:gosec + + for _, signup := range userSignups.Items { + userSignup := signup // drop with go 1.22 + if userSignup.Spec.IdentityClaims.Sub != userID && userSignup.Spec.IdentityClaims.PreferredUsername != username && !states.Deactivated(&userSignup) { return errors.NewForbiddenError("cannot re-register with phone number", "phone number already in use") } diff --git a/pkg/signup/service/signup_service_test.go b/pkg/signup/service/signup_service_test.go index a568cd28..7268ad1a 100644 --- a/pkg/signup/service/signup_service_test.go +++ b/pkg/signup/service/signup_service_test.go @@ -17,7 +17,6 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/context" errors2 "github.com/codeready-toolchain/registration-service/pkg/errors" infservice "github.com/codeready-toolchain/registration-service/pkg/informers/service" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" "github.com/codeready-toolchain/registration-service/pkg/signup/service" "github.com/codeready-toolchain/registration-service/pkg/util" "github.com/codeready-toolchain/registration-service/test" @@ -617,6 +616,7 @@ func (s *TestSignupServiceSuite) TestPhoneNumberAlreadyInUseUserSignup() { Labels: map[string]string{ toolchainv1alpha1.UserSignupUserEmailHashLabelKey: "a7b1b413c1cbddbcd19a51222ef8e20a", toolchainv1alpha1.UserSignupUserPhoneHashLabelKey: "fd276563a8232d16620da8ec85d0575f", + toolchainv1alpha1.UserSignupStateLabelKey: toolchainv1alpha1.UserSignupStateLabelValueApproved, }, }, } @@ -1432,28 +1432,14 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespace() { space := s.newSpace("dave") fakeClient := commontest.NewFakeClient(s.T(), space) - crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) - require.NoError(s.T(), err) - crtClientProvider := service.CrtClientProvider{Cl: crtClient} + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "dave", "dave") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "dave", "dave") // then assert.Equal(s.T(), "dave-dev", defaultUserNamespace) assert.Equal(s.T(), "member-123", targetCluster) - - s.T().Run("informer", func(t *testing.T) { - // given - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - - // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "dave", "dave") - - // then - assert.Equal(t, "dave-dev", defaultUserNamespace) - assert.Equal(s.T(), "member-123", targetCluster) - }) } // TestGetDefaultUserNamespaceFromFirstUnownedSpace tests that the default user namespace is returned even if the only accessible Space was not created as the home space. @@ -1471,28 +1457,14 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFromFirstUnownedSpac spaceCindingC := s.newSpaceBinding("userB", spaceC.Name) fakeClient := commontest.NewFakeClient(s.T(), space, spacebindingB, spaceC, spaceCindingC) - crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) - require.NoError(s.T(), err) - crtClientProvider := service.CrtClientProvider{Cl: crtClient} + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "", "userB") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "", "userB") // then assert.Equal(s.T(), "userA-dev", defaultUserNamespace) assert.Equal(s.T(), "member-123", targetCluster) - - s.T().Run("informer", func(t *testing.T) { - // given - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - - // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "", "userB") - - // then - assert.Equal(t, "userA-dev", defaultUserNamespace) - assert.Equal(s.T(), "member-123", targetCluster) - }) } // TestGetDefaultUserNamespaceMultiSpace tests that the home Space created for the user is prioritized when there are multiple spaces @@ -1510,29 +1482,15 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceMultiSpace() { spacebinding2 := s.newSpaceBinding("userB", space2.Name) fakeClient := commontest.NewFakeClient(s.T(), space1, space2, spacebinding1, spacebinding2) - crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) - require.NoError(s.T(), err) - crtClientProvider := service.CrtClientProvider{Cl: crtClient} + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when - // get default namespace for userB - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "userB", "userB") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "userB", "userB") // then assert.Equal(s.T(), "userB-dev", defaultUserNamespace) // space2 is prioritized over space1 because it was created by the userB assert.Equal(s.T(), "member-123", targetCluster) - s.T().Run("informer", func(t *testing.T) { - // given - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - - // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "userB", "userB") - - // then - assert.Equal(t, "userB-dev", defaultUserNamespace) - assert.Equal(s.T(), "member-123", targetCluster) - }) } func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpaceBinding() { @@ -1541,62 +1499,28 @@ func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoHomeSpaceNoSpa space := s.newSpace("dave") fakeClient := commontest.NewFakeClient(s.T(), space) - crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) - require.NoError(s.T(), err) - crtClientProvider := service.CrtClientProvider{Cl: crtClient} + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "", "dave") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "", "dave") // then assert.Empty(s.T(), defaultUserNamespace) assert.Empty(s.T(), targetCluster) - - s.T().Run("informer", func(t *testing.T) { - // given - fakeClient.MockList = func(ctx gocontext.Context, list client.ObjectList, opts ...client.ListOption) error { - if _, ok := list.(*toolchainv1alpha1.SpaceBindingList); ok { - return apierrors.NewInternalError(fmt.Errorf("something went wrong")) - } - return fakeClient.Client.List(ctx, list, opts...) - } - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - - // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "", "dave") - - // then - assert.Empty(t, defaultUserNamespace) - assert.Empty(s.T(), targetCluster) - }) } func (s *TestSignupServiceSuite) TestGetDefaultUserNamespaceFailNoSpace() { // given s.ServiceConfiguration(true, "", 5) fakeClient := commontest.NewFakeClient(s.T()) - crtClient, err := kubeclient.NewCRTRESTClient(fakeClient, commontest.HostOperatorNs) - require.NoError(s.T(), err) - crtClientProvider := service.CrtClientProvider{Cl: crtClient} + inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(crtClientProvider, "dave", "dave") + targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "dave", "dave") // then assert.Empty(s.T(), defaultUserNamespace) assert.Empty(s.T(), targetCluster) - - s.T().Run("informer", func(t *testing.T) { - // given - inf := infservice.NewInformerService(fakeClient, commontest.HostOperatorNs) - - // when - targetCluster, defaultUserNamespace := service.GetDefaultUserTarget(inf, "dave", "dave") - - // then - assert.Empty(t, defaultUserNamespace) - assert.Empty(s.T(), targetCluster) - }) } func (s *TestSignupServiceSuite) TestGetUserSignup() { diff --git a/pkg/verification/service/verification_service.go b/pkg/verification/service/verification_service.go index 84bb1952..7fdd3919 100644 --- a/pkg/verification/service/verification_service.go +++ b/pkg/verification/service/verification_service.go @@ -1,6 +1,7 @@ package service import ( + gocontext "context" "crypto/rand" "errors" "fmt" @@ -8,8 +9,8 @@ import ( "strconv" "time" + "github.com/codeready-toolchain/registration-service/pkg/namespaced" signuppkg "github.com/codeready-toolchain/registration-service/pkg/signup" - "github.com/codeready-toolchain/registration-service/pkg/verification/sender" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" @@ -37,6 +38,7 @@ const ( // ServiceImpl represents the implementation of the verification service. type ServiceImpl struct { // nolint:revive base.BaseService + namespaced.Client HTTPClient *http.Client NotificationService sender.NotificationSender } @@ -47,6 +49,7 @@ type VerificationServiceOption func(svc *ServiceImpl) func NewVerificationService(context servicecontext.ServiceContext, opts ...VerificationServiceOption) service.VerificationService { s := &ServiceImpl{ BaseService: base.NewBaseService(context), + Client: context.Client(), } for _, opt := range opts { @@ -444,8 +447,8 @@ func (s *ServiceImpl) VerifyActivationCode(ctx *gin.Context, userID, username, c annotationValues[toolchainv1alpha1.UserVerificationAttemptsAnnotationKey] = strconv.Itoa(attemptsMade) // look-up the SocialEvent - event, err := s.CRTClient().V1Alpha1().SocialEvents().Get(code) - if err != nil { + event := &toolchainv1alpha1.SocialEvent{} + if err := s.Get(gocontext.TODO(), s.NamespacedName(code), event); err != nil { if apierrors.IsNotFound(err) { // a SocialEvent was not found for the provided code return crterrors.NewForbiddenError("invalid code", "the provided code is invalid") diff --git a/pkg/verification/service/verification_service_test.go b/pkg/verification/service/verification_service_test.go index 65bd524f..ad4486c2 100644 --- a/pkg/verification/service/verification_service_test.go +++ b/pkg/verification/service/verification_service_test.go @@ -521,6 +521,7 @@ func (s *TestVerificationServiceSuite) TestInitVerificationFailsWhenPhoneNumberI Namespace: configuration.Namespace(), Labels: map[string]string{ toolchainv1alpha1.UserSignupUserPhoneHashLabelKey: phoneHash, + toolchainv1alpha1.UserSignupStateLabelKey: toolchainv1alpha1.UserSignupStateLabelValueApproved, }, }, Spec: toolchainv1alpha1.UserSignupSpec{ diff --git a/test/fake/mockable_application.go b/test/fake/mockable_application.go index d1ddf1d9..62d94fd1 100644 --- a/test/fake/mockable_application.go +++ b/test/fake/mockable_application.go @@ -3,12 +3,9 @@ package fake import ( "github.com/codeready-toolchain/registration-service/pkg/application/service" "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" ) -func NewMockableApplication(crtClient kubeclient.CRTClient, - options ...factory.Option) *MockableApplication { - options = append(options, factory.WithServiceContextOptions(factory.CRTClientOption(crtClient))) +func NewMockableApplication(options ...factory.Option) *MockableApplication { return &MockableApplication{ serviceFactory: factory.NewServiceFactory(options...), } diff --git a/test/fake/proxy.go b/test/fake/proxy.go index c3ebacbc..8853f4e9 100644 --- a/test/fake/proxy.go +++ b/test/fake/proxy.go @@ -3,11 +3,10 @@ package fake import ( toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" "github.com/codeready-toolchain/registration-service/pkg/application/service" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" + "github.com/codeready-toolchain/registration-service/pkg/namespaced" "github.com/codeready-toolchain/registration-service/pkg/proxy/access" "github.com/codeready-toolchain/registration-service/pkg/signup" "github.com/gin-gonic/gin" - "sigs.k8s.io/controller-runtime/pkg/client" ) // This whole service abstraction is such a huge pain. We have to get rid of it!!! @@ -126,16 +125,12 @@ func (m *SignupService) PhoneNumberAlreadyInUse(_, _, _ string) error { } type MemberClusterServiceContext struct { - CrtClient kubeclient.CRTClient - Svcs service.Services + NamespacedClient namespaced.Client + Svcs service.Services } -func (sc MemberClusterServiceContext) CRTClient() kubeclient.CRTClient { - return sc.CrtClient -} - -func (sc MemberClusterServiceContext) Client() client.Client { - panic("shouldn't need informer in mock member cluster service") +func (sc MemberClusterServiceContext) Client() namespaced.Client { + return sc.NamespacedClient } func (sc MemberClusterServiceContext) Services() service.Services { diff --git a/test/testsuite.go b/test/testsuite.go index 9f6a35bb..30d85691 100644 --- a/test/testsuite.go +++ b/test/testsuite.go @@ -43,12 +43,12 @@ func (s *UnitTestSuite) SetupTest() { func (s *UnitTestSuite) SetupDefaultApplication() { // initialize the toolchainconfig cache s.DefaultConfig() - s.Application = fake.NewMockableApplication(nil, s.factoryOptions...) + s.Application = fake.NewMockableApplication(s.factoryOptions...) } func (s *UnitTestSuite) OverrideApplicationDefault(opts ...testconfig.ToolchainConfigOption) { s.SetConfig(opts...) - s.Application = fake.NewMockableApplication(nil, s.factoryOptions...) + s.Application = fake.NewMockableApplication(s.factoryOptions...) } func (s *UnitTestSuite) SetConfig(opts ...testconfig.ToolchainConfigOption) configuration.RegistrationServiceConfig { diff --git a/test/util/application.go b/test/util/application.go index 2ffdf116..54cfed82 100644 --- a/test/util/application.go +++ b/test/util/application.go @@ -7,7 +7,6 @@ import ( "github.com/codeready-toolchain/registration-service/pkg/application/service/factory" "github.com/codeready-toolchain/registration-service/pkg/server" commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" - "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/runtime" ) @@ -18,7 +17,6 @@ func PrepareInClusterApp(t *testing.T, objects ...runtime.Object) (*commontest.F func PrepareInClusterAppWithOption(t *testing.T, option factory.Option, objects ...runtime.Object) (*commontest.FakeClient, application.Application) { fakeClient := commontest.NewFakeClient(t, objects...) - app, err := server.NewInClusterApplication(fakeClient, commontest.HostOperatorNs, option) - require.NoError(t, err) + app := server.NewInClusterApplication(fakeClient, commontest.HostOperatorNs, option) return fakeClient, app } diff --git a/test/util/service_context.go b/test/util/service_context.go index 41135a61..7847c4f8 100644 --- a/test/util/service_context.go +++ b/test/util/service_context.go @@ -3,21 +3,16 @@ package util import ( "testing" - "github.com/codeready-toolchain/registration-service/pkg/kubeclient" + "github.com/codeready-toolchain/registration-service/pkg/namespaced" "github.com/codeready-toolchain/registration-service/pkg/server" "github.com/codeready-toolchain/registration-service/test/fake" commontest "github.com/codeready-toolchain/toolchain-common/pkg/test" - "github.com/stretchr/testify/require" "sigs.k8s.io/controller-runtime/pkg/client" ) -func NewMemberClusterServiceContext(t *testing.T, cl client.Client) fake.MemberClusterServiceContext { - crtClient, err := kubeclient.NewCRTRESTClient(cl, commontest.HostOperatorNs) - require.NoError(t, err) - application, err := server.NewInClusterApplication(cl, commontest.HostOperatorNs) - require.NoError(t, err) +func NewMemberClusterServiceContext(_ *testing.T, cl client.Client) fake.MemberClusterServiceContext { return fake.MemberClusterServiceContext{ - CrtClient: crtClient, - Svcs: application, + NamespacedClient: namespaced.NewClient(cl, commontest.HostOperatorNs), + Svcs: server.NewInClusterApplication(cl, commontest.HostOperatorNs), } }