PatchValue (AddCleanup) unsafe with non pointer receiver test

John Meinel john at arbash-meinel.com
Thu Mar 17 04:52:53 UTC 2016


I came across this in the LXD test suite today, which was hard to track
down, so I figured I'd let everyone know about it.

We have a nice helper in testing.IsolationSuite with "PatchValue()" that
will change a global for you during the test, and then during TearDown()
will cleanup the patch it made.
It turns out that if your test doesn't have a pointer receiver this fails,
because the "suite" object is a copy, so when PatchValue calls AddCleanup
to do s.testStack = append(...) the suite object goes away before TearDown
is called.

You can see this with the attached test suite.

Example:

func (s mySuite) TestFoo(c *gc.C) {
 // This is unsafe because s.PatchValue ends up modifying s.testStack but
that attribute only exists
 // for the life of the TestFoo function
  s.PatchValue(&globalVar, "newvalue")
}

I tried adding the attached patch so that we catch places we are using
AddCleanup unsafely, but it fails a few tests I wasn't expecting, so I'm
not sure if I'm actually doing the right thing.

John
=:->
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ubuntu.com/archives/juju-dev/attachments/20160317/8d773d82/attachment.html>
-------------- next part --------------
diff --git a/cleanup.go b/cleanup.go
index 48a48bb..2b88f7e 100644
--- a/cleanup.go
+++ b/cleanup.go
@@ -18,10 +18,13 @@ type cleanupStack []CleanupFunc
 type CleanupSuite struct {
 	testStack  cleanupStack
 	suiteStack cleanupStack
+	suiteSuite *CleanupSuite
+	testSuite  *CleanupSuite
 }
 
 func (s *CleanupSuite) SetUpSuite(c *gc.C) {
 	s.suiteStack = nil
+	s.suiteSuite = s
 }
 
 func (s *CleanupSuite) TearDownSuite(c *gc.C) {
@@ -30,6 +33,7 @@ func (s *CleanupSuite) TearDownSuite(c *gc.C) {
 
 func (s *CleanupSuite) SetUpTest(c *gc.C) {
 	s.testStack = nil
+	s.testSuite = s
 }
 
 func (s *CleanupSuite) TearDownTest(c *gc.C) {
@@ -45,12 +49,18 @@ func (s *CleanupSuite) callStack(c *gc.C, stack cleanupStack) {
 // AddCleanup pushes the cleanup function onto the stack of functions to be
 // called during TearDownTest.
 func (s *CleanupSuite) AddCleanup(cleanup CleanupFunc) {
+	if s != s.testSuite {
+		panic("testSuite changed from SetUp to TearDown")
+	}
 	s.testStack = append(s.testStack, cleanup)
 }
 
 // AddSuiteCleanup pushes the cleanup function onto the stack of functions to
 // be called during TearDownSuite.
 func (s *CleanupSuite) AddSuiteCleanup(cleanup CleanupFunc) {
+	if s != s.testSuite {
+		panic("test suite changed from SetUpSuite before AddSuiteCleanup")
+	}
 	s.suiteStack = append(s.suiteStack, cleanup)
 }
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: cleanup_test.go
Type: text/x-go
Size: 827 bytes
Desc: not available
URL: <https://lists.ubuntu.com/archives/juju-dev/attachments/20160317/8d773d82/attachment.bin>


More information about the Juju-dev mailing list