Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test to ensure http.server.active_requests metric is set #645

Merged
merged 1 commit into from
Dec 30, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Tests/HummingbirdTests/MetricsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import XCTest
final class TestMetrics: MetricsFactory {
private let lock = NIOLock()
let counters = NIOLockedValueBox([String: CounterHandler]())
let meters = NIOLockedValueBox([String: MeterHandler]())
let recorders = NIOLockedValueBox([String: RecorderHandler]())
let timers = NIOLockedValueBox([String: TimerHandler]())

Expand All @@ -30,6 +31,12 @@ final class TestMetrics: MetricsFactory {
}
}

public func makeMeter(label: String, dimensions: [(String, String)]) -> MeterHandler {
self.meters.withLockedValue { counters in
self.make(label: label, dimensions: dimensions, registry: &counters, maker: TestMeter.init)
}
}

public func makeRecorder(label: String, dimensions: [(String, String)], aggregate: Bool) -> RecorderHandler {
let maker = { (label: String, dimensions: [(String, String)]) -> RecorderHandler in
TestRecorder(label: label, dimensions: dimensions, aggregate: aggregate)
Expand Down Expand Up @@ -64,6 +71,14 @@ final class TestMetrics: MetricsFactory {
}
}

func destroyMeter(_ handler: MeterHandler) {
if let testMeter = handler as? TestMeter {
_ = self.counters.withLockedValue { counters in
counters.removeValue(forKey: testMeter.label)
}
}
}

func destroyRecorder(_ handler: RecorderHandler) {
if let testRecorder = handler as? TestRecorder {
_ = self.recorders.withLockedValue { recorders in
Expand Down Expand Up @@ -112,6 +127,52 @@ internal final class TestCounter: CounterHandler, Equatable {
}
}

internal final class TestMeter: MeterHandler, Equatable {
let id: String
let label: String
let dimensions: [(String, String)]
let values = NIOLockedValueBox([(Date, Double)]())

init(label: String, dimensions: [(String, String)]) {
self.id = NSUUID().uuidString
self.label = label
self.dimensions = dimensions
}

func set(_ value: Int64) {
self.set(Double(value))
}

func set(_ value: Double) {
self.values.withLockedValue { values in
values.append((Date(), value))
}
print("adding \(value) to \(self.label)")
}

func increment(by: Double) {
self.values.withLockedValue { values in
let value = values.last?.1 ?? 0.0
values.append((Date(), value + by))
}
print("incrementing \(by) to \(self.label)")

}

func decrement(by: Double) {
self.values.withLockedValue { values in
let value = values.last?.1 ?? 0.0
values.append((Date(), value - by))
}
print("decrementing \(by) to \(self.label)")

}

static func == (lhs: TestMeter, rhs: TestMeter) -> Bool {
lhs.id == rhs.id
}
}

internal final class TestRecorder: RecorderHandler, Equatable {
let id: String
let label: String
Expand Down Expand Up @@ -314,4 +375,21 @@ final class MetricsTests: XCTestCase {
let timer = try XCTUnwrap(Self.testMetrics.timers.withLockedValue { $0 }["http.server.request.duration"] as? TestTimer)
XCTAssertGreaterThan(timer.values.withLockedValue { $0 }[0].1, 5_000_000)
}

func testActiveRequestsMetric() async throws {
let router = Router()
router.middlewares.add(MetricsMiddleware())
router.get("/hello") { _, _ -> Response in
Response(status: .ok)
}
let app = Application(responder: router.buildResponder())
try await app.test(.router) { client in
try await client.execute(uri: "/hello", method: .get) { _ in }
}

let meter = try XCTUnwrap(Self.testMetrics.meters.withLockedValue { $0 }["http.server.active_requests"] as? TestMeter)
let values = meter.values.withLockedValue { $0 }.map { $0.1 }
let maxValue = values.max() ?? 0.0
XCTAssertGreaterThan(maxValue, 0.0)
}
}
Loading