Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suite may race when its test creates goroutine #1168

Closed
lance6716 opened this issue Mar 18, 2022 · 5 comments
Closed

suite may race when its test creates goroutine #1168

lance6716 opened this issue Mar 18, 2022 · 5 comments
Labels
concurrency pkg-suite Change related to package testify/suite rejected/invalid Not a bug but a misunderstanding by the requester

Comments

@lance6716
Copy link

lance6716 commented Mar 18, 2022

in testify/suite/suite_test.go

// SuiteGoroutineRace is intended to test there should be no race when creating
// goroutine in tests.
type SuiteGoroutineRace struct{ Suite }

// TestSuiteRequireTwice...
func TestSuiteGoroutineRace(t *testing.T) {
	ok := testing.RunTests(
		allTestsFilter,
		[]testing.InternalTest{{
			Name: "TestSuiteGoroutineRace",
			F: func(t *testing.T) {
				suite := new(SuiteGoroutineRace)
				Run(t, suite)
			},
		}},
	)
	assert.Equal(t, true, ok)
}

func (s *SuiteGoroutineRace) TestGoroutine() {
	go func() {
		s.Equal(1, 1)
		s.Equal(1, 1)
		s.Equal(1, 1)
	}()
	go func() {
		s.Equal(1, 1)
		s.Equal(1, 1)
		s.Equal(1, 1)
	}()
	go func() {
		s.Equal(1, 1)
		s.Equal(1, 1)
		s.Equal(1, 1)
	}()
}
=== RUN   TestSuiteGoroutineRace
=== RUN   TestSuiteGoroutineRace
=== CONT  TestSuiteGoroutineRace
    testing.go:1152: race detected during execution of test
--- FAIL: TestSuiteGoroutineRace (0.01s)
=== RUN   TestSuiteGoroutineRace/TestGoroutine
==================
WARNING: DATA RACE
Write at 0x00c0000b8150 by goroutine 9:
  github.com/stretchr/testify/suite.(*Suite).SetT()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite.go:36 +0xc4
  github.com/stretchr/testify/suite.(*SuiteGoroutineRace).SetT()
      <autogenerated>:1 +0x44
  github.com/stretchr/testify/suite.Run.func1.1()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite.go:144 +0x2f4
  github.com/stretchr/testify/suite.Run.func1()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite.go:159 +0x71f
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1259 +0x22f
  testing.(*T).Run·dwrap·21()
      /usr/local/go/src/testing/testing.go:1306 +0x47

Previous read at 0x00c0000b8150 by goroutine 10:
  github.com/stretchr/testify/suite.(*SuiteGoroutineRace).TestGoroutine.func1()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite_test.go:612 +0x36

Goroutine 9 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1306 +0x726
  github.com/stretchr/testify/suite.runTests()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite.go:203 +0x18f
  github.com/stretchr/testify/suite.Run()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite.go:176 +0x994
  github.com/stretchr/testify/suite.TestSuiteGoroutineRace.func1()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite_test.go:603 +0x44
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1259 +0x22f
  testing.(*T).Run·dwrap·21()
      /usr/local/go/src/testing/testing.go:1306 +0x47

Goroutine 10 (finished) created at:
  github.com/stretchr/testify/suite.(*SuiteGoroutineRace).TestGoroutine()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite_test.go:611 +0x90
  runtime.call16()
      /usr/local/go/src/runtime/asm_amd64.s:625 +0x48
  reflect.Value.Call()
      /usr/local/go/src/reflect/value.go:339 +0xd7
  github.com/stretchr/testify/suite.Run.func1()
      /home/lance/go/src/github.com/stretchr/testify/suite/suite.go:158 +0x71c
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1259 +0x22f
  testing.(*T).Run·dwrap·21()
      /usr/local/go/src/testing/testing.go:1306 +0x47
==================
    testing.go:1152: race detected during execution of test
    --- FAIL: TestSuiteGoroutineRace/TestGoroutine (0.00s)

--- FAIL: TestSuiteGoroutineRace (0.01s)


=== CONT  
    testing.go:1152: race detected during execution of test
    suite_test.go:607: 
        	Error Trace:	suite_test.go:607
        	Error:      	Not equal: 
        	            	expected: true
        	            	actual  : false
        	Test:       	TestSuiteGoroutineRace
    testing.go:1152: race detected during execution of test
=== CONT  
    testing.go:1152: race detected during execution of test
FAIL
@lance6716 lance6716 changed the title suite may face race when its test creates goroutine suite may race when its test creates goroutine Mar 18, 2022
@D3Hunter
Copy link

cannot reproduce locally

maybe paste complete code, some symbol is missing

@lance6716
Copy link
Author

How about we add a Suite.Go(func()) that wraps a wait group? And we expect user to use this helper.

Our usage is in tests, we spawn a new goroutine to do some asynchronizing job, in the main test goroutine there is barrier to make sure the job is finished.

// in test function
go func() {
  err := someAsyncJob()
}()

but if we use suite to check the err, the checking may happen after the main test goroutine finished, so the cleaning up will cause race about checker.

@lance6716
Copy link
Author

cannot reproduce locally

maybe paste complete code, some symbol is missing

the snippet should be put in testify/suite/suite_test.go

@lichunzhu
Copy link

How about we add a Suite.Go(func()) that wraps a wait group? And we expect user to use this helper.

SGTM.

To me, it's better to help users do the right thing(close all goroutines after a test) easier.

bors bot added a commit to onflow/flow-go that referenced this issue May 10, 2022
2293: Fix race detector issues. r=zhangchiqing a=SaveTheRbtz

While exploring code base I've stumbled upon a couple of race-detector problems. Most of them are harmless issues that only affect test flakiness.  Nevertheless, here is a sample of interesting ones:

* Unprotected `OnSucceed` callback access in badger batches: 35babdb
* Potential error clobbering in ledger migration's "storage-used" calculation: c42159f
* EpochMgr `epochs` access without lock on `Done`: a0c6cee
* `BLS12_381` verification accesses uninitialized memory: #2293 (comment)
* Unprotected global access in tests d26ca03
* Lock being copied by value by the mock framework: a89101e
* `time.Sleep` references in tests: 05a87c7
* Ignore `runtime.noescape` in `checkptr`: 1288c1d

I needed to disable the network topology test in `-race` since it was triggering the goroutine limit of the race detector
bb24d8f.  For this one we'll need to wait until the support of infinite number of goroutines is released golang/go@d6a1ffd is available (go likely 1.19).

Also there is a race condition in herocache that can be solved by either:
* Making Counter and Timestamp atomic: SaveTheRbtz@d1cc406
* Removing `logTelemetry` methods from the "read-only" methods protected only by `RLock`: SaveTheRbtz@6b0dcbd
What is the better approach here? (cc: `@yhassanzadeh13)`

Testify also has couple of nasty races in their `Suite` implementation if coupled with spawning gorouptines: stretchr/testify#1168 (comment): 4851614 71b3fdc

Looking at [race detector](https://go.dev/doc/articles/race_detector)'s ability to find timing/concurrency related problems in both tests and code it looks like it should likely be a first-class citizen in the Flow's CI/CD pipeline. WDYT about its ROI?
Seems like `@huitseeker` did look at this problem some time ago but since then race detector work was mostly abandoned.  Maybe it is possible to make it an optional part of the CI/CD pipeline, like fuzzing and benchmarking?


Co-authored-by: Alexey Ivanov <rbtz@ph34r.me>
@dolmen
Copy link
Collaborator

dolmen commented Jul 12, 2023

Calling s.Equal after the test is finished (which is what usually happens if s.Equals is called from another goroutine) is unsupported.

More generally (beyond this case) parallel testing with suite is severely broken. Don't use concurrency with suite.

@dolmen dolmen added concurrency pkg-suite Change related to package testify/suite rejected/invalid Not a bug but a misunderstanding by the requester labels Jul 12, 2023
@dolmen dolmen closed this as not planned Won't fix, can't repro, duplicate, stale Jul 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
concurrency pkg-suite Change related to package testify/suite rejected/invalid Not a bug but a misunderstanding by the requester
Projects
None yet
Development

No branches or pull requests

4 participants