-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathKnownTests.swift
More file actions
157 lines (136 loc) · 5.3 KB
/
Copy pathKnownTests.swift
File metadata and controls
157 lines (136 loc) · 5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2020-Present Datadog, Inc.
*/
import Foundation
internal import EventsExporter
final class KnownTests: TestHooksFeature {
static var id: FeatureId = "Known Tests"
let modules: [String: Module]
init(tests: KnownTestsMap) {
let mapped = tests.map { (name, suites) in
(name, Module(name: name, suites: suites))
}
self.modules = Dictionary(uniqueKeysWithValues: mapped)
}
func isKnown(test: String, in suite: String, and module: String) -> Bool {
modules[module]?.suites[suite]?.tests.contains(test) ?? false
}
func isNew(test: String, in suite: String, and module: String) -> Bool {
!isKnown(test: test, in: suite, and: module)
}
func isNew(test: any TestRun) -> Bool {
isNew(test: test.name, in: test.suite.name, and: test.module.name)
}
func testWillStart(test: any TestRun, info: TestRunInfoStart) {
// Mark new tests
if isNew(test: test) {
test.set(tag: DDTestTags.testIsNew, value: "true")
}
}
func stop() {}
}
extension KnownTests {
struct Module {
let name: String
let suites: [String: Suite]
init(name: String, suites: [String: [String]]) {
let mapped = suites.map { (name, tests) in
(name, Suite(name: name, tests: tests))
}
self.name = name
self.suites = Dictionary(uniqueKeysWithValues: mapped)
}
}
struct Suite {
let name: String
let tests: Set<String>
init(name: String, tests: [String]) {
self.name = name
self.tests = Set(tests)
}
}
}
struct KnownTestsFactory: FeatureFactory {
typealias FT = KnownTests
let repository: String
let service: String
let environment: String
let configurations: [String: String]
let customConfigurations: [String: String]
let cacheFolder: Directory
let api: KnownTestsApi
let telemetry: Telemetry?
let cacheFileName = "known_tests.json"
init(repository: String, service: String, environment: String,
configurations: [String: String], custom: [String: String],
api: KnownTestsApi, cache: Directory, telemetry: Telemetry? = nil)
{
self.configurations = configurations
self.customConfigurations = custom
self.cacheFolder = cache
self.repository = repository
self.service = service
self.environment = environment
self.api = api
self.telemetry = telemetry
}
static func isEnabled(config: Config, env: Environment, remote: TracerSettings) -> Bool {
remote.knownTestsEnabled
}
func create(log: Logger) async throws -> KnownTests {
if let tests = loadTestsFromDisk(log: log) {
log.debug("Known Tests Enabled")
return KnownTests(tests: tests)
}
let tests = try await fetchTests()
saveTests(tests: tests)
log.debug("Known Tests Enabled")
return KnownTests(tests: tests)
}
private func loadTestsFromDisk(log: Logger) -> KnownTestsMap? {
guard cacheFolder.hasFile(named: cacheFileName) else { return nil }
guard let data = try? cacheFolder.file(named: cacheFileName).read() else {
log.print("Known Tests: Can't read \(cacheFileName) from \(cacheFolder)")
return nil
}
do {
let tests = try JSONDecoder().decode(KnownTestsMap.self, from: data)
log.debug("Known Tests: loaded tests: \(tests)")
return tests
} catch {
log.print("Known Tests: Can't decode tests data: \(error)")
return nil
}
}
private func fetchTests() async throws -> KnownTestsMap {
let result: KnownTestsResult
do {
result = try await api.tests(service: service, env: environment,
repositoryURL: repository,
configurations: configurations,
customConfigurations: customConfigurations,
observer: telemetry?.knownTestsRequestObserver)
} catch {
throw LibraryConfigurationCommunicationError(
requestName: "Known Tests Request",
payload: "service: \(service), env: \(environment)",
error: error
)
}
if let telemetry {
let totalTests = result.tests.values.flatMap { $0.values }.reduce(0) { $0 + $1.count }
telemetry.metrics.knownTests.responseTests.record(Double(totalTests))
}
// if we have empty array we should disable Known Tests functionality
guard result.tests.count > 0 else { throw FeatureEmptyResponseError(featureName: "Known Tests") }
return result.tests
}
private func saveTests(tests: KnownTestsMap) {
if let data = try? JSONEncoder().encode(tests) {
let testsFile = try? cacheFolder.createFile(named: cacheFileName)
try? testsFile?.append(data: data)
}
}
}