mirror of
https://github.com/jangraefen/hcloud-pricing-exporter
synced 2024-11-10 05:54:15 +00:00
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:
parent
3600616dda
commit
7ae251751f
12 changed files with 522 additions and 80 deletions
164
.github/workflows/build.yaml
vendored
164
.github/workflows/build.yaml
vendored
|
@ -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
|
||||
|
|
|
@ -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
22
e2e/e2e_suite_test.go
Normal 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")
|
||||
}
|
47
e2e/fetcher_floatingip_test.go
Normal file
47
e2e/fetcher_floatingip_test.go
Normal 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))
|
||||
})
|
||||
})
|
||||
})
|
52
e2e/fetcher_loadbalancer_test.go
Normal file
52
e2e/fetcher_loadbalancer_test.go
Normal 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))
|
||||
})
|
||||
})
|
||||
})
|
70
e2e/fetcher_primaryip_test.go
Normal file
70
e2e/fetcher_primaryip_test.go
Normal 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))
|
||||
})
|
||||
})
|
||||
})
|
99
e2e/fetcher_server_test.go
Normal file
99
e2e/fetcher_server_test.go
Normal 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))
|
||||
})
|
||||
})
|
||||
})
|
49
e2e/fetcher_volume_test.go
Normal file
49
e2e/fetcher_volume_test.go
Normal 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
54
e2e/utils_test.go
Normal 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))
|
||||
}
|
|
@ -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
13
go.mod
|
@ -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
28
go.sum
|
@ -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=
|
||||
|
|
Loading…
Reference in a new issue