Description of feature
commands/stub_task_test.go drives the apply and plan executors without a server by registering a dokku_stub task that reads its canned result out of a process-wide map. stubFixtures is a map[string]StubFixture keyed by a short caller-chosen string, guarded by stubMu, and stubReset() wipes the whole map - which every test calls as its first deferred statement.
The mutex means there is no data race, but the map is still one shared namespace. Two tests running at the same time and both calling stubSet("a", ...) clobber each other, and either one's stubReset() erases the other's fixtures mid-run. Sixteen test files depend on it, so this is the largest of the three things standing between commands/ and t.Parallel().
The fix is the same move ContextWithRunner made for the exec seam: StubTask reads its fixture off the context rather than the package map, so each test installs its own set and the key namespace is per-test rather than per-process. Deriving keys from t.Name() would paper over the collision without removing the shared map, and would still leave stubReset() erasing another test's state.
Independent of #502's ContextWithRunner migration - the stub does not use the exec seam at all - and worth doing separately from the argv/working-directory work in #505, which it does not depend on either. All three are prerequisites for the commands/ half of #502.
Description of feature
commands/stub_task_test.godrives the apply and plan executors without a server by registering adokku_stubtask that reads its canned result out of a process-wide map.stubFixturesis amap[string]StubFixturekeyed by a short caller-chosen string, guarded bystubMu, andstubReset()wipes the whole map - which every test calls as its first deferred statement.The mutex means there is no data race, but the map is still one shared namespace. Two tests running at the same time and both calling
stubSet("a", ...)clobber each other, and either one'sstubReset()erases the other's fixtures mid-run. Sixteen test files depend on it, so this is the largest of the three things standing betweencommands/andt.Parallel().The fix is the same move
ContextWithRunnermade for the exec seam:StubTaskreads its fixture off the context rather than the package map, so each test installs its own set and the key namespace is per-test rather than per-process. Deriving keys fromt.Name()would paper over the collision without removing the shared map, and would still leavestubReset()erasing another test's state.Independent of #502's
ContextWithRunnermigration - the stub does not use the exec seam at all - and worth doing separately from the argv/working-directory work in #505, which it does not depend on either. All three are prerequisites for thecommands/half of #502.