-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(cli): prevent test interference (#32270)
Our CLI unit tests were interfering with each other because they were writing files from and to the current directory, which is shared between all of them. Solve it by making a non-writeable directory before running the tests, so that the tests that do that start throwing errors and we can identify them. Then fix those. I tried papering over the issue by trying to create tempdirs automatically, but that started to introduce all kinds of errors in tests that were already doing tempdir management themselves, and it took too long to go and figure out what was wrong there, so I'm doing this instead. Also in this PR: - Switch off global `silent` mode for the tests. It's very annoying if `console.log` statements don't make it out when you're debugging. - This PR caused a couple of lines in `init.ts` to be useless (they were there for tests), and removing those causes a lack of coverage in `init.ts`'s entirety, so add some tests for that file. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
- Loading branch information
Showing
6 changed files
with
143 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import * as fs from 'fs'; | ||
import * as os from 'os'; | ||
import * as path from 'path'; | ||
import { isPromise } from 'util/types'; | ||
|
||
/** | ||
* Global test setup for Jest tests | ||
* | ||
* It's easy to accidentally write tests that interfere with each other by | ||
* writing files to disk in the "current directory". To prevent this, the global | ||
* test setup creates a directory in the temporary directory and chmods it to | ||
* being non-writable. That way, whenever a test tries to write to the current | ||
* directory, it will produce an error and we'll be able to find and fix the | ||
* test. | ||
* | ||
* If you see `EACCES: permission denied`, you have a test that creates files | ||
* in the current directory, and you should be sure to do it in a temporary | ||
* directory that you clean up afterwards. | ||
* | ||
* ## Alternate approach | ||
* | ||
* I tried an approach where I would automatically try to create and clean up | ||
* temp directories for every test, but it was introducing too many conflicts | ||
* with existing test behavior (around specific ordering of temp directory | ||
* creation and cleanup tasks that are already present) in many places that I | ||
* didn't want to go and chase down. | ||
* | ||
*/ | ||
|
||
let tmpDir: string; | ||
let oldDir: string; | ||
|
||
beforeAll(() => { | ||
tmpDir = path.join(os.tmpdir(), 'cdk-nonwritable-on-purpose'); | ||
fs.mkdirSync(tmpDir, { recursive: true }); | ||
fs.chmodSync(tmpDir, 0o500); | ||
oldDir = process.cwd(); | ||
process.chdir(tmpDir); | ||
tmpDir = process.cwd(); // This will have resolved symlinks | ||
}); | ||
|
||
const reverseAfterAll: Array<jest.ProvidesHookCallback> = []; | ||
|
||
/** | ||
* We need a cleanup here | ||
* | ||
* 99% of the time, Jest runs the tests in a subprocess and this isn't | ||
* necessary because we would have `chdir`ed in the subprocess. | ||
* | ||
* But sometimes we ask Jest with `-i` to run the tests in the main process, | ||
* or if you only ask for a single test suite Jest runs the tests in the main | ||
* process, and then we `chdir`ed the main process away. | ||
* | ||
* Jest will then try to write the `coverage` directory to the readonly directory, | ||
* and fail. Chdir back to the original dir. | ||
* | ||
* If the test file has an `afterAll()` hook it installed as well, we need to run | ||
* it before our cleanup, otherwise the wrong thing will happen (by default, | ||
* all `afterAll()`s run in call order, but they should be run in reverse). | ||
*/ | ||
afterAll(async () => { | ||
for (const aft of reverseAfterAll.reverse()) { | ||
await new Promise<void>((resolve, reject) => { | ||
const response = aft(resolve as any); | ||
if (isPromise(response)) { | ||
response.then(() => { return resolve(); }, reject); | ||
} else { | ||
resolve(); | ||
} | ||
}); | ||
} | ||
|
||
// eslint-disable-next-line no-console | ||
process.stderr.write(`${process.cwd()}, ${tmpDir}\n`); | ||
if (process.cwd() === tmpDir) { | ||
// eslint-disable-next-line no-console | ||
process.stderr.write('chmod\n'); | ||
process.chdir(oldDir); | ||
} | ||
}); | ||
|
||
// Patch afterAll to make later-provided afterAll's run before us (in reverse order even). | ||
afterAll = (after: jest.ProvidesHookCallback) => { | ||
reverseAfterAll.push(after); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters