Skip to content

Commit 81f1bc1

Browse files
committed
bring in mqtt5 metrics
1 parent ef0e817 commit 81f1bc1

6 files changed

Lines changed: 205 additions & 3 deletions

File tree

include/aws/mqtt/v5/mqtt5_types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <aws/common/array_list.h>
1212
#include <aws/common/byte_buf.h>
1313

14+
struct aws_mqtt_iot_sdk_metrics;
15+
1416
AWS_PUSH_SANE_WARNING_LEVEL
1517

1618
/**
@@ -394,6 +396,9 @@ struct aws_mqtt5_packet_connect_view {
394396
/* Do not bind these. We don't support AUTH packets yet. For decode/encade testing purposes only. */
395397
const struct aws_byte_cursor *authentication_method;
396398
const struct aws_byte_cursor *authentication_data;
399+
400+
/* IoT SDK metrics configuration */
401+
const struct aws_mqtt_iot_sdk_metrics *metrics;
397402
};
398403

399404
/**

source/v5/mqtt5_options_storage.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <aws/common/uuid.h>
1212
#include <aws/io/channel_bootstrap.h>
1313
#include <aws/io/event_loop.h>
14+
#include <aws/mqtt/private/client_impl_shared.h>
1415
#include <aws/mqtt/private/v5/mqtt5_client_impl.h>
1516
#include <aws/mqtt/private/v5/mqtt5_utils.h>
1617
#include <aws/mqtt/v5/mqtt5_client.h>
@@ -377,6 +378,16 @@ int aws_mqtt5_packet_connect_view_validate(const struct aws_mqtt5_packet_connect
377378
}
378379
}
379380

381+
if (connect_options->metrics != NULL) {
382+
if (aws_mqtt_validate_iot_sdk_metrics_utf8(connect_options->metrics)) {
383+
AWS_LOGF_ERROR(
384+
AWS_LS_MQTT5_GENERAL,
385+
"id=%p: aws_mqtt5_packet_connect_view - metrics not valid UTF-8",
386+
(void *)connect_options);
387+
return aws_raise_error(AWS_ERROR_MQTT5_CONNECT_OPTIONS_VALIDATION);
388+
}
389+
}
390+
380391
if (connect_options->receive_maximum != NULL) {
381392
if (*connect_options->receive_maximum == 0) {
382393
AWS_LOGF_ERROR(
@@ -643,7 +654,11 @@ static size_t s_aws_mqtt5_packet_connect_compute_storage_size(const struct aws_m
643654

644655
storage_size += view->client_id.len;
645656
if (view->username != NULL) {
646-
storage_size += view->username->len;
657+
if (view->metrics) {
658+
storage_size += aws_mqtt_append_sdk_metrics_to_username_size(view->username, *view->metrics);
659+
} else {
660+
storage_size += view->username->len;
661+
}
647662
}
648663
if (view->password != NULL) {
649664
storage_size += view->password->len;
@@ -652,6 +667,8 @@ static size_t s_aws_mqtt5_packet_connect_compute_storage_size(const struct aws_m
652667
storage_size +=
653668
s_aws_mqtt5_user_property_set_compute_storage_size(view->user_properties, view->user_property_count);
654669

670+
storage_size += aws_mqtt_iot_sdk_metrics_compute_storage_size(view->metrics);
671+
655672
if (view->authentication_method != NULL) {
656673
storage_size += view->authentication_method->len;
657674
}
@@ -686,9 +703,24 @@ int aws_mqtt5_packet_connect_storage_init(
686703

687704
if (view->username != NULL) {
688705
storage->username = *view->username;
706+
struct aws_byte_buf metrics_username_buf;
707+
AWS_ZERO_STRUCT(metrics_username_buf);
708+
709+
/* Apply metrics to username if configured */
710+
if (view->metrics) {
711+
struct aws_byte_cursor username_cur = storage->username;
712+
if (aws_mqtt_append_sdk_metrics_to_username(
713+
allocator, &username_cur, *view->metrics, &metrics_username_buf)) {
714+
return AWS_OP_ERR;
715+
}
716+
storage->username = aws_byte_cursor_from_buf(&metrics_username_buf);
717+
}
718+
689719
if (aws_byte_buf_append_and_update(&storage->storage, &storage->username)) {
720+
aws_byte_buf_clean_up(&metrics_username_buf);
690721
return AWS_OP_ERR;
691722
}
723+
aws_byte_buf_clean_up(&metrics_username_buf);
692724

693725
storage_view->username = &storage->username;
694726
}

tests/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ add_test_case(mqtt5_client_options_validation_failure_no_bootstrap)
265265
add_test_case(mqtt5_client_options_validation_failure_no_publish_received)
266266
add_test_case(mqtt5_client_options_validation_failure_invalid_socket_options)
267267
add_test_case(mqtt5_client_options_validation_failure_invalid_connect)
268+
add_test_case(mqtt5_client_options_validation_failure_invalid_metrics_string)
268269
add_test_case(mqtt5_client_options_validation_failure_invalid_port)
269270
add_test_case(mqtt5_operation_subscribe_connection_settings_validation_failure_exceeds_maximum_packet_size)
270271
add_test_case(mqtt5_operation_unsubscribe_connection_settings_validation_failure_exceeds_maximum_packet_size)
@@ -397,6 +398,10 @@ add_test_case(mqtt5_client_outbound_alias_manual_failure_empty_topic)
397398
add_test_case(mqtt5_client_outbound_alias_manual_success_a_b_ar_br)
398399
add_test_case(mqtt5_client_outbound_alias_lru_success_a_b_c_br_cr_a)
399400

401+
# Mqtt5 Metrics tests
402+
add_test_case(mqtt5_client_set_metrics_valid)
403+
add_test_case(mqtt5_client_set_metrics_null)
404+
400405
add_test_case(rate_limiter_token_bucket_init_invalid)
401406
add_test_case(rate_limiter_token_bucket_regeneration_integral)
402407
add_test_case(rate_limiter_token_bucket_regeneration_fractional)

tests/v5/mqtt5_client_tests.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <aws/io/channel_bootstrap.h>
1212
#include <aws/io/event_loop.h>
1313
#include <aws/mqtt/mqtt.h>
14+
#include <aws/mqtt/private/client_impl_shared.h>
1415
#include <aws/mqtt/private/v5/mqtt5_utils.h>
1516
#include <aws/mqtt/v5/mqtt5_client.h>
1617
#include <aws/mqtt/v5/mqtt5_listener.h>
@@ -6652,3 +6653,135 @@ static int s_mqtt5_client_auto_assigned_client_id_iot_core_fn(struct aws_allocat
66526653
}
66536654

66546655
AWS_TEST_CASE(mqtt5_client_auto_assigned_client_id_iot_core, s_mqtt5_client_auto_assigned_client_id_iot_core_fn)
6656+
/*
6657+
* Test that verifies metrics are properly appended to username in CONNECT packet
6658+
* Based on s_mqtt5_client_direct_connect_success_fn
6659+
*/
6660+
static int s_mqtt5_client_metrics_in_username_fn(
6661+
struct aws_allocator *allocator,
6662+
struct aws_mqtt_iot_sdk_metrics *metrics,
6663+
void *ctx) {
6664+
(void)ctx;
6665+
6666+
aws_mqtt_library_init(allocator);
6667+
6668+
struct mqtt5_client_test_options test_options;
6669+
aws_mqtt5_client_test_init_default_options(&test_options);
6670+
6671+
/* Set up username and metrics */
6672+
struct aws_byte_cursor original_username = aws_byte_cursor_from_c_str("test_user");
6673+
6674+
struct aws_mqtt5_packet_connect_view connect_view = {
6675+
.keep_alive_interval_seconds = 30,
6676+
.client_id = aws_byte_cursor_from_string(g_default_client_id),
6677+
.clean_start = true,
6678+
.metrics = metrics,
6679+
.username = &original_username};
6680+
6681+
test_options.connect_options = connect_view;
6682+
6683+
struct aws_mqtt5_client_mqtt5_mock_test_fixture_options test_fixture_options = {
6684+
.client_options = &test_options.client_options,
6685+
.server_function_table = &test_options.server_function_table,
6686+
};
6687+
6688+
struct aws_mqtt5_client_mock_test_fixture test_context;
6689+
ASSERT_SUCCESS(aws_mqtt5_client_mock_test_fixture_init(&test_context, allocator, &test_fixture_options));
6690+
6691+
struct aws_mqtt5_client *client = test_context.client;
6692+
ASSERT_SUCCESS(aws_mqtt5_client_start(client));
6693+
6694+
aws_wait_for_connected_lifecycle_event(&test_context);
6695+
6696+
struct aws_mqtt5_packet_disconnect_view disconnect_options = {
6697+
.reason_code = AWS_MQTT5_DRC_NORMAL_DISCONNECTION,
6698+
};
6699+
6700+
struct aws_mqtt5_disconnect_completion_options completion_options = {
6701+
.completion_callback = s_on_disconnect_completion,
6702+
.completion_user_data = &test_context,
6703+
};
6704+
6705+
ASSERT_SUCCESS(aws_mqtt5_client_stop(client, &disconnect_options, &completion_options));
6706+
6707+
aws_wait_for_stopped_lifecycle_event(&test_context);
6708+
s_wait_for_disconnect_completion(&test_context);
6709+
s_wait_for_mock_server_to_receive_disconnect_packet(&test_context);
6710+
6711+
struct aws_mqtt5_client_lifecycle_event expected_events[] = {
6712+
{
6713+
.event_type = AWS_MQTT5_CLET_ATTEMPTING_CONNECT,
6714+
},
6715+
{
6716+
.event_type = AWS_MQTT5_CLET_CONNECTION_SUCCESS,
6717+
},
6718+
{
6719+
.event_type = AWS_MQTT5_CLET_DISCONNECTION,
6720+
.error_code = AWS_ERROR_MQTT5_USER_REQUESTED_STOP,
6721+
},
6722+
{
6723+
.event_type = AWS_MQTT5_CLET_STOPPED,
6724+
},
6725+
};
6726+
ASSERT_SUCCESS(
6727+
s_verify_simple_lifecycle_event_sequence(&test_context, expected_events, AWS_ARRAY_SIZE(expected_events)));
6728+
6729+
enum aws_mqtt5_client_state expected_states[] = {
6730+
AWS_MCS_CONNECTING,
6731+
AWS_MCS_MQTT_CONNECT,
6732+
AWS_MCS_CONNECTED,
6733+
AWS_MCS_CLEAN_DISCONNECT,
6734+
AWS_MCS_CHANNEL_SHUTDOWN,
6735+
AWS_MCS_STOPPED,
6736+
};
6737+
6738+
ASSERT_SUCCESS(aws_verify_client_state_sequence(&test_context, expected_states, AWS_ARRAY_SIZE(expected_states)));
6739+
6740+
struct aws_mqtt5_packet_connect_storage expected_connect_storage;
6741+
6742+
aws_mqtt5_packet_connect_storage_init(&expected_connect_storage, allocator, &connect_view);
6743+
6744+
struct aws_mqtt5_packet_disconnect_storage expected_disconnect_storage;
6745+
ASSERT_SUCCESS(s_aws_mqtt5_client_test_init_default_disconnect_storage(&expected_disconnect_storage, allocator));
6746+
expected_disconnect_storage.storage_view.reason_code = AWS_MQTT5_DRC_NORMAL_DISCONNECTION;
6747+
6748+
struct aws_mqtt5_mock_server_packet_record expected_packets[] = {
6749+
{
6750+
.packet_type = AWS_MQTT5_PT_CONNECT,
6751+
.packet_storage = &expected_connect_storage,
6752+
},
6753+
{
6754+
.packet_type = AWS_MQTT5_PT_DISCONNECT,
6755+
.packet_storage = &expected_disconnect_storage,
6756+
},
6757+
};
6758+
ASSERT_SUCCESS(
6759+
aws_verify_received_packet_sequence(&test_context, expected_packets, AWS_ARRAY_SIZE(expected_packets)));
6760+
6761+
aws_mqtt5_packet_connect_storage_clean_up(&expected_connect_storage);
6762+
6763+
aws_mqtt5_client_mock_test_fixture_clean_up(&test_context);
6764+
aws_mqtt_library_clean_up();
6765+
6766+
return AWS_OP_SUCCESS;
6767+
}
6768+
6769+
static int s_test_mqtt5_client_set_metrics_valid(struct aws_allocator *allocator, void *ctx) {
6770+
struct aws_mqtt_iot_sdk_metrics metrics = {
6771+
.library_name = aws_byte_cursor_from_c_str("TestSDK/1.0")
6772+
// TODO: enable when metadata is supported
6773+
// .metadata_entries = NULL,
6774+
// .metadata_count = 0,
6775+
};
6776+
6777+
return s_mqtt5_client_metrics_in_username_fn(allocator, &metrics, ctx);
6778+
}
6779+
6780+
AWS_TEST_CASE(mqtt5_client_set_metrics_valid, s_test_mqtt5_client_set_metrics_valid)
6781+
6782+
static int s_test_mqtt5_client_set_metrics_null(struct aws_allocator *allocator, void *ctx) {
6783+
6784+
return s_mqtt5_client_metrics_in_username_fn(allocator, NULL, ctx);
6785+
}
6786+
6787+
AWS_TEST_CASE(mqtt5_client_set_metrics_null, s_test_mqtt5_client_set_metrics_null)

tests/v5/mqtt5_operation_and_storage_tests.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* SPDX-License-Identifier: Apache-2.0.
44
*/
55

6+
#include "../v3/mqtt311_testing_utils.h"
7+
68
#include <aws/common/string.h>
79

810
#include "mqtt5_testing_utils.h"
@@ -672,6 +674,13 @@ static int s_mqtt5_connect_storage_new_set_all_fn(struct aws_allocator *allocato
672674
.topic = aws_byte_cursor_from_c_str(PUBLISH_TOPIC),
673675
};
674676

677+
struct aws_mqtt_iot_sdk_metrics metrics = {
678+
.library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
679+
// TODO: add more metrics fields as needed
680+
// .metadata_entries = NULL,
681+
// .metadata_count = 0,
682+
};
683+
675684
struct aws_mqtt5_packet_connect_view connect_options = {
676685
.keep_alive_interval_seconds = 50,
677686
.client_id = aws_byte_cursor_from_string(s_client_id),
@@ -690,7 +699,7 @@ static int s_mqtt5_connect_storage_new_set_all_fn(struct aws_allocator *allocato
690699
.user_properties = s_user_properties,
691700
.authentication_method = &s_authentication_method_cursor,
692701
.authentication_data = &s_authentication_data_cursor,
693-
};
702+
.metrics = &metrics};
694703

695704
struct aws_mqtt5_packet_connect_storage connect_storage;
696705
AWS_ZERO_STRUCT(connect_storage);
@@ -701,7 +710,15 @@ static int s_mqtt5_connect_storage_new_set_all_fn(struct aws_allocator *allocato
701710

702711
struct aws_mqtt5_packet_connect_view *stored_view = &connect_storage.storage_view;
703712

704-
AWS_VERIFY_VIEW_STORAGE_RELATIONSHIP_NULLABLE_CURSOR(&connect_storage, &connect_options, username);
713+
/* Build expected username with metrics */
714+
struct aws_byte_buf expected_username;
715+
AWS_ZERO_STRUCT(expected_username);
716+
aws_test_mqtt_build_expected_metrics(
717+
allocator, connect_options.username, metrics.library_name, NULL, &expected_username);
718+
ASSERT_BIN_ARRAYS_EQUALS(
719+
expected_username.buffer, expected_username.len, connect_storage.username.ptr, connect_storage.username.len);
720+
aws_byte_buf_clean_up(&expected_username);
721+
705722
AWS_VERIFY_VIEW_STORAGE_RELATIONSHIP_NULLABLE_CURSOR(&connect_storage, &connect_options, password);
706723
AWS_VERIFY_VIEW_STORAGE_RELATIONSHIP_NULLABLE_UINT(
707724
&connect_storage, &connect_options, session_expiry_interval_seconds);

tests/v5/mqtt5_operation_validation_failure_tests.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,16 @@ static void s_make_invalid_connect_client_options(struct aws_mqtt5_client_option
11701170

11711171
AWS_CLIENT_CREATION_VALIDATION_FAILURE(invalid_connect, s_good_client_options, s_make_invalid_connect_client_options)
11721172

1173+
static struct aws_mqtt_iot_sdk_metrics invalid_utf8_metrics = {
1174+
.library_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("TestSDK\xFF\xFE")};
1175+
1176+
static struct aws_mqtt5_packet_connect_view s_invalid_utf8_metrics_connect_view = {.metrics = &invalid_utf8_metrics};
1177+
static void s_make_invalid_utf8_metrics(struct aws_mqtt5_client_options *options) {
1178+
options->connect_options = &s_invalid_utf8_metrics_connect_view;
1179+
}
1180+
1181+
AWS_CLIENT_CREATION_VALIDATION_FAILURE(invalid_metrics_string, s_good_client_options, s_make_invalid_utf8_metrics)
1182+
11731183
static void s_make_invalid_port_client_options(struct aws_mqtt5_client_options *options) {
11741184
options->port = 0xFFFFFFFF;
11751185
}

0 commit comments

Comments
 (0)