Skip to content

Commit 6b3a8f3

Browse files
authored
Define an experimental event stream version and use it to conditionalize relevant content (#1287)
This PR formally defines an "experimental" event stream version (named `ABI.ExperimentalVersion`) which represents content that is considered experimental. It then adopts the new experimental version in several places to conditionalize the inclusion of fields on event stream models which are not yet officially included in any defined, supported version. Finally, it uses this new version everywhere that intentionally always uses the _highest experimental_ version, such as the exit test back channel and the [recently-added](#1253) experimental console output recorder. ### Motivation: The event stream now has an established versioning system (as of #956) and can easily conditionalize content based on version. As a general rule, we prefer to exclude content which has not gone through Swift Evolution review when delivering data to event stream consumers which expect to receive content from a supported version. The fields this PR conditionalizes have underscore prefixes and have code-level documentation indicating their unofficial-ness, but the fact that they are included at all in supported/non-experimental version streams could lead to misuse or unintentional breakages in the future if the names or semantics of these fields change. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 8500bd0 commit 6b3a8f3

File tree

7 files changed

+70
-26
lines changed

7 files changed

+70
-26
lines changed

Sources/Testing/ABI/ABI.swift

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ extension ABI {
4545
/// The current supported ABI version (ignoring any experimental versions.)
4646
typealias CurrentVersion = v0
4747

48-
/// The highest supported ABI version (including any experimental versions.)
48+
/// The highest defined and supported ABI version (including any experimental
49+
/// versions.)
4950
typealias HighestVersion = v6_3
5051

5152
#if !hasFeature(Embedded)
@@ -93,6 +94,39 @@ extension ABI {
9394
#endif
9495
}
9596

97+
/// The value of the environment variable flag which enables experimental event
98+
/// stream fields, if any.
99+
private let _shouldIncludeExperimentalFlags = Environment.flag(named: "SWT_EXPERIMENTAL_EVENT_STREAM_FIELDS_ENABLED")
100+
101+
extension ABI.Version {
102+
/// Whether or not experimental fields should be included when using this
103+
/// ABI version.
104+
///
105+
/// The value of this property is `true` if any of the following conditions
106+
/// are satisfied:
107+
///
108+
/// - The version number is less than 6.3. This is to preserve compatibility
109+
/// with existing clients before the inclusion of experimental fields became
110+
/// opt-in starting in 6.3.
111+
/// - The version number is greater than or equal to 6.3 and the environment
112+
/// variable flag `SWT_EXPERIMENTAL_EVENT_STREAM_FIELDS_ENABLED` is set to a
113+
/// true value.
114+
/// - The version number is greater than or equal to that of ``ABI/ExperimentalVersion``.
115+
///
116+
/// Otherwise, the value of this property is `false`.
117+
static var includesExperimentalFields: Bool {
118+
switch versionNumber {
119+
case ABI.ExperimentalVersion.versionNumber...:
120+
true
121+
case ABI.v6_3.versionNumber...:
122+
_shouldIncludeExperimentalFlags == true
123+
default:
124+
// Maintain behavior for pre-6.3 versions.
125+
true
126+
}
127+
}
128+
}
129+
96130
// MARK: - Concrete ABI versions
97131

98132
extension ABI {
@@ -125,6 +159,14 @@ extension ABI {
125159
VersionNumber(6, 3)
126160
}
127161
}
162+
163+
/// A namespace and type representing the ABI version whose symbols are
164+
/// considered experimental.
165+
enum ExperimentalVersion: Sendable, Version {
166+
static var versionNumber: VersionNumber {
167+
VersionNumber(99, 0)
168+
}
169+
}
128170
}
129171

130172
/// A namespace for ABI version 0 symbols.

Sources/Testing/ABI/Encoded/ABI.EncodedEvent.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,12 @@ extension ABI {
145145
instant = EncodedInstant(encoding: event.instant)
146146
self.messages = messages.map(EncodedMessage.init)
147147
testID = event.testID.map(EncodedTest.ID.init)
148-
if eventContext.test?.isParameterized == true {
149-
_testCase = eventContext.testCase.map(EncodedTestCase.init)
148+
149+
// Experimental fields
150+
if V.includesExperimentalFields {
151+
if eventContext.test?.isParameterized == true {
152+
_testCase = eventContext.testCase.map(EncodedTestCase.init)
153+
}
150154
}
151155
}
152156
}

Sources/Testing/ABI/Encoded/ABI.EncodedIssue.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,14 @@ extension ABI {
7272
isFailure = issue.isFailure
7373
}
7474

75-
// Experimental
76-
if let backtrace = issue.sourceContext.backtrace {
77-
_backtrace = EncodedBacktrace(encoding: backtrace, in: eventContext)
78-
}
79-
if let error = issue.error {
80-
_error = EncodedError(encoding: error, in: eventContext)
75+
// Experimental fields
76+
if V.includesExperimentalFields {
77+
if let backtrace = issue.sourceContext.backtrace {
78+
_backtrace = EncodedBacktrace(encoding: backtrace, in: eventContext)
79+
}
80+
if let error = issue.error {
81+
_error = EncodedError(encoding: error, in: eventContext)
82+
}
8183
}
8284
}
8385
}

Sources/Testing/ABI/Encoded/ABI.EncodedTest.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,29 +76,26 @@ extension ABI {
7676
/// The tags associated with the test.
7777
///
7878
/// - Warning: Tags are not yet part of the JSON schema.
79-
///
80-
/// @Metadata {
81-
/// @Available("Swift Testing ABI", introduced: 6.3)
82-
/// }
8379
var _tags: [String]?
8480

8581
init(encoding test: borrowing Test) {
8682
if test.isSuite {
8783
kind = .suite
8884
} else {
8985
kind = .function
90-
let testIsParameterized = test.isParameterized
91-
isParameterized = testIsParameterized
92-
if testIsParameterized {
93-
_testCases = test.uncheckedTestCases?.map(EncodedTestCase.init(encoding:))
94-
}
86+
isParameterized = test.isParameterized
9587
}
9688
name = test.name
9789
displayName = test.displayName
9890
sourceLocation = test.sourceLocation
9991
id = ID(encoding: test.id)
10092

101-
if V.versionNumber >= ABI.v6_3.versionNumber {
93+
// Experimental fields
94+
if V.includesExperimentalFields {
95+
if isParameterized == true {
96+
_testCases = test.uncheckedTestCases?.map(EncodedTestCase.init(encoding:))
97+
}
98+
10299
let tags = test.tags
103100
if !tags.isEmpty {
104101
_tags = tags.map(String.init(describing:))

Sources/Testing/ABI/EntryPoints/EntryPoint.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ func entryPoint(passing args: __CommandLineArguments_v0?, eventHandler: Event.Ha
5757
// Check for experimental console output flag
5858
if Environment.flag(named: "SWT_ENABLE_EXPERIMENTAL_CONSOLE_OUTPUT") == true {
5959
// Use experimental AdvancedConsoleOutputRecorder
60-
var advancedOptions = Event.AdvancedConsoleOutputRecorder<ABI.HighestVersion>.Options()
60+
var advancedOptions = Event.AdvancedConsoleOutputRecorder<ABI.ExperimentalVersion>.Options()
6161
advancedOptions.base = .for(.stderr)
6262

63-
let eventRecorder = Event.AdvancedConsoleOutputRecorder<ABI.HighestVersion>(options: advancedOptions) { string in
63+
let eventRecorder = Event.AdvancedConsoleOutputRecorder<ABI.ExperimentalVersion>(options: advancedOptions) { string in
6464
try? FileHandle.stderr.write(string)
6565
}
6666

Sources/Testing/ExitTests/ExitTest.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,10 +542,9 @@ extension ABI {
542542
/// The ABI version to use for encoding and decoding events sent over the back
543543
/// channel.
544544
///
545-
/// The back channel always uses the latest ABI version (even if experimental)
546-
/// since both the producer and consumer use this exact version of the testing
547-
/// library.
548-
fileprivate typealias BackChannelVersion = v6_3
545+
/// The back channel always uses the experimental ABI version since both the
546+
/// producer and consumer use this exact version of the testing library.
547+
fileprivate typealias BackChannelVersion = ExperimentalVersion
549548
}
550549

551550
@_spi(ForToolsIntegrationOnly)

Tests/TestingTests/SwiftPMTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ struct SwiftPMTests {
376376
}
377377
#expect(testRecords.count == 1)
378378
for testRecord in testRecords {
379-
if version.versionNumber >= ABI.v6_3.versionNumber {
379+
if version.includesExperimentalFields {
380380
#expect(testRecord._tags != nil)
381381
} else {
382382
#expect(testRecord._tags == nil)

0 commit comments

Comments
 (0)