Skip to content

Commit 909ebf6

Browse files
authored
Add IoT Metrics Support (#371)
1 parent 9c6a3c6 commit 909ebf6

File tree

2 files changed

+82
-6
lines changed

2 files changed

+82
-6
lines changed

Source/AwsCommonRuntimeKit/mqtt/Mqtt5Options.swift

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,21 @@ public class MqttConnectOptions: CStruct {
201201
}
202202
}
203203

204+
/// Configuration for the AWS IoT Metrics, including SDK name, version, and platforms.
205+
private class AwsIoTSDKMetrics: CStruct {
206+
public let libraryName: String = "IoTDeviceSDK/Swift"
207+
208+
typealias RawType = aws_mqtt_iot_metrics
209+
func withCStruct<Result>(_ body: (aws_mqtt_iot_metrics) -> Result) -> Result {
210+
var raw_metrics = aws_mqtt_iot_metrics()
211+
return libraryName.withByteCursor { libraryNameByteCursor in
212+
raw_metrics.library_name = libraryNameByteCursor
213+
return body(raw_metrics)
214+
}
215+
}
216+
217+
}
218+
204219
/// Configuration for the creation of MQTT5 clients
205220
public class MqttClientOptions: CStructWithUserData {
206221
/// Host name of the MQTT server to connect to.
@@ -278,6 +293,12 @@ public class MqttClientOptions: CStructWithUserData {
278293
/// Callback for Lifecycle Event Disconnection.
279294
public let onLifecycleEventDisconnectionFn: OnLifecycleEventDisconnection?
280295

296+
/// Enable AWS IoT Metrics, including SDK name, version, and platform. Default to True.
297+
public let enableMetrics: Bool
298+
299+
/// AWS IoT Metrics. This is internally set only.
300+
private let metrics: AwsIoTSDKMetrics?
301+
281302
public init(
282303
hostName: String,
283304
port: UInt32,
@@ -303,7 +324,8 @@ public class MqttClientOptions: CStructWithUserData {
303324
onLifecycleEventAttemptingConnectFn: OnLifecycleEventAttemptingConnect? = nil,
304325
onLifecycleEventConnectionSuccessFn: OnLifecycleEventConnectionSuccess? = nil,
305326
onLifecycleEventConnectionFailureFn: OnLifecycleEventConnectionFailure? = nil,
306-
onLifecycleEventDisconnectionFn: OnLifecycleEventDisconnection? = nil
327+
onLifecycleEventDisconnectionFn: OnLifecycleEventDisconnection? = nil,
328+
enableMetrics: Bool = true
307329
) {
308330

309331
self.hostName = hostName
@@ -347,6 +369,8 @@ public class MqttClientOptions: CStructWithUserData {
347369
self.onLifecycleEventConnectionSuccessFn = onLifecycleEventConnectionSuccessFn
348370
self.onLifecycleEventConnectionFailureFn = onLifecycleEventConnectionFailureFn
349371
self.onLifecycleEventDisconnectionFn = onLifecycleEventDisconnectionFn
372+
self.enableMetrics = enableMetrics
373+
self.metrics = enableMetrics ? AwsIoTSDKMetrics() : nil
350374
}
351375

352376
func validateConversionToNative() throws {
@@ -476,19 +500,22 @@ public class MqttClientOptions: CStructWithUserData {
476500
tls_options,
477501
self.httpProxyOptions,
478502
self.topicAliasingOptions,
503+
self.metrics,
479504
connnectOptions
480505
) {
481506
socketOptionsCPointer,
482507
tlsOptionsCPointer,
483508
httpProxyOptionsCPointer,
484509
topicAliasingOptionsCPointer,
510+
metricsCPointer,
485511
connectOptionsCPointer in
486512

487513
raw_options.socket_options = socketOptionsCPointer
488514
raw_options.tls_options = tlsOptionsCPointer
489515
raw_options.http_proxy_options = httpProxyOptionsCPointer
490516
raw_options.topic_aliasing_options = topicAliasingOptionsCPointer
491517
raw_options.connect_options = connectOptionsCPointer
518+
raw_options.metrics = metricsCPointer
492519

493520
guard let userData else {
494521
// directly return

Test/AwsCommonRuntimeKitTests/mqtt/Mqtt5ClientTests.swift

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ class Mqtt5ClientTests: XCBaseTestCase, @unchecked Sendable {
207207
onLifecycleEventAttemptingConnectFn: testContext.onLifecycleEventAttemptingConnect,
208208
onLifecycleEventConnectionSuccessFn: testContext.onLifecycleEventConnectionSuccess,
209209
onLifecycleEventConnectionFailureFn: testContext.onLifecycleEventConnectionFailure,
210-
onLifecycleEventDisconnectionFn: testContext.onLifecycleEventDisconnection)
210+
onLifecycleEventDisconnectionFn: testContext.onLifecycleEventDisconnection,
211+
enableMetrics: clientOptions.enableMetrics)
211212
} else {
212213
let elg = try EventLoopGroup()
213214
let resolver = try HostResolver(
@@ -407,20 +408,67 @@ class Mqtt5ClientTests: XCBaseTestCase, @unchecked Sendable {
407408
let connectOptions = MqttConnectOptions(
408409
clientId: createClientId(),
409410
username: inputUsername,
410-
password: inputPassword.data(using: .utf8)
411-
)
411+
password: inputPassword.data(using: .utf8))
412412

413413
let clientOptions = MqttClientOptions(
414414
hostName: inputHost,
415415
port: UInt32(inputPort)!,
416-
connectOptions: connectOptions)
416+
connectOptions: connectOptions,
417+
enableMetrics: false)
417418

418419
let testContext = MqttTestContext()
419420
let client = try createClient(clientOptions: clientOptions, testContext: testContext)
420421
try await connectClient(client: client, testContext: testContext)
421422
try await disconnectClientCleanup(client: client, testContext: testContext)
422423
}
423424

425+
/*
426+
* [Metrics-UC2-B] Direct Connection with Basic Auth - Metrics Disabled (should succeed)
427+
*
428+
* When metrics are disabled, the username is not modified and basic authentication
429+
* works correctly.
430+
*/
431+
func testMqtt5DirectConnectBasicAuthMetricsEnabled() async throws {
432+
433+
let inputUsername = try getEnvironmentVarOrSkipTest(
434+
environmentVarName: "AWS_TEST_MQTT5_BASIC_AUTH_USERNAME")
435+
let inputPassword = try getEnvironmentVarOrSkipTest(
436+
environmentVarName: "AWS_TEST_MQTT5_BASIC_AUTH_PASSWORD")
437+
let inputHost = try getEnvironmentVarOrSkipTest(
438+
environmentVarName: "AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_HOST")
439+
let inputPort = try getEnvironmentVarOrSkipTest(
440+
environmentVarName: "AWS_TEST_MQTT5_DIRECT_MQTT_BASIC_AUTH_PORT")
441+
442+
let connectOptions = MqttConnectOptions(
443+
clientId: createClientId(),
444+
username: inputUsername,
445+
password: inputPassword.data(using: .utf8))
446+
447+
// Metrics enabled
448+
let clientOptions = MqttClientOptions(
449+
hostName: inputHost,
450+
port: UInt32(inputPort)!,
451+
connectOptions: connectOptions,
452+
enableMetrics: true)
453+
454+
let testContext: Mqtt5ClientTests.MqttTestContext = MqttTestContext()
455+
let client = try createClient(clientOptions: clientOptions, testContext: testContext)
456+
457+
try client.start()
458+
// The connection should fail with metrics in username
459+
await awaitExpectation([testContext.connectionFailureExpectation], 5)
460+
461+
if let failureData = testContext.lifecycleConnectionFailureData {
462+
XCTAssertEqual(
463+
failureData.crtError.code, Int32(AWS_ERROR_MQTT5_CONNACK_CONNECTION_REFUSED.rawValue))
464+
} else {
465+
XCTFail("lifecycleConnectionFailureData Missing")
466+
return
467+
}
468+
469+
try await stopClient(client: client, testContext: testContext)
470+
}
471+
424472
/*
425473
* [ConnDC-UC3] Direct Connection with TLS
426474
*/
@@ -663,7 +711,8 @@ class Mqtt5ClientTests: XCBaseTestCase, @unchecked Sendable {
663711
let clientOptions = MqttClientOptions(
664712
hostName: inputHost,
665713
port: UInt32(inputPort)!,
666-
connectOptions: connectOptions)
714+
connectOptions: connectOptions,
715+
enableMetrics: false)
667716

668717
let testContext = MqttTestContext()
669718
testContext.withWebsocketTransform(isSuccess: true)

0 commit comments

Comments
 (0)