chore: Add test suite draft for most of the fetchers (#42)

* Add test suite draft for most of the fetchers
* Make the tests passing
* Suppress code duplication warning
* Add tests to actions
* Add hcloud token to test action
* Move test files to own folder
* Rename tests to e2e tests
* Fix wrong type guard
This commit is contained in:
Jan Gräfen 2022-12-29 00:56:37 +01:00 committed by GitHub
parent 3600616dda
commit 7ae251751f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 522 additions and 80 deletions

View file

@ -1,70 +1,94 @@
name: Build
on:
push:
branches: [ main ]
paths-ignore:
- README.md
- LICENSE
- .gitignore
- .editorconfig
- .chartreleaser.yaml
- .github/workflows/*-helm.yaml
- helm/**
- version.yaml
pull_request:
branches: [ main ]
paths-ignore:
- README.md
- LICENSE
- .gitignore
- .editorconfig
- .chartreleaser.yaml
- .github/workflows/*-helm.yaml
- helm/**
- version.yaml
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ^1.19
- name: Checkout code
uses: actions/checkout@v3
- name: Get dependencies
run: |
export GO111MODULE=on
go get -v -t -d ./...
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.48
build:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ^1.19
- name: Checkout code
uses: actions/checkout@v3
- name: Get dependencies
run: |
export GO111MODULE=on
go get -v -t -d ./...
- name: Build
run: |
export GO111MODULE=on
go mod download
GOOS=linux GOARCH=amd64 go build -o bin/hcloud-pricing-exporter-linux-amd64 main.go
GOOS=linux GOARCH=arm64 go build -o bin/hcloud-pricing-exporter-linux-arm64 main.go
GOOS=windows GOARCH=amd64 go build -o bin/hcloud-pricing-exporter-windows-amd64.exe main.go
- name: Upload Artifacts
uses: actions/upload-artifact@master
with:
name: binaries
path: bin/
name: Build
on:
push:
branches: [main]
paths-ignore:
- README.md
- LICENSE
- .gitignore
- .editorconfig
- .chartreleaser.yaml
- .github/workflows/*-helm.yaml
- helm/**
- version.yaml
pull_request:
branches: [main]
paths-ignore:
- README.md
- LICENSE
- .gitignore
- .editorconfig
- .chartreleaser.yaml
- .github/workflows/*-helm.yaml
- helm/**
- version.yaml
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ^1.19
- name: Checkout code
uses: actions/checkout@v3
- name: Get dependencies
run: |
export GO111MODULE=on
go get -v -t -d ./...
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.48
build:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ^1.19
- name: Checkout code
uses: actions/checkout@v3
- name: Get dependencies
run: |
export GO111MODULE=on
go get -v -t -d ./...
- name: Build
run: |
export GO111MODULE=on
go mod download
GOOS=linux GOARCH=amd64 go build -o bin/hcloud-pricing-exporter-linux-amd64 main.go
GOOS=linux GOARCH=arm64 go build -o bin/hcloud-pricing-exporter-linux-arm64 main.go
GOOS=windows GOARCH=amd64 go build -o bin/hcloud-pricing-exporter-windows-amd64.exe main.go
- name: Upload Artifacts
uses: actions/upload-artifact@master
with:
name: binaries
path: bin/
test:
runs-on: ubuntu-latest
# if: github.ref == 'refs/heads/main'
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ^1.19
- name: Checkout code
uses: actions/checkout@v3
- name: Get dependencies
run: |
export GO111MODULE=on
go get -v -t -d ./...
- name: Run tests
env:
HCLOUD_API_TOKEN: ${{ secrets.HCLOUD_API_TOKEN }}
run: go test -v -race -covermode=atomic "-coverprofile=coverprofile.out" ./...
- name: Report coverage
uses: codecov/codecov-action@v3
with:
file: coverprofile.out
fail_ci_if_error: true

View file

@ -48,6 +48,8 @@ helm upgrade --install hcloud-pricing-exporter hcloud-pricing-exporter/hcloud-pr
- `hcloud_pricing_floatingip_hourly{name, location}` _(Estimated based on the monthly price)_
- `hcloud_pricing_floatingip_monthly{name, location}`
- `hcloud_pricing_primaryip_hourly{name, location}` _(Estimated based on the monthly price)_
- `hcloud_pricing_primaryip_monthly{name, location}`
- `hcloud_pricing_loadbalancer_hourly{name, location, type}`
- `hcloud_pricing_loadbalancer_monthly{name, location, type}`
- `hcloud_pricing_server_hourly{name, location, type}`

22
e2e/e2e_suite_test.go Normal file
View file

@ -0,0 +1,22 @@
package e2e_test
import (
"testing"
"github.com/hetznercloud/hcloud-go/hcloud"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var (
testClient = hcloud.NewClient(hcloud.WithToken(hcloudAPITokenFromENV()))
testLabels = map[string]string{
"test": "github.com_jangraefen_hcloud-pricing-exporter",
"suite": "e2e_suite_test",
}
)
func TestFetcher(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "E2E Suite")
}

View file

@ -0,0 +1,47 @@
package e2e_test
import (
"context"
"github.com/hetznercloud/hcloud-go/hcloud"
"github.com/jangraefen/hcloud-pricing-exporter/fetcher"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/prometheus/client_golang/prometheus/testutil"
)
var _ = Describe("For floating IPs", Ordered, Label("floatingips"), func() {
sut := fetcher.NewFloatingIP(&fetcher.PriceProvider{Client: testClient})
BeforeAll(func(ctx context.Context) {
location, _, err := testClient.Location.GetByName(ctx, "fsn1")
Expect(err).NotTo(HaveOccurred())
res, _, err := testClient.FloatingIP.Create(ctx, hcloud.FloatingIPCreateOpts{
Name: hcloud.String("test-floatingip"),
Labels: testLabels,
HomeLocation: location,
Type: hcloud.FloatingIPTypeIPv6,
})
Expect(err).ShouldNot(HaveOccurred())
DeferCleanup(testClient.FloatingIP.Delete, res.FloatingIP)
waitUntilActionSucceeds(ctx, res.Action)
})
When("getting prices", func() {
It("should fetch them", func() {
Expect(sut.Run(testClient)).To(Succeed())
})
It("should get prices for correct values", func() {
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-floatingip", "fsn1"))).Should(BeNumerically(">", 0.0))
Expect(testutil.ToFloat64(sut.GetMonthly().WithLabelValues("test-floatingip", "fsn1"))).Should(BeNumerically(">", 0.0))
})
It("should get zero for incorrect values", func() {
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("invalid-name", "fsn1"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-floatingip", "nbg1"))).Should(BeNumerically("==", 0))
})
})
})

View file

@ -0,0 +1,52 @@
package e2e_test
import (
"context"
"github.com/hetznercloud/hcloud-go/hcloud"
"github.com/jangraefen/hcloud-pricing-exporter/fetcher"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/prometheus/client_golang/prometheus/testutil"
)
var _ = Describe("For loadbalancers", Ordered, Label("loadbalancers"), func() {
sut := fetcher.NewLoadbalancer(&fetcher.PriceProvider{Client: testClient})
BeforeAll(func(ctx context.Context) {
location, _, err := testClient.Location.GetByName(ctx, "fsn1")
Expect(err).NotTo(HaveOccurred())
lbType, _, err := testClient.LoadBalancerType.GetByName(ctx, "lb11")
Expect(err).NotTo(HaveOccurred())
res, _, err := testClient.LoadBalancer.Create(ctx, hcloud.LoadBalancerCreateOpts{
Name: "test-loadbalancer",
Labels: testLabels,
Location: location,
LoadBalancerType: lbType,
})
Expect(err).ShouldNot(HaveOccurred())
DeferCleanup(testClient.LoadBalancer.Delete, res.LoadBalancer)
waitUntilActionSucceeds(ctx, res.Action)
})
//nolint:dupl
When("getting prices", func() {
It("should fetch them", func() {
Expect(sut.Run(testClient)).To(Succeed())
})
It("should get prices for correct values", func() {
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-loadbalancer", "fsn1", "lb11"))).Should(BeNumerically(">", 0.0))
Expect(testutil.ToFloat64(sut.GetMonthly().WithLabelValues("test-loadbalancer", "fsn1", "lb11"))).Should(BeNumerically(">", 0.0))
})
It("should get zero for incorrect values", func() {
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("invalid-name", "fsn1", "lb11"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-loadbalancer", "nbg1", "lb11"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-loadbalancer", "fsn1", "lb21"))).Should(BeNumerically("==", 0))
})
})
})

View file

@ -0,0 +1,70 @@
package e2e_test
import (
"context"
"github.com/hetznercloud/hcloud-go/hcloud"
"github.com/jangraefen/hcloud-pricing-exporter/fetcher"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/prometheus/client_golang/prometheus/testutil"
)
var _ = Describe("For primary IPs", Pending, Ordered, Label("primaryips"), func() {
sut := fetcher.NewPrimaryIP(&fetcher.PriceProvider{Client: testClient})
BeforeAll(func(ctx context.Context) {
By("Creating a IPv4 address")
resv4, _, err := testClient.PrimaryIP.Create(ctx, hcloud.PrimaryIPCreateOpts{
Name: "test-primaryipv4",
Labels: testLabels,
Datacenter: "fsn1-dc14",
Type: hcloud.PrimaryIPTypeIPv4,
AssigneeType: "server",
})
Expect(err).ShouldNot(HaveOccurred())
DeferCleanup(testClient.PrimaryIP.Delete, resv4.PrimaryIP)
waitUntilActionSucceeds(ctx, resv4.Action)
By("Creating a IPv6 address")
resv6, _, err := testClient.PrimaryIP.Create(ctx, hcloud.PrimaryIPCreateOpts{
Name: "test-primaryipv6",
Labels: testLabels,
Datacenter: "fsn1-dc14",
Type: hcloud.PrimaryIPTypeIPv6,
AssigneeType: "server",
})
Expect(err).ShouldNot(HaveOccurred())
DeferCleanup(testClient.PrimaryIP.Delete, resv6.PrimaryIP)
waitUntilActionSucceeds(ctx, resv6.Action)
})
When("getting prices", func() {
It("should fetch them", func() {
By("Running the price collection")
Expect(sut.Run(testClient)).To(Succeed())
})
It("should get prices for correct values for v4", func() {
By("Checking IPv4 prices")
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-primaryipv4", "fsn1"))).Should(BeNumerically(">", 0.0))
Expect(testutil.ToFloat64(sut.GetMonthly().WithLabelValues("test-primaryipv4", "fsn1"))).Should(BeNumerically(">", 0.0))
})
It("should get prices for correct values for v6", func() {
By("Checking IPv6 prices")
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-primaryipv6", "fsn1"))).Should(BeNumerically("==", 0.0))
Expect(testutil.ToFloat64(sut.GetMonthly().WithLabelValues("test-primaryipv6", "fsn1"))).Should(BeNumerically("==", 0.0))
})
It("should get zero for incorrect values", func() {
By("Checking IPv4 prices")
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("invalid-name", "fsn1"))).Should(BeNumerically("==", 0))
By("Checking IPv6 prices")
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-primaryip", "nbg1"))).Should(BeNumerically("==", 0))
})
})
})

View file

@ -0,0 +1,99 @@
package e2e_test
import (
"context"
"time"
"github.com/hetznercloud/hcloud-go/hcloud"
"github.com/jangraefen/hcloud-pricing-exporter/fetcher"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/prometheus/client_golang/prometheus/testutil"
)
var _ = Describe("For servers", Ordered, Label("servers"), func() {
sutServer := fetcher.NewServer(&fetcher.PriceProvider{Client: testClient})
sutBackup := fetcher.NewServerBackup(&fetcher.PriceProvider{Client: testClient})
BeforeAll(func(ctx context.Context) {
location, _, err := testClient.Location.GetByName(ctx, "fsn1")
Expect(err).NotTo(HaveOccurred())
serverType, _, err := testClient.ServerType.GetByName(ctx, "cx11")
Expect(err).NotTo(HaveOccurred())
image, _, err := testClient.Image.GetByName(ctx, "ubuntu-22.04")
Expect(err).NotTo(HaveOccurred())
sshKey, _, err := testClient.SSHKey.Create(ctx, hcloud.SSHKeyCreateOpts{
Name: "test-key",
Labels: testLabels,
PublicKey: generatePublicKey(),
})
Expect(err).ShouldNot(HaveOccurred())
DeferCleanup(testClient.SSHKey.Delete, sshKey)
By("Setting up a server")
res, _, err := testClient.Server.Create(ctx, hcloud.ServerCreateOpts{
Name: "test-server",
Labels: testLabels,
Location: location,
ServerType: serverType,
Image: image,
SSHKeys: []*hcloud.SSHKey{sshKey},
PublicNet: &hcloud.ServerCreatePublicNet{EnableIPv4: false, EnableIPv6: true},
})
Expect(err).ShouldNot(HaveOccurred())
DeferCleanup(testClient.Server.Delete, res.Server)
waitUntilActionSucceeds(ctx, res.Action)
By("Enabling backups for the server")
Eventually(func() (hcloud.ServerStatus, error) {
server, _, serverErr := testClient.Server.GetByID(ctx, res.Server.ID)
if serverErr != nil {
return hcloud.ServerStatusOff, err
}
return server.Status, nil
}).
Within(1 * time.Minute).
ProbeEvery(5 * time.Second).
Should(Equal(hcloud.ServerStatusRunning))
action, _, err := testClient.Server.EnableBackup(ctx, res.Server, "")
Expect(err).ShouldNot(HaveOccurred())
waitUntilActionSucceeds(ctx, action)
})
When("getting prices", func() {
It("should fetch them", func() {
By("Running the price collection")
Expect(sutServer.Run(testClient)).To(Succeed())
Expect(sutBackup.Run(testClient)).To(Succeed())
})
It("should get prices for correct values", func() {
By("Checking server prices")
Expect(testutil.ToFloat64(sutServer.GetHourly().WithLabelValues("test-server", "fsn1", "cx11"))).Should(BeNumerically(">", 0.0))
Expect(testutil.ToFloat64(sutServer.GetMonthly().WithLabelValues("test-server", "fsn1", "cx11"))).Should(BeNumerically(">", 0.0))
By("Checking server backup prices")
Expect(testutil.ToFloat64(sutBackup.GetHourly().WithLabelValues("test-server", "fsn1", "cx11"))).Should(BeNumerically(">", 0.0))
Expect(testutil.ToFloat64(sutBackup.GetMonthly().WithLabelValues("test-server", "fsn1", "cx11"))).Should(BeNumerically(">", 0.0))
})
It("should get zero for incorrect values", func() {
By("Checking server prices")
Expect(testutil.ToFloat64(sutServer.GetHourly().WithLabelValues("invalid-name", "fsn1", "cx11"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sutServer.GetHourly().WithLabelValues("test-server", "nbg1", "cx11"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sutServer.GetHourly().WithLabelValues("test-server", "fsn1", "cx21"))).Should(BeNumerically("==", 0))
By("Checking server backup prices")
Expect(testutil.ToFloat64(sutBackup.GetHourly().WithLabelValues("invalid-name", "fsn1", "cx11"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sutBackup.GetHourly().WithLabelValues("test-server", "nbg1", "cx11"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sutBackup.GetHourly().WithLabelValues("test-server", "fsn1", "cx21"))).Should(BeNumerically("==", 0))
})
})
})

View file

@ -0,0 +1,49 @@
package e2e_test
import (
"context"
"github.com/hetznercloud/hcloud-go/hcloud"
"github.com/jangraefen/hcloud-pricing-exporter/fetcher"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/prometheus/client_golang/prometheus/testutil"
)
var _ = Describe("For volumes", Ordered, Label("volumes"), func() {
sut := fetcher.NewVolume(&fetcher.PriceProvider{Client: testClient})
BeforeAll(func(ctx context.Context) {
location, _, err := testClient.Location.GetByName(ctx, "fsn1")
Expect(err).NotTo(HaveOccurred())
res, _, err := testClient.Volume.Create(ctx, hcloud.VolumeCreateOpts{
Name: ("test-volume"),
Labels: testLabels,
Location: location,
Size: 10,
})
Expect(err).ShouldNot(HaveOccurred())
DeferCleanup(testClient.Volume.Delete, res.Volume)
waitUntilActionSucceeds(ctx, res.Action)
})
//nolint:dupl
When("getting prices", func() {
It("should fetch them", func() {
Expect(sut.Run(testClient)).To(Succeed())
})
It("should get prices for correct values", func() {
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-volume", "fsn1", "10"))).Should(BeNumerically(">", 0.0))
Expect(testutil.ToFloat64(sut.GetMonthly().WithLabelValues("test-volume", "fsn1", "10"))).Should(BeNumerically(">", 0.0))
})
It("should get zero for incorrect values", func() {
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("invalid-name", "fsn1", "10"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-volume", "nbg1", "10"))).Should(BeNumerically("==", 0))
Expect(testutil.ToFloat64(sut.GetHourly().WithLabelValues("test-volume", "fsn1", "99"))).Should(BeNumerically("==", 0))
})
})
})

54
e2e/utils_test.go Normal file
View file

@ -0,0 +1,54 @@
package e2e_test
import (
"context"
"crypto/ed25519"
"crypto/rand"
"fmt"
"os"
"time"
. "github.com/onsi/gomega"
"golang.org/x/crypto/ssh"
"github.com/hetznercloud/hcloud-go/hcloud"
)
func hcloudAPITokenFromENV() string {
if token, ok := os.LookupEnv("HCLOUD_API_TOKEN"); ok {
return token
}
panic(fmt.Errorf("environment variable HCLOUD_API_TOKEN not set, but required"))
}
func waitUntilActionSucceeds(ctx context.Context, actionToTrack *hcloud.Action) {
if actionToTrack != nil {
Eventually(func() (hcloud.ActionStatus, error) {
action, _, err := testClient.Action.GetByID(ctx, actionToTrack.ID)
if err != nil {
return hcloud.ActionStatusError, err
}
return action.Status, nil
}).
WithOffset(1).
Within(1 * time.Minute).
ProbeEvery(5 * time.Second).
Should(Equal(hcloud.ActionStatusSuccess))
}
}
func generatePublicKey() string {
public, _, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
sshKey, err := ssh.NewPublicKey(public)
if err != nil {
panic(err)
}
return string(ssh.MarshalAuthorizedKey(sshKey))
}

View file

@ -6,7 +6,7 @@ import (
"github.com/hetznercloud/hcloud-go/hcloud"
)
var _ Fetcher = &server{}
var _ Fetcher = &serverBackup{}
// NewServerBackup creates a new fetcher that will collect pricing information on server backups.
func NewServerBackup(pricing *PriceProvider) Fetcher {

13
go.mod
View file

@ -5,19 +5,26 @@ go 1.19
require (
github.com/hetznercloud/hcloud-go v1.38.0
github.com/jtaczanowski/go-scheduler v0.1.0
github.com/onsi/ginkgo/v2 v2.6.1
github.com/onsi/gomega v1.24.2
github.com/prometheus/client_golang v1.14.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/crypto v0.4.0
golang.org/x/net v0.4.0 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/text v0.5.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

28
go.sum
View file

@ -69,6 +69,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
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 v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@ -110,7 +112,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/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 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.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=
@ -144,8 +147,10 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
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/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@ -156,6 +161,10 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q=
github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE=
github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk=
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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -211,6 +220,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
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=
@ -271,8 +282,9 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
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=
@ -327,18 +339,20 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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=
@ -466,6 +480,7 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -474,7 +489,8 @@ 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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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=