Skip to content

Commit

Permalink
Add flaky tests detector. (gravitational#20320)
Browse files Browse the repository at this point in the history
Co-authored-by: Victor Sokolov <[email protected]>
  • Loading branch information
r0mant and gzigzigzeo authored Jan 18, 2023
1 parent 30d51b6 commit a496783
Show file tree
Hide file tree
Showing 23 changed files with 2,342 additions and 35 deletions.
43 changes: 43 additions & 0 deletions .github/actions/difftest/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Run difftest
description: Runs difftest
inputs:
flags:
description: difftest flags
required: true

target:
description: make target
required: true

attempts:
description: Number of runs
required: false
default: 30

bin:
description: difftest binary location
required: false
default: ${GITHUB_WORKSPACE}/build.assets/tooling/bin/difftest

path:
description: difftest path
required: false
default: ${GITHUB_WORKSPACE}

runs:
using: "composite"
steps:
- name: Build
shell: bash
run: make ${{ inputs.bin }}

- name: Show
id: diffs
shell: bash
run: |
${{ inputs.bin }} diff --path ${{ inputs.path }} --branch remotes/origin/${GITHUB_BASE_REF} ${{ inputs.flags }}
echo "subject=$(${{ inputs.bin }} test --path ${{ inputs.path }} --branch remotes/origin/${GITHUB_BASE_REF} ${{ inputs.flags }} -u -d)" > $GITHUB_OUTPUT
- name: Run
shell: bash
run: SUBJECT='${{ steps.diffs.outputs.subject }}' ADDFLAGS='-count ${{ inputs.attempts }}' make ${{ inputs.target }}
86 changes: 86 additions & 0 deletions .github/workflows/flaky-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Flaky Tests Detector
run-name: Flaky Tests Detector - ${{ github.run_id }} - @${{ github.actor }}

on:
pull_request:
paths:
- '**.go'

env:
ATTEMPTS: 30

jobs:
test:
name: Flaky tests detector
runs-on: ubuntu-22.04-32core

permissions:
contents: read
packages: read

container:
image: ghcr.io/gravitational/teleport-buildbox:teleport12
env:
TELEPORT_ETCD_TEST: yes
TELEPORT_ETCD_TEST_ENDPOINT: https://etcd0:2379
TELEPORT_XAUTH_TEST: yes
TELEPORT_BPF_TEST: yes
options: --cap-add=SYS_ADMIN --privileged

services:
etcd0:
image: ghcr.io/gravitational/ci-etcd:3.3.9
options: >-
--health-interval 10s
--health-timeout 5s
--health-retries 5
--add-host etcd0:127.0.0.1
ports:
- 2379:2379
- 2380:2380
- 3379:3379

steps:
- name: Checkout Teleport
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Prepare workspace
uses: ./.github/actions/prepare-workspace

- name: Mount debugfs
run: mount -t debugfs none /sys/kernel/debug/

- name: Prepare unit tests
run: make test-go-prepare

- name: Run base difftest
uses: ./.github/actions/difftest
with:
flags: -e "operator/**/*" -e "tool/tsh/**/*" -e "integration/**/*" -e "build.assets/**/*" -e "lib/auth/webauthncli/**/*" -e "lib/auth/touchid/**/*" -e "api/**/*"
target: test-go-unit

- name: Run libfido2 difftest
uses: ./.github/actions/difftest
with:
flags: --include "lib/auth/webauthncli/**/*"
target: test-go-libfido2

- name: Run touch-id difftest
uses: ./.github/actions/difftest
with:
flags: --include "lib/auth/touchid/**/*"
target: test-go-touch-id

- name: Run tsh difftest
uses: ./.github/actions/difftest
with:
flags: --include "tool/tsh/**/*"
target: test-go-tsh

- name: Run api difftest
uses: ./.github/actions/difftest
with:
flags: --include "api/**/*" --relative "api"
target: test-api
63 changes: 49 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,14 @@ TOOLINGDIR := ${abspath ./build.assets/tooling}
RENDER_TESTS := $(TOOLINGDIR)/bin/render-tests
$(RENDER_TESTS): $(wildcard $(TOOLINGDIR)/cmd/render-tests/*.go)
cd $(TOOLINGDIR) && go build -o "$@" ./cmd/render-tests

DIFF_TEST := $(TOOLINGDIR)/bin/difftest
$(DIFF_TEST): $(wildcard $(TOOLINGDIR)/cmd/difftest/*.go)
cd $(TOOLINGDIR) && go build -o "$@" ./cmd/difftest

.PHONY: tooling
tooling: $(RENDER_TESTS) $(DIFF_TEST)

#
# Runs all Go/shell tests, called by CI/CD.
#
Expand Down Expand Up @@ -606,39 +614,66 @@ test-helm-update-snapshots: helmunit/installed

#
# Runs all Go tests except integration, called by CI/CD.
# Chaos tests have high concurrency, run without race detector and have TestChaos prefix.
#
.PHONY: test-go
test-go: ensure-webassets bpf-bytecode rdpclient $(TEST_LOG_DIR) $(RENDER_TESTS)
test-go: FLAGS ?= -race -shuffle on
test-go: PACKAGES = $(shell go list ./... | grep -v -e integration -e tool/tsh -e operator )
test-go: CHAOS_FOLDERS = $(shell find . -type f -name '*chaos*.go' | xargs dirname | uniq)
test-go: $(VERSRC) $(TEST_LOG_DIR)
$(CGOFLAG) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(RDPCLIENT_TAG) $(TOUCHID_TAG) $(PIV_TEST_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) \
test-go: test-go-prepare test-go-unit test-go-libfido2 test-go-touch-id test-go-tsh test-go-chaos

# Runs test prepare steps
.PHONY: test-go-prepare
test-go-prepare: ensure-webassets bpf-bytecode rdpclient $(TEST_LOG_DIR) $(RENDER_TESTS) $(VERSRC)

# Runs base unit tests
.PHONY: test-go-unit
test-go-unit: FLAGS ?= -race -shuffle on
test-go-unit: SUBJECT ?= $(shell go list ./... | grep -v -e integration -e tool/tsh -e operator )
test-go-unit:
$(CGOFLAG) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(RDPCLIENT_TAG) $(TOUCHID_TAG) $(PIV_TEST_TAG)" $(PACKAGES) $(SUBJECT) $(FLAGS) $(ADDFLAGS) \
| tee $(TEST_LOG_DIR)/unit.json \
| ${RENDER_TESTS}

# rdpclient and libfido2 don't play well together, so we run libfido2 tests
# separately.
# TODO(codingllama): Run libfido2 tests along with others once RDP doesn't
# embed openssl/libcrypto.
.PHONY: test-go-libfido2
test-go-libfido2: FLAGS ?= -race -shuffle on
test-go-libfido2: SUBJECT ?= ./lib/auth/webauthncli/...
test-go-libfido2:
ifneq ("$(LIBFIDO2_TEST_TAG)", "")
$(CGOFLAG) go test -cover -json -tags "$(LIBFIDO2_TEST_TAG)" ./lib/auth/webauthncli/... $(FLAGS) $(ADDFLAGS) \
$(CGOFLAG) go test -cover -json -tags "$(LIBFIDO2_TEST_TAG)" $(PACKAGES) $(SUBJECT) $(FLAGS) $(ADDFLAGS) \
| tee $(TEST_LOG_DIR)/unit.json \
| ${RENDER_TESTS}
endif

# Make sure untagged touchid code build/tests.
.PHONY: test-go-touch-id
test-go-touch-id: FLAGS ?= -race -shuffle on
test-go-touch-id: SUBJECT ?= ./lib/auth/touchid/...
test-go-touch-id:
ifneq ("$(TOUCHID_TAG)", "")
$(CGOFLAG) go test -cover -json ./lib/auth/touchid/... $(FLAGS) $(ADDFLAGS) \
$(CGOFLAG) go test -cover -json $(PACKAGES) $(SUBJECT) $(FLAGS) $(ADDFLAGS) \
| tee $(TEST_LOG_DIR)/unit.json \
| ${RENDER_TESTS}
endif
$(CGOFLAG_TSH) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(LIBFIDO2_TEST_TAG) $(TOUCHID_TAG) $(PIV_TEST_TAG)" github.com/gravitational/teleport/tool/tsh $(FLAGS) $(ADDFLAGS) \

# Runs ci tsh tests
.PHONY: test-go-tsh
test-go-tsh: FLAGS ?= -race -shuffle on
test-go-tsh: SUBJECT ?= github.com/gravitational/teleport/tool/tsh
test-go-tsh:
$(CGOFLAG_TSH) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(LIBFIDO2_TEST_TAG) $(TOUCHID_TAG) $(PIV_TEST_TAG)" $(PACKAGES) $(SUBJECT) $(FLAGS) $(ADDFLAGS) \
| tee $(TEST_LOG_DIR)/unit.json \
| ${RENDER_TESTS}

# Chaos tests have high concurrency, run without race detector and have TestChaos prefix.
.PHONY: test-go-chaos
test-go-chaos: CHAOS_FOLDERS = $(shell find . -type f -name '*chaos*.go' | xargs dirname | uniq)
test-go-chaos:
$(CGOFLAG) go test -cover -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG) $(RDPCLIENT_TAG)" -test.run=TestChaos $(CHAOS_FOLDERS) \
| tee $(TEST_LOG_DIR)/chaos.json \
| ${RENDER_TESTS}

# Runs ci scripts tests
.PHONY: test-ci
test-ci: $(TEST_LOG_DIR) $(RENDER_TESTS)
(cd .cloudbuild/scripts && \
Expand All @@ -663,11 +698,11 @@ test-go-root: $(VERSRC)
# Runs Go tests on the api module. These have to be run separately as the package name is different.
#
.PHONY: test-api
test-api:
test-api: FLAGS ?= -race -shuffle on
test-api: PACKAGES = $(shell cd api && go list ./...)
test-api: $(VERSRC) $(TEST_LOG_DIR) $(RENDER_TESTS)
$(CGOFLAG) go test -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG)" $(PACKAGES) $(FLAGS) $(ADDFLAGS) \
test-api: FLAGS ?= -race -shuffle on
test-api: SUBJECT ?= $(shell cd api && go list ./...)
test-api:
cd api && $(CGOFLAG) go test -json -tags "$(PAM_TAG) $(FIPS_TAG) $(BPF_TAG)" $(PACKAGES) $(SUBJECT) $(FLAGS) $(ADDFLAGS) \
| tee $(TEST_LOG_DIR)/api.json \
| ${RENDER_TESTS}

Expand Down
1 change: 1 addition & 0 deletions build.assets/tooling/cmd/difftest/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
difftest
40 changes: 40 additions & 0 deletions build.assets/tooling/cmd/difftest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# difftest

This tool finds tests which were changed since a previous git revision.

## Usage

To see changes:

```
difftest diff --path . --branch master
```

To get `go test` flags to run only newly appeared tests:

```
difftest test --path . --branch master --exclude-updates
```

## How it works

1. Calls `git diff $(git merge-base --fork-point <branch>)`
2. Filters all added/modified files ending with `_test.go`.
3. Builds a map of `Test*` methods in every file.
4. Calculates `SHA1` hash of each method body.
5. Does the same for the counterpart files at the fork point.
6. Compares the results. If a method was not there previously, it's marked as new. If a method's contents was changed, it is marked as changed.

## `testify/suite` support

1. Tool detects suite start signatures like the following:

```
func TestSingleSuite(t *testing.T) { suite.Run(t, &SingleSuite{}) }
```
where `suite` references to `testify/suite` package, and `t` references `testing` package.
2. All methods related to a single suite must be in the same package (directory).
3. All suite parts must redside in a files matching `*_test.go` pattern.
3. If a test method has a receiver, which was not detected as a `testify/suite` previously, such method got skipped.
Loading

0 comments on commit a496783

Please sign in to comment.