From 1c5360fadc1a21090d5d7e0ca5c637c6aeb543a9 Mon Sep 17 00:00:00 2001 From: Dhruv Jain Date: Mon, 24 Jul 2023 20:58:00 -0700 Subject: [PATCH] Update go to v1.20 (#299) Updating go to version 1.20. Go v1.20 comes with many updates to coverage, additional functionality for some methods, library changes, as well as a method deprecation. Fixes issue #297 Fixes issue #178 Signed-off-by: Dhruv-J --- .github/workflows/go.yml | 2 +- .github/workflows/kind.yml | 10 +- Makefile | 18 ++-- build/charts/theia/templates/_helpers.tpl | 9 ++ .../templates/theia-manager/deployment.yaml | 8 ++ build/charts/theia/values.yaml | 1 + .../Dockerfile.clickhouse-monitor.ubuntu | 3 +- build/images/Dockerfile.theia-manager.ubuntu | 1 + build/images/deps/go-version | 2 +- build/yamls/flow-visibility.yml | 17 ++++ ci/kind/test-e2e-kind.sh | 31 ++++++- codecov.yml | 11 +++ go.mod | 2 +- .../commands/anomaly_detection_list_test.go | 2 +- .../anomaly_detection_retrieve_test.go | 2 +- .../commands/anomaly_detection_status_test.go | 2 +- pkg/theia/commands/clickhouse_status_test.go | 2 +- .../policy_recommendation_list_test.go | 2 +- .../policy_recommendation_retrieve_test.go | 2 +- .../policy_recommendation_run_test.go | 2 +- .../policy_recommendation_status_test.go | 2 +- plugins/clickhouse-monitor/main.go | 15 ++- plugins/clickhouse-monitor/main_test.go | 2 +- snowflake/cmd/deleteBucket_test.go | 4 +- snowflake/cmd/onboard.go | 16 ++-- snowflake/cmd/receiveSqsMessage_test.go | 2 +- snowflake/cmd/root.go | 4 - snowflake/pkg/infra/stack.go | 5 +- test/e2e/e2e_coverage_and_cleanup_test.go | 91 +++++++++++++++++++ test/e2e/framework.go | 39 ++++++++ test/e2e/main_test.go | 3 - test/e2e/util.go | 7 +- 32 files changed, 267 insertions(+), 52 deletions(-) create mode 100644 test/e2e/e2e_coverage_and_cleanup_test.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 52a8c205..af011b2c 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -47,7 +47,7 @@ jobs: uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} - file: .coverage/coverage-unit.txt + file: .coverage/unit/coverage-unit.txt flags: unit-tests name: codecov-unit-test diff --git a/.github/workflows/kind.yml b/.github/workflows/kind.yml index bf0932ed..5376ae1d 100644 --- a/.github/workflows/kind.yml +++ b/.github/workflows/kind.yml @@ -154,10 +154,18 @@ jobs: - name: Run e2e tests run: | mkdir log - ANTREA_LOG_DIR=$PWD/log ./ci/kind/test-e2e-kind.sh + ANTREA_LOG_DIR=$PWD/log ./ci/kind/test-e2e-kind.sh --coverage - name: Tar log files if: ${{ failure() }} run: tar -czf log.tar.gz log + - name: Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: .coverage/complete-kind-e2e-coverage.txt + fail_ci_if_error: ${{ github.event_name == 'push' }} + flags: kind-e2e-tests + name: codecov-kind-e2e-test - name: Upload test log uses: actions/upload-artifact@v3 if: ${{ failure() }} diff --git a/Makefile b/Makefile index ffbff38b..e315ced2 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ trivy-scan: .trivy-bin check-TRIVY_TARGET_IMAGE .PHONY: .coverage .coverage: - mkdir -p $(CURDIR)/.coverage + mkdir -p $(CURDIR)/.coverage/unit .PHONY: test-unit ifeq ($(UNAME_S),Linux) @@ -72,7 +72,7 @@ DOCKER_ENV := \ -v $(DOCKER_CACHE)/gopath:/tmp/gopath \ -v $(DOCKER_CACHE)/gocache:/tmp/gocache \ -v $(CURDIR):/usr/src/antrea.io/theia \ - golang:1.19 + golang:1.20 .PHONY: docker-test-unit docker-test-unit: $(DOCKER_CACHE) @@ -96,9 +96,9 @@ add-copyright: .linux-test-unit: .coverage @echo @echo "==> Running unit tests <==" - $(GO) test -race -coverpkg=antrea.io/theia/plugins/...,antrea.io/theia/pkg/... \ - -coverprofile=.coverage/coverage-unit.txt -covermode=atomic \ - antrea.io/theia/plugins/... antrea.io/theia/pkg/... + $(GO) test -race -coverpkg=antrea.io/theia/plugins/...,antrea.io/theia/pkg/...,antrea.io/theia/cmd/... \ + -coverprofile=.coverage/unit/coverage-unit.txt -covermode=atomic \ + antrea.io/theia/plugins/... antrea.io/theia/pkg/... antrea.io/theia/cmd/... \ .PHONY: tidy tidy: @@ -118,7 +118,7 @@ fmt: .golangci-bin: @echo "===> Installing Golangci-lint <===" - @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $@ v1.50.0 + @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $@ v1.52.2 .PHONY: golangci golangci: .golangci-bin @@ -187,7 +187,7 @@ clickhouse-monitor: .PHONY: clickhouse-monitor-plugin clickhouse-monitor-plugin: @mkdir -p $(BINDIR) - GOOS=linux $(GO) build -o $(BINDIR) $(GOFLAGS) -ldflags '$(LDFLAGS)' antrea.io/theia/plugins/clickhouse-monitor + GOOS=linux $(GO) build -o $(BINDIR) $(GOFLAGS) -cover -ldflags '$(LDFLAGS)' antrea.io/theia/plugins/clickhouse-monitor .PHONY: theia-manager theia-manager: @@ -200,7 +200,7 @@ theia-manager: .PHONY: theia-manager-bin theia-manager-bin: @mkdir -p $(BINDIR) - GOOS=linux $(GO) build -o $(BINDIR) $(GOFLAGS) -ldflags '$(LDFLAGS)' antrea.io/theia/cmd/theia-manager + GOOS=linux $(GO) build -o $(BINDIR) $(GOFLAGS) -cover -ldflags '$(LDFLAGS)' antrea.io/theia/cmd/theia-manager .PHONY: clickhouse-server clickhouse-server: @@ -218,7 +218,7 @@ clickhouse-server-multi-arch: .PHONY: clickhouse-schema-management-plugin clickhouse-schema-management-plugin: @mkdir -p $(BINDIR) - GOOS=linux $(GO) build -o $(BINDIR) $(GOFLAGS) -ldflags '$(LDFLAGS)' antrea.io/theia/plugins/clickhouse-schema-management + GOOS=linux CGO_ENABLED=0 $(GO) build -o $(BINDIR) $(GOFLAGS) -ldflags '$(LDFLAGS)' antrea.io/theia/plugins/clickhouse-schema-management # Theia currently supports two spark jobs, Throughput Anomaly Detection and Policy Recommendation. # This Dockerfile helps create unified dockerfile for both the spark jobs. diff --git a/build/charts/theia/templates/_helpers.tpl b/build/charts/theia/templates/_helpers.tpl index def9bc77..3609eea8 100644 --- a/build/charts/theia/templates/_helpers.tpl +++ b/build/charts/theia/templates/_helpers.tpl @@ -4,6 +4,9 @@ - name: clickhouse-monitor image: {{ include "clickHouseMonitorImage" . | quote }} imagePullPolicy: {{ $clickhouse.monitor.image.pullPolicy }} + volumeMounts: + - name: clickhouse-monitor-coverage + mountPath: /clickhouse-monitor-coverage env: - name: CLICKHOUSE_USERNAME valueFrom: @@ -31,6 +34,8 @@ value: {{ $clickhouse.monitor.execInterval }} - name: SKIP_ROUNDS_NUM value: {{ $clickhouse.monitor.skipRoundsNum | quote }} + - name: GOCOVERDIR + value: "/clickhouse-monitor-coverage" {{- end }} {{- define "clickhouse.server.container" }} @@ -88,6 +93,10 @@ medium: Memory sizeLimit: {{ $clickhouse.storage.size }} {{- end }} +- hostPath: + path: /var/log/cm-coverage + type: DirectoryOrCreate + name: clickhouse-monitor-coverage {{- end }} diff --git a/build/charts/theia/templates/theia-manager/deployment.yaml b/build/charts/theia/templates/theia-manager/deployment.yaml index a73614fd..455239e7 100644 --- a/build/charts/theia/templates/theia-manager/deployment.yaml +++ b/build/charts/theia/templates/theia-manager/deployment.yaml @@ -52,6 +52,8 @@ spec: key: password - name: CLICKHOUSE_URL value: "tcp://clickhouse-clickhouse.{{ .Release.Namespace }}.svc:{{ .Values.clickhouse.service.tcpPort }}" + - name: GOCOVERDIR + value: "/theia-manager-coverage" ports: - name: "theia-api-http" containerPort: {{ .Values.theiaManager.apiServer.apiPort }} @@ -63,6 +65,8 @@ spec: name: theia-manager-tls - mountPath: /var/log/antrea/theia-manager name: host-var-log-antrea-theia-manager + - mountPath: /theia-manager-coverage + name: theia-manager-coverage nodeSelector: kubernetes.io/os: linux kubernetes.io/arch: amd64 @@ -81,4 +85,8 @@ spec: hostPath: path: /var/log/antrea/theia-manager type: DirectoryOrCreate + - name: theia-manager-coverage + hostPath: + path: /var/log/tm-coverage + type: DirectoryOrCreate {{- end }} diff --git a/build/charts/theia/values.yaml b/build/charts/theia/values.yaml index 279f1f83..7c4ada72 100644 --- a/build/charts/theia/values.yaml +++ b/build/charts/theia/values.yaml @@ -270,3 +270,4 @@ theiaManager: tlsMinVersion: "" # -- Log verbosity switch for Theia Manager. logVerbosity: 0 + \ No newline at end of file diff --git a/build/images/Dockerfile.clickhouse-monitor.ubuntu b/build/images/Dockerfile.clickhouse-monitor.ubuntu index 980e4025..a468d8a6 100644 --- a/build/images/Dockerfile.clickhouse-monitor.ubuntu +++ b/build/images/Dockerfile.clickhouse-monitor.ubuntu @@ -7,7 +7,8 @@ WORKDIR /theia # Statically links clickhouse-monitor-plugin binary. RUN CGO_ENABLED=0 make clickhouse-monitor-plugin -FROM scratch +FROM ubuntu:22.04 +RUN mkdir -p clickhouse-monitor-coverage LABEL maintainer="Antrea " LABEL description="A docker image to deploy the ClickHouse monitor plugin." diff --git a/build/images/Dockerfile.theia-manager.ubuntu b/build/images/Dockerfile.theia-manager.ubuntu index 60bb4ca7..ad7fb107 100644 --- a/build/images/Dockerfile.theia-manager.ubuntu +++ b/build/images/Dockerfile.theia-manager.ubuntu @@ -5,6 +5,7 @@ COPY . /theia WORKDIR /theia RUN make theia-manager-bin +RUN mkdir theia-manager-coverage # Chose this base image so that a shell is available for users to exec into the container FROM ubuntu:23.04 diff --git a/build/images/deps/go-version b/build/images/deps/go-version index bc449347..5fb5a6b4 100644 --- a/build/images/deps/go-version +++ b/build/images/deps/go-version @@ -1 +1 @@ -1.19 +1.20 diff --git a/build/yamls/flow-visibility.yml b/build/yamls/flow-visibility.yml index 61b0fcea..6ebf0a4a 100644 --- a/build/yamls/flow-visibility.yml +++ b/build/yamls/flow-visibility.yml @@ -6977,6 +6977,8 @@ spec: name: clickhouse-secret - name: CLICKHOUSE_URL value: tcp://clickhouse-clickhouse.flow-visibility.svc:9000 + - name: GOCOVERDIR + value: /theia-manager-coverage image: projects.registry.vmware.com/antrea/theia-manager:latest imagePullPolicy: IfNotPresent name: theia-manager @@ -6991,6 +6993,8 @@ spec: name: theia-manager-tls - mountPath: /var/log/antrea/theia-manager name: host-var-log-antrea-theia-manager + - mountPath: /theia-manager-coverage + name: theia-manager-coverage nodeSelector: kubernetes.io/arch: amd64 kubernetes.io/os: linux @@ -7008,6 +7012,10 @@ spec: path: /var/log/antrea/theia-manager type: DirectoryOrCreate name: host-var-log-antrea-theia-manager + - hostPath: + path: /var/log/tm-coverage + type: DirectoryOrCreate + name: theia-manager-coverage --- apiVersion: apps/v1 kind: StatefulSet @@ -7282,9 +7290,14 @@ spec: value: 1m - name: SKIP_ROUNDS_NUM value: "3" + - name: GOCOVERDIR + value: /clickhouse-monitor-coverage image: projects.registry.vmware.com/antrea/theia-clickhouse-monitor:latest imagePullPolicy: IfNotPresent name: clickhouse-monitor + volumeMounts: + - mountPath: /clickhouse-monitor-coverage + name: clickhouse-monitor-coverage volumes: - configMap: items: @@ -7318,6 +7331,10 @@ spec: medium: Memory sizeLimit: 8Gi name: clickhouse-storage-volume + - hostPath: + path: /var/log/cm-coverage + type: DirectoryOrCreate + name: clickhouse-monitor-coverage serviceTemplates: - name: service-template spec: diff --git a/ci/kind/test-e2e-kind.sh b/ci/kind/test-e2e-kind.sh index 659cb1b8..c91c06cc 100755 --- a/ci/kind/test-e2e-kind.sh +++ b/ci/kind/test-e2e-kind.sh @@ -28,6 +28,7 @@ _usage="Usage: $0 [--ip-family ] [--help|-h] --setup-only Only perform setting up the cluster and run test. --cleanup-only Only perform cleaning up the cluster. --test-only Only run test on current cluster. Not set up/clean up the cluster. + --coverage Collect coverage data while running test. --help, -h Print this message and exit. " @@ -60,6 +61,7 @@ skiplist="" setup_only=false cleanup_only=false test_only=false +coverage=false while [[ $# -gt 0 ]] do key="$1" @@ -85,6 +87,10 @@ case $key in test_only=true shift ;; + --coverage) + coverage=true + shift + ;; -h|--help) print_usage exit 0 @@ -100,6 +106,11 @@ if [[ $cleanup_only == "true" ]];then $TESTBED_CMD destroy kind exit 0 fi +if [[ $coverage == "true" ]];then + mkdir -p .coverage/clickhouse-monitor-coverage/ + mkdir -p .coverage/theia-manager-coverage/ + mkdir -p .coverage/merged/ +fi trap "quit" INT EXIT @@ -173,7 +184,24 @@ function run_test { rm -rf $TMP_DIR sleep 1 - go test -v -timeout=45m antrea.io/theia/test/e2e -provider=kind --logs-export-dir=$ANTREA_LOG_DIR --skip=$skiplist + if $coverage; then + go test -v -timeout=30m antrea.io/theia/test/e2e -provider=kind --logs-export-dir=$ANTREA_LOG_DIR -cover -covermode=atomic --skip=$skiplist + else + go test -v -timeout=30m antrea.io/theia/test/e2e -provider=kind --logs-export-dir=$ANTREA_LOG_DIR --skip=$skiplist + fi + +} + +function coverage_and_cleanup_test { + if $coverage; then + COVERAGE=true go test -v -timeout=10m -run=TestCoverageAndCleanup antrea.io/theia/test/e2e -provider=kind --logs-export-dir=$ANTREA_LOG_DIR --skip=$skiplist + touch .coverage/complete-kind-e2e-coverage.txt + go tool covdata merge -i=.coverage/clickhouse-monitor-coverage,.coverage/theia-manager-coverage -o .coverage/merged + go tool covdata textfmt -i=.coverage/merged -o .coverage/complete-kind-e2e-coverage.txt + rm -rf .coverage/clickhouse-monitor-coverage + rm -rf .coverage/theia-manager-coverage + rm -rf .coverage/merged + fi } echo "======== Test encap mode ==========" @@ -181,6 +209,7 @@ if [[ $test_only == "false" ]];then setup_cluster "--images \"$COMMON_IMAGES\"" fi run_test +coverage_and_cleanup_test rm -rf $PWD/bin diff --git a/codecov.yml b/codecov.yml index 97082985..64c43d4f 100644 --- a/codecov.yml +++ b/codecov.yml @@ -33,6 +33,16 @@ coverage: threshold: 1% flags: - unit-tests + theia-kind-e2e-tests: + target: 60% + threshold: 1% + flags: + - kind-e2e-tests + python-unit-tests: + target: 50% + threshold: 1% + flags: + - python-coverage flag_management: default_rules: @@ -45,3 +55,4 @@ ignore: - "**/pkg/client" - "third_party" - "pkg/api" + - "snowflake" diff --git a/go.mod b/go.mod index fad80dfe..2ae00175 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module antrea.io/theia -go 1.19 +go 1.20 require ( antrea.io/antrea v1.11.1 diff --git a/pkg/theia/commands/anomaly_detection_list_test.go b/pkg/theia/commands/anomaly_detection_list_test.go index e0463c18..e5cf289c 100644 --- a/pkg/theia/commands/anomaly_detection_list_test.go +++ b/pkg/theia/commands/anomaly_detection_list_test.go @@ -114,11 +114,11 @@ func TestAnomalyDetectionList(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() err := anomalyDetectionList(cmd, []string{}) if tt.expectedErrorMsg == "" { assert.NoError(t, err) outcome := readStdout(t, r, w) - os.Stdout = orig assert.Contains(t, outcome, "test1") for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) diff --git a/pkg/theia/commands/anomaly_detection_retrieve_test.go b/pkg/theia/commands/anomaly_detection_retrieve_test.go index 0bf3cf78..38014598 100644 --- a/pkg/theia/commands/anomaly_detection_retrieve_test.go +++ b/pkg/theia/commands/anomaly_detection_retrieve_test.go @@ -302,6 +302,7 @@ func TestAnomalyDetectorRetrieve(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() err := throughputAnomalyDetectionRetrieve(cmd, []string{}) if tt.expectedErrorMsg == "" { if tt.filePath != "" { @@ -314,7 +315,6 @@ func TestAnomalyDetectorRetrieve(t *testing.T) { } else { assert.NoError(t, err) outcome := readStdouttad(t, r, w) - os.Stdout = orig for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) } diff --git a/pkg/theia/commands/anomaly_detection_status_test.go b/pkg/theia/commands/anomaly_detection_status_test.go index 30b4f422..bb1ccfc7 100644 --- a/pkg/theia/commands/anomaly_detection_status_test.go +++ b/pkg/theia/commands/anomaly_detection_status_test.go @@ -181,6 +181,7 @@ func TestAnomalyDetectorStatus(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() if tt.name == "Valid case with args" { err = anomalyDetectionStatus(cmd, []string{tadName}) } else { @@ -189,7 +190,6 @@ func TestAnomalyDetectorStatus(t *testing.T) { if tt.expectedErrorMsg == "" { assert.NoError(t, err) outcome := readStdout(t, r, w) - os.Stdout = orig for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) } diff --git a/pkg/theia/commands/clickhouse_status_test.go b/pkg/theia/commands/clickhouse_status_test.go index ca1c158d..d991e30e 100644 --- a/pkg/theia/commands/clickhouse_status_test.go +++ b/pkg/theia/commands/clickhouse_status_test.go @@ -219,11 +219,11 @@ func TestGetStatus(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() err := getStatus(cmd, []string{}) if tt.expectedErrorMsg == "" { assert.NoError(t, err) outcome := readStdout(t, r, w) - os.Stdout = orig for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) } diff --git a/pkg/theia/commands/policy_recommendation_list_test.go b/pkg/theia/commands/policy_recommendation_list_test.go index 095d4df5..0358817d 100644 --- a/pkg/theia/commands/policy_recommendation_list_test.go +++ b/pkg/theia/commands/policy_recommendation_list_test.go @@ -114,11 +114,11 @@ func TestPolicyRecommendationList(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() err := policyRecommendationList(cmd, []string{}) if tt.expectedErrorMsg == "" { assert.NoError(t, err) outcome := readStdout(t, r, w) - os.Stdout = orig assert.Contains(t, outcome, "test1") for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) diff --git a/pkg/theia/commands/policy_recommendation_retrieve_test.go b/pkg/theia/commands/policy_recommendation_retrieve_test.go index 495e0d23..958e1009 100644 --- a/pkg/theia/commands/policy_recommendation_retrieve_test.go +++ b/pkg/theia/commands/policy_recommendation_retrieve_test.go @@ -167,6 +167,7 @@ func TestPolicyRecommendationRetrieve(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() err := policyRecommendationRetrieve(cmd, []string{}) if tt.expectedErrorMsg == "" { if tt.filePath != "" { @@ -179,7 +180,6 @@ func TestPolicyRecommendationRetrieve(t *testing.T) { } else { assert.NoError(t, err) outcome := readStdout(t, r, w) - os.Stdout = orig for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) } diff --git a/pkg/theia/commands/policy_recommendation_run_test.go b/pkg/theia/commands/policy_recommendation_run_test.go index 33572eb1..10db67d0 100644 --- a/pkg/theia/commands/policy_recommendation_run_test.go +++ b/pkg/theia/commands/policy_recommendation_run_test.go @@ -141,11 +141,11 @@ func TestPolicyRecommendationRun(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() err := policyRecommendationRun(cmd, []string{}) if tt.expectedErrorMsg == "" { assert.NoError(t, err) outcome := readStdout(t, r, w) - os.Stdout = orig for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) } diff --git a/pkg/theia/commands/policy_recommendation_status_test.go b/pkg/theia/commands/policy_recommendation_status_test.go index 305c25ef..dc1f36e1 100644 --- a/pkg/theia/commands/policy_recommendation_status_test.go +++ b/pkg/theia/commands/policy_recommendation_status_test.go @@ -179,6 +179,7 @@ func TestPolicyRecommendationStatus(t *testing.T) { orig := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { os.Stdout = orig }() if tt.name == "Valid case with args" { err = policyRecommendationStatus(cmd, []string{nprName}) } else { @@ -187,7 +188,6 @@ func TestPolicyRecommendationStatus(t *testing.T) { if tt.expectedErrorMsg == "" { assert.NoError(t, err) outcome := readStdout(t, r, w) - os.Stdout = orig for _, msg := range tt.expectedMsg { assert.Contains(t, outcome, msg) } diff --git a/plugins/clickhouse-monitor/main.go b/plugins/clickhouse-monitor/main.go index c6db0df5..b180620f 100644 --- a/plugins/clickhouse-monitor/main.go +++ b/plugins/clickhouse-monitor/main.go @@ -24,6 +24,8 @@ import ( "strings" "time" + "antrea.io/antrea/pkg/signals" + "github.com/ClickHouse/clickhouse-go" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/util/wait" @@ -44,9 +46,9 @@ const ( ) var ( - getEnv = os.Getenv - openSql = sql.Open - foreverRun = wait.Forever + getEnv = os.Getenv + openSql = sql.Open + runUntil = wait.Until ) var ( @@ -103,7 +105,10 @@ func main() { } func startMonitor(connect *sql.DB) { - foreverRun(func() { + stopCh := signals.RegisterSignalHandlers() + // Set up signal capture: the first SIGINT signal is expected to be received from + // intentional SIGINT sending to collect coverage + runUntil(func() { // The monitor stops working for several rounds after a deletion // as the release of memory space by the ClickHouse MergeTree engine requires time if remainingRoundsNum > 0 { @@ -115,7 +120,7 @@ func startMonitor(connect *sql.DB) { klog.ErrorS(nil, "Remaining rounds number to be skipped should be larger than or equal to 0", "number", remainingRoundsNum) os.Exit(1) } - }, monitorExecInterval) + }, monitorExecInterval, stopCh) } func loadEnvVariables() error { diff --git a/plugins/clickhouse-monitor/main_test.go b/plugins/clickhouse-monitor/main_test.go index e07e50c6..f8b8ea47 100644 --- a/plugins/clickhouse-monitor/main_test.go +++ b/plugins/clickhouse-monitor/main_test.go @@ -32,7 +32,7 @@ func TestMonitorWithMockDB(t *testing.T) { defer db.Close() initEnv() - foreverRun = func(f func(), period time.Duration) { + runUntil = func(f func(), period time.Duration, stopCh <-chan struct{}) { f() } diff --git a/snowflake/cmd/deleteBucket_test.go b/snowflake/cmd/deleteBucket_test.go index d66806a1..36d7c2fc 100644 --- a/snowflake/cmd/deleteBucket_test.go +++ b/snowflake/cmd/deleteBucket_test.go @@ -44,13 +44,13 @@ func TestDeleteS3Objects(t *testing.T) { mockS3Client := s3clienttesting.NewMockInterface(ctrl) k := "" output := s3.ListObjectsV2Output{ - Contents: []s3types.Object{s3types.Object{Key: &k}}, + Contents: []s3types.Object{{Key: &k}}, } mockS3Client.EXPECT().ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{ Bucket: &name, Prefix: &prefix, }).Return(&output, nil) - keys := []s3types.ObjectIdentifier{s3types.ObjectIdentifier{ + keys := []s3types.ObjectIdentifier{{ Key: &k, }} deleteObjectsInput := s3.DeleteObjectsInput{ diff --git a/snowflake/cmd/onboard.go b/snowflake/cmd/onboard.go index 0242ec51..74c98227 100644 --- a/snowflake/cmd/onboard.go +++ b/snowflake/cmd/onboard.go @@ -98,14 +98,14 @@ own by using the "--warehouse-name" parameter.`, func showResults(result *infra.Result) { table := tablewriter.NewWriter(os.Stdout) data := [][]string{ - []string{"Region", result.Region}, - []string{"Bucket Name", result.BucketName}, - []string{"Bucket Flows Folder", result.BucketFlowsFolder}, - []string{"Snowflake Database Name", result.DatabaseName}, - []string{"Snowflake Schema Name", result.SchemaName}, - []string{"Snowflake Flows Table Name", result.FlowsTableName}, - []string{"SNS Topic ARN", result.SNSTopicARN}, - []string{"SQS Queue ARN", result.SQSQueueARN}, + {"Region", result.Region}, + {"Bucket Name", result.BucketName}, + {"Bucket Flows Folder", result.BucketFlowsFolder}, + {"Snowflake Database Name", result.DatabaseName}, + {"Snowflake Schema Name", result.SchemaName}, + {"Snowflake Flows Table Name", result.FlowsTableName}, + {"SNS Topic ARN", result.SNSTopicARN}, + {"SQS Queue ARN", result.SQSQueueARN}, } table.SetAlignment(tablewriter.ALIGN_LEFT) table.AppendBulk(data) diff --git a/snowflake/cmd/receiveSqsMessage_test.go b/snowflake/cmd/receiveSqsMessage_test.go index a91157d2..5355ed5e 100644 --- a/snowflake/cmd/receiveSqsMessage_test.go +++ b/snowflake/cmd/receiveSqsMessage_test.go @@ -79,7 +79,7 @@ func TestReceiveSQSMessage(t *testing.T) { } else { receiptHandle := "randomReceiptHandle" receiveMessageOutput := sqs.ReceiveMessageOutput{ - Messages: []types.Message{types.Message{Body: &messageBody, ReceiptHandle: &receiptHandle}}, + Messages: []types.Message{{Body: &messageBody, ReceiptHandle: &receiptHandle}}, } mockSqsClient.EXPECT().ReceiveMessage(context.TODO(), &receiveMessageInput).Return(&receiveMessageOutput, nil) if tc.deleteExpected { diff --git a/snowflake/cmd/root.go b/snowflake/cmd/root.go index 9fb0d358..11c1b984 100644 --- a/snowflake/cmd/root.go +++ b/snowflake/cmd/root.go @@ -16,9 +16,7 @@ package cmd import ( "fmt" - "math/rand" "os" - "time" "github.com/go-logr/logr" "github.com/go-logr/zapr" @@ -76,7 +74,5 @@ func Execute() { } func init() { - rand.Seed(time.Now().UnixNano()) - rootCmd.PersistentFlags().IntVarP(&verbosity, "verbosity", "v", 0, "log verbosity") } diff --git a/snowflake/pkg/infra/stack.go b/snowflake/pkg/infra/stack.go index cdb75fb1..03a39011 100644 --- a/snowflake/pkg/infra/stack.go +++ b/snowflake/pkg/infra/stack.go @@ -266,6 +266,8 @@ func declareSnowflakeDatabase( return nil, err } + // add random seeding for generator + r := rand.New(rand.NewSource(time.Now().UnixNano())) // ideally this would be a dynamic provider: https://www.pulumi.com/docs/intro/concepts/resources/dynamic-providers/ // however, dynamic providers are not supported at the moment for Golang // maybe this is a change that we can make at a future time if support is added @@ -278,7 +280,7 @@ func declareSnowflakeDatabase( "SNOWFLAKE_PASSWORD": pulumi.ToSecret(os.Getenv("SNOWFLAKE_PASSWORD")).(pulumi.StringOutput), }, // migrations are idempotent so for now we always run them - Triggers: pulumi.Array([]pulumi.Input{db.ID(), schema.ID(), pulumi.Int(rand.Int())}), + Triggers: pulumi.Array([]pulumi.Input{db.ID(), schema.ID(), pulumi.Int(r.Int())}), }, pulumi.Parent(schema), pulumi.DeleteBeforeReplace(true), pulumi.ReplaceOnChanges([]string{"environment"}), pulumi.IgnoreChanges([]string{"create"})) if err != nil { return nil, err @@ -459,5 +461,4 @@ func declareStack(warehouseName string) func(ctx *pulumi.Context) error { } func init() { - rand.Seed(time.Now().UnixNano()) } diff --git a/test/e2e/e2e_coverage_and_cleanup_test.go b/test/e2e/e2e_coverage_and_cleanup_test.go new file mode 100644 index 00000000..5885c467 --- /dev/null +++ b/test/e2e/e2e_coverage_and_cleanup_test.go @@ -0,0 +1,91 @@ +// Copyright 2023 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + log "github.com/sirupsen/logrus" +) + +var workerNodeNames = []string{"kind-worker", "kind-worker2"} +var covDirs = []string{".coverage/clickhouse-monitor-coverage", ".coverage/theia-manager-coverage"} +var covDirPrefixes = []string{"cm", "tm"} + +func copyCovFolder(nodeName, covDir, covPrefix string) error { + covDirAbs, err := filepath.Abs("../../" + covDir) + if err != nil { + return fmt.Errorf("error while creating absolute file path: %v", err) + } + pathOnNode := nodeName + ":" + "/var/log/" + covPrefix + "-coverage/." + cmd := exec.Command("docker", "cp", pathOnNode, covDirAbs) + var outb, errb bytes.Buffer + cmd.Stdout = &outb + cmd.Stderr = &errb + if err := cmd.Run(); err != nil { + errStr := errb.String() + outStr := outb.String() + if !strings.Contains(errb.String(), "Could not find the file") { + return fmt.Errorf("error while running docker cp command[%v] from node: %s: stdout: %s, stderr: %s", cmd, nodeName, outStr, errStr) + } + } + return nil +} + +func clearCovFolder(nodeName, covPrefix string) error { + nestedCmd := "`rm -rf /var/log/" + covPrefix + "-coverage/*`" + cmd := exec.Command("docker", "exec", nodeName, "sh", "-c", nestedCmd) + var outb, errb bytes.Buffer + cmd.Stdout = &outb + cmd.Stderr = &errb + if err := cmd.Run(); err != nil { + errStr := errb.String() + outStr := outb.String() + if !strings.Contains(errb.String(), "not found") { + return fmt.Errorf("error while running docker exec command[%v] from node: %s: stdout: %s, stderr: %s", cmd, nodeName, outStr, errStr) + } + } + return nil +} + +func tearDownBothNodes() error { + log.Infof("Running final coverage copy and cleanup.\n") + for _, prefix := range covDirPrefixes { + for _, workerNode := range workerNodeNames { + for _, covDir := range covDirs { + if err := copyCovFolder(workerNode, covDir, prefix); err != nil { + return err + } + } + if err := clearCovFolder(workerNode, prefix); err != nil { + return err + } + } + } + return nil +} + +func TestCoverageAndCleanup(t *testing.T) { + if os.Getenv("COVERAGE") == "" { + t.Skipf("COVERAGE env variable is not set until all tests are run, skipping test.") + } + tearDownBothNodes() +} diff --git a/test/e2e/framework.go b/test/e2e/framework.go index c4f9e1b9..c9dcee81 100644 --- a/test/e2e/framework.go +++ b/test/e2e/framework.go @@ -93,6 +93,8 @@ const ( antreaPodLabel string = "app=antrea,component=antrea-agent" clickHouseLocalPvLabel string = "antrea.io/clickhouse-data-node" clickHouseLocalPvPath string = "/data/clickhouse" + clickHouseMonitorContName string = "clickhouse-monitor" + theiaManagerContName string = "theia-manager" agnhostImage = "registry.k8s.io/e2e-test-images/agnhost:2.29" busyboxImage = "projects.registry.vmware.com/antrea/busybox" @@ -1392,7 +1394,44 @@ func (data *TestData) deleteClickHouseOperator(chOperatorYML string) error { return nil } +func (data *TestData) killProcesses(namespace, podName, containerName, processName string) error { + cmds := []string{"pgrep", "-f", processName} + stdout, stderr, err := data.RunCommandFromPod(namespace, podName, containerName, cmds) + if err != nil { + if strings.Contains(err.Error(), "does not have a host assigned") { + return nil + } + return fmt.Errorf("error when getting pid of '%s', stderr: <%v>, err: <%v>", processName, stderr, err) + } + cmds = []string{"kill", "-SIGINT", strings.TrimSpace(stdout)} + _, stderr, err = data.RunCommandFromPod(namespace, podName, containerName, cmds) + if err != nil { + return fmt.Errorf("error when sending SIGINT signal to '%s', stderr: <%v>, err: <%v>", processName, stderr, err) + } + return nil +} + +func (data *TestData) killProcessesOnPods() error { + pods, err := data.clientset.CoreV1().Pods(flowVisibilityNamespace).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to list flow-visibility pods: %v", err) + } + for _, pod := range pods.Items { + podName := pod.Name + if strings.Contains(podName, "chi-clickhouse-clickhouse") { + err = data.killProcesses("flow-visibility", podName, clickHouseMonitorContName, clickHouseMonitorContName) + } else if strings.Contains(podName, theiaManagerContName) { + err = data.killProcesses("flow-visibility", podName, theiaManagerContName, theiaManagerContName) + } + if err != nil { + return fmt.Errorf("error when killing processes on pod: %v", err) + } + } + return nil +} + func teardownFlowVisibility(tb testing.TB, data *TestData, config FlowVisibilitySetUpConfig) { + data.killProcessesOnPods() if config.withFlowAggregator { if err := data.DeleteNamespace(flowAggregatorNamespace, defaultTimeout); err != nil { tb.Logf("Error when tearing down flow aggregator: %v", err) diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 43b4d560..5d2a4dfb 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -17,10 +17,8 @@ package e2e import ( "flag" "log" - "math/rand" "os" "testing" - "time" ) // setupLogging creates a temporary directory to export the test logs if necessary. If a directory @@ -103,7 +101,6 @@ func testMain(m *testing.M) int { if err != nil { log.Fatalf("Error when getting antrea-config configmap: %v", err) } - rand.Seed(time.Now().UnixNano()) ret := m.Run() return ret } diff --git a/test/e2e/util.go b/test/e2e/util.go index e0cc0c2c..1b529a16 100644 --- a/test/e2e/util.go +++ b/test/e2e/util.go @@ -15,9 +15,10 @@ package e2e import ( + "crypto/rand" "fmt" "io" - "math/rand" + "math/big" "os" "strings" "testing" @@ -83,8 +84,8 @@ func randSeq(n int) string { b := make([]rune, n) for i := range b { // #nosec G404: random number generator not used for security purposes - randIdx := rand.Intn(len(lettersAndDigits)) - b[i] = lettersAndDigits[randIdx] + randIdx, _ := rand.Int(rand.Reader, big.NewInt(int64(len(lettersAndDigits)))) + b[i] = lettersAndDigits[randIdx.Int64()] } return string(b) }