Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoongo committed Oct 16, 2023
1 parent 7ff855d commit e408154
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ public class StableOtlpHTTPMetricExporter: StableOtlpHTTPExporterBase, StableMet
}

let request = createRequest(body: body, endpoint: endpoint)
print("[JG] header: \(request.allHTTPHeaderFields)")
print("[JG] body description: \(body.debugDescription)")
print("[JG] body description: \(try? body.jsonString())")
httpClient.send(request: request) { [weak self] result in
switch result {
case .success(_):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class AggregationTemporalitySelector : AggregationTemporalitySelectorProt
return aggregationTemporalitySelector(instrument)
}

init(aggregationTemporalitySelector: @escaping (InstrumentType) -> AggregationTemporality) {
public init(aggregationTemporalitySelector: @escaping (InstrumentType) -> AggregationTemporality) {
self.aggregationTemporalitySelector = aggregationTemporalitySelector
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ final class MetricsAdapterTest: XCTestCase {
let pointValue = Int.random(in: 1...999)
let point:PointData = LongPointData(startEpochNanos: 0, endEpochNanos: 1, attributes: [:], exemplars: [], value: pointValue)
let sumData = StableSumData(aggregationTemporality: .cumulative, points: [point])
let metricData = StableMetricData.createLongSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: name, description: description, unit: unit, data: sumData)
let metricData = StableMetricData.createLongSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: name, description: description, unit: unit, isMonotonic: true, data: sumData)

let result = MetricsAdapter.toProtoMetric(stableMetric: metricData)
guard let value = result?.sum.dataPoints as? [Opentelemetry_Proto_Metrics_V1_NumberDataPoint] else {
Expand All @@ -46,6 +46,7 @@ final class MetricsAdapterTest: XCTestCase {
}

XCTAssertEqual(value.first?.asInt, Int64(pointValue))
XCTAssertEqual(result?.sum.isMonotonic, true)
}

func testToProtoResourceMetricsWithDoubleGuage() throws {
Expand All @@ -69,7 +70,7 @@ final class MetricsAdapterTest: XCTestCase {
let pointValue: Double = Double.random(in: 1...999)
let point:PointData = DoublePointData(startEpochNanos: 0, endEpochNanos: 1, attributes: [:], exemplars: [], value: pointValue)
let sumData = StableSumData(aggregationTemporality: .cumulative, points: [point])
let metricData = StableMetricData.createDoubleSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: name, description: description, unit: unit, data: sumData)
let metricData = StableMetricData.createDoubleSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: name, description: description, unit: unit, isMonotonic: false, data: sumData)

let result = MetricsAdapter.toProtoMetric(stableMetric: metricData)
guard let value = result?.sum.dataPoints as? [Opentelemetry_Proto_Metrics_V1_NumberDataPoint] else {
Expand All @@ -80,6 +81,7 @@ final class MetricsAdapterTest: XCTestCase {
}

XCTAssertEqual(value.first?.asDouble, pointValue)
XCTAssertEqual(result?.sum.isMonotonic, false)
}

func testToProtoResourceMetricsWithHistogram() throws {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import Logging
import NIO
import NIOHTTP1
import NIOTestUtils
import OpenTelemetryApi
import OpenTelemetryProtocolExporterCommon
@testable import OpenTelemetryProtocolExporterHttp
@testable import OpenTelemetrySdk
import XCTest

class StableOtlpHttpMetricsExporterTest: XCTestCase {
var testServer: NIOHTTP1TestServer!
var group: MultiThreadedEventLoopGroup!

override func setUp() {
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
testServer = NIOHTTP1TestServer(group: group)
}

override func tearDown() {
XCTAssertNoThrow(try testServer.stop())
XCTAssertNoThrow(try group.syncShutdownGracefully())
}

// The shutdown() function is a no-op, This test is just here to make codecov happy
func testShutdown() {
let endpoint = URL(string: "http://localhost:\(testServer.serverPort)")!
let exporter = StableOtlpHTTPMetricExporter(endpoint: endpoint)
XCTAssertEqual(exporter.shutdown(), .success)
}

func testExportHeader() {
let metric = generateSumStableMetricData()

let endpoint = URL(string: "http://localhost:\(testServer.serverPort)")!
let exporter = StableOtlpHTTPMetricExporter(endpoint: endpoint, config: OtlpConfiguration(headers: [("headerName", "headerValue")]))
let result = exporter.export(metrics: [metric])
XCTAssertEqual(result, ExportResult.success)

XCTAssertNoThrow(try testServer.receiveHeadAndVerify { head in
XCTAssertTrue(head.headers.contains(name: "headerName"))
XCTAssertEqual("headerValue", head.headers.first(name: "headerName"))
})

XCTAssertNotNil(try testServer.receiveBodyAndVerify())
XCTAssertNoThrow(try testServer.receiveEnd())
}

func testExport() {
let words = ["foo", "bar", "fizz", "buzz"]
var metrics: [StableMetricData] = []
var metricDescriptions: [String] = []
for word in words {
let metricDescription = word + String(Int.random(in: 1...100))
metricDescriptions.append(metricDescription)
metrics.append(generateSumStableMetricData(description: metricDescription))
}

let endpoint = URL(string: "http://localhost:\(testServer.serverPort)")!
let exporter = StableOtlpHTTPMetricExporter(endpoint: endpoint)
let result = exporter.export(metrics: metrics)
XCTAssertEqual(result, ExportResult.success)

XCTAssertNoThrow(try testServer.receiveHeadAndVerify { head in
let otelVersion = Headers.getUserAgentHeader()
XCTAssertTrue(head.headers.contains(name: Constants.HTTP.userAgent))
XCTAssertEqual(otelVersion, head.headers.first(name: Constants.HTTP.userAgent))
})

XCTAssertNoThrow(try testServer.receiveBodyAndVerify { body in
var contentsBuffer = ByteBuffer(buffer: body)
let contents = contentsBuffer.readString(length: contentsBuffer.readableBytes)!
for metricDescription in metricDescriptions {
XCTAssertTrue(contents.contains(metricDescription))
}
})

XCTAssertNoThrow(try testServer.receiveEnd())
}

func testGaugeExport() {
let words = ["foo", "bar", "fizz", "buzz"]
var metrics: [StableMetricData] = []
var metricDescriptions: [String] = []
for word in words {
let metricDescription = word + String(Int.random(in: 1...100))
metricDescriptions.append(metricDescription)
metrics.append(generateGaugeStableMetricData(description: metricDescription))
}

let endpoint = URL(string: "http://localhost:\(testServer.serverPort)")!
let exporter = StableOtlpHTTPMetricExporter(endpoint: endpoint)
let result = exporter.export(metrics: metrics)
XCTAssertEqual(result, ExportResult.success)

XCTAssertNoThrow(try testServer.receiveHeadAndVerify { head in
let otelVersion = Headers.getUserAgentHeader()
XCTAssertTrue(head.headers.contains(name: Constants.HTTP.userAgent))
XCTAssertEqual(otelVersion, head.headers.first(name: Constants.HTTP.userAgent))
})

XCTAssertNoThrow(try testServer.receiveBodyAndVerify { body in
var contentsBuffer = ByteBuffer(buffer: body)
let contents = contentsBuffer.readString(length: contentsBuffer.readableBytes)!
for metricDescription in metricDescriptions {
XCTAssertTrue(contents.contains(metricDescription))
}
})

XCTAssertNoThrow(try testServer.receiveEnd())
}

func testFlushWithoutPendingMetrics() {
let metric = generateSumStableMetricData()

let endpoint = URL(string: "http://localhost:\(testServer.serverPort)")!
let exporter = StableOtlpHTTPMetricExporter(endpoint: endpoint, config: OtlpConfiguration(headers: [("headerName", "headerValue")]))
XCTAssertEqual(exporter.flush(), .success)
}

func testCustomAggregationTemporalitySelector() {
let aggregationTemporalitySelector = AggregationTemporalitySelector() { (type) in
switch type {
case .counter:
return .cumulative
case .histogram:
return .delta
case .observableCounter:
return .delta
case .observableGauge:
return .delta
case .observableUpDownCounter:
return .cumulative
case .upDownCounter:
return .delta
}
}

let endpoint = URL(string: "http://localhost:\(testServer.serverPort)")!
let exporter = StableOtlpHTTPMetricExporter(endpoint: endpoint, aggregationTemporalitySelector: aggregationTemporalitySelector)
XCTAssertTrue(exporter.getAggregationTemporality(for: .counter) == .cumulative)
XCTAssertTrue(exporter.getAggregationTemporality(for: .histogram) == .delta)
XCTAssertTrue(exporter.getAggregationTemporality(for: .observableCounter) == .delta)
XCTAssertTrue(exporter.getAggregationTemporality(for: .observableGauge) == .delta)
XCTAssertTrue(exporter.getAggregationTemporality(for: .observableUpDownCounter) == .cumulative)
XCTAssertTrue(exporter.getAggregationTemporality(for: .upDownCounter) == .delta)
}

func testCustomAggregation() {
let aggregationSelector = CustomDefaultAggregationSelector()

let endpoint = URL(string: "http://localhost:\(testServer.serverPort)")!
let exporter = StableOtlpHTTPMetricExporter(endpoint: endpoint, defaultAggregationSelector: aggregationSelector)
XCTAssertTrue(exporter.getDefaultAggregation(for: .counter) is SumAggregation)
XCTAssertTrue(exporter.getDefaultAggregation(for: .histogram) is SumAggregation)
XCTAssertTrue(exporter.getDefaultAggregation(for: .observableCounter) is DropAggregation)
XCTAssertTrue(exporter.getDefaultAggregation(for: .upDownCounter) is DropAggregation)
}


func generateSumStableMetricData(description: String = "description") -> StableMetricData {
let scope = InstrumentationScopeInfo(name: "lib", version: "semver:0.0.0")
let sumPointData = DoublePointData(startEpochNanos: 0, endEpochNanos: 1, attributes: [:], exemplars: [], value: 1)
let metric = StableMetricData(resource: Resource(), instrumentationScopeInfo: scope, name: "metric", description: description, unit: "", type: .DoubleSum, isMonotonic: true, data: StableMetricData.Data(aggregationTemporality: .cumulative, points: [sumPointData]))
return metric
}

func generateGaugeStableMetricData(description: String = "description") -> StableMetricData {
let scope = InstrumentationScopeInfo(name: "lib", version: "semver:0.0.0")
let sumPointData = DoublePointData(startEpochNanos: 0, endEpochNanos: 1, attributes: [:], exemplars: [], value: 100)
let metric = StableMetricData(resource: Resource(), instrumentationScopeInfo: scope, name: "MyGauge", description: description, unit: "", type: .LongGauge, isMonotonic: true, data: StableMetricData.Data(aggregationTemporality: .cumulative, points: [sumPointData]))
return metric
}
}

public class CustomDefaultAggregationSelector: DefaultAggregationSelector {
public func getDefaultAggregation(for instrument: OpenTelemetrySdk.InstrumentType) -> OpenTelemetrySdk.Aggregation {
switch instrument {
case .counter, .histogram:
return SumAggregation()
default:
return DropAggregation()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@ class StableMetricDataTests: XCTestCase {

func testStableMetricDataCreation() {
let type = MetricDataType.Summary
let data = StableMetricData.Data(points: emptyPointData)

let metricData = StableMetricData(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: metricName, description: metricDescription, unit: unit, type: type, data: data)
let data = StableMetricData.Data(aggregationTemporality: .delta, points: emptyPointData)

let metricData = StableMetricData(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: metricName, description: metricDescription, unit: unit, type: type, isMonotonic: false, data: data)

assertCommon(metricData)
XCTAssertEqual(metricData.type, type)
XCTAssertEqual(metricData.data, data)
XCTAssertEqual(metricData.data.aggregationTemporality, .delta)
XCTAssertEqual(metricData.isMonotonic, false)
}

func testEmptyStableMetricData() {
XCTAssertEqual(StableMetricData.empty, StableMetricData(resource: Resource.empty, instrumentationScopeInfo: InstrumentationScopeInfo(), name: "", description: "", unit: "", type: .Summary, data: StableMetricData.Data(points: [PointData]())))
XCTAssertEqual(StableMetricData.empty, StableMetricData(resource: Resource.empty, instrumentationScopeInfo: InstrumentationScopeInfo(), name: "", description: "", unit: "", type: .Summary, isMonotonic: false, data: StableMetricData.Data(aggregationTemporality: .cumulative, points: [PointData]())))
}

func testCreateExponentialHistogram() {
Expand All @@ -39,6 +41,8 @@ class StableMetricDataTests: XCTestCase {
assertCommon(metricData)
XCTAssertEqual(metricData.type, type)
XCTAssertEqual(metricData.data, histogramData)
XCTAssertEqual(metricData.data.aggregationTemporality, .delta)
XCTAssertEqual(metricData.isMonotonic, false)
}

func testCreateHistogram() {
Expand All @@ -60,6 +64,8 @@ class StableMetricDataTests: XCTestCase {
assertCommon(metricData)
XCTAssertEqual(metricData.type, type)
XCTAssertEqual(metricData.data, histogramData)
XCTAssertEqual(metricData.data.aggregationTemporality, .cumulative)
XCTAssertEqual(metricData.isMonotonic, false)

XCTAssertFalse(metricData.isEmpty())

Expand All @@ -79,6 +85,8 @@ class StableMetricDataTests: XCTestCase {
assertCommon(metricData)
XCTAssertEqual(metricData.type, type)
XCTAssertEqual(metricData.data.points.first, point)
XCTAssertEqual(metricData.data.aggregationTemporality, .cumulative)
XCTAssertEqual(metricData.isMonotonic, false)
}

func testCreateDoubleSum() {
Expand All @@ -87,11 +95,13 @@ class StableMetricDataTests: XCTestCase {

let point:PointData = DoublePointData(startEpochNanos: 0, endEpochNanos: 1, attributes: [:], exemplars: [], value: d)
let sumData = StableSumData(aggregationTemporality: .cumulative, points: [point])
let metricData = StableMetricData.createDoubleSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: metricName, description: metricDescription, unit: unit, data: sumData)
let metricData = StableMetricData.createDoubleSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: metricName, description: metricDescription, unit: unit, isMonotonic: true, data: sumData)

assertCommon(metricData)
XCTAssertEqual(metricData.type, type)
XCTAssertEqual(metricData.data.points.first, point)
XCTAssertEqual(metricData.data.aggregationTemporality, .cumulative)
XCTAssertEqual(metricData.isMonotonic, true)
}

func testCreateLongGuage() {
Expand All @@ -104,18 +114,22 @@ class StableMetricDataTests: XCTestCase {
assertCommon(metricData)
XCTAssertEqual(metricData.type, type)
XCTAssertEqual(metricData.data.points.first, point)
XCTAssertEqual(metricData.data.aggregationTemporality, .cumulative)
XCTAssertEqual(metricData.isMonotonic, false)
}

func testCreateLongSum() {
let type = MetricDataType.LongSum
let point:PointData = LongPointData(startEpochNanos: 0, endEpochNanos: 1, attributes: [:], exemplars: [], value: 55)
let sumData = StableSumData(aggregationTemporality: .cumulative, points: [point])

let metricData = StableMetricData.createLongSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: metricName, description: metricDescription, unit: unit, data: sumData)
let metricData = StableMetricData.createLongSum(resource: resource, instrumentationScopeInfo: instrumentationScopeInfo, name: metricName, description: metricDescription, unit: unit, isMonotonic: true, data: sumData)

assertCommon(metricData)
XCTAssertEqual(metricData.type, type)
XCTAssertEqual(metricData.data.points.first, point)
XCTAssertEqual(metricData.data.aggregationTemporality, .cumulative)
XCTAssertEqual(metricData.isMonotonic, true)
}


Expand Down

0 comments on commit e408154

Please sign in to comment.