ci: go-test-race switch to exclude list

Most packages should pass the race detector. An exclude list ensures
that new packages are automatically tested with -race.

Also fix a couple small test races to allow more packages to be tested.

Returning readyCh requires a lock because it can be set to nil, and
setting it to nil will race without the lock.

Move the TestServer.Listening calls around so that they properly guard
setting TestServer.l. Otherwise it races.

Remove t.Parallel in a small package. The entire package tests run in a
few seconds, so t.Parallel does very little.

In auto-config, wait for the AutoConfig.run goroutine to stop before
calling readPersistedAutoConfig. Without this change there was a data
race on reading ac.config.
This commit is contained in:
Daniel Nephin 2020-11-11 13:15:33 -05:00
parent 79a1eb7daf
commit b27457dac8
7 changed files with 27 additions and 27 deletions

View File

@ -236,16 +236,15 @@ jobs:
name: go test -race name: go test -race
command: | command: |
mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile
pkgs="$(go list ./... | \
grep -E -v '^github.com/hashicorp/consul/agent(/consul|/local|/xds|/routine-leak-checker)?$' | \
grep -E -v '^github.com/hashicorp/consul/command/')"
gotestsum \ gotestsum \
--format=short-verbose \
--jsonfile /tmp/jsonfile/go-test-race.log \ --jsonfile /tmp/jsonfile/go-test-race.log \
--junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \
-tags="$GOTAGS" -p 2 \ -tags="$GOTAGS" -p 2 \
-race -gcflags=all=-d=checkptr=0 \ -race -gcflags=all=-d=checkptr=0 \
./agent/{ae,cache,cache-types,checks,config,pool,proxycfg,router}/... \ $pkgs
./agent/consul/{authmethod,fsm,state,stream}/... \
./agent/{grpc,rpc,rpcclient,submatview}/... \
./snapshot
- store_test_results: - store_test_results:
path: *TEST_RESULTS_DIR path: *TEST_RESULTS_DIR

View File

@ -634,6 +634,7 @@ type testAutoConfig struct {
ac *AutoConfig ac *AutoConfig
tokenUpdates chan struct{} tokenUpdates chan struct{}
originalToken string originalToken string
stop func()
initialRoots *structs.IndexedCARoots initialRoots *structs.IndexedCARoots
initialCert *structs.IssuedCert initialCert *structs.IssuedCert
@ -835,6 +836,7 @@ func startedAutoConfig(t *testing.T, autoEncrypt bool) testAutoConfig {
initialRoots: indexedRoots, initialRoots: indexedRoots,
initialCert: cert, initialCert: cert,
extraCerts: extraCerts, extraCerts: extraCerts,
stop: cancel,
} }
} }
@ -1098,16 +1100,15 @@ func TestFallback(t *testing.T) {
// now wait for the fallback routine to be invoked // now wait for the fallback routine to be invoked
require.True(t, waitForChans(100*time.Millisecond, fallbackCtx.Done()), "fallback routines did not get invoked within the alotted time") require.True(t, waitForChans(100*time.Millisecond, fallbackCtx.Done()), "fallback routines did not get invoked within the alotted time")
// persisting these to disk happens after the RPC we waited on above will have fired testAC.stop()
// There is no deterministic way to know once its been written so we wrap this in a retry. <-testAC.ac.done
testretry.Run(t, func(r *testretry.R) {
resp, err := testAC.ac.readPersistedAutoConfig()
require.NoError(r, err)
// ensure the roots got persisted to disk resp, err := testAC.ac.readPersistedAutoConfig()
require.Equal(r, thirdCert.CertPEM, resp.Certificate.GetCertPEM()) require.NoError(t, err)
require.Equal(r, secondRoots.ActiveRootID, resp.CARoots.GetActiveRootID())
}) // ensure the roots got persisted to disk
require.Equal(t, thirdCert.CertPEM, resp.Certificate.GetCertPEM())
require.Equal(t, secondRoots.ActiveRootID, resp.CARoots.GetActiveRootID())
} }
func TestIntroToken(t *testing.T) { func TestIntroToken(t *testing.T) {

View File

@ -5,12 +5,12 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent" "github.com/hashicorp/consul/agent"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/connect" "github.com/hashicorp/consul/connect"
"github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil"
"github.com/stretchr/testify/require"
) )
func TestUpstreamResolverFuncFromClient(t *testing.T) { func TestUpstreamResolverFuncFromClient(t *testing.T) {
@ -79,8 +79,6 @@ func TestUpstreamResolverFuncFromClient(t *testing.T) {
} }
func TestAgentConfigWatcherSidecarProxy(t *testing.T) { func TestAgentConfigWatcherSidecarProxy(t *testing.T) {
t.Parallel()
a := agent.StartTestAgent(t, agent.TestAgent{Name: "agent_smith"}) a := agent.StartTestAgent(t, agent.TestAgent{Name: "agent_smith"})
defer a.Shutdown() defer a.Shutdown()

View File

@ -5,7 +5,7 @@ import (
"net" "net"
"testing" "testing"
"github.com/hashicorp/consul/testrpc" "github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent" "github.com/hashicorp/consul/agent"
agConnect "github.com/hashicorp/consul/agent/connect" agConnect "github.com/hashicorp/consul/agent/connect"
@ -14,12 +14,10 @@ import (
"github.com/hashicorp/consul/sdk/freeport" "github.com/hashicorp/consul/sdk/freeport"
"github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil"
"github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/stretchr/testify/require" "github.com/hashicorp/consul/testrpc"
) )
func TestProxy_public(t *testing.T) { func TestProxy_public(t *testing.T) {
t.Parallel()
require := require.New(t) require := require.New(t)
ports := freeport.MustTake(1) ports := freeport.MustTake(1)

View File

@ -14,13 +14,13 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent" "github.com/hashicorp/consul/agent"
"github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/hashicorp/consul/testrpc" "github.com/hashicorp/consul/testrpc"
"github.com/stretchr/testify/require"
) )
// Assert io.Closer implementation // Assert io.Closer implementation
@ -89,8 +89,8 @@ func TestService_Dial(t *testing.T) {
err := testSvr.Serve() err := testSvr.Serve()
require.NoError(err) require.NoError(err)
}() }()
defer testSvr.Close()
<-testSvr.Listening <-testSvr.Listening
defer testSvr.Close()
} }
// Always expect to be connecting to a "DB" // Always expect to be connecting to a "DB"

View File

@ -10,11 +10,12 @@ import (
"net/http" "net/http"
"sync/atomic" "sync/atomic"
"github.com/hashicorp/go-hclog"
testing "github.com/mitchellh/go-testing-interface"
"github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/sdk/freeport" "github.com/hashicorp/consul/sdk/freeport"
"github.com/hashicorp/go-hclog"
testing "github.com/mitchellh/go-testing-interface"
) )
// TestService returns a Service instance based on a static TLS Config. // TestService returns a Service instance based on a static TLS Config.
@ -124,8 +125,8 @@ func (s *TestServer) Serve() error {
if err != nil { if err != nil {
return err return err
} }
close(s.Listening)
s.l = l s.l = l
close(s.Listening)
log.Printf("test connect service listening on %s", s.Addr) log.Printf("test connect service listening on %s", s.Addr)
for { for {

View File

@ -13,9 +13,10 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/hashicorp/go-hclog"
) )
// parseLeafX509Cert will parse an X509 certificate // parseLeafX509Cert will parse an X509 certificate
@ -460,5 +461,7 @@ func (cfg *dynamicTLSConfig) Ready() bool {
// method will not stop returning a nil chan in that case. It is only useful // method will not stop returning a nil chan in that case. It is only useful
// for initial startup. For ongoing health Ready() should be used. // for initial startup. For ongoing health Ready() should be used.
func (cfg *dynamicTLSConfig) ReadyWait() <-chan struct{} { func (cfg *dynamicTLSConfig) ReadyWait() <-chan struct{} {
cfg.RLock()
defer cfg.RUnlock()
return cfg.readyCh return cfg.readyCh
} }