Skip to content

Commit d597758

Browse files
committed
Add error forcing mechanics
1 parent 0c0ebf6 commit d597758

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

Sources/App/Commands/Ingest.swift

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import Dependencies
1516
import Fluent
1617
import PostgresKit
1718
import Vapor
@@ -168,13 +169,17 @@ func ingest(client: Client,
168169
extension Ingestion {
169170
static func ingest(client: Client, database: Database, package: Joined<Package, Repository>) async {
170171
let result = await Result { () async throws(Ingestion.Error) -> Joined<Package, Repository> in
172+
@Dependency(\.environment) var environment
171173
Current.logger().info("Ingesting \(package.package.url)")
172174

173175
// Even though we have a `Joined<Package, Repository>` as a parameter, we must not rely
174176
// on `repository` for owner/name as it will be nil when a package is first ingested.
175177
// The only way to get `owner` and `repository` here is by parsing them from the URL.
176178
let (owner, repository) = try await run {
177-
try Github.parseOwnerName(url: package.model.url)
179+
if environment.shouldFail(failureMode: .invalidURL) {
180+
throw Github.Error.invalidURL(package.model.url)
181+
}
182+
return try Github.parseOwnerName(url: package.model.url)
178183
} rethrowing: { _ in
179184
Ingestion.Error.invalidURL(packageId: package.model.id!, url: package.model.url)
180185
}
@@ -223,7 +228,12 @@ extension Ingestion {
223228

224229
static func findOrCreateRepository(on database: Database, for package: Joined<Package, Repository>) async throws(Ingestion.Error) -> Repository {
225230
try await run {
226-
try await Repository.findOrCreate(on: database, for: package.model)
231+
@Dependency(\.environment) var environment
232+
if environment.shouldFail(failureMode: .findOrCreateRepositoryFailed) {
233+
throw Abort(.internalServerError)
234+
}
235+
236+
return try await Repository.findOrCreate(on: database, for: package.model)
227237
} rethrowing: {
228238
Ingestion.Error(
229239
packageId: package.model.id!,
@@ -251,6 +261,11 @@ extension Ingestion {
251261

252262

253263
static func fetchMetadata(client: Client, package: Package, owner: String, repository: String) async throws(Github.Error) -> (Github.Metadata, Github.License?, Github.Readme?) {
264+
@Dependency(\.environment) var environment
265+
if environment.shouldFail(failureMode: .fetchMetadataFailed) {
266+
throw Github.Error.requestFailed(.internalServerError)
267+
}
268+
254269
async let metadata = try await Current.fetchMetadata(client, owner, repository)
255270
async let license = await Current.fetchLicense(client, owner, repository)
256271
async let readme = await Current.fetchReadme(client, owner, repository)
@@ -286,6 +301,20 @@ func updateRepository(on database: Database,
286301
readmeInfo: Github.Readme?,
287302
s3Readme: S3Readme?,
288303
fork: Fork? = nil) async throws(Ingestion.Error.UnderlyingError) {
304+
@Dependency(\.environment) var environment
305+
if environment.shouldFail(failureMode: .noRepositoryMetadata) {
306+
throw .noRepositoryMetadata(owner: repository.owner, name: repository.name)
307+
}
308+
if environment.shouldFail(failureMode: .repositorySaveFailed) {
309+
throw .repositorySaveFailed(owner: repository.owner,
310+
name: repository.name,
311+
details: "TestError")
312+
}
313+
if environment.shouldFail(failureMode: .repositorySaveUniqueViolation) {
314+
throw .repositorySaveUniqueViolation(owner: repository.owner,
315+
name: repository.name,
316+
details: "TestError")
317+
}
289318
guard let repoMetadata = metadata.repository else {
290319
throw .noRepositoryMetadata(owner: repository.owner, name: repository.name)
291320
}

Sources/App/Core/Dependencies/EnvironmentClient.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ struct EnvironmentClient {
4444
var mastodonCredentials: @Sendable () -> Mastodon.Credentials?
4545
var mastodonPost: @Sendable (_ client: Client, _ post: String) async throws -> Void
4646
var random: @Sendable (_ range: ClosedRange<Double>) -> Double = { XCTFail("random"); return Double.random(in: $0) }
47+
48+
enum FailureMode: String {
49+
case fetchMetadataFailed
50+
case findOrCreateRepositoryFailed
51+
case invalidURL
52+
case noRepositoryMetadata
53+
case repositorySaveFailed
54+
case repositorySaveUniqueViolation
55+
}
56+
var shouldFail: @Sendable (_ failureMode: FailureMode) -> Bool = { _ in false }
4757
}
4858

4959

@@ -100,7 +110,14 @@ extension EnvironmentClient: DependencyKey {
100110
.map(Mastodon.Credentials.init(accessToken:))
101111
},
102112
mastodonPost: { client, message in try await Mastodon.post(client: client, message: message) },
103-
random: { range in Double.random(in: range) }
113+
random: { range in Double.random(in: range) },
114+
shouldFail: { failureMode in
115+
let shouldFail = Environment.get("FAILURE_MODE")
116+
.map { Data($0.utf8) }
117+
.flatMap { try? JSONDecoder().decode([String: Double].self, from: $0) } ?? [:]
118+
guard let rate = shouldFail[failureMode.rawValue] else { return false }
119+
return Double.random(in: 0...1) <= rate
120+
}
104121
)
105122
}
106123
}

app.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ x-shared: &shared
4646
DATABASE_USERNAME: ${DATABASE_USERNAME}
4747
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
4848
DATABASE_USE_TLS: ${DATABASE_USE_TLS}
49+
FAILURE_MODE: ${FAILURE_MODE}
4950
GITHUB_TOKEN: ${GITHUB_TOKEN}
5051
GITLAB_API_TOKEN: ${GITLAB_API_TOKEN}
5152
GITLAB_PIPELINE_LIMIT: ${GITLAB_PIPELINE_LIMIT}

0 commit comments

Comments
 (0)