swift-metrics/Tests/MetricsTests/TestMetrics.swift

149 lines
4.5 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Metrics API open source project
//
// Copyright (c) 2018-2019 Apple Inc. and the Swift Metrics API project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift Metrics API project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
@testable import CoreMetrics
@testable import class CoreMetrics.Timer
import Foundation
internal class TestMetrics: MetricsFactory {
private let lock = NSLock() // TODO: consider lock per cache?
var counters = [String: CounterHandler]()
var recorders = [String: RecorderHandler]()
var timers = [String: TimerHandler]()
public func makeCounter(label: String, dimensions: [(String, String)]) -> CounterHandler {
return self.make(label: label, dimensions: dimensions, registry: &self.counters, maker: TestCounter.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)
}
return self.make(label: label, dimensions: dimensions, registry: &self.recorders, maker: maker)
}
public func makeTimer(label: String, dimensions: [(String, String)]) -> TimerHandler {
return self.make(label: label, dimensions: dimensions, registry: &self.timers, maker: TestTimer.init)
}
private func make<Item>(label: String, dimensions: [(String, String)], registry: inout [String: Item], maker: (String, [(String, String)]) -> Item) -> Item {
let item = maker(label, dimensions)
return self.lock.withLock {
registry[label] = item
return item
}
}
}
internal class TestCounter: CounterHandler, Equatable {
let id: String
let label: String
let dimensions: [(String, String)]
let lock = NSLock()
var values = [(Date, Int64)]()
init(label: String, dimensions: [(String, String)]) {
self.id = NSUUID().uuidString
self.label = label
self.dimensions = dimensions
}
func increment<DataType: BinaryInteger>(_ value: DataType) {
self.lock.withLock {
self.values.append((Date(), Int64(value)))
}
print("adding \(value) to \(self.label)")
}
func reset() {
self.lock.withLock {
self.values = []
}
}
public static func == (lhs: TestCounter, rhs: TestCounter) -> Bool {
return lhs.id == rhs.id
}
}
internal class TestRecorder: RecorderHandler, Equatable {
let id: String
let label: String
let dimensions: [(String, String)]
let aggregate: Bool
let lock = NSLock()
var values = [(Date, Double)]()
init(label: String, dimensions: [(String, String)], aggregate: Bool) {
self.id = NSUUID().uuidString
self.label = label
self.dimensions = dimensions
self.aggregate = aggregate
}
func record<DataType: BinaryInteger>(_ value: DataType) {
self.record(Double(value))
}
func record<DataType: BinaryFloatingPoint>(_ value: DataType) {
self.lock.withLock {
// this may loose precision but good enough as an example
values.append((Date(), Double(value)))
}
print("recoding \(value) in \(self.label)")
}
public static func == (lhs: TestRecorder, rhs: TestRecorder) -> Bool {
return lhs.id == rhs.id
}
}
internal class TestTimer: TimerHandler, Equatable {
let id: String
let label: String
let dimensions: [(String, String)]
let lock = NSLock()
var values = [(Date, Int64)]()
init(label: String, dimensions: [(String, String)]) {
self.id = NSUUID().uuidString
self.label = label
self.dimensions = dimensions
}
func recordNanoseconds(_ duration: Int64) {
self.lock.withLock {
values.append((Date(), duration))
}
print("recoding \(duration) \(self.label)")
}
public static func == (lhs: TestTimer, rhs: TestTimer) -> Bool {
return lhs.id == rhs.id
}
}
private extension NSLock {
func withLock<T>(_ body: () -> T) -> T {
self.lock()
defer {
self.unlock()
}
return body()
}
}