Skip to content

Commit a72b0f1

Browse files
committed
refactor: more robust E2E tests
Added a new test case for the COSIGN_REPOSITORY variable and made the e2e tests more robust by properly handling timeouts, which weren't working half the time. Signed-off-by: Bruno Bressi <[email protected]>
1 parent 9f57e0e commit a72b0f1

File tree

11 files changed

+355
-145
lines changed

11 files changed

+355
-145
lines changed

.golangci.yaml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
linters-settings:
2+
dupl:
3+
threshold: 100
4+
funlen:
5+
lines: -1 # the number of lines (code + empty lines) is not a right metric and leads to code without empty line or one-liner.
6+
statements: 50
7+
goconst:
8+
min-len: 2
9+
min-occurrences: 3
10+
gocritic:
11+
enabled-tags:
12+
- diagnostic
13+
- experimental
14+
- opinionated
15+
- performance
16+
- style
17+
disabled-checks:
18+
- dupImport # https://github.com/go-critic/go-critic/issues/845
19+
- ifElseChain
20+
- octalLiteral
21+
- whyNoLint
22+
gocyclo:
23+
min-complexity: 15
24+
gofmt:
25+
rewrite-rules:
26+
- pattern: 'interface{}'
27+
replacement: 'any'
28+
goimports:
29+
local-prefixes: github.com/golangci/golangci-lint
30+
gomnd:
31+
# don't include the "operation" and "assign"
32+
checks:
33+
- argument
34+
- case
35+
- condition
36+
- return
37+
ignored-numbers:
38+
- '0'
39+
- '1'
40+
- '2'
41+
- '3'
42+
ignored-functions:
43+
- strings.SplitN
44+
45+
govet:
46+
check-shadowing: true
47+
settings:
48+
printf:
49+
funcs:
50+
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
51+
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
52+
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
53+
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
54+
lll:
55+
line-length: 140
56+
misspell:
57+
locale: US
58+
nolintlint:
59+
allow-unused: false # report any unused nolint directives
60+
require-explanation: false # don't require an explanation for nolint directives
61+
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
62+
revive:
63+
rules:
64+
- name: unexported-return
65+
disabled: true
66+
- name: unused-parameter
67+
68+
linters:
69+
disable-all: true
70+
enable:
71+
- bodyclose
72+
- dogsled
73+
- dupl
74+
- errcheck
75+
- exportloopref
76+
- funlen
77+
- gocheckcompilerdirectives
78+
- gochecknoinits
79+
- goconst
80+
- gocritic
81+
- gocyclo
82+
- gofmt
83+
- goimports
84+
- gomnd
85+
- goprintffuncname
86+
- gosec
87+
- gosimple
88+
- govet
89+
- ineffassign
90+
- misspell
91+
- nakedret
92+
- noctx
93+
- nolintlint
94+
- revive
95+
- staticcheck
96+
- typecheck
97+
- unconvert
98+
- unparam
99+
- unused
100+
- whitespace
101+
102+
run:
103+
timeout: 5m
104+
skip-files:
105+
- .*_test\.go

.pre-commit-config.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
repos:
2+
- repo: local
3+
hooks:
4+
- id: go-test
5+
name: go-unit-tests
6+
entry: make test-unit
7+
language: system
8+
types: [go]
9+
- repo: https://github.com/tekwizely/pre-commit-golang
10+
rev: v1.0.0-rc.1
11+
hooks:
12+
- id: go-mod-tidy-repo
13+
- id: go-vet-repo-mod
14+
- id: go-fumpt-repo
15+
args: [ -l, -w ]
16+
- id: golangci-lint-repo-mod
17+
args: [ --config, .golangci.yaml, --, --fix ]

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ e2e-keys:
3737

3838
e2e-images:
3939
@echo "Checking for cosign.key..."
40-
@test -f cosign.key || (echo "cosign.key not found. Run 'make generate-key' to generate one." && exit 1)
40+
@test -f cosign.key || (echo "cosign.key not found. Run 'make e2e-keys' to generate the pairs needed for the tests." && exit 1)
4141
@echo "Building test image..."
4242
@docker build -t k3d-registry.localhost:5000/cosignwebhook:dev .
4343
@echo "Pushing test image..."

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ targets. To run the tests the following is required:
136136

137137
To run the E2E tests, the following steps are required (in order):
138138

139+
- create a k3d local cluster for the tests and a local iamge registry (`make e2e-cluster`)
139140
- signing keys are generated (`make e2e-keys`)
140141
- a new `cosignwebhook` image is build and signed with a temp key (`make e2e-images`)
141142
- the image is pushed to a local registry & deployed to the test cluster (`make e2e-deploy`)

main.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import (
55
"crypto/tls"
66
"flag"
77
"fmt"
8+
"github.com/gookit/slog"
89
"net/http"
910
"os"
1011
"os/signal"
1112
"syscall"
1213

1314
"github.com/eumel8/cosignwebhook/webhook"
14-
log "github.com/gookit/slog"
1515

1616
"github.com/prometheus/client_golang/prometheus/promhttp"
1717
)
@@ -34,26 +34,26 @@ func main() {
3434
// set log level
3535
switch *logLevel {
3636
case "fatal":
37-
log.SetLogLevel(log.FatalLevel)
37+
slog.SetLogLevel(slog.FatalLevel)
3838
case "trace":
39-
log.SetLogLevel(log.TraceLevel)
39+
slog.SetLogLevel(slog.TraceLevel)
4040
case "debug":
41-
log.SetLogLevel(log.DebugLevel)
41+
slog.SetLogLevel(slog.DebugLevel)
4242
case "error":
43-
log.SetLogLevel(log.ErrorLevel)
43+
slog.SetLogLevel(slog.ErrorLevel)
4444
case "warn":
45-
log.SetLogLevel(log.WarnLevel)
45+
slog.SetLogLevel(slog.WarnLevel)
4646
case "info":
47-
log.SetLogLevel(log.InfoLevel)
47+
slog.SetLogLevel(slog.InfoLevel)
4848
default:
49-
log.SetLogLevel(log.InfoLevel)
49+
slog.SetLogLevel(slog.InfoLevel)
5050
}
5151

52-
log.GetFormatter().(*log.TextFormatter).SetTemplate(logTemplate)
52+
slog.GetFormatter().(*slog.TextFormatter).SetTemplate(logTemplate)
5353

5454
certs, err := tls.LoadX509KeyPair(tlscert, tlskey)
5555
if err != nil {
56-
log.Errorf("Failed to load key pair: ", err)
56+
slog.Error("failed to load key pair", "error", err)
5757
}
5858

5959
server := &http.Server{
@@ -79,23 +79,23 @@ func main() {
7979
// start webhook server in new rountine
8080
go func() {
8181
if err := server.ListenAndServeTLS("", ""); err != nil {
82-
log.Errorf("Failed to listen and serve webhook server %v", err)
82+
slog.Error("Failed to listen and serve webhook server", "error", err)
8383
}
8484
}()
8585
go func() {
8686
if err := mserver.ListenAndServe(); err != nil {
87-
log.Errorf("Failed to listen and serve monitor server %v", err)
87+
slog.Error("Failed to listen and serve monitor server %v", "error", err)
8888
}
8989
}()
9090

91-
log.Infof("Server running listening in port: %s,%s", port, mport)
91+
slog.Info("Webhook server running", "port", port, "metricsPort", mport)
9292

9393
// listening shutdown signal
9494
signalChan := make(chan os.Signal, 1)
9595
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
9696
<-signalChan
9797

98-
log.Info("Got shutdown signal, shutting down webhook server gracefully...")
99-
server.Shutdown(context.Background())
100-
mserver.Shutdown(context.Background())
98+
slog.Info("Got shutdown signal, shutting down webhook server gracefully...")
99+
_ = server.Shutdown(context.Background())
100+
_ = mserver.Shutdown(context.Background())
101101
}

test/framework/client.go

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ package framework
33
import (
44
"context"
55
"fmt"
6+
"os"
7+
"testing"
8+
"time"
9+
610
appsv1 "k8s.io/api/apps/v1"
711
corev1 "k8s.io/api/core/v1"
812
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
913
"k8s.io/client-go/kubernetes"
1014
"k8s.io/client-go/tools/clientcmd"
11-
"os"
12-
"testing"
13-
"time"
1415
)
1516

1617
// Framework is a helper struct for testing
@@ -61,13 +62,11 @@ func (f *Framework) Cleanup(t testing.TB) {
6162
// cleanupDeployments removes all deployments from the testing namespace
6263
// if they exist
6364
func (f *Framework) cleanupDeployments(t testing.TB) {
64-
6565
t.Logf("cleaning up deployments")
6666
deployments, err := f.k8s.AppsV1().Deployments("test-cases").List(context.Background(), metav1.ListOptions{})
6767
if err != nil {
6868
f.Cleanup(t)
6969
t.Fatal(err)
70-
7170
}
7271
for _, d := range deployments.Items {
7372
err = f.k8s.AppsV1().Deployments("test-cases").Delete(context.Background(), d.Name, metav1.DeleteOptions{})
@@ -100,7 +99,6 @@ func (f *Framework) cleanupDeployments(t testing.TB) {
10099

101100
// cleanupSecrets removes all secrets from the testing namespace
102101
func (f *Framework) cleanupSecrets(t testing.TB) {
103-
104102
t.Logf("cleaning up secrets")
105103
secrets, err := f.k8s.CoreV1().Secrets("test-cases").List(context.Background(), metav1.ListOptions{})
106104
if err != nil {
@@ -130,25 +128,24 @@ func (f *Framework) CreateDeployment(t testing.TB, d appsv1.Deployment) {
130128

131129
// WaitForDeployment waits until the deployment is ready
132130
func (f *Framework) WaitForDeployment(t *testing.T, d appsv1.Deployment) {
133-
134131
t.Logf("waiting for deployment %s to be ready", d.Name)
135132
// wait until the deployment is ready
136-
w, err := f.k8s.AppsV1().Deployments(d.Namespace).Watch(context.Background(), metav1.ListOptions{
133+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
134+
defer cancel()
135+
w, err := f.k8s.AppsV1().Deployments(d.Namespace).Watch(ctx, metav1.ListOptions{
137136
FieldSelector: fmt.Sprintf("metadata.name=%s", d.Name),
138137
})
139-
140138
if err != nil {
141139
f.Cleanup(t)
142140
t.Fatal(err)
143141
}
144142

145-
timeout := time.After(30 * time.Second)
146-
for event := range w.ResultChan() {
143+
for {
147144
select {
148-
case <-timeout:
145+
case <-ctx.Done():
149146
f.Cleanup(t)
150147
t.Fatal("timeout reached while waiting for deployment to be ready")
151-
default:
148+
case event := <-w.ResultChan():
152149
deployment, ok := event.Object.(*appsv1.Deployment)
153150
if !ok {
154151
time.Sleep(5 * time.Second)
@@ -162,9 +159,6 @@ func (f *Framework) WaitForDeployment(t *testing.T, d appsv1.Deployment) {
162159
time.Sleep(5 * time.Second)
163160
}
164161
}
165-
166-
f.Cleanup(t)
167-
t.Fatal("failed to wait for deployment to be ready")
168162
}
169163

170164
// CreateSecret creates a secret in the testing namespace
@@ -180,7 +174,6 @@ func (f *Framework) CreateSecret(t *testing.T, secret corev1.Secret) {
180174

181175
// AssertDeploymentFailed asserts that the deployment cannot start
182176
func (f *Framework) AssertDeploymentFailed(t *testing.T, d appsv1.Deployment) {
183-
184177
t.Logf("waiting for deployment %s to fail", d.Name)
185178

186179
// watch for replicasets of the deployment
@@ -222,7 +215,6 @@ func (f *Framework) AssertDeploymentFailed(t *testing.T, d appsv1.Deployment) {
222215

223216
// AssertEventForPod asserts that a PodVerified event is created
224217
func (f *Framework) AssertEventForPod(t *testing.T, reason string, p corev1.Pod) {
225-
226218
t.Logf("waiting for %s event to be created for pod %s", reason, p.Name)
227219

228220
// watch for events of deployment's namespace and check if the podverified event is created

test/framework/cosign.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ package framework
22

33
import (
44
"fmt"
5-
"github.com/sigstore/cosign/v2/cmd/cosign/cli"
65
"os"
76
"regexp"
87
"testing"
8+
9+
"github.com/sigstore/cosign/v2/cmd/cosign/cli"
910
)
1011

1112
// cleanupKeys removes all keypair files from the testing directory
1213
func cleanupKeys(t testing.TB) {
13-
1414
t.Logf("cleaning up keypair files")
1515
files, err := os.ReadDir(".")
1616
if err != nil {
@@ -87,5 +87,6 @@ func (f *Framework) SignContainer(t *testing.T, priv, img string) {
8787
err := cmd.Execute()
8888
if err != nil {
8989
f.Cleanup(t)
90+
t.Fatal(err)
9091
}
9192
}

test/main_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66

77
// TestPassingDeployments tests deployments that should pass signature verification
88
func TestPassingDeployments(t *testing.T) {
9-
109
testFuncs := map[string]func(t *testing.T){
1110
"OneContainerSinglePubKeyEnvRef": testOneContainerSinglePubKeyEnvRef,
1211
"TwoContainersSinglePubKeyEnvRef": testTwoContainersSinglePubKeyEnvRef,
@@ -16,6 +15,7 @@ func TestPassingDeployments(t *testing.T) {
1615
"TwoContainersSingleWithInitPubKeyMixedRef": testTwoContainersWithInitSinglePubKeyMixedRef,
1716
"EventEmittedOnSignatureVerification": testEventEmittedOnSignatureVerification,
1817
"EventEmittedOnNoSignatureVerification": testEventEmittedOnNoSignatureVerification,
18+
"OneContainerWithCosingRepoVariable": testOneContainerWithCosingRepoVariable,
1919
}
2020

2121
for name, tf := range testFuncs {
@@ -25,7 +25,6 @@ func TestPassingDeployments(t *testing.T) {
2525

2626
// TestFailingDeployments tests deployments that should fail signature verification
2727
func TestFailingDeployments(t *testing.T) {
28-
2928
testFuncs := map[string]func(t *testing.T){
3029
"OneContainerSinglePubKeyMalformedEnvRef": testOneContainerSinglePubKeyMalformedEnvRef,
3130
"TwoContainersSinglePubKeyMalformedEnvRef": testTwoContainersSinglePubKeyMalformedEnvRef,

0 commit comments

Comments
 (0)