Skip to content

Commit b461f8f

Browse files
authored
Add Release Test Run Profiles (#856)
* Add Release Test Run Profiles Add two new test run profiles, `Run Tests (Release Mode)` and `Debug Tests (Release Mode)`. These are identical to their Debug mode counterparts, except they pass `-c release` during the build. Adds tests to ensure that tests are being run in either debug or release mode. These can be quite slow, so they've been tagged with @slow. @slow tests are not run during CI runs. The plan is in the future to add a nightly test suite that runs the full suite. This should keep CI fast while allowing us to catch issues that may manifest in expensive tests. * Consistently check if test kind is debug * Rename isDebug to isDebugging * Run fast test suite in CI
1 parent 0d67749 commit b461f8f

File tree

8 files changed

+429
-229
lines changed

8 files changed

+429
-229
lines changed

assets/test/defaultPackage/Tests/PackageTests/PackageTests.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ final class MixedXCTestSuite: XCTestCase {
2424
}
2525
}
2626

27+
final class DebugReleaseTestSuite: XCTestCase {
28+
func testRelease() throws {
29+
#if DEBUG
30+
XCTFail("Test was run in debug mode.")
31+
#endif
32+
}
33+
34+
func testDebug() throws {
35+
#if RELEASE
36+
XCTFail("Test was run in release mode.")
37+
#endif
38+
}
39+
}
40+
2741
#if swift(>=6.0)
2842
import Testing
2943

@@ -37,6 +51,18 @@ func parameterizedTest(_ arg: Int) {
3751
#expect(arg != 2)
3852
}
3953

54+
@Test func testRelease() throws {
55+
#if DEBUG
56+
Issue.record("Test was run in debug mode.")
57+
#endif
58+
}
59+
60+
@Test func testDebug() throws {
61+
#if RELEASE
62+
Issue.record("Test was run in release mode.")
63+
#endif
64+
}
65+
4066
@Suite
4167
struct MixedSwiftTestingSuite {
4268
@Test

docker/docker-compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ services:
1414
image: vscode-swift:default
1515
environment:
1616
- CI=1
17+
- FAST_TEST_RUN=1
1718
depends_on: [runtime-setup]
1819
volumes:
1920
- ~/.ssh:/root/.ssh

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,8 +1162,8 @@
11621162
"watch": "tsc --watch",
11631163
"lint": "eslint ./ --ext ts && tsc --noEmit",
11641164
"format": "prettier --check src test",
1165-
"pretest": "npm run compile && npm run lint",
1166-
"test": "find ./assets/test -type d -name '.build' -exec rm -rf {} + && find . -type d -name 'Package.resolved' -exec rm -rf {} + && tsc -p ./ && node ./out/test/runTest.js",
1165+
"pretest": "npm run compile && npm run lint && find ./assets/test -type d -name '.build' -exec rm -rf {} + && find . -type d -name 'Package.resolved' -exec rm -rf {} + && tsc -p ./",
1166+
"test": "node ./out/test/runTest.js",
11671167
"coverage": "c8 --clean npm run test",
11681168
"compile-tests": "find ./assets/test -type d -name '.build' -exec rm -rf {} + && npm run compile && npm run esbuild",
11691169
"package": "vsce package",
@@ -1201,4 +1201,4 @@
12011201
"vscode-languageclient": "^9.0.1",
12021202
"xml2js": "^0.6.2"
12031203
}
1204-
}
1204+
}

src/TestExplorer/TestKind.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the VS Code Swift open source project
4+
//
5+
// Copyright (c) 2021-2024 the VS Code Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of VS Code Swift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
/** Workspace Folder events */
16+
export enum TestKind {
17+
// run tests serially
18+
standard = "Run Tests",
19+
// run tests in parallel
20+
parallel = "Run Tests (Parallel)",
21+
// run tests and extract test coverage
22+
coverage = "Run With Test Coverage",
23+
// run tests with the debugger
24+
debug = "Debug Tests",
25+
// run tests compiled in release mode
26+
release = "Run Tests (Release Mode)",
27+
// run tests compiled in release mode with debugger
28+
debugRelease = "Debug Tests (Release Mode)",
29+
}
30+
31+
export function isDebugging(testKind: TestKind): boolean {
32+
return testKind === TestKind.debug || testKind === TestKind.debugRelease;
33+
}
34+
35+
export function isRelease(testKind: TestKind): boolean {
36+
return testKind === TestKind.release || testKind === TestKind.debugRelease;
37+
}

src/TestExplorer/TestRunner.ts

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,7 @@ import { TestClass, runnableTag, upsertTestItem } from "./TestDiscovery";
3838
import { TestCoverage } from "../coverage/LcovResults";
3939
import { TestingDebugConfigurationFactory } from "../debugger/buildConfig";
4040
import { SwiftExecution } from "../tasks/SwiftExecution";
41-
42-
/** Workspace Folder events */
43-
export enum TestKind {
44-
// run tests serially
45-
standard = "Standard",
46-
// run tests in parallel
47-
parallel = "Parallel",
48-
// run tests and extract test coverage
49-
coverage = "Coverage",
50-
// run tests and extract test coverage
51-
debug = "Debug",
52-
}
53-
54-
export enum RunProfileName {
55-
run = "Run Tests",
56-
runParallel = "Run Tests (Parallel)",
57-
coverage = "Test Coverage",
58-
debug = "Debug Tests",
59-
}
41+
import { TestKind, isDebugging, isRelease } from "./TestKind";
6042

6143
export enum TestLibrary {
6244
xctest = "XCTest",
@@ -248,7 +230,7 @@ export class TestRunner {
248230
) {
249231
this.testArgs = new TestRunArguments(
250232
this.ensureRequestIncludesTests(this.request),
251-
testKind === TestKind.debug
233+
isDebugging(testKind)
252234
);
253235
this.testRun = new TestRunProxy(request, controller, this.testArgs, folderContext);
254236
this.xcTestOutputParser =
@@ -291,9 +273,9 @@ export class TestRunner {
291273
onCreateTestRun: vscode.EventEmitter<TestRunProxy>
292274
): vscode.TestRunProfile[] {
293275
return [
294-
// Add non-debug profile
276+
// Add non-debug profiles
295277
controller.createRunProfile(
296-
RunProfileName.run,
278+
TestKind.standard,
297279
vscode.TestRunProfileKind.Run,
298280
async (request, token) => {
299281
const runner = new TestRunner(
@@ -308,9 +290,8 @@ export class TestRunner {
308290
true,
309291
runnableTag
310292
),
311-
// Add non-debug profile
312293
controller.createRunProfile(
313-
RunProfileName.runParallel,
294+
TestKind.parallel,
314295
vscode.TestRunProfileKind.Run,
315296
async (request, token) => {
316297
const runner = new TestRunner(
@@ -325,9 +306,25 @@ export class TestRunner {
325306
false,
326307
runnableTag
327308
),
309+
controller.createRunProfile(
310+
TestKind.release,
311+
vscode.TestRunProfileKind.Run,
312+
async (request, token) => {
313+
const runner = new TestRunner(
314+
TestKind.release,
315+
request,
316+
folderContext,
317+
controller
318+
);
319+
onCreateTestRun.fire(runner.testRun);
320+
await runner.runHandler(token);
321+
},
322+
false,
323+
runnableTag
324+
),
328325
// Add coverage profile
329326
controller.createRunProfile(
330-
RunProfileName.coverage,
327+
TestKind.coverage,
331328
vscode.TestRunProfileKind.Coverage,
332329
async (request, token) => {
333330
const runner = new TestRunner(
@@ -350,7 +347,7 @@ export class TestRunner {
350347
),
351348
// Add debug profile
352349
controller.createRunProfile(
353-
RunProfileName.debug,
350+
TestKind.debug,
354351
vscode.TestRunProfileKind.Debug,
355352
async (request, token) => {
356353
const runner = new TestRunner(
@@ -365,6 +362,22 @@ export class TestRunner {
365362
false,
366363
runnableTag
367364
),
365+
controller.createRunProfile(
366+
TestKind.debugRelease,
367+
vscode.TestRunProfileKind.Debug,
368+
async (request, token) => {
369+
const runner = new TestRunner(
370+
TestKind.debugRelease,
371+
request,
372+
folderContext,
373+
controller
374+
);
375+
onCreateTestRun.fire(runner.testRun);
376+
await runner.runHandler(token);
377+
},
378+
false,
379+
runnableTag
380+
),
368381
];
369382
}
370383

@@ -377,7 +390,7 @@ export class TestRunner {
377390
async runHandler(token: vscode.CancellationToken) {
378391
const runState = new TestRunnerTestRunState(this.testRun);
379392
try {
380-
if (this.testKind === TestKind.debug) {
393+
if (isDebugging(this.testKind)) {
381394
await this.debugSession(token, runState);
382395
} else {
383396
await this.runSession(token, runState);
@@ -549,7 +562,13 @@ export class TestRunner {
549562
kindLabel = " In Parallel";
550563
break;
551564
case TestKind.debug:
552-
kindLabel = "For Debugging";
565+
kindLabel = " For Debugging";
566+
break;
567+
case TestKind.release:
568+
kindLabel = " in Release Mode";
569+
break;
570+
case TestKind.debugRelease:
571+
kindLabel = " For Debugging in Release Mode";
553572
break;
554573
case TestKind.standard:
555574
kindLabel = "";
@@ -662,6 +681,17 @@ export class TestRunner {
662681
return;
663682
}
664683

684+
if (isRelease(this.testKind)) {
685+
buildAllTask.definition.args = [
686+
...buildAllTask.definition.args,
687+
"-c",
688+
"release",
689+
"-Xswiftc",
690+
"-enable-testing",
691+
];
692+
buildAllTask.detail = `swift ${buildAllTask.definition.args.join(" ")}`;
693+
}
694+
665695
const subscriptions: vscode.Disposable[] = [];
666696
let buildExitCode = 0;
667697
const buildTask = vscode.tasks.onDidStartTask(e => {
@@ -699,20 +729,21 @@ export class TestRunner {
699729
const swiftTestBuildConfig = TestingDebugConfigurationFactory.swiftTestingConfig(
700730
this.folderContext,
701731
fifoPipePath,
702-
TestKind.debug,
732+
this.testKind,
703733
this.testArgs.swiftTestArgs,
704734
true
705735
);
706736

707737
if (swiftTestBuildConfig !== null) {
708-
// output test build configuration
709-
if (configuration.diagnostics) {
710-
const configJSON = JSON.stringify(swiftTestBuildConfig);
711-
this.workspaceContext.outputChannel.logDiagnostic(
712-
`swift-testing Debug Config: ${configJSON}`,
713-
this.folderContext.name
714-
);
715-
}
738+
swiftTestBuildConfig.testType = TestLibrary.swiftTesting;
739+
swiftTestBuildConfig.preLaunchTask = null;
740+
741+
// If we're testing in both frameworks we're going to start more than one debugging
742+
// session. If both build configurations have the same name LLDB will replace the
743+
// output of the first one in the Debug Console with the output of the second one.
744+
// If they each have a unique name the Debug Console gets a nice dropdown the user
745+
// can switch between to see the output for both sessions.
746+
swiftTestBuildConfig.name = `Swift Testing: ${swiftTestBuildConfig.name}`;
716747

717748
// output test build configuration
718749
if (configuration.diagnostics) {
@@ -723,15 +754,6 @@ export class TestRunner {
723754
);
724755
}
725756

726-
swiftTestBuildConfig.testType = TestLibrary.swiftTesting;
727-
swiftTestBuildConfig.preLaunchTask = null;
728-
729-
// If we're testing in both frameworks we're going to start more than one debugging
730-
// session. If both build configurations have the same name LLDB will replace the
731-
// output of the first one in the Debug Console with the output of the second one.
732-
// If they each have a unique name the Debug Console gets a nice dropdown the user
733-
// can switch between to see the output for both sessions.
734-
swiftTestBuildConfig.name = `Swift Testing: ${swiftTestBuildConfig.name}`;
735757
buildConfigs.push(swiftTestBuildConfig);
736758
}
737759
}
@@ -740,12 +762,16 @@ export class TestRunner {
740762
if (this.testArgs.hasXCTests) {
741763
const xcTestBuildConfig = TestingDebugConfigurationFactory.xcTestConfig(
742764
this.folderContext,
743-
TestKind.debug,
765+
this.testKind,
744766
this.testArgs.xcTestArgs,
745767
true
746768
);
747769

748770
if (xcTestBuildConfig !== null) {
771+
xcTestBuildConfig.testType = TestLibrary.xctest;
772+
xcTestBuildConfig.preLaunchTask = null;
773+
xcTestBuildConfig.name = `XCTest: ${xcTestBuildConfig.name}`;
774+
749775
// output test build configuration
750776
if (configuration.diagnostics) {
751777
const configJSON = JSON.stringify(xcTestBuildConfig);
@@ -755,9 +781,6 @@ export class TestRunner {
755781
);
756782
}
757783

758-
xcTestBuildConfig.testType = TestLibrary.xctest;
759-
xcTestBuildConfig.preLaunchTask = null;
760-
xcTestBuildConfig.name = `XCTest: ${xcTestBuildConfig.name}`;
761784
buildConfigs.push(xcTestBuildConfig);
762785
}
763786
}

0 commit comments

Comments
 (0)