Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package aws-c-mqtt for openSUSE:Factory 
checked in at 2026-05-26 16:34:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/aws-c-mqtt (Old)
 and      /work/SRC/openSUSE:Factory/.aws-c-mqtt.new.2084 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "aws-c-mqtt"

Tue May 26 16:34:59 2026 rev:18 rq:1355151 version:0.16.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/aws-c-mqtt/aws-c-mqtt.changes    2026-03-27 
06:36:39.702212956 +0100
+++ /work/SRC/openSUSE:Factory/.aws-c-mqtt.new.2084/aws-c-mqtt.changes  
2026-05-26 16:35:13.210946473 +0200
@@ -1,0 +2,9 @@
+Fri May 22 07:55:57 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 0.16.0
+  * Metrics metadata by @xiazhvera in (#422)
+  * builder -> v0.9.92 and clang-latest by @sbSteveK in (#424)
+  * Refactor IoT metrics parsing by @xiazhvera in (#423)
+  * Keep metadata param order by @xiazhvera in (#426)
+
+-------------------------------------------------------------------

Old:
----
  v0.15.2.tar.gz

New:
----
  v0.16.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ aws-c-mqtt.spec ++++++
--- /var/tmp/diff_new_pack.Buh9KS/_old  2026-05-26 16:35:14.122984206 +0200
+++ /var/tmp/diff_new_pack.Buh9KS/_new  2026-05-26 16:35:14.126984371 +0200
@@ -18,7 +18,7 @@
 
 %global library_version 1_0_0
 Name:           aws-c-mqtt
-Version:        0.15.2
+Version:        0.16.0
 Release:        0
 Summary:        AWS C99 implementation of the MQTT 3.1.1 specification
 License:        Apache-2.0

++++++ v0.15.2.tar.gz -> v0.16.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/.github/workflows/ci.yml 
new/aws-c-mqtt-0.16.0/.github/workflows/ci.yml
--- old/aws-c-mqtt-0.15.2/.github/workflows/ci.yml      2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/.github/workflows/ci.yml      2026-05-18 
20:49:17.000000000 +0200
@@ -6,7 +6,7 @@
       - 'main'
 
 env:
-  BUILDER_VERSION: v0.9.73
+  BUILDER_VERSION: v0.9.92
   BUILDER_SOURCE: releases
   BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net
   PACKAGE_NAME: aws-c-mqtt
@@ -55,6 +55,7 @@
           - clang-11
           - clang-15
           - clang-17
+          - clang-latest
           - gcc-4.8
           - gcc-5
           - gcc-6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/include/aws/mqtt/client.h 
new/aws-c-mqtt-0.16.0/include/aws/mqtt/client.h
--- old/aws-c-mqtt-0.15.2/include/aws/mqtt/client.h     2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/include/aws/mqtt/client.h     2026-05-18 
20:49:17.000000000 +0200
@@ -697,8 +697,6 @@
  * Sets IoT SDK metrics configuration for the connection.
  * These metrics will be appended to the username field during connection.
  *
- * NOTE: DO NOT USE METADATA. Metadata will not be set.
- *
  * \param connection The connection object
  * \param metrics The IoT SDK metrics configuration (pass NULL to disable 
metrics)
  * \returns AWS_OP_SUCCESS if successful, AWS_OP_ERR otherwise
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/include/aws/mqtt/mqtt.h 
new/aws-c-mqtt-0.16.0/include/aws/mqtt/mqtt.h
--- old/aws-c-mqtt-0.15.2/include/aws/mqtt/mqtt.h       2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/include/aws/mqtt/mqtt.h       2026-05-18 
20:49:17.000000000 +0200
@@ -127,6 +127,12 @@
      * Library name string (SDK attribute)
      */
     struct aws_byte_cursor library_name;
+
+    /**
+     * Metadata entries, key value pair to set in metrics "Metadata" field
+     */
+    size_t metadata_count;
+    const struct aws_mqtt_metadata_entry *metadata_entries;
 };
 
 AWS_EXTERN_C_BEGIN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/aws-c-mqtt-0.15.2/include/aws/mqtt/private/mqtt_iot_metrics.h 
new/aws-c-mqtt-0.16.0/include/aws/mqtt/private/mqtt_iot_metrics.h
--- old/aws-c-mqtt-0.15.2/include/aws/mqtt/private/mqtt_iot_metrics.h   
2026-03-18 21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/include/aws/mqtt/private/mqtt_iot_metrics.h   
2026-05-18 20:49:17.000000000 +0200
@@ -16,6 +16,8 @@
 
     struct aws_byte_cursor library_name;
 
+    struct aws_array_list metadata_entries;
+
     struct aws_byte_buf storage;
 };
 
@@ -54,4 +56,17 @@
 AWS_MQTT_API
 int aws_mqtt_validate_iot_metrics(const struct aws_mqtt_iot_metrics *metrics);
 
+/**
+ * Checks if username should be included in the CONNECT packet.
+ * Returns true if either username is provided or metrics are configured.
+ *
+ * @param username The username cursor (can be NULL)
+ * @param metrics_storage The metrics storage (can be NULL)
+ * @return true if username should be included, false otherwise
+ */
+AWS_MQTT_API
+bool aws_mqtt_has_non_empty_username(
+    const struct aws_byte_cursor *username,
+    const struct aws_mqtt_iot_metrics_storage *metrics_storage);
+
 #endif /* AWS_MQTT_IOT_METRICS_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/source/client.c 
new/aws-c-mqtt-0.16.0/source/client.c
--- old/aws-c-mqtt-0.15.2/source/client.c       2026-03-18 21:44:05.000000000 
+0100
+++ new/aws-c-mqtt-0.16.0/source/client.c       2026-05-18 20:49:17.000000000 
+0200
@@ -635,12 +635,13 @@
             &connect, topic_cur, connection->will.qos, 
connection->will.retain, payload_cur);
     }
 
-    if (connection->username || connection->metrics_storage) {
-        struct aws_byte_cursor username_cur;
-        AWS_ZERO_STRUCT(username_cur);
-        if (connection->username) {
-            username_cur = aws_byte_cursor_from_string(connection->username);
-        }
+    struct aws_byte_cursor username_cur;
+    AWS_ZERO_STRUCT(username_cur);
+    if (connection->username) {
+        username_cur = aws_byte_cursor_from_string(connection->username);
+    }
+
+    if (aws_mqtt_has_non_empty_username(&username_cur, 
connection->metrics_storage)) {
 
         /* Apply metrics to username if configured */
         if (connection->metrics_storage) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/source/mqtt_iot_metrics.c 
new/aws-c-mqtt-0.16.0/source/mqtt_iot_metrics.c
--- old/aws-c-mqtt-0.15.2/source/mqtt_iot_metrics.c     2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/source/mqtt_iot_metrics.c     2026-05-18 
20:49:17.000000000 +0200
@@ -15,86 +15,324 @@
 const size_t AWS_IOT_MAX_USERNAME_SIZE = UINT16_MAX;
 const size_t DEFAULT_QUERY_PARAM_COUNT = 10;
 
+/*********************************************************************************************************************
+ * Helper functions for parsing and merging key-value pairs
+ 
********************************************************************************************************************/
+
 /**
- * Builds final username with query parameters appended.
+ * Find a parameter by key in a list of aws_uri_param.
  *
- * @param base_username The original username cursor
- * @param base_username_length Length of base username to use (may differ from 
cursor length)
- * @param params_list List of query parameters to append
- * @param output_username [Optional] Buffer to write result. Caller must 
init/cleanup the buffer.
- * @param out_final_username_size [Optional] Outputs the final username size
- *
- * @return AWS_OP_SUCCESS on success, AWS_OP_ERR on failure
+ * @param params_list List of aws_uri_param to search
+ * @param key The key to search for
+ * @param out_index [Optional] If not NULL and key is found, will be set to 
the index of the found parameter
+ * @return Pointer to the found parameter, or NULL if not found
  */
-int s_build_username_query(
-    const struct aws_byte_cursor *base_username,
-    size_t base_username_length,
+static struct aws_uri_param *s_find_param_by_key(
     const struct aws_array_list *params_list,
-    struct aws_byte_buf *output_username,
-    size_t *out_final_username_size) {
+    const struct aws_byte_cursor key,
+    size_t *out_index) {
 
-    AWS_ASSERT(base_username);
-    AWS_ASSERT(params_list);
+    size_t params_count = aws_array_list_length(params_list);
+    for (size_t i = 0; i < params_count; ++i) {
+        struct aws_uri_param *param = NULL;
+        aws_array_list_get_at_ptr(params_list, (void **)&param, i);
+        if (aws_byte_cursor_eq(&param->key, &key)) {
+            if (out_index) {
+                *out_index = i;
+            }
+            return param;
+        }
+    }
+    return NULL;
+}
 
-    if (output_username) {
-        if (!aws_byte_buf_write(output_username, base_username->ptr, 
base_username_length)) {
-            return AWS_OP_ERR;
+/**
+ * Add a parameter to the list only if a parameter with the same key doesn't 
already exist.
+ *
+ * @param params_list List of aws_uri_param to add to
+ * @param key The key for the new parameter
+ * @param value The value for the new parameter
+ * @return true if the parameter was added, false if a parameter with the same 
key already exists
+ */
+static bool s_add_param_if_not_exists(
+    struct aws_array_list *params_list,
+    const struct aws_byte_cursor key,
+    const struct aws_byte_cursor value) {
+
+    if (s_find_param_by_key(params_list, key, NULL) != NULL) {
+        return false;
+    }
+
+    struct aws_uri_param param = {
+        .key = key,
+        .value = value,
+    };
+    aws_array_list_push_back(params_list, &param);
+    return true;
+}
+
+/**
+ * Parse key-value entries from a aws_byte_cursor using a specified delimiter.
+ * Each entry is expected to be in the format "key=value" or just "key". 
(e.g., "key1=value1&key2=value2")
+ *
+ * @param content The content to parse
+ * @param delimiter The delimiter cursor (e.g., ";" or "&"), length of 
delimiter must > 0.
+ * @param out_entries List to populate with parsed aws_uri_param entries. Must 
be initialized by caller.
+ * @return AWS_OP_SUCCESS on success, AWS_OP_ERR on failure
+ */
+static int s_parse_delimited_entries(
+    const struct aws_byte_cursor content,
+    const struct aws_byte_cursor delimiter,
+    struct aws_array_list *out_entries) {
+
+    AWS_ASSERT(delimiter.len > 0);
+
+    struct aws_byte_cursor equals_delim = aws_byte_cursor_from_c_str("=");
+    struct aws_byte_cursor entry_cursor;
+    AWS_ZERO_STRUCT(entry_cursor);
+
+    while (aws_byte_cursor_next_split_on_cursor(&content, delimiter, 
&entry_cursor)) {
+        /* Skip empty entries */
+        if (entry_cursor.len == 0) {
+            continue;
+        }
+
+        /* Parse key=value from entry_cursor */
+        struct aws_uri_param entry_param;
+        AWS_ZERO_STRUCT(entry_param);
+
+        /* Use a copy to avoid modifying entry_cursor which tracks iteration 
state */
+        struct aws_byte_cursor working_cursor = entry_cursor;
+        struct aws_byte_cursor equals_pos;
+        if (aws_byte_cursor_find_exact(&working_cursor, &equals_delim, 
&equals_pos) == AWS_OP_SUCCESS) {
+            size_t equals_offset = equals_pos.ptr - working_cursor.ptr;
+            entry_param.key = aws_byte_cursor_advance(&working_cursor, 
equals_offset);
+            /* Skip the "=" delimiter */
+            aws_byte_cursor_advance(&working_cursor, 1);
+            entry_param.value = working_cursor;
+        } else {
+            /* No equals sign, treat entire entry as key */
+            entry_param.key = entry_cursor;
         }
+
+        aws_array_list_push_back(out_entries, &entry_param);
     }
 
-    if (out_final_username_size) {
-        *out_final_username_size = base_username_length;
+    return AWS_OP_SUCCESS;
+}
+
+/**
+ * Merge new entries into an existing entries list without overwriting 
existing keys.
+ *
+ * @param existing_metadata_list List of existing aws_uri_param entries (will 
be modified)
+ * @param new_entries Array of new entries to merge
+ * @param new_entries_count Number of new entries
+ */
+static void s_merge_metadata_entries_no_overwrite(
+    struct aws_array_list *existing_metadata_list,
+    const struct aws_mqtt_metadata_entry *new_entries_list,
+    const size_t new_entries_list_count) {
+
+    for (size_t i = 0; i < new_entries_list_count; ++i) {
+        const struct aws_mqtt_metadata_entry *new_entry = &new_entries_list[i];
+        s_add_param_if_not_exists(existing_metadata_list, new_entry->key, 
new_entry->value);
     }
+}
 
-    struct aws_byte_cursor query_delim = aws_byte_cursor_from_c_str("?");
-    struct aws_byte_cursor query_param_amp = aws_byte_cursor_from_c_str("&");
+/**
+ * Build a delimited key-value string from a list of parameters.
+ * Can be used to either calculate the size, build the string, or both.
+ *
+ * Format: {prefix}{key1}={value1}{delimiter}{key2}={value2}...{suffix}
+ * If params_list is empty, returns empty string (no prefix/suffix).
+ *
+ * @param params_list List of aws_uri_param entries
+ * @param prefix [Optional] String to prepend (e.g., "?" for query strings, 
"(" for metadata)
+ * @param suffix [Optional] String to append (e.g., ")" for metadata)
+ * @param entry_delimiter Delimiter between entries (e.g., "&" for query 
strings, ";" for metadata)
+ * @param output_buf [Optional] Buffer to write the result to. Must be 
initialized with sufficient capacity.
+ * @param out_size [Optional] If not NULL, will be set to the size of the 
result string
+ * @return AWS_OP_SUCCESS on success, AWS_OP_ERR on failure
+ */
+static int s_build_delimited_params(
+    const struct aws_array_list *params_list,
+    const struct aws_byte_cursor *prefix,
+    const struct aws_byte_cursor *suffix,
+    const struct aws_byte_cursor entry_delimiter,
+    struct aws_byte_buf *output_buf,
+    size_t *out_size) {
+
+    AWS_ASSERT(entry_delimiter.len > 0);
+
+    size_t local_out_size = 0;
     struct aws_byte_cursor key_value_delim = aws_byte_cursor_from_c_str("=");
 
     size_t params_count = aws_array_list_length(params_list);
+
+    /* If params_list is empty, return empty string (no prefix/suffix) */
+    if (params_count == 0) {
+        if (out_size) {
+            *out_size = 0;
+        }
+        return AWS_OP_SUCCESS;
+    }
+
+    if (prefix) {
+        local_out_size += prefix->len;
+    }
+    if (suffix) {
+        local_out_size += suffix->len;
+    }
+
+    if (output_buf && prefix && prefix->len > 0) {
+        if (aws_byte_buf_append(output_buf, prefix)) {
+            return AWS_OP_ERR;
+        }
+    }
+
     for (size_t i = 0; i < params_count; ++i) {
         struct aws_uri_param param;
         AWS_ZERO_STRUCT(param);
         aws_array_list_get_at(params_list, &param, i);
 
-        if (output_username) {
-            if (i == 0) {
-                aws_byte_buf_append(output_username, &query_delim);
-            } else {
-                aws_byte_buf_append(output_username, &query_param_amp);
+        /* Add delimiter between entries (not before the first one) */
+        if (i > 0) {
+            if (output_buf) {
+                if (aws_byte_buf_append(output_buf, &entry_delimiter)) {
+                    return AWS_OP_ERR;
+                }
             }
+            local_out_size += entry_delimiter.len;
         }
 
-        if (out_final_username_size) {
-            *out_final_username_size += 1;
+        /* Append key */
+        if (output_buf && param.key.len > 0) {
+            if (aws_byte_buf_append(output_buf, &param.key)) {
+                return AWS_OP_ERR;
+            }
         }
+        local_out_size += param.key.len;
 
-        if (output_username) {
-            if (param.key.len > 0) {
-                // append key if key exists
-                if (aws_byte_buf_append(output_username, &param.key)) {
+        /* Append =value if value exists */
+        if (param.value.len > 0) {
+            if (output_buf) {
+                if (aws_byte_buf_append(output_buf, &key_value_delim) ||
+                    aws_byte_buf_append(output_buf, &param.value)) {
                     return AWS_OP_ERR;
                 }
             }
+            local_out_size += 1 + param.value.len; /* '=' + value */
+        }
+    }
 
-            // append value if value exists
-            if (param.value.len > 0)
-                // Note: If value exists without a key, append "=" and value 
(e.g., "?=abc").
-                // Please note server treats "a=", "a", and "=a" equivalently.
-                if ((aws_byte_buf_append(output_username, &key_value_delim)) ||
-                    aws_byte_buf_append(output_username, &param.value)) {
-                    return AWS_OP_ERR;
-                }
+    if (output_buf && suffix && suffix->len > 0) {
+        if (aws_byte_buf_append(output_buf, suffix)) {
+            return AWS_OP_ERR;
         }
+    }
+
+    if (out_size) {
+        *out_size = local_out_size;
+    }
 
-        if (out_final_username_size) {
-            *out_final_username_size += param.key.len + (param.value.len > 0 ? 
1 : 0) + param.value.len;
+    return AWS_OP_SUCCESS;
+}
+
+/**
+ * Build the metadata value string from entries: (key1=value1;key2=value2;...)
+ * Can be used to either calculate the size, build the string, or both.
+ *
+ * @param entries List of aws_uri_param entries
+ * @param output_buf [Optional] Buffer to write the metadata value to. Must be 
initialized with sufficient capacity.
+ * @param out_size [Optional] If not NULL, will be set to the size of the 
metadata value string
+ * @return AWS_OP_SUCCESS on success, AWS_OP_ERR on failure
+ */
+static int s_build_metadata_value(
+    const struct aws_array_list *entries,
+    struct aws_byte_buf *output_buf,
+    size_t *out_size) {
+
+    struct aws_byte_cursor open_paren = aws_byte_cursor_from_c_str("(");
+    struct aws_byte_cursor close_paren = aws_byte_cursor_from_c_str(")");
+    struct aws_byte_cursor semicolon_delim = aws_byte_cursor_from_c_str(";");
+
+    return s_build_delimited_params(entries, &open_paren, &close_paren, 
semicolon_delim, output_buf, out_size);
+}
+
+/**
+ * Builds final username with query parameters appended.
+ *
+ * @param base_username The original username cursor
+ * @param base_username_length Length of base username to use (may differ from 
cursor length)
+ * @param params_list List of query parameters to append
+ * @param output_username [Optional] Buffer to write result. Caller must 
init/cleanup the buffer.
+ * @param out_final_username_size [Optional] Outputs the final username size
+ *
+ * @return AWS_OP_SUCCESS on success, AWS_OP_ERR on failure
+ */
+static int s_build_username_query(
+    const struct aws_byte_cursor base_username,
+    const size_t base_username_length,
+    const struct aws_array_list *params_list,
+    struct aws_byte_buf *output_username,
+    size_t *out_final_username_size) {
+
+    /* Write base username first */
+    if (output_username) {
+        if (!aws_byte_buf_write(output_username, base_username.ptr, 
base_username_length)) {
+            return AWS_OP_ERR;
         }
     }
 
+    if (out_final_username_size) {
+        *out_final_username_size = base_username_length;
+    }
+
+    /* Build query parameters using the generic helper */
+    struct aws_byte_cursor query_prefix = aws_byte_cursor_from_c_str("?");
+    struct aws_byte_cursor ampersand_delim = aws_byte_cursor_from_c_str("&");
+
+    size_t params_size = 0;
+    if (s_build_delimited_params(params_list, &query_prefix, NULL, 
ampersand_delim, output_username, &params_size)) {
+        return AWS_OP_ERR;
+    }
+
+    if (out_final_username_size) {
+        *out_final_username_size += params_size;
+    }
+
     return AWS_OP_SUCCESS;
 }
 
-// TODO Future Work: we ignored the metadata field for now, will add them in 
future support
+/**
+ * Appends SDK metrics to an MQTT username for IoT service telemetry.
+ *
+ * This function transforms a username by appending SDK metrics as query 
parameters.
+ * The IoT service uses the last '?' in the username to identify the metrics 
section.
+ *
+ * Step-by-step process:
+ * 1. Parse existing username: Find the last '?' in the original username and 
parse query params into
+ * username_params_list
+ * 2. Add "SDK" and "Platform" parameters if not already present
+ * 3. Handle Metadata entries if metadata entries are provided
+ *  a. Check if existing "Metadata" parameter exists in username_params_list
+ *  b. If existing Metadata found with valid format:
+ *     - Parse existing entries into a key-value metadata_param_list
+ *     - Remove existing Metadata from username_params_list (will be rebuilt 
later)
+ *  c. If existing Metadata has an invalid format:
+ *     - Log debug message and skip adding metrics metadata entries
+ *     - Keep original Metadata value unchanged, skip (d)
+ *  d. Append metrics metadata entries to metadata_param_list
+ *     - Add new metadata entries into metadata_param_list (existing keys take 
precedence, won't be overwritten)
+ *     - build metadata value string from metadata_param_list
+ *     - Add Metadata parameter to username_params_list
+ * 4. Build final username from username_params_list
+ *
+ * Example transformation:
+ *   Input:  "myuser?existing=value"
+ *   Metrics: {library_name="MySDK/1.0", metadata=[{key="ver", value="1.0"}]}
+ *   Output: 
"myuser?existing=value&SDK=MySDK/1.0&Platform=Darwin&Metadata=(ver=1.0)"
+ */
 int aws_mqtt_append_sdk_metrics_to_username(
     struct aws_allocator *allocator,
     const struct aws_byte_cursor *original_username,
@@ -128,22 +366,29 @@
     }
 
     int result = AWS_OP_ERR;
-    // The length of the base username part not including query parameters
     size_t base_username_length = 0;
     struct aws_byte_cursor question_mark_str = aws_byte_cursor_from_c_str("?");
     struct aws_byte_cursor sdk_str = aws_byte_cursor_from_c_str("SDK");
     struct aws_byte_cursor platform_str = 
aws_byte_cursor_from_c_str("Platform");
+    struct aws_byte_cursor metadata_str = 
aws_byte_cursor_from_c_str("Metadata");
+
+    struct aws_array_list username_params_list;
+    aws_array_list_init_dynamic(
+        &username_params_list, allocator, DEFAULT_QUERY_PARAM_COUNT, 
sizeof(struct aws_uri_param));
 
-    struct aws_array_list params_list;
-    aws_array_list_init_dynamic(&params_list, allocator, 
DEFAULT_QUERY_PARAM_COUNT, sizeof(struct aws_uri_param));
+    struct aws_byte_buf metadata_value_buf;
+    AWS_ZERO_STRUCT(metadata_value_buf);
 
-    // Looking for any existing query in the original username
+    struct aws_array_list metadata_param_list;
+    AWS_ZERO_STRUCT(metadata_param_list);
+
+    /* Parse existing query parameters from the original username */
     if (local_original_username.len > 0) {
         struct aws_byte_cursor question_mark_find = local_original_username;
 
         bool found_query = false;
-        // Find the last question mark. The IoT service will trim string after 
last question mark and handle it as
-        // metrics metadata
+        /* Find the last question mark. The IoT service will trim string after 
last question mark and handle it as
+         * metrics metadata */
         while (AWS_OP_SUCCESS ==
                aws_byte_cursor_find_exact(&question_mark_find, 
&question_mark_str, &question_mark_find)) {
             // Advance cursor to skip the "?" character
@@ -154,53 +399,98 @@
         if (found_query) {
             // Trim out the query delimiter from the base username
             base_username_length = question_mark_find.ptr - 1 - 
local_original_username.ptr;
-            aws_query_string_params(question_mark_find, &params_list);
+            aws_query_string_params(question_mark_find, &username_params_list);
         } else {
             base_username_length = local_original_username.len;
         }
     }
 
-    // Verify if the username already contains "SDK" and "Platform" fields.
-    bool found_sdk = false;
-    bool found_platform = false;
-
-    size_t params_count = aws_array_list_length(&params_list);
-    for (size_t i = 0; i < params_count; ++i) {
-        struct aws_uri_param param;
-        AWS_ZERO_STRUCT(param);
-        aws_array_list_get_at(&params_list, &param, i);
-        if (aws_byte_cursor_eq(&param.key, &sdk_str)) {
-            found_sdk = true;
-        } else if (aws_byte_cursor_eq(&param.key, &platform_str)) {
-            found_platform = true;
+    /* Add SDK parameter if not already present */
+    struct aws_byte_cursor sdk_value =
+        metrics->library_name.len > 0 ? metrics->library_name : 
aws_byte_cursor_from_c_str("IoTDeviceSDK/C");
+    s_add_param_if_not_exists(&username_params_list, sdk_str, sdk_value);
+
+    /* Add Platform parameter if not already present */
+    s_add_param_if_not_exists(&username_params_list, platform_str, 
aws_get_platform_build_os_string());
+
+    /* Handle metadata entries: parse existing, merge with new, and rebuild */
+    bool has_new_metadata = metrics->metadata_entries != NULL && 
metrics->metadata_count > 0;
+
+    if (has_new_metadata) {
+        struct aws_byte_cursor semicolon_delim = 
aws_byte_cursor_from_c_str(";");
+        bool should_merge_metadata = true;
+
+        aws_array_list_init_dynamic(
+            &metadata_param_list, allocator, DEFAULT_QUERY_PARAM_COUNT, 
sizeof(struct aws_uri_param));
+
+        /* Find existing Metadata parameter */
+        size_t existing_metadata_index = 0;
+        struct aws_uri_param *existing_metadata_param =
+            s_find_param_by_key(&username_params_list, metadata_str, 
&existing_metadata_index);
+
+        if (existing_metadata_param != NULL && 
existing_metadata_param->value.len > 0) {
+            /* Extract content without parentheses: (key1=value1;key2=value2) 
-> key1=value1;key2=value2 */
+            struct aws_byte_cursor existing_content = 
existing_metadata_param->value;
+            if (existing_content.len >= 2 && existing_content.ptr[0] == '(' &&
+                existing_content.ptr[existing_content.len - 1] == ')') {
+                aws_byte_cursor_advance(&existing_content, 1);
+                existing_content.len -= 1;
+
+                /* Parse existing metadata entries */
+                if (existing_content.len > 0) {
+                    s_parse_delimited_entries(existing_content, 
semicolon_delim, &metadata_param_list);
+                }
+            } else {
+                /* Wrong format: keep the original metadata value unchanged 
and don't append new metadata */
+                AWS_LOGF_DEBUG(
+                    AWS_LS_MQTT_GENERAL,
+                    "Existing Metadata parameter has invalid format (expected 
parentheses). "
+                    "Keeping original value and skipping new metadata 
entries.");
+                should_merge_metadata = false;
+            }
         }
-    }
 
-    if (!found_sdk) {
-        struct aws_uri_param sdk_params = {
-            .key = sdk_str,
-            .value =
-                metrics->library_name.len > 0 ? metrics->library_name : 
aws_byte_cursor_from_c_str("IoTDeviceSDK/C"),
-        };
-        aws_array_list_push_back(&params_list, &sdk_params);
-    }
+        if (should_merge_metadata) {
+            /* Merge new metadata entries (won't overwrite existing keys) */
+            s_merge_metadata_entries_no_overwrite(
+                &metadata_param_list, metrics->metadata_entries, 
metrics->metadata_count);
+
+            /* Calculate size needed for metadata value string first */
+            size_t metadata_value_size = 0;
+            s_build_metadata_value(&metadata_param_list, NULL, 
&metadata_value_size);
+
+            /* Initialize buffer and build the metadata value string */
+            if (aws_byte_buf_init(&metadata_value_buf, allocator, 
metadata_value_size)) {
+                goto cleanup;
+            }
+
+            if (s_build_metadata_value(&metadata_param_list, 
&metadata_value_buf, NULL)) {
+                goto cleanup;
+            }
 
-    if (!found_platform) {
-        struct aws_uri_param platform_params = {
-            .key = platform_str,
-            .value = aws_get_platform_build_os_string(),
-        };
-        aws_array_list_push_back(&params_list, &platform_params);
+            /* Add or replace Metadata parameter in username_params_list */
+            struct aws_uri_param metadata_params = {
+                .key = metadata_str,
+                .value = aws_byte_cursor_from_buf(&metadata_value_buf),
+            };
+            if (existing_metadata_param != NULL) {
+                /* Replace existing Metadata parameter at the same index */
+                aws_array_list_set_at(&username_params_list, &metadata_params, 
existing_metadata_index);
+            } else {
+                aws_array_list_push_back(&username_params_list, 
&metadata_params);
+            }
+        }
     }
 
-    // Rebuild metrics string from params_list
-    // First parse to get final username size
+    /* Rebuild metrics string from username_params_list */
+    // Calculate the final username size first.
     size_t total_size = 0;
-    s_build_username_query(&local_original_username, base_username_length, 
&params_list, NULL, &total_size);
+    s_build_username_query(local_original_username, base_username_length, 
&username_params_list, NULL, &total_size);
 
     if (total_size > AWS_IOT_MAX_USERNAME_SIZE) {
         AWS_LOGF_ERROR(
-            AWS_LL_DEBUG, "Failed to append SDK metrics to username: resulting 
username exceeds max username size.");
+            AWS_LS_MQTT_GENERAL,
+            "Failed to append SDK metrics to username: resulting username 
exceeds max username size.");
         aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
         goto cleanup;
     }
@@ -209,16 +499,23 @@
         goto cleanup;
     }
 
-    // build final output username
     if (s_build_username_query(
-            &local_original_username, base_username_length, &params_list, 
output_username, out_full_username_size)) {
+            local_original_username,
+            base_username_length,
+            &username_params_list,
+            output_username,
+            out_full_username_size)) {
         goto cleanup;
     }
 
     result = AWS_OP_SUCCESS;
 
 cleanup:
-    aws_array_list_clean_up(&params_list);
+    aws_byte_buf_clean_up(&metadata_value_buf);
+    aws_array_list_clean_up(&username_params_list);
+    if (aws_array_list_is_valid(&metadata_param_list)) {
+        aws_array_list_clean_up(&metadata_param_list);
+    }
 
     if (result == AWS_OP_ERR) {
         aws_byte_buf_clean_up(output_username);
@@ -238,6 +535,15 @@
     size_t storage_size = 0;
     storage_size += metrics->library_name.len;
 
+    /* Add storage for metadata entries */
+    if (metrics->metadata_entries != NULL && metrics->metadata_count > 0) {
+        for (size_t i = 0; i < metrics->metadata_count; ++i) {
+            const struct aws_mqtt_metadata_entry *entry = 
&metrics->metadata_entries[i];
+            storage_size += entry->key.len;
+            storage_size += entry->value.len;
+        }
+    }
+
     return storage_size;
 }
 
@@ -270,13 +576,49 @@
         storage_view->library_name = metrics_storage->library_name;
     }
 
+    /* Copy metadata entries */
+    if (metrics_options->metadata_entries != NULL && 
metrics_options->metadata_count > 0) {
+        if (aws_array_list_init_dynamic(
+                &metrics_storage->metadata_entries,
+                allocator,
+                metrics_options->metadata_count,
+                sizeof(struct aws_mqtt_metadata_entry))) {
+            goto cleanup_storage;
+        }
+
+        for (size_t i = 0; i < metrics_options->metadata_count; ++i) {
+            struct aws_mqtt_metadata_entry entry;
+            entry.key = metrics_options->metadata_entries[i].key;
+            entry.value = metrics_options->metadata_entries[i].value;
+
+            /* Copy key into storage buffer and update cursor */
+            if (entry.key.len > 0) {
+                if (aws_byte_buf_append_and_update(&metrics_storage->storage, 
&entry.key)) {
+                    goto cleanup_storage;
+                }
+            }
+
+            /* Copy value into storage buffer and update cursor */
+            if (entry.value.len > 0) {
+                if (aws_byte_buf_append_and_update(&metrics_storage->storage, 
&entry.value)) {
+                    goto cleanup_storage;
+                }
+            }
+
+            aws_array_list_push_back(&metrics_storage->metadata_entries, 
&entry);
+        }
+
+        /* Set storage_view to point to the metadata entries array */
+        storage_view->metadata_count = 
aws_array_list_length(&metrics_storage->metadata_entries);
+        storage_view->metadata_entries = 
metrics_storage->metadata_entries.data;
+    }
+
     return metrics_storage;
 
 cleanup_storage:
-    // TODO Future Work: add metadata entries once we implemented the metadata 
feature
-    // if (aws_array_list_is_valid(&metrics_storage->metadata_entries)) {
-    //     aws_array_list_clean_up(&metrics_storage->metadata_entries);
-    // }
+    if (aws_array_list_is_valid(&metrics_storage->metadata_entries)) {
+        aws_array_list_clean_up(&metrics_storage->metadata_entries);
+    }
 
     aws_byte_buf_clean_up(&metrics_storage->storage);
     aws_mem_release(allocator, metrics_storage);
@@ -288,6 +630,10 @@
         return;
     }
 
+    if (aws_array_list_is_valid(&metrics_storage->metadata_entries)) {
+        aws_array_list_clean_up(&metrics_storage->metadata_entries);
+    }
+
     aws_byte_buf_clean_up(&metrics_storage->storage);
 
     aws_mem_release(metrics_storage->allocator, metrics_storage);
@@ -302,5 +648,23 @@
         return AWS_OP_ERR;
     }
 
+    /* Validate metadata entries */
+    if (metrics->metadata_entries != NULL && metrics->metadata_count > 0) {
+        for (size_t i = 0; i < metrics->metadata_count; ++i) {
+            if (aws_mqtt_validate_utf8_text(metrics->metadata_entries[i].key)) 
{
+                return AWS_OP_ERR;
+            }
+            if 
(aws_mqtt_validate_utf8_text(metrics->metadata_entries[i].value)) {
+                return AWS_OP_ERR;
+            }
+        }
+    }
+
     return AWS_OP_SUCCESS;
 }
+
+bool aws_mqtt_has_non_empty_username(
+    const struct aws_byte_cursor *username,
+    const struct aws_mqtt_iot_metrics_storage *metrics_storage) {
+    return (username != NULL && username->len > 0) || metrics_storage != NULL;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/source/v5/mqtt5_options_storage.c 
new/aws-c-mqtt-0.16.0/source/v5/mqtt5_options_storage.c
--- old/aws-c-mqtt-0.15.2/source/v5/mqtt5_options_storage.c     2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/source/v5/mqtt5_options_storage.c     2026-05-18 
20:49:17.000000000 +0200
@@ -645,7 +645,9 @@
     size_t storage_size = 0;
 
     storage_size += view->client_id.len;
-    if (view->username != NULL) {
+
+    if (aws_mqtt_has_non_empty_username(view->username, options ? 
options->metrics_storage : NULL)) {
+
         if (options) {
             size_t username_size = 0;
             aws_mqtt_append_sdk_metrics_to_username(
@@ -699,17 +701,19 @@
         return AWS_OP_ERR;
     }
 
-    if (view->username != NULL) {
-        storage->username = *view->username;
+    if (aws_mqtt_has_non_empty_username(
+            view->username, client_options_storage ? 
client_options_storage->metrics_storage : NULL)) {
+        if (view->username) {
+            storage->username = *view->username;
+        }
         struct aws_byte_buf metrics_username_buf;
         AWS_ZERO_STRUCT(metrics_username_buf);
 
         /* Apply metrics to username if configured */
         if (client_options_storage) {
-            struct aws_byte_cursor username_cur = storage->username;
             if (aws_mqtt_append_sdk_metrics_to_username(
                     allocator,
-                    &username_cur,
+                    &storage->username,
                     client_options_storage->metrics_storage ? 
&client_options_storage->metrics_storage->storage_view
                                                             : NULL,
                     &metrics_username_buf,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/tests/CMakeLists.txt 
new/aws-c-mqtt-0.16.0/tests/CMakeLists.txt
--- old/aws-c-mqtt-0.15.2/tests/CMakeLists.txt  2026-03-18 21:44:05.000000000 
+0100
+++ new/aws-c-mqtt-0.16.0/tests/CMakeLists.txt  2026-05-18 20:49:17.000000000 
+0200
@@ -115,6 +115,7 @@
 # Connection state tests
 add_test_case(mqtt_connection_set_metrics_valid)
 add_test_case(mqtt_connection_set_metrics_null)
+add_test_case(mqtt_connection_set_metrics_with_null_username)
 add_test_case(mqtt_connection_set_metrics_invalid_utf8_library)
 add_test_case(mqtt_connection_set_metrics_modify_on_reconnect)
 
@@ -149,6 +150,13 @@
 add_test_case(mqtt_append_sdk_metrics_long_strings)
 add_test_case(mqtt_append_sdk_metrics_invalid_utf8)
 add_test_case(mqtt_append_sdk_metrics_multiple_question_mark)
+add_test_case(mqtt_append_sdk_metrics_with_metadata)
+add_test_case(mqtt_append_sdk_metrics_with_metadata_invalid_utf8)
+add_test_case(mqtt_append_sdk_metrics_with_metadata_invalid_utf8_value)
+add_test_case(mqtt_iot_metrics_storage_with_metadata)
+add_test_case(mqtt_iot_metrics_storage_empty_metadata)
+add_test_case(mqtt_append_sdk_metrics_existing_metadata)
+add_test_case(mqtt_append_sdk_metrics_existing_metadata_no_new)
 
 # topic aliasing
 add_test_case(mqtt5_inbound_topic_alias_register_failure)
@@ -414,6 +422,7 @@
 # Mqtt5 Metrics tests
 add_test_case(mqtt5_client_set_metrics_valid)
 add_test_case(mqtt5_client_set_metrics_null)
+add_test_case(mqtt5_client_set_metrics_with_null_username)
 
 add_test_case(rate_limiter_token_bucket_init_invalid)
 add_test_case(rate_limiter_token_bucket_regeneration_integral)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/tests/shared_utils_tests.c 
new/aws-c-mqtt-0.16.0/tests/shared_utils_tests.c
--- old/aws-c-mqtt-0.15.2/tests/shared_utils_tests.c    2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/tests/shared_utils_tests.c    2026-05-18 
20:49:17.000000000 +0200
@@ -175,7 +175,7 @@
     struct aws_byte_buf expected_buf;
     AWS_ZERO_STRUCT(expected_buf);
     aws_test_mqtt_build_expected_metrics(
-        allocator, NULL, aws_byte_cursor_from_c_str("IoTDeviceSDK/C"), NULL, 
&expected_buf);
+        allocator, NULL, aws_byte_cursor_from_c_str("IoTDeviceSDK/C"), NULL, 
NULL, 0, &expected_buf);
 
     ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&output_cursor, &expected_buf));
 
@@ -192,9 +192,6 @@
 
     struct aws_mqtt_iot_metrics metrics = {
         .library_name = aws_byte_cursor_from_c_str("TEST_SDK_STRING"),
-        // TODO: add metadata entries when enabled
-        // .metadata_entries = NULL,
-        // .metadata_count = 0,
     };
 
     struct aws_byte_buf output_username;
@@ -211,7 +208,7 @@
     struct aws_byte_buf expected_buf;
     AWS_ZERO_STRUCT(expected_buf);
     aws_test_mqtt_build_expected_metrics(
-        allocator, &original_username, 
aws_byte_cursor_from_c_str("TEST_SDK_STRING"), NULL, &expected_buf);
+        allocator, &original_username, 
aws_byte_cursor_from_c_str("TEST_SDK_STRING"), NULL, NULL, 0, &expected_buf);
 
     ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&output_cursor, &expected_buf));
 
@@ -228,9 +225,6 @@
 
     struct aws_mqtt_iot_metrics metrics = {
         .library_name = aws_byte_cursor_from_c_str("NewSDK"),
-        // TODO: add metadata entries when enabled
-        // .metadata_entries = NULL,
-        // .metadata_count = 0,
     };
 
     struct aws_byte_buf output_username;
@@ -272,7 +266,7 @@
     struct aws_byte_buf expected_buf;
     AWS_ZERO_STRUCT(expected_buf);
     aws_test_mqtt_build_expected_metrics(
-        allocator, &original_username, 
aws_byte_cursor_from_c_str("SDK/Test-1.0"), NULL, &expected_buf);
+        allocator, &original_username, 
aws_byte_cursor_from_c_str("SDK/Test-1.0"), NULL, NULL, 0, &expected_buf);
 
     ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&output_cursor, &expected_buf));
 
@@ -304,7 +298,7 @@
     struct aws_byte_buf expected_buf;
     AWS_ZERO_STRUCT(expected_buf);
     aws_test_mqtt_build_expected_metrics(
-        allocator, &base_username, aws_byte_cursor_from_c_str("SDK/Test-1.0"), 
NULL, &expected_buf);
+        allocator, &base_username, aws_byte_cursor_from_c_str("SDK/Test-1.0"), 
NULL, NULL, 0, &expected_buf);
 
     ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&output_cursor, &expected_buf));
 
@@ -376,3 +370,270 @@
 }
 
 AWS_TEST_CASE(mqtt_append_sdk_metrics_invalid_utf8, 
s_test_mqtt_append_sdk_metrics_invalid_utf8)
+
+static int s_test_mqtt_append_sdk_metrics_with_metadata(struct aws_allocator 
*allocator, void *ctx) {
+    (void)ctx;
+
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("CustomKey1"),
+            .value = aws_byte_cursor_from_c_str("CustomValue1"),
+        },
+        {
+            .key = aws_byte_cursor_from_c_str("CustomKey2"),
+            .value = aws_byte_cursor_from_c_str("CustomValue2"),
+        },
+    };
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
+    };
+
+    struct aws_byte_buf output_username;
+    AWS_ZERO_STRUCT(output_username);
+
+    struct aws_byte_cursor original_username = 
aws_byte_cursor_from_c_str("testuser");
+
+    ASSERT_SUCCESS(
+        aws_mqtt_append_sdk_metrics_to_username(allocator, &original_username, 
&metrics, &output_username, NULL));
+
+    struct aws_byte_cursor output_cursor = 
aws_byte_cursor_from_buf(&output_username);
+
+    /* Verify the output contains the metadata in the format: 
&Metadata=(key1=value1;key2=value2) */
+    struct aws_byte_cursor metadata_format =
+        
aws_byte_cursor_from_c_str("&Metadata=(CustomKey1=CustomValue1;CustomKey2=CustomValue2)");
+    struct aws_byte_cursor found;
+
+    ASSERT_SUCCESS(aws_byte_cursor_find_exact(&output_cursor, 
&metadata_format, &found));
+
+    aws_byte_buf_clean_up(&output_username);
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(mqtt_append_sdk_metrics_with_metadata, 
s_test_mqtt_append_sdk_metrics_with_metadata)
+
+static int s_test_mqtt_append_sdk_metrics_with_metadata_invalid_utf8(struct 
aws_allocator *allocator, void *ctx) {
+    (void)ctx;
+
+    /* Invalid UTF-8 sequence in metadata key */
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("InvalidKey\xFF\xFE"),
+            .value = aws_byte_cursor_from_c_str("ValidValue"),
+        },
+    };
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
+    };
+
+    struct aws_byte_buf output_username;
+    AWS_ZERO_STRUCT(output_username);
+
+    struct aws_byte_cursor original_username = 
aws_byte_cursor_from_c_str("testuser");
+
+    /* Should fail due to invalid UTF-8 in metadata key */
+    ASSERT_FAILS(
+        aws_mqtt_append_sdk_metrics_to_username(allocator, &original_username, 
&metrics, &output_username, NULL));
+    ASSERT_INT_EQUALS(aws_last_error(), AWS_ERROR_INVALID_UTF8);
+
+    aws_byte_buf_clean_up(&output_username);
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(
+    mqtt_append_sdk_metrics_with_metadata_invalid_utf8,
+    s_test_mqtt_append_sdk_metrics_with_metadata_invalid_utf8)
+
+static int 
s_test_mqtt_append_sdk_metrics_with_metadata_invalid_utf8_value(struct 
aws_allocator *allocator, void *ctx) {
+    (void)ctx;
+
+    /* Invalid UTF-8 sequence in metadata value */
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("ValidKey"),
+            .value = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("InvalidValue\xFF\xFE"),
+        },
+    };
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
+    };
+
+    struct aws_byte_buf output_username;
+    AWS_ZERO_STRUCT(output_username);
+
+    struct aws_byte_cursor original_username = 
aws_byte_cursor_from_c_str("testuser");
+
+    /* Should fail due to invalid UTF-8 in metadata value */
+    ASSERT_FAILS(
+        aws_mqtt_append_sdk_metrics_to_username(allocator, &original_username, 
&metrics, &output_username, NULL));
+    ASSERT_INT_EQUALS(aws_last_error(), AWS_ERROR_INVALID_UTF8);
+
+    aws_byte_buf_clean_up(&output_username);
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(
+    mqtt_append_sdk_metrics_with_metadata_invalid_utf8_value,
+    s_test_mqtt_append_sdk_metrics_with_metadata_invalid_utf8_value)
+
+static int s_test_mqtt_iot_metrics_storage_with_metadata(struct aws_allocator 
*allocator, void *ctx) {
+    (void)ctx;
+
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("Key1"),
+            .value = aws_byte_cursor_from_c_str("Value1"),
+        },
+        {
+            .key = aws_byte_cursor_from_c_str("Key2"),
+            .value = aws_byte_cursor_from_c_str("Value2"),
+        },
+    };
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
+    };
+
+    struct aws_mqtt_iot_metrics_storage *storage = 
aws_mqtt_iot_metrics_storage_new(allocator, &metrics);
+    ASSERT_NOT_NULL(storage);
+
+    /* Verify the storage view has the correct values */
+    ASSERT_TRUE(aws_byte_cursor_eq_c_str(&storage->storage_view.library_name, 
"TestSDK/1.0"));
+    ASSERT_INT_EQUALS(2, storage->storage_view.metadata_count);
+    ASSERT_NOT_NULL(storage->storage_view.metadata_entries);
+
+    /* Verify metadata entries are correctly stored */
+    
ASSERT_TRUE(aws_byte_cursor_eq_c_str(&storage->storage_view.metadata_entries[0].key,
 "Key1"));
+    
ASSERT_TRUE(aws_byte_cursor_eq_c_str(&storage->storage_view.metadata_entries[0].value,
 "Value1"));
+    
ASSERT_TRUE(aws_byte_cursor_eq_c_str(&storage->storage_view.metadata_entries[1].key,
 "Key2"));
+    
ASSERT_TRUE(aws_byte_cursor_eq_c_str(&storage->storage_view.metadata_entries[1].value,
 "Value2"));
+
+    aws_mqtt_iot_metrics_storage_destroy(storage);
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(mqtt_iot_metrics_storage_with_metadata, 
s_test_mqtt_iot_metrics_storage_with_metadata)
+
+static int s_test_mqtt_iot_metrics_storage_empty_metadata(struct aws_allocator 
*allocator, void *ctx) {
+    (void)ctx;
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = 0,
+        .metadata_entries = NULL,
+    };
+
+    struct aws_mqtt_iot_metrics_storage *storage = 
aws_mqtt_iot_metrics_storage_new(allocator, &metrics);
+    ASSERT_NOT_NULL(storage);
+
+    /* Verify the storage view has the correct values */
+    ASSERT_TRUE(aws_byte_cursor_eq_c_str(&storage->storage_view.library_name, 
"TestSDK/1.0"));
+    ASSERT_INT_EQUALS(0, storage->storage_view.metadata_count);
+
+    aws_mqtt_iot_metrics_storage_destroy(storage);
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(mqtt_iot_metrics_storage_empty_metadata, 
s_test_mqtt_iot_metrics_storage_empty_metadata)
+
+static int s_test_mqtt_append_sdk_metrics_existing_metadata(struct 
aws_allocator *allocator, void *ctx) {
+    (void)ctx;
+
+    /* New metadata entries to add */
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("NewKey"),
+            .value = aws_byte_cursor_from_c_str("NewValue"),
+        },
+    };
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
+    };
+
+    struct aws_byte_buf output_username;
+    AWS_ZERO_STRUCT(output_username);
+
+    /* Username already contains SDK, Platform, and Metadata fields */
+    struct aws_byte_cursor original_username = aws_byte_cursor_from_c_str(
+        
"testuser?SDK=ExistingSDK&Platform=ExistingPlatform&Metadata=(ExistingKey1=ExistingValue1;ExistingKey2="
+        "ExistingValue2)");
+
+    ASSERT_SUCCESS(
+        aws_mqtt_append_sdk_metrics_to_username(allocator, &original_username, 
&metrics, &output_username, NULL));
+
+    struct aws_byte_cursor output_cursor = 
aws_byte_cursor_from_buf(&output_username);
+
+    /* Verify the output contains merged metadata:
+     * 
((ExistingKey1=ExistingValue1;ExistingKey2=ExistingValue2;NewKey=NewValue) */
+    struct aws_byte_cursor merged_metadata = aws_byte_cursor_from_c_str(
+        
"Metadata=(ExistingKey1=ExistingValue1;ExistingKey2=ExistingValue2;NewKey=NewValue)");
+    struct aws_byte_cursor found;
+
+    ASSERT_SUCCESS(aws_byte_cursor_find_exact(&output_cursor, 
&merged_metadata, &found));
+
+    /* Verify SDK and Platform are preserved (not duplicated) */
+    struct aws_byte_cursor sdk_check = 
aws_byte_cursor_from_c_str("SDK=ExistingSDK");
+    ASSERT_SUCCESS(aws_byte_cursor_find_exact(&output_cursor, &sdk_check, 
&found));
+
+    struct aws_byte_cursor platform_check = 
aws_byte_cursor_from_c_str("Platform=ExistingPlatform");
+    ASSERT_SUCCESS(aws_byte_cursor_find_exact(&output_cursor, &platform_check, 
&found));
+
+    aws_byte_buf_clean_up(&output_username);
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(mqtt_append_sdk_metrics_existing_metadata, 
s_test_mqtt_append_sdk_metrics_existing_metadata)
+
+static int s_test_mqtt_append_sdk_metrics_existing_metadata_no_new(struct 
aws_allocator *allocator, void *ctx) {
+    (void)ctx;
+
+    /* No new metadata entries */
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = 0,
+        .metadata_entries = NULL,
+    };
+
+    struct aws_byte_buf output_username;
+    AWS_ZERO_STRUCT(output_username);
+
+    /* Username already contains Metadata field */
+    struct aws_byte_cursor original_username = aws_byte_cursor_from_c_str(
+        
"testuser?SDK=ExistingSDK&Platform=ExistingPlatform&Metadata=(ExistingKey=ExistingValue)");
+
+    ASSERT_SUCCESS(
+        aws_mqtt_append_sdk_metrics_to_username(allocator, &original_username, 
&metrics, &output_username, NULL));
+
+    struct aws_byte_cursor output_cursor = 
aws_byte_cursor_from_buf(&output_username);
+
+    /* Verify the existing metadata is preserved */
+    struct aws_byte_cursor existing_metadata = 
aws_byte_cursor_from_c_str("Metadata=(ExistingKey=ExistingValue)");
+    struct aws_byte_cursor found;
+
+    ASSERT_SUCCESS(aws_byte_cursor_find_exact(&output_cursor, 
&existing_metadata, &found));
+
+    aws_byte_buf_clean_up(&output_username);
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(mqtt_append_sdk_metrics_existing_metadata_no_new, 
s_test_mqtt_append_sdk_metrics_existing_metadata_no_new)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/tests/v3/connection_state_test.c 
new/aws-c-mqtt-0.16.0/tests/v3/connection_state_test.c
--- old/aws-c-mqtt-0.15.2/tests/v3/connection_state_test.c      2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/tests/v3/connection_state_test.c      2026-05-18 
20:49:17.000000000 +0200
@@ -4115,10 +4115,15 @@
 
 /**
  * helper function to test client with different metrics by checking the 
received username field
+ * @param allocator The allocator to use
+ * @param metrics The metrics to set (can be NULL to disable metrics)
+ * @param username The username to set (can be NULL to skip setting username)
+ * @param ctx The test context
  */
 static int s_create_mqtt_connection_and_set_metrics(
     struct aws_allocator *allocator,
     struct aws_mqtt_iot_metrics *metrics,
+    struct aws_byte_cursor *username,
     void *ctx) {
     struct mqtt_connection_state_test *state_test_data = ctx;
 
@@ -4131,8 +4136,9 @@
         .on_connection_complete = aws_test311_on_connection_complete_fn,
     };
 
-    struct aws_byte_cursor username = aws_byte_cursor_from_c_str("testuser");
-    
ASSERT_SUCCESS(aws_mqtt_client_connection_set_login(state_test_data->mqtt_connection,
 &username, NULL));
+    if (username != NULL) {
+        
ASSERT_SUCCESS(aws_mqtt_client_connection_set_login(state_test_data->mqtt_connection,
 username, NULL));
+    }
 
     
ASSERT_SUCCESS(aws_mqtt_client_connection_set_metrics(state_test_data->mqtt_connection,
 metrics));
 
@@ -4154,9 +4160,16 @@
     struct aws_byte_buf expected_buf;
     AWS_ZERO_STRUCT(expected_buf);
     if (metrics) {
-        aws_test_mqtt_build_expected_metrics(allocator, &username, 
metrics->library_name, NULL, &expected_buf);
-    } else {
-        aws_byte_buf_init_copy_from_cursor(&expected_buf, allocator, username);
+        aws_test_mqtt_build_expected_metrics(
+            allocator,
+            username,
+            metrics->library_name,
+            NULL,
+            metrics->metadata_entries,
+            metrics->metadata_count,
+            &expected_buf);
+    } else if (username != NULL) {
+        aws_byte_buf_init_copy_from_cursor(&expected_buf, allocator, 
*username);
     }
 
     ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&received_packet->username, 
&expected_buf));
@@ -4172,14 +4185,26 @@
 static int s_test_mqtt_connection_set_metrics_valid_fn(struct aws_allocator 
*allocator, void *ctx) {
     (void)allocator;
 
+    /* Create metadata entries */
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("key1"),
+            .value = aws_byte_cursor_from_c_str("value1"),
+        },
+        {
+            .key = aws_byte_cursor_from_c_str("key2"),
+            .value = aws_byte_cursor_from_c_str("value2"),
+        },
+    };
+
     struct aws_mqtt_iot_metrics metrics = {
         .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
-        // TODO: enable metadata testing when metadata support is added
-        // .metadata_entries = NULL,
-        // .metadata_count = 0,
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
     };
 
-    ASSERT_SUCCESS(s_create_mqtt_connection_and_set_metrics(allocator, 
&metrics, ctx));
+    struct aws_byte_cursor username = aws_byte_cursor_from_c_str("testuser");
+    ASSERT_SUCCESS(s_create_mqtt_connection_and_set_metrics(allocator, 
&metrics, &username, ctx));
 
     return AWS_OP_SUCCESS;
 }
@@ -4196,7 +4221,8 @@
  */
 static int s_test_mqtt_connection_set_metrics_null_fn(struct aws_allocator 
*allocator, void *ctx) {
 
-    ASSERT_SUCCESS(s_create_mqtt_connection_and_set_metrics(allocator, NULL, 
ctx));
+    struct aws_byte_cursor username = aws_byte_cursor_from_c_str("testuser");
+    ASSERT_SUCCESS(s_create_mqtt_connection_and_set_metrics(allocator, NULL, 
&username, ctx));
 
     return AWS_OP_SUCCESS;
 }
@@ -4208,6 +4234,38 @@
     s_clean_up_mqtt_server_fn,
     &test_data)
 
+static int s_test_mqtt_connection_set_metrics_with_null_username_fn(struct 
aws_allocator *allocator, void *ctx) {
+
+    /* Create metadata entries */
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("key1"),
+            .value = aws_byte_cursor_from_c_str("value1"),
+        },
+        {
+            .key = aws_byte_cursor_from_c_str("key2"),
+            .value = aws_byte_cursor_from_c_str("value2"),
+        },
+    };
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
+    };
+
+    ASSERT_SUCCESS(s_create_mqtt_connection_and_set_metrics(allocator, 
&metrics, NULL, ctx));
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE_FIXTURE(
+    mqtt_connection_set_metrics_with_null_username,
+    s_setup_mqtt_server_fn,
+    s_test_mqtt_connection_set_metrics_with_null_username_fn,
+    s_clean_up_mqtt_server_fn,
+    &test_data)
+
 /**
  * Test that aws_mqtt_client_connection_set_metrics rejects invalid UTF-8 in 
library name
  */
@@ -4277,7 +4335,7 @@
     /* verify the username and metrics is setup properly */
     struct aws_byte_buf expected_buf;
     AWS_ZERO_STRUCT(expected_buf);
-    aws_test_mqtt_build_expected_metrics(allocator, &username1, 
metrics1.library_name, NULL, &expected_buf);
+    aws_test_mqtt_build_expected_metrics(allocator, &username1, 
metrics1.library_name, NULL, NULL, 0, &expected_buf);
     ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&received_packet1->username, 
&expected_buf));
     aws_byte_buf_clean_up(&expected_buf);
 
@@ -4298,7 +4356,7 @@
 
     /* verify the username and metrics is setup properly */
     AWS_ZERO_STRUCT(expected_buf);
-    aws_test_mqtt_build_expected_metrics(allocator, &username2, 
metrics2.library_name, NULL, &expected_buf);
+    aws_test_mqtt_build_expected_metrics(allocator, &username2, 
metrics2.library_name, NULL, NULL, 0, &expected_buf);
     ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&received_packet2->username, 
&expected_buf));
     aws_byte_buf_clean_up(&expected_buf);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/tests/v3/mqtt311_testing_utils.c 
new/aws-c-mqtt-0.16.0/tests/v3/mqtt311_testing_utils.c
--- old/aws-c-mqtt-0.15.2/tests/v3/mqtt311_testing_utils.c      2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/tests/v3/mqtt311_testing_utils.c      2026-05-18 
20:49:17.000000000 +0200
@@ -583,13 +583,20 @@
 
 static const struct aws_byte_cursor SDK_ATT_STR = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("?SDK=");
 static const struct aws_byte_cursor PLATFORM_ATT_STR = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("&Platform=");
+static const struct aws_byte_cursor METADATA_ATT_STR = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("&Metadata=(");
+static const struct aws_byte_cursor METADATA_CLOSE_PAREN = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(")");
+static const struct aws_byte_cursor METADATA_KEY_VALUE_DELIM = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("=");
+static const struct aws_byte_cursor METADATA_ENTRY_DELIM = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(";");
 
 void aws_test_mqtt_build_expected_metrics(
     struct aws_allocator *allocator,
     const struct aws_byte_cursor *original_username,
     const struct aws_byte_cursor sdk,
     const struct aws_byte_cursor *platform,
+    const struct aws_mqtt_metadata_entry *metadata_entries,
+    size_t metadata_count,
     struct aws_byte_buf *expected_buf) {
+
     struct aws_byte_cursor platform_to_use = platform ? *platform : 
aws_get_platform_build_os_string();
     if (original_username) {
         aws_byte_buf_init_copy_from_cursor(expected_buf, allocator, 
*original_username);
@@ -600,4 +607,23 @@
     aws_byte_buf_append_dynamic(expected_buf, &sdk);
     aws_byte_buf_append_dynamic(expected_buf, &PLATFORM_ATT_STR);
     aws_byte_buf_append_dynamic(expected_buf, &platform_to_use);
+
+    /* Append metadata if present */
+    if (metadata_entries != NULL && metadata_count > 0) {
+        aws_byte_buf_append_dynamic(expected_buf, &METADATA_ATT_STR);
+
+        for (size_t i = 0; i < metadata_count; ++i) {
+            const struct aws_mqtt_metadata_entry *entry = &metadata_entries[i];
+            aws_byte_buf_append_dynamic(expected_buf, &entry->key);
+            aws_byte_buf_append_dynamic(expected_buf, 
&METADATA_KEY_VALUE_DELIM);
+            aws_byte_buf_append_dynamic(expected_buf, &entry->value);
+
+            /* Add semicolon separator between entries (not after the last 
one) */
+            if (i < metadata_count - 1) {
+                aws_byte_buf_append_dynamic(expected_buf, 
&METADATA_ENTRY_DELIM);
+            }
+        }
+
+        aws_byte_buf_append_dynamic(expected_buf, &METADATA_CLOSE_PAREN);
+    }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/tests/v3/mqtt311_testing_utils.h 
new/aws-c-mqtt-0.16.0/tests/v3/mqtt311_testing_utils.h
--- old/aws-c-mqtt-0.15.2/tests/v3/mqtt311_testing_utils.h      2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/tests/v3/mqtt311_testing_utils.h      2026-05-18 
20:49:17.000000000 +0200
@@ -151,11 +151,25 @@
 
 void aws_test311_on_connection_termination_fn(void *userdata);
 
+/**
+ * Build expected metrics string with optional metadata support.
+ * Format: 
username?SDK=<sdk>&Platform=<platform>[&Metadata=(key1=value1;key2=value2)]
+ *
+ * @param allocator The allocator to use
+ * @param original_username The original username (can be NULL)
+ * @param sdk The SDK string
+ * @param platform The platform string (can be NULL to use default)
+ * @param metadata_entries Array of metadata entries (can be NULL if 
metadata_count is 0)
+ * @param metadata_count Number of metadata entries (0 for no metadata)
+ * @param expected_buf Output buffer for the expected metrics string
+ */
 void aws_test_mqtt_build_expected_metrics(
     struct aws_allocator *allocator,
     const struct aws_byte_cursor *original_username,
     const struct aws_byte_cursor sdk,
     const struct aws_byte_cursor *platform,
+    const struct aws_mqtt_metadata_entry *metadata_entries,
+    size_t metadata_count,
     struct aws_byte_buf *expected_buf);
 
 AWS_EXTERN_C_END
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-mqtt-0.15.2/tests/v5/mqtt5_client_tests.c 
new/aws-c-mqtt-0.16.0/tests/v5/mqtt5_client_tests.c
--- old/aws-c-mqtt-0.15.2/tests/v5/mqtt5_client_tests.c 2026-03-18 
21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/tests/v5/mqtt5_client_tests.c 2026-05-18 
20:49:17.000000000 +0200
@@ -6659,6 +6659,7 @@
 static int s_mqtt5_client_metrics_in_username_fn(
     struct aws_allocator *allocator,
     struct aws_mqtt_iot_metrics *metrics,
+    struct aws_byte_cursor *original_username,
     void *ctx) {
     (void)ctx;
 
@@ -6668,14 +6669,11 @@
     aws_mqtt5_client_test_init_default_options(&test_options);
     test_options.client_options.metrics = metrics;
 
-    /* Set up username and metrics */
-    struct aws_byte_cursor original_username = 
aws_byte_cursor_from_c_str("test_user");
-
     struct aws_mqtt5_packet_connect_view connect_view = {
         .keep_alive_interval_seconds = 30,
         .client_id = aws_byte_cursor_from_string(g_default_client_id),
         .clean_start = true,
-        .username = &original_username};
+        .username = original_username};
 
     test_options.connect_options = connect_view;
 
@@ -6769,21 +6767,59 @@
 }
 
 static int s_test_mqtt5_client_set_metrics_valid(struct aws_allocator 
*allocator, void *ctx) {
+
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("lang"),
+            .value = aws_byte_cursor_from_c_str("C"),
+        },
+        {
+            .key = aws_byte_cursor_from_c_str("version"),
+            .value = aws_byte_cursor_from_c_str("1.0.0"),
+        },
+    };
+
     struct aws_mqtt_iot_metrics metrics = {
-        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0")
-        // TODO: enable when metadata is supported
-        // .metadata_entries = NULL,
-        // .metadata_count = 0,
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
     };
 
-    return s_mqtt5_client_metrics_in_username_fn(allocator, &metrics, ctx);
+    struct aws_byte_cursor username = aws_byte_cursor_from_c_str("test_user");
+
+    return s_mqtt5_client_metrics_in_username_fn(allocator, &metrics, 
&username, ctx);
 }
 
 AWS_TEST_CASE(mqtt5_client_set_metrics_valid, 
s_test_mqtt5_client_set_metrics_valid)
 
+static int s_test_mqtt5_client_set_metrics_with_null_username(struct 
aws_allocator *allocator, void *ctx) {
+
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("lang"),
+            .value = aws_byte_cursor_from_c_str("C"),
+        },
+        {
+            .key = aws_byte_cursor_from_c_str("version"),
+            .value = aws_byte_cursor_from_c_str("1.0.0"),
+        },
+    };
+
+    struct aws_mqtt_iot_metrics metrics = {
+        .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
+    };
+
+    return s_mqtt5_client_metrics_in_username_fn(allocator, &metrics, NULL, 
ctx);
+}
+
+AWS_TEST_CASE(mqtt5_client_set_metrics_with_null_username, 
s_test_mqtt5_client_set_metrics_with_null_username)
+
 static int s_test_mqtt5_client_set_metrics_null(struct aws_allocator 
*allocator, void *ctx) {
 
-    return s_mqtt5_client_metrics_in_username_fn(allocator, NULL, ctx);
+    struct aws_byte_cursor username = aws_byte_cursor_from_c_str("test_user");
+    return s_mqtt5_client_metrics_in_username_fn(allocator, NULL, &username, 
ctx);
 }
 
 AWS_TEST_CASE(mqtt5_client_set_metrics_null, 
s_test_mqtt5_client_set_metrics_null)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/aws-c-mqtt-0.15.2/tests/v5/mqtt5_to_mqtt3_adapter_tests.c 
new/aws-c-mqtt-0.16.0/tests/v5/mqtt5_to_mqtt3_adapter_tests.c
--- old/aws-c-mqtt-0.15.2/tests/v5/mqtt5_to_mqtt3_adapter_tests.c       
2026-03-18 21:44:05.000000000 +0100
+++ new/aws-c-mqtt-0.16.0/tests/v5/mqtt5_to_mqtt3_adapter_tests.c       
2026-05-18 20:49:17.000000000 +0200
@@ -4428,8 +4428,21 @@
 
     struct aws_mqtt_client_connection *connection = fixture.connection;
 
+    struct aws_mqtt_metadata_entry metadata_entries[] = {
+        {
+            .key = aws_byte_cursor_from_c_str("lang"),
+            .value = aws_byte_cursor_from_c_str("C"),
+        },
+        {
+            .key = aws_byte_cursor_from_c_str("version"),
+            .value = aws_byte_cursor_from_c_str("1.0.0"),
+        },
+    };
+
     struct aws_mqtt_iot_metrics metrics = {
         .library_name = aws_byte_cursor_from_c_str("TestSDK/1.0"),
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
     };
 
     ASSERT_SUCCESS(aws_mqtt_client_connection_set_metrics(connection, 
&metrics));
@@ -4499,8 +4512,15 @@
     /* Invalid UTF-8 sequence */
     struct aws_byte_cursor invalid_utf8_library = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("TestSDK\xFF\xFE");
 
+    struct aws_mqtt_metadata_entry metadata_entries[] = {{
+        .key = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("key1\xFF\xFE"),
+        .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("value1\xFF\xFE"),
+    }};
+
     struct aws_mqtt_iot_metrics metrics = {
         .library_name = invalid_utf8_library,
+        .metadata_count = AWS_ARRAY_SIZE(metadata_entries),
+        .metadata_entries = metadata_entries,
     };
 
     ASSERT_FAILS(aws_mqtt_client_connection_set_metrics(connection, &metrics));

Reply via email to