add increment and decrement public API to Meter (#132)

motivation: expose increment and decrement public APIs

changes:
* add increment and decrement public API to Meter
* improve the implementation of AccumulatingMeter and TestMeter
* add tests for new APIs
* refactor/modernize other tests
This commit is contained in:
tomer doron 2023-06-21 14:15:23 -07:00 committed by GitHub
parent bf7ea93e17
commit 971ba26378
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 299 additions and 61 deletions

View File

@ -231,6 +231,36 @@ public final class Meter {
public func set<DataType: BinaryFloatingPoint>(_ value: DataType) { public func set<DataType: BinaryFloatingPoint>(_ value: DataType) {
self._handler.set(Double(value)) self._handler.set(Double(value))
} }
/// Increment the Meter.
///
/// - parameters:
/// - by: Amount to increment by.
@inlinable
public func increment<DataType: BinaryFloatingPoint>(by amount: DataType) {
self._handler.increment(by: Double(amount))
}
/// Increment the Meter by one.
@inlinable
public func increment() {
self.increment(by: 1.0)
}
/// Decrement the Meter.
///
/// - parameters:
/// - by: Amount to decrement by.
@inlinable
public func decrement<DataType: BinaryFloatingPoint>(by amount: DataType) {
self._handler.decrement(by: Double(amount))
}
/// Decrement the Meter by one.
@inlinable
public func decrement() {
self.decrement(by: 1.0)
}
} }
extension Meter { extension Meter {
@ -787,6 +817,24 @@ internal final class AccumulatingMeter: MeterHandler {
} }
func increment(by amount: Double) { func increment(by amount: Double) {
// Drop illegal values
// - cannot increment by NaN
guard !amount.isNaN else {
return
}
// - cannot increment by infinite quantities
guard !amount.isInfinite else {
return
}
// - cannot increment by negative values
guard amount.sign == .plus else {
return
}
// - cannot increment by zero
guard !amount.isZero else {
return
}
let newValue: Double = self.lock.withLock { let newValue: Double = self.lock.withLock {
self.value += amount self.value += amount
return self.value return self.value
@ -795,6 +843,24 @@ internal final class AccumulatingMeter: MeterHandler {
} }
func decrement(by amount: Double) { func decrement(by amount: Double) {
// Drop illegal values
// - cannot decrement by NaN
guard !amount.isNaN else {
return
}
// - cannot decrement by infinite quantities
guard !amount.isInfinite else {
return
}
// - cannot decrement by negative values
guard amount.sign == .plus else {
return
}
// - cannot decrement by zero
guard !amount.isZero else {
return
}
let newValue: Double = self.lock.withLock { let newValue: Double = self.lock.withLock {
self.value -= amount self.value -= amount
return self.value return self.value

View File

@ -57,7 +57,7 @@ public final class TestMetrics: MetricsFactory {
// nothing to do // nothing to do
} }
/// Reset method to destroy all created ``TestCounter``, ``TestRecorder`` and ``TestTimer``. /// Reset method to destroy all created ``TestCounter``, ``TestMeter``, ``TestRecorder`` and ``TestTimer``.
/// Invoke this method in between test runs to verify that Counters are created as needed. /// Invoke this method in between test runs to verify that Counters are created as needed.
public func reset() { public func reset() {
self.lock.withLock { self.lock.withLock {
@ -361,7 +361,7 @@ public final class TestMeter: TestMetric, MeterHandler, Equatable {
private var _values = [(Date, Double)]() private var _values = [(Date, Double)]()
init(label: String, dimensions: [(String, String)]) { init(label: String, dimensions: [(String, String)]) {
self.id = NSUUID().uuidString self.id = UUID().uuidString
self.label = label self.label = label
self.dimensions = dimensions self.dimensions = dimensions
} }
@ -378,18 +378,54 @@ public final class TestMeter: TestMetric, MeterHandler, Equatable {
} }
public func increment(by amount: Double) { public func increment(by amount: Double) {
// Drop illegal values
// - cannot increment by NaN
guard !amount.isNaN else {
return
}
// - cannot increment by infinite quantities
guard !amount.isInfinite else {
return
}
// - cannot increment by negative values
guard amount.sign == .plus else {
return
}
// - cannot increment by zero
guard !amount.isZero else {
return
}
self.lock.withLock { self.lock.withLock {
let lastValue = self._values.last?.1 ?? 0 let lastValue: Double = self._values.last?.1 ?? 0
let newValue = lastValue - amount let newValue = lastValue + amount
_values.append((Date(), Double(newValue))) _values.append((Date(), newValue))
} }
} }
public func decrement(by amount: Double) { public func decrement(by amount: Double) {
// Drop illegal values
// - cannot decrement by NaN
guard !amount.isNaN else {
return
}
// - cannot decrement by infinite quantities
guard !amount.isInfinite else {
return
}
// - cannot decrement by negative values
guard amount.sign == .plus else {
return
}
// - cannot decrement by zero
guard !amount.isZero else {
return
}
self.lock.withLock { self.lock.withLock {
let lastValue = self._values.last?.1 ?? 0 let lastValue: Double = self._values.last?.1 ?? 0
let newValue = lastValue - amount let newValue = lastValue - amount
_values.append((Date(), Double(newValue))) _values.append((Date(), newValue))
} }
} }
@ -428,7 +464,7 @@ public final class TestRecorder: TestMetric, RecorderHandler, Equatable {
private var _values = [(Date, Double)]() private var _values = [(Date, Double)]()
init(label: String, dimensions: [(String, String)], aggregate: Bool) { init(label: String, dimensions: [(String, String)], aggregate: Bool) {
self.id = NSUUID().uuidString self.id = UUID().uuidString
self.label = label self.label = label
self.dimensions = dimensions self.dimensions = dimensions
self.aggregate = aggregate self.aggregate = aggregate

View File

@ -46,6 +46,14 @@ extension MetricsTests {
("testGaugeBlock", testGaugeBlock), ("testGaugeBlock", testGaugeBlock),
("testMeter", testMeter), ("testMeter", testMeter),
("testMeterBlock", testMeterBlock), ("testMeterBlock", testMeterBlock),
("testMeterInt", testMeterInt),
("testMeterFloat", testMeterFloat),
("testMeterIncrement", testMeterIncrement),
("testMeterDecrement", testMeterDecrement),
("testDefaultMeterIgnoresNan", testDefaultMeterIgnoresNan),
("testDefaultMeterIgnoresInfinity", testDefaultMeterIgnoresInfinity),
("testDefaultMeterIgnoresNegativeValues", testDefaultMeterIgnoresNegativeValues),
("testDefaultMeterIgnoresZero", testDefaultMeterIgnoresZero),
("testMUX_Counter", testMUX_Counter), ("testMUX_Counter", testMUX_Counter),
("testMUX_Meter", testMUX_Meter), ("testMUX_Meter", testMUX_Meter),
("testMUX_Recorder", testMUX_Recorder), ("testMUX_Recorder", testMUX_Recorder),

View File

@ -24,17 +24,17 @@ class MetricsTests: XCTestCase {
let group = DispatchGroup() let group = DispatchGroup()
let name = "counter-\(UUID().uuidString)" let name = "counter-\(UUID().uuidString)"
let counter = Counter(label: name) let counter = Counter(label: name)
let testCounter = counter._handler as! TestCounter let testCounter = try metrics.expectCounter(counter)
let total = Int.random(in: 500 ... 1000) let total = Int.random(in: 500 ... 1000)
for _ in 0 ... total { for _ in 0 ..< total {
group.enter() group.enter()
DispatchQueue(label: "\(name)-queue").async { DispatchQueue(label: "\(name)-queue").async {
defer { group.leave() }
counter.increment(by: Int.random(in: 0 ... 1000)) counter.increment(by: Int.random(in: 0 ... 1000))
group.leave()
} }
} }
group.wait() group.wait()
XCTAssertEqual(testCounter.values.count - 1, total, "expected number of entries to match") XCTAssertEqual(testCounter.values.count, total, "expected number of entries to match")
testCounter.reset() testCounter.reset()
XCTAssertEqual(testCounter.values.count, 0, "expected number of entries to match") XCTAssertEqual(testCounter.values.count, 0, "expected number of entries to match")
} }
@ -153,17 +153,17 @@ class MetricsTests: XCTestCase {
let group = DispatchGroup() let group = DispatchGroup()
let name = "recorder-\(UUID().uuidString)" let name = "recorder-\(UUID().uuidString)"
let recorder = Recorder(label: name) let recorder = Recorder(label: name)
let testRecorder = recorder._handler as! TestRecorder let testRecorder = try metrics.expectRecorder(recorder)
let total = Int.random(in: 500 ... 1000) let total = Int.random(in: 500 ... 1000)
for _ in 0 ... total { for _ in 0 ..< total {
group.enter() group.enter()
DispatchQueue(label: "\(name)-queue").async { DispatchQueue(label: "\(name)-queue").async {
defer { group.leave() }
recorder.record(Int.random(in: Int.min ... Int.max)) recorder.record(Int.random(in: Int.min ... Int.max))
group.leave()
} }
} }
group.wait() group.wait()
XCTAssertEqual(testRecorder.values.count - 1, total, "expected number of entries to match") XCTAssertEqual(testRecorder.values.count, total, "expected number of entries to match")
} }
func testRecordersInt() throws { func testRecordersInt() throws {
@ -171,13 +171,13 @@ class MetricsTests: XCTestCase {
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
let recorder = Recorder(label: "test-recorder") let recorder = Recorder(label: "test-recorder")
let testRecorder = recorder._handler as! TestRecorder let testRecorder = try metrics.expectRecorder(recorder)
let values = (0 ... 999).map { _ in Int32.random(in: Int32.min ... Int32.max) } let values = (0 ... 999).map { _ in Int32.random(in: Int32.min ... Int32.max) }
for i in 0 ... values.count - 1 { for i in 0 ..< values.count {
recorder.record(values[i]) recorder.record(values[i])
} }
XCTAssertEqual(values.count, testRecorder.values.count, "expected number of entries to match") XCTAssertEqual(values.count, testRecorder.values.count, "expected number of entries to match")
for i in 0 ... values.count - 1 { for i in 0 ..< values.count {
XCTAssertEqual(Int32(testRecorder.values[i]), values[i], "expected value #\(i) to match.") XCTAssertEqual(Int32(testRecorder.values[i]), values[i], "expected value #\(i) to match.")
} }
} }
@ -187,13 +187,13 @@ class MetricsTests: XCTestCase {
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
let recorder = Recorder(label: "test-recorder") let recorder = Recorder(label: "test-recorder")
let testRecorder = recorder._handler as! TestRecorder let testRecorder = try metrics.expectRecorder(recorder)
let values = (0 ... 999).map { _ in Float.random(in: Float(Int32.min) ... Float(Int32.max)) } let values = (0 ... 999).map { _ in Float.random(in: Float(Int32.min) ... Float(Int32.max)) }
for i in 0 ... values.count - 1 { for i in 0 ..< values.count {
recorder.record(values[i]) recorder.record(values[i])
} }
XCTAssertEqual(values.count, testRecorder.values.count, "expected number of entries to match") XCTAssertEqual(values.count, testRecorder.values.count, "expected number of entries to match")
for i in 0 ... values.count - 1 { for i in 0 ..< values.count {
XCTAssertEqual(Float(testRecorder.values[i]), values[i], "expected value #\(i) to match.") XCTAssertEqual(Float(testRecorder.values[i]), values[i], "expected value #\(i) to match.")
} }
} }
@ -218,17 +218,17 @@ class MetricsTests: XCTestCase {
let group = DispatchGroup() let group = DispatchGroup()
let name = "timer-\(UUID().uuidString)" let name = "timer-\(UUID().uuidString)"
let timer = Timer(label: name) let timer = Timer(label: name)
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
let total = Int.random(in: 500 ... 1000) let total = Int.random(in: 500 ... 1000)
for _ in 0 ... total { for _ in 0 ..< total {
group.enter() group.enter()
DispatchQueue(label: "\(name)-queue").async { DispatchQueue(label: "\(name)-queue").async {
defer { group.leave() }
timer.recordNanoseconds(Int64.random(in: Int64.min ... Int64.max)) timer.recordNanoseconds(Int64.random(in: Int64.min ... Int64.max))
group.leave()
} }
} }
group.wait() group.wait()
XCTAssertEqual(testTimer.values.count - 1, total, "expected number of entries to match") XCTAssertEqual(testTimer.values.count, total, "expected number of entries to match")
} }
func testTimerBlock() throws { func testTimerBlock() throws {
@ -250,7 +250,7 @@ class MetricsTests: XCTestCase {
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
// run the test // run the test
let timer = Timer(label: "test-timer") let timer = Timer(label: "test-timer")
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
// nano // nano
let nano = Int64.random(in: 0 ... 5) let nano = Int64.random(in: 0 ... 5)
timer.recordNanoseconds(nano) timer.recordNanoseconds(nano)
@ -279,7 +279,7 @@ class MetricsTests: XCTestCase {
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
// run the test // run the test
let timer = Timer(label: "test-timer") let timer = Timer(label: "test-timer")
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
// nano (integer) // nano (integer)
timer.recordNanoseconds(Int64.max) timer.recordNanoseconds(Int64.max)
XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match") XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match")
@ -316,7 +316,7 @@ class MetricsTests: XCTestCase {
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
// run the test // run the test
let timer = Timer(label: "test-timer") let timer = Timer(label: "test-timer")
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
// nano // nano
timer.recordNanoseconds(UInt64.max) timer.recordNanoseconds(UInt64.max)
XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match") XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match")
@ -344,7 +344,7 @@ class MetricsTests: XCTestCase {
let value = Double.random(in: -1000 ... 1000) let value = Double.random(in: -1000 ... 1000)
let gauge = Gauge(label: name) let gauge = Gauge(label: name)
gauge.record(value) gauge.record(value)
let recorder = gauge._handler as! TestRecorder let recorder = try metrics.expectRecorder(gauge)
XCTAssertEqual(recorder.values.count, 1, "expected number of entries to match") XCTAssertEqual(recorder.values.count, 1, "expected number of entries to match")
XCTAssertEqual(recorder.lastValue, value, "expected value to match") XCTAssertEqual(recorder.lastValue, value, "expected value to match")
} }
@ -367,11 +367,11 @@ class MetricsTests: XCTestCase {
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
// run the test // run the test
let name = "meter-\(NSUUID().uuidString)" let name = "meter-\(UUID().uuidString)"
let value = Double.random(in: -1000 ... 1000) let value = Double.random(in: -1000 ... 1000)
let meter = Meter(label: name) let meter = Meter(label: name)
meter.set(value) meter.set(value)
let testMeter = meter._handler as! TestMeter let testMeter = try metrics.expectMeter(meter)
XCTAssertEqual(testMeter.values.count, 1, "expected number of entries to match") XCTAssertEqual(testMeter.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testMeter.values[0], value, "expected value to match") XCTAssertEqual(testMeter.values[0], value, "expected value to match")
} }
@ -381,7 +381,7 @@ class MetricsTests: XCTestCase {
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
// run the test // run the test
let name = "meter-\(NSUUID().uuidString)" let name = "meter-\(UUID().uuidString)"
let value = Double.random(in: -1000 ... 1000) let value = Double.random(in: -1000 ... 1000)
Meter(label: name).set(value) Meter(label: name).set(value)
let testMeter = try metrics.expectMeter(name) let testMeter = try metrics.expectMeter(name)
@ -389,6 +389,134 @@ class MetricsTests: XCTestCase {
XCTAssertEqual(testMeter.values[0], value, "expected value to match") XCTAssertEqual(testMeter.values[0], value, "expected value to match")
} }
func testMeterInt() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
let values = (0 ... 999).map { _ in Int32.random(in: Int32.min ... Int32.max) }
for i in 0 ..< values.count {
meter.set(values[i])
}
XCTAssertEqual(values.count, testMeter.values.count, "expected number of entries to match")
for i in 0 ..< values.count {
XCTAssertEqual(Int32(testMeter.values[i]), values[i], "expected value #\(i) to match.")
}
}
func testMeterFloat() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
let values = (0 ... 999).map { _ in Float.random(in: Float(Int32.min) ... Float(Int32.max)) }
for i in 0 ..< values.count {
meter.set(values[i])
}
XCTAssertEqual(values.count, testMeter.values.count, "expected number of entries to match")
for i in 0 ..< values.count {
XCTAssertEqual(Float(testMeter.values[i]), values[i], "expected value #\(i) to match.")
}
}
func testMeterIncrement() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
// run the test
let group = DispatchGroup()
let name = "meter-\(UUID().uuidString)"
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
let values = (500 ... 1000).map { _ in Double.random(in: 0 ... Double(Int32.max)) }
for i in 0 ..< values.count {
group.enter()
DispatchQueue(label: "\(name)-queue").async {
defer { group.leave() }
meter.increment(by: values[i])
}
}
group.wait()
XCTAssertEqual(testMeter.values.count, values.count, "expected number of entries to match")
XCTAssertEqual(testMeter.values.last!, values.reduce(0.0, +), accuracy: 0.1, "expected total value to match")
}
func testMeterDecrement() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
// run the test
let group = DispatchGroup()
let name = "meter-\(UUID().uuidString)"
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
let values = (500 ... 1000).map { _ in Double.random(in: 0 ... Double(Int32.max)) }
for i in 0 ..< values.count {
group.enter()
DispatchQueue(label: "\(name)-queue").async {
defer { group.leave() }
meter.decrement(by: values[i])
}
}
group.wait()
XCTAssertEqual(testMeter.values.count, values.count, "expected number of entries to match")
XCTAssertEqual(testMeter.values.last!, values.reduce(0.0, -), accuracy: 0.1, "expected total value to match")
}
func testDefaultMeterIgnoresNan() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
// run the test
let name = "meter-\(UUID().uuidString)"
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
meter.increment(by: Double.nan)
meter.increment(by: Double.signalingNaN)
XCTAssertEqual(testMeter.values.count, 0, "expected nan values to be ignored")
}
func testDefaultMeterIgnoresInfinity() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
// run the test
let name = "meter-\(UUID().uuidString)"
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
meter.increment(by: Double.infinity)
meter.increment(by: -Double.infinity)
XCTAssertEqual(testMeter.values.count, 0, "expected infinite values to be ignored")
}
func testDefaultMeterIgnoresNegativeValues() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
// run the test
let name = "meter-\(UUID().uuidString)"
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
meter.increment(by: -100)
XCTAssertEqual(testMeter.values.count, 0, "expected negative values to be ignored")
}
func testDefaultMeterIgnoresZero() throws {
// bootstrap with our test metrics
let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics)
// run the test
let name = "meter-\(UUID().uuidString)"
let meter = Meter(label: name)
let testMeter = try metrics.expectMeter(meter)
meter.increment(by: 0)
meter.increment(by: -0)
XCTAssertEqual(testMeter.values.count, 0, "expected zero values to be ignored")
}
func testMUX_Counter() throws { func testMUX_Counter() throws {
// bootstrap with our test metrics // bootstrap with our test metrics
let factories = [TestMetrics(), TestMetrics(), TestMetrics()] let factories = [TestMetrics(), TestMetrics(), TestMetrics()]
@ -416,7 +544,7 @@ class MetricsTests: XCTestCase {
let factories = [TestMetrics(), TestMetrics(), TestMetrics()] let factories = [TestMetrics(), TestMetrics(), TestMetrics()]
MetricsSystem.bootstrapInternal(MultiplexMetricsHandler(factories: factories)) MetricsSystem.bootstrapInternal(MultiplexMetricsHandler(factories: factories))
// run the test // run the test
let name = NSUUID().uuidString let name = UUID().uuidString
let value = Double.random(in: 0 ... 1) let value = Double.random(in: 0 ... 1)
let muxMeter = Meter(label: name) let muxMeter = Meter(label: name)
muxMeter.set(value) muxMeter.set(value)
@ -486,7 +614,7 @@ class MetricsTests: XCTestCase {
let gauge = Gauge(label: name) let gauge = Gauge(label: name)
gauge.record(value) gauge.record(value)
let recorder = gauge._handler as! TestRecorder let recorder = try metrics.expectRecorder(gauge)
XCTAssertEqual(recorder.values.count, 1, "expected number of entries to match") XCTAssertEqual(recorder.values.count, 1, "expected number of entries to match")
XCTAssertEqual(recorder.values.first, value, "expected value to match") XCTAssertEqual(recorder.values.first, value, "expected value to match")
XCTAssertEqual(metrics.recorders.count, 1, "recorder should have been stored") XCTAssertEqual(metrics.recorders.count, 1, "recorder should have been stored")
@ -498,7 +626,7 @@ class MetricsTests: XCTestCase {
let gaugeAgain = Gauge(label: name) let gaugeAgain = Gauge(label: name)
gaugeAgain.record(-value) gaugeAgain.record(-value)
let recorderAgain = gaugeAgain._handler as! TestRecorder let recorderAgain = try metrics.expectRecorder(gaugeAgain)
XCTAssertEqual(recorderAgain.values.count, 1, "expected number of entries to match") XCTAssertEqual(recorderAgain.values.count, 1, "expected number of entries to match")
XCTAssertEqual(recorderAgain.values.first, -value, "expected value to match") XCTAssertEqual(recorderAgain.values.first, -value, "expected value to match")
@ -510,13 +638,13 @@ class MetricsTests: XCTestCase {
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
let name = "meter-\(NSUUID().uuidString)" let name = "meter-\(UUID().uuidString)"
let value = Double.random(in: -1000 ... 1000) let value = Double.random(in: -1000 ... 1000)
let meter = Meter(label: name) let meter = Meter(label: name)
meter.set(value) meter.set(value)
let testMeter = meter._handler as! TestMeter let testMeter = try metrics.expectMeter(meter)
XCTAssertEqual(testMeter.values.count, 1, "expected number of entries to match") XCTAssertEqual(testMeter.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testMeter.values.first, value, "expected value to match") XCTAssertEqual(testMeter.values.first, value, "expected value to match")
XCTAssertEqual(metrics.meters.count, 1, "recorder should have been stored") XCTAssertEqual(metrics.meters.count, 1, "recorder should have been stored")
@ -528,7 +656,7 @@ class MetricsTests: XCTestCase {
let meterAgain = Meter(label: name) let meterAgain = Meter(label: name)
meterAgain.set(-value) meterAgain.set(-value)
let testMeterAgain = meterAgain._handler as! TestMeter let testMeterAgain = try metrics.expectMeter(meterAgain)
XCTAssertEqual(testMeterAgain.values.count, 1, "expected number of entries to match") XCTAssertEqual(testMeterAgain.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testMeterAgain.values.first, -value, "expected value to match") XCTAssertEqual(testMeterAgain.values.first, -value, "expected value to match")
@ -546,7 +674,7 @@ class MetricsTests: XCTestCase {
let counter = Counter(label: name) let counter = Counter(label: name)
counter.increment(by: value) counter.increment(by: value)
let testCounter = counter._handler as! TestCounter let testCounter = try metrics.expectCounter(counter)
XCTAssertEqual(testCounter.values.count, 1, "expected number of entries to match") XCTAssertEqual(testCounter.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testCounter.values.first, Int64(value), "expected value to match") XCTAssertEqual(testCounter.values.first, Int64(value), "expected value to match")
XCTAssertEqual(metrics.counters.count, 1, "counter should have been stored") XCTAssertEqual(metrics.counters.count, 1, "counter should have been stored")
@ -558,7 +686,7 @@ class MetricsTests: XCTestCase {
let counterAgain = Counter(label: name) let counterAgain = Counter(label: name)
counterAgain.increment(by: value) counterAgain.increment(by: value)
let testCounterAgain = counterAgain._handler as! TestCounter let testCounterAgain = try metrics.expectCounter(counterAgain)
XCTAssertEqual(testCounterAgain.values.count, 1, "expected number of entries to match") XCTAssertEqual(testCounterAgain.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testCounterAgain.values.first, Int64(value), "expected value to match") XCTAssertEqual(testCounterAgain.values.first, Int64(value), "expected value to match")
@ -576,7 +704,7 @@ class MetricsTests: XCTestCase {
let timer = Timer(label: name) let timer = Timer(label: name)
timer.recordNanoseconds(value) timer.recordNanoseconds(value)
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match") XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testTimer.values.first, value, "expected value to match") XCTAssertEqual(testTimer.values.first, value, "expected value to match")
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored") XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
@ -587,7 +715,7 @@ class MetricsTests: XCTestCase {
let timerAgain = Timer(label: name) let timerAgain = Timer(label: name)
timerAgain.recordNanoseconds(value) timerAgain.recordNanoseconds(value)
let testTimerAgain = timerAgain._handler as! TestTimer let testTimerAgain = try metrics.expectTimer(timerAgain)
XCTAssertEqual(testTimerAgain.values.count, 1, "expected number of entries to match") XCTAssertEqual(testTimerAgain.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testTimerAgain.values.first, value, "expected value to match") XCTAssertEqual(testTimerAgain.values.first, value, "expected value to match")

View File

@ -39,7 +39,7 @@ class MetricsExtensionsTests: XCTestCase {
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
// run the test // run the test
let timer = Timer(label: "test-timer") let timer = Timer(label: "test-timer")
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
let timeInterval = TimeInterval(Double.random(in: 1 ... 500)) let timeInterval = TimeInterval(Double.random(in: 1 ... 500))
timer.record(timeInterval) timer.record(timeInterval)
XCTAssertEqual(1, testTimer.values.count, "expected number of entries to match") XCTAssertEqual(1, testTimer.values.count, "expected number of entries to match")
@ -52,7 +52,7 @@ class MetricsExtensionsTests: XCTestCase {
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
// run the test // run the test
let timer = Timer(label: "test-timer") let timer = Timer(label: "test-timer")
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
// nano // nano
let nano = DispatchTimeInterval.nanoseconds(Int.random(in: 1 ... 500)) let nano = DispatchTimeInterval.nanoseconds(Int.random(in: 1 ... 500))
timer.record(nano) timer.record(nano)
@ -79,7 +79,7 @@ class MetricsExtensionsTests: XCTestCase {
XCTAssertEqual(testTimer.values[4], 0, "expected value to match") XCTAssertEqual(testTimer.values[4], 0, "expected value to match")
} }
func testTimerWithDispatchTimeInterval() { func testTimerWithDispatchTimeInterval() throws {
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
@ -90,7 +90,7 @@ class MetricsExtensionsTests: XCTestCase {
let end = DispatchTime(uptimeNanoseconds: start.uptimeNanoseconds + 1000 * 1000 * 1000) let end = DispatchTime(uptimeNanoseconds: start.uptimeNanoseconds + 1000 * 1000 * 1000)
timer.recordInterval(since: start, end: end) timer.recordInterval(since: start, end: end)
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match") XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match")
XCTAssertEqual(UInt64(testTimer.values.first!), end.uptimeNanoseconds - start.uptimeNanoseconds, "expected value to match") XCTAssertEqual(UInt64(testTimer.values.first!), end.uptimeNanoseconds - start.uptimeNanoseconds, "expected value to match")
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored") XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
@ -106,7 +106,7 @@ class MetricsExtensionsTests: XCTestCase {
let timer = Timer(label: name) let timer = Timer(label: name)
timer.recordNanoseconds(value) timer.recordNanoseconds(value)
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match") XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match")
XCTAssertEqual(testTimer.values.first, value, "expected value to match") XCTAssertEqual(testTimer.values.first, value, "expected value to match")
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored") XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
@ -116,12 +116,12 @@ class MetricsExtensionsTests: XCTestCase {
let secondsTimer = Timer(label: secondsName, preferredDisplayUnit: .seconds) let secondsTimer = Timer(label: secondsName, preferredDisplayUnit: .seconds)
secondsTimer.recordSeconds(secondsValue) secondsTimer.recordSeconds(secondsValue)
let testSecondsTimer = secondsTimer._handler as! TestTimer let testSecondsTimer = try metrics.expectTimer(secondsTimer)
XCTAssertEqual(testSecondsTimer.values.count, 1, "expected number of entries to match") XCTAssertEqual(testSecondsTimer.values.count, 1, "expected number of entries to match")
XCTAssertEqual(metrics.timers.count, 2, "timer should have been stored") XCTAssertEqual(metrics.timers.count, 2, "timer should have been stored")
} }
func testPreferDisplayUnit() { func testPreferDisplayUnit() throws {
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
@ -129,7 +129,7 @@ class MetricsExtensionsTests: XCTestCase {
let timer = Timer(label: "test", preferredDisplayUnit: .seconds) let timer = Timer(label: "test", preferredDisplayUnit: .seconds)
timer.recordSeconds(value) timer.recordSeconds(value)
let testTimer = timer._handler as! TestTimer let testTimer = try metrics.expectTimer(timer)
testTimer.preferDisplayUnit(.nanoseconds) testTimer.preferDisplayUnit(.nanoseconds)
XCTAssertEqual(testTimer.valueInPreferredUnit(atIndex: 0), value * 1000 * 1000 * 1000, accuracy: 1.0, "expected value to match") XCTAssertEqual(testTimer.valueInPreferredUnit(atIndex: 0), value * 1000 * 1000 * 1000, accuracy: 1.0, "expected value to match")

View File

@ -19,7 +19,7 @@ import XCTest
class SendableTest: XCTestCase { class SendableTest: XCTestCase {
#if compiler(>=5.6) #if compiler(>=5.6)
func testSendableMetrics() async { func testSendableMetrics() async throws {
// bootstrap with our test metrics // bootstrap with our test metrics
let metrics = TestMetrics() let metrics = TestMetrics()
MetricsSystem.bootstrapInternal(metrics) MetricsSystem.bootstrapInternal(metrics)
@ -31,10 +31,10 @@ class SendableTest: XCTestCase {
let task = Task.detached { () -> [Int64] in let task = Task.detached { () -> [Int64] in
counter.increment(by: value) counter.increment(by: value)
let handler = counter._handler as! TestCounter let handler = try metrics.expectCounter(counter)
return handler.values return handler.values
} }
let values = await task.value let values = try await task.value
XCTAssertEqual(values.count, 1, "expected number of entries to match") XCTAssertEqual(values.count, 1, "expected number of entries to match")
XCTAssertEqual(values[0], Int64(value), "expected value to match") XCTAssertEqual(values[0], Int64(value), "expected value to match")
} }
@ -60,25 +60,25 @@ class SendableTest: XCTestCase {
let task = Task.detached { () -> [Double] in let task = Task.detached { () -> [Double] in
recorder.record(value) recorder.record(value)
let handler = recorder._handler as! TestRecorder let handler = try metrics.expectRecorder(recorder)
return handler.values return handler.values
} }
let values = await task.value let values = try await task.value
XCTAssertEqual(values.count, 1, "expected number of entries to match") XCTAssertEqual(values.count, 1, "expected number of entries to match")
XCTAssertEqual(values[0], value, "expected value to match") XCTAssertEqual(values[0], value, "expected value to match")
} }
do { do {
let name = "meter-\(NSUUID().uuidString)" let name = "meter-\(UUID().uuidString)"
let value = Double.random(in: -1000 ... 1000) let value = Double.random(in: -1000 ... 1000)
let meter = Meter(label: name) let meter = Meter(label: name)
let task = Task.detached { () -> [Double] in let task = Task.detached { () -> [Double] in
meter.set(value) meter.set(value)
let handler = meter._handler as! TestMeter let handler = try metrics.expectMeter(meter)
return handler.values return handler.values
} }
let values = await task.value let values = try await task.value
XCTAssertEqual(values.count, 1, "expected number of entries to match") XCTAssertEqual(values.count, 1, "expected number of entries to match")
XCTAssertEqual(values[0], value, "expected value to match") XCTAssertEqual(values[0], value, "expected value to match")
} }
@ -90,10 +90,10 @@ class SendableTest: XCTestCase {
let task = Task.detached { () -> [Int64] in let task = Task.detached { () -> [Int64] in
timer.recordNanoseconds(value) timer.recordNanoseconds(value)
let handler = timer._handler as! TestTimer let handler = try metrics.expectTimer(timer)
return handler.values return handler.values
} }
let values = await task.value let values = try await task.value
XCTAssertEqual(values.count, 1, "expected number of entries to match") XCTAssertEqual(values.count, 1, "expected number of entries to match")
XCTAssertEqual(values[0], value, "expected value to match") XCTAssertEqual(values[0], value, "expected value to match")
} }