Skip to content

Commit 767a260

Browse files
committed
Add W3C.TraceParent
1 parent 429e67a commit 767a260

File tree

4 files changed

+189
-20
lines changed

4 files changed

+189
-20
lines changed

Sources/W3CTraceContext/TraceContext.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
// SPDX-License-Identifier: Apache-2.0
1111
//
1212
//===----------------------------------------------------------------------===//
13+
public enum W3C {}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift W3C Trace Context open source project
4+
//
5+
// Copyright (c) YEARS Moritz Lang and the Swift W3C Trace Context project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
extension W3C {
15+
public struct TraceParent {
16+
public let traceID: String
17+
public let parentID: String
18+
public let traceFlags: String
19+
20+
public var sampled: Bool {
21+
self.traceFlags == "01"
22+
}
23+
24+
static let version = "00"
25+
}
26+
27+
// TODO: Trace State
28+
}
29+
30+
extension W3C.TraceParent: Equatable {
31+
public static func == (lhs: Self, rhs: Self) -> Bool {
32+
lhs.traceID == rhs.traceID
33+
&& lhs.parentID == rhs.parentID
34+
}
35+
}
36+
37+
extension W3C.TraceParent: RawRepresentable {
38+
public init?(rawValue: String) {
39+
let components = rawValue.split(separator: "-")
40+
guard components.count == 4 else { return nil }
41+
42+
// version
43+
let versionComponent = components[0]
44+
guard versionComponent == Self.version else { return nil }
45+
46+
// trace-id
47+
let traceIDComponent = components[1]
48+
guard traceIDComponent.count == 32 else { return nil }
49+
guard traceIDComponent != String(repeating: "0", count: 32) else { return nil }
50+
self.traceID = String(traceIDComponent)
51+
52+
// parent-id
53+
let parentIDComponent = components[2]
54+
guard parentIDComponent.count == 16 else { return nil }
55+
guard parentIDComponent != String(repeating: "0", count: 16) else { return nil }
56+
self.parentID = String(parentIDComponent)
57+
58+
// trace-flags
59+
let traceFlagsComponent = components[3]
60+
guard traceFlagsComponent.count == 2 else { return nil }
61+
self.traceFlags = String(traceFlagsComponent)
62+
}
63+
64+
public var rawValue: String {
65+
"\(Self.version)-\(self.traceID)-\(self.parentID)-\(self.traceFlags)"
66+
}
67+
}

Tests/W3CTraceContextTests/TraceContextTests.swift

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift W3C Trace Context open source project
4+
//
5+
// Copyright (c) YEARS Moritz Lang and the Swift W3C Trace Context project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
@testable import W3CTraceContext
15+
import XCTest
16+
17+
final class TraceParentRawRepresentableTests: XCTestCase {
18+
// MARK: - Trace Parent -
19+
20+
func testDecodeValidTraceParentStringWithSampledFlag() {
21+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
22+
guard let traceParent = W3C.TraceParent(rawValue: rawValue) else {
23+
XCTFail("Could not decode valid trace parent")
24+
return
25+
}
26+
27+
XCTAssertEqual(
28+
traceParent,
29+
W3C.TraceParent(traceID: "0af7651916cd43dd8448eb211c80319c", parentID: "b7ad6b7169203331", traceFlags: "01")
30+
)
31+
32+
XCTAssert(traceParent.sampled)
33+
}
34+
35+
func testDecodeValidTraceParentStringWithoutSampledFlag() {
36+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-00"
37+
guard let traceParent = W3C.TraceParent(rawValue: rawValue) else {
38+
XCTFail("Could not decode valid trace parent")
39+
return
40+
}
41+
42+
XCTAssertEqual(
43+
traceParent,
44+
W3C.TraceParent(traceID: "0af7651916cd43dd8448eb211c80319c", parentID: "b7ad6b7169203331", traceFlags: "00")
45+
)
46+
47+
XCTAssertFalse(traceParent.sampled)
48+
}
49+
50+
func testEncodesToValidRawValue() {
51+
let traceParent = W3C.TraceParent(
52+
traceID: "0af7651916cd43dd8448eb211c80319c",
53+
parentID: "b7ad6b7169203331",
54+
traceFlags: "01"
55+
)
56+
57+
XCTAssertEqual(traceParent.rawValue, "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01")
58+
}
59+
60+
func testDecodeFailsWithTooManyComponents() {
61+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01-additional-components"
62+
XCTAssertUninitializedTraceParent(rawValue)
63+
}
64+
65+
func testDecodeFailsWithTooFewComponents() {
66+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c"
67+
XCTAssertUninitializedTraceParent(rawValue)
68+
}
69+
70+
func testDecodeFailsWithInvalidVersionComponent() {
71+
let rawValue = "ff-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
72+
XCTAssertUninitializedTraceParent(rawValue)
73+
}
74+
75+
func testDecodeFailsWithTooLongTraceID() {
76+
let rawValue = "00-0af7651916cd43dd8448eb211c80319cclearlylongerthan16bytes-b7ad6b7169203331-01"
77+
XCTAssertUninitializedTraceParent(rawValue)
78+
}
79+
80+
func testDecodeFailsWithTooShortTraceID() {
81+
let rawValue = "00-tooshort-b7ad6b7169203331-01"
82+
XCTAssertUninitializedTraceParent(rawValue)
83+
}
84+
85+
func testDecodeFailsWithAllZeroesTraceID() {
86+
let rawValue = "00-00000000000000000000000000000000-b7ad6b7169203331-01"
87+
XCTAssertUninitializedTraceParent(rawValue)
88+
}
89+
90+
func testDecodeFailsWithTooShortParentID() {
91+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c-tooshort-01"
92+
XCTAssertUninitializedTraceParent(rawValue)
93+
}
94+
95+
func testDecodeFailsWithAllZeroesParentID() {
96+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c-0000000000000000-01"
97+
XCTAssertUninitializedTraceParent(rawValue)
98+
}
99+
100+
func testDecodeFailsWithTooLongTraceFlags() {
101+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-toolong"
102+
XCTAssertUninitializedTraceParent(rawValue)
103+
}
104+
105+
func testDecodeFailsWithTooShortTraceFlags() {
106+
let rawValue = "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-0"
107+
XCTAssertUninitializedTraceParent(rawValue)
108+
}
109+
110+
// TODO: Trace State
111+
}
112+
113+
private func XCTAssertUninitializedTraceParent(_ rawValue: String, file: StaticString = #file, line: UInt = #line) {
114+
if let traceParent = W3C.TraceParent(rawValue: rawValue) {
115+
XCTFail(
116+
"Expected trace parent not to be initialized from invalid raw value: \(traceParent)",
117+
file: file,
118+
line: line
119+
)
120+
}
121+
}

0 commit comments

Comments
 (0)