BLE Host - unit tests for persisted CCCDs.

Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/f98cc567
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/f98cc567
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/f98cc567

Branch: refs/heads/develop
Commit: f98cc5679ce1b3ac803fdde36907b8cd9ee21f81
Parents: 54a4b7f
Author: Christopher Collins <[email protected]>
Authored: Tue May 24 14:24:18 2016 -0700
Committer: Christopher Collins <[email protected]>
Committed: Tue May 24 14:27:21 2016 -0700

----------------------------------------------------------------------
 .../host/src/test/ble_gatts_notify_test.c       | 337 +++++++++++++++++--
 net/nimble/host/src/test/ble_hs_test_util.c     |   8 +-
 net/nimble/host/src/test/ble_l2cap_sm_test.c    |  18 +
 3 files changed, 325 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f98cc567/net/nimble/host/src/test/ble_gatts_notify_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gatts_notify_test.c 
b/net/nimble/host/src/test/ble_gatts_notify_test.c
index 29ebd92..96730f1 100644
--- a/net/nimble/host/src/test/ble_gatts_notify_test.c
+++ b/net/nimble/host/src/test/ble_gatts_notify_test.c
@@ -24,6 +24,7 @@
 #include "host/ble_uuid.h"
 #include "host/ble_hs_test.h"
 #include "ble_hs_test_util.h"
+#include "ble_hs_test_util_store.h"
 
 #define BLE_GATTS_NOTIFY_TEST_CHR_1_UUID    0x1111
 #define BLE_GATTS_NOTIFY_TEST_CHR_2_UUID    0x2222
@@ -66,13 +67,50 @@ static uint16_t ble_gatts_notify_test_chr_2_def_handle;
 static uint8_t ble_gatts_notify_test_chr_2_val[1024];
 static int ble_gatts_notify_test_chr_2_len;
 
+typedef int ble_store_write_fn(int obj_type, union ble_store_value *val);
+
+typedef int ble_store_delete_fn(int obj_type, union ble_store_key *key);
+
+static uint16_t
+ble_gatts_notify_test_misc_read_notify(uint16_t conn_handle,
+                                       uint16_t chr_def_handle)
+{
+    struct ble_att_read_req req;
+    struct os_mbuf *om;
+    uint8_t buf[BLE_ATT_READ_REQ_SZ];
+    uint16_t flags;
+    int rc;
+
+    req.barq_handle = chr_def_handle + 2;
+    ble_att_read_req_write(buf, sizeof buf, &req);
+
+    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
+                                                buf, sizeof buf);
+    TEST_ASSERT(rc == 0);
+
+    ble_hs_test_util_tx_all();
+
+    om = ble_hs_test_util_prev_tx_dequeue_pullup();
+    TEST_ASSERT_FATAL(om != NULL);
+    TEST_ASSERT_FATAL(om->om_len == 3);
+    TEST_ASSERT_FATAL(om->om_data[0] == BLE_ATT_OP_READ_RSP);
+
+    flags = le16toh(om->om_data + 1);
+    return flags;
+}
+
 static void
 ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle)
 {
+    uint16_t flags;
     int rc;
 
     ble_hs_test_util_init();
 
+    ble_hs_test_util_store_init(10, 10, 10);
+    ble_hs_cfg.store_read_cb = ble_hs_test_util_store_read;
+    ble_hs_cfg.store_write_cb = ble_hs_test_util_store_write;
+
     rc = ble_gatts_register_svcs(ble_gatts_notify_test_svcs,
                                  ble_gatts_notify_test_misc_reg_cb, NULL);
     TEST_ASSERT_FATAL(rc == 0);
@@ -84,6 +122,14 @@ ble_gatts_notify_test_misc_init(uint16_t *out_conn_handle)
     ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
                                  NULL, NULL);
     *out_conn_handle = 2;
+
+    /* Ensure notifications disabled on new connection. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        2, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == 0);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        2, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == 0);
 }
 
 static void
@@ -104,34 +150,6 @@ ble_gatts_notify_test_misc_enable_notify(uint16_t 
conn_handle,
     TEST_ASSERT(rc == 0);
 }
 
-static uint16_t
-ble_gatts_notify_test_misc_read_notify(uint16_t conn_handle,
-                                       uint16_t chr_def_handle)
-{
-    struct ble_att_read_req req;
-    struct os_mbuf *om;
-    uint8_t buf[BLE_ATT_READ_REQ_SZ];
-    uint16_t flags;
-    int rc;
-
-    req.barq_handle = chr_def_handle + 2;
-    ble_att_read_req_write(buf, sizeof buf, &req);
-
-    rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
-                                                buf, sizeof buf);
-    TEST_ASSERT(rc == 0);
-
-    ble_hs_test_util_tx_all();
-
-    om = ble_hs_test_util_prev_tx_dequeue_pullup();
-    TEST_ASSERT_FATAL(om != NULL);
-    TEST_ASSERT_FATAL(om->om_len == 3);
-    TEST_ASSERT_FATAL(om->om_data[0] == BLE_ATT_OP_READ_RSP);
-
-    flags = le16toh(om->om_data + 1);
-    return flags;
-}
-
 static void
 ble_gatts_notify_test_misc_reg_cb(uint8_t op,
                                   union ble_gatt_register_ctxt *ctxt,
@@ -253,9 +271,18 @@ TEST_CASE(ble_gatts_notify_test_n)
         BLE_GATTS_CLT_CFG_F_NOTIFY);
 
     /* Toss both write responses. */
-    ble_hs_test_util_tx_all();
-    ble_hs_test_util_prev_tx_dequeue();
-    ble_hs_test_util_prev_tx_dequeue();
+    ble_hs_test_util_prev_tx_queue_clear();
+
+    /* Ensure nothing got persisted since peer is not bonded. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 0);
+
+    /* Ensure notifications read back as enabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY);
 
     /* Update characteristic 1's value. */
     ble_gatts_notify_test_chr_1_len = 1;
@@ -325,9 +352,18 @@ TEST_CASE(ble_gatts_notify_test_i)
         BLE_GATTS_CLT_CFG_F_INDICATE);
 
     /* Toss both write responses. */
-    ble_hs_test_util_tx_all();
-    ble_hs_test_util_prev_tx_dequeue();
-    ble_hs_test_util_prev_tx_dequeue();
+    ble_hs_test_util_prev_tx_queue_clear();
+
+    /* Ensure nothing got persisted since peer is not bonded. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 0);
+
+    /* Ensure indications read back as enabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE);
 
     /* Update characteristic 1's value. */
     ble_gatts_notify_test_chr_1_len = 1;
@@ -397,10 +433,243 @@ TEST_CASE(ble_gatts_notify_test_i)
     TEST_ASSERT(flags == 0);
 }
 
+TEST_CASE(ble_gatts_notify_test_bonded_n)
+{
+    struct ble_hs_conn *conn;
+    uint16_t conn_handle;
+    uint16_t flags;
+
+    ble_gatts_notify_test_misc_init(&conn_handle);
+
+    /* Enable bonding. */
+    ble_hs_lock();
+    conn = ble_hs_conn_find(conn_handle);
+    TEST_ASSERT_FATAL(conn != NULL);
+    conn->bhc_sec_state.enc_enabled = 1;
+    conn->bhc_sec_state.authenticated = 1;
+    conn->bhc_sec_state.bonded = 1;
+    ble_hs_unlock();
+
+    /* Enable notifications on both characteristics. */
+    ble_gatts_notify_test_misc_enable_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle,
+        BLE_GATTS_CLT_CFG_F_NOTIFY);
+    ble_gatts_notify_test_misc_enable_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle,
+        BLE_GATTS_CLT_CFG_F_NOTIFY);
+
+    /* Toss both write responses. */
+    ble_hs_test_util_prev_tx_queue_clear();
+
+    /* Ensure both CCCDs got persisted. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2);
+
+    /* Ensure notifications read back as enabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY);
+
+    /* Disconnect. */
+    ble_hs_test_util_conn_disconnect(conn_handle);
+
+    /* Ensure both CCCDs still persisted. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2);
+
+    /* Update characteristic 1's value. */
+    ble_gatts_notify_test_chr_1_len = 1;
+    ble_gatts_notify_test_chr_1_val[0] = 0xdd;
+    ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1);
+
+    /* Update characteristic 2's value. */
+    ble_gatts_notify_test_chr_2_len = 16;
+    memcpy(ble_gatts_notify_test_chr_2_val,
+           ((uint8_t[]){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}), 16);
+    ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1);
+
+    /* Reconnect; ensure notifications don't get sent while unbonded and that
+     * notifications appear disabled.
+     */
+
+    ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+
+    /* Ensure no notifications sent. */
+    TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL);
+
+    /* Ensure notifications disabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == 0);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == 0);
+
+    /* Simulate a successful encryption procedure (bonding restoration). */
+    ble_hs_lock();
+    conn = ble_hs_conn_find(conn_handle);
+    TEST_ASSERT_FATAL(conn != NULL);
+    conn->bhc_sec_state.enc_enabled = 1;
+    conn->bhc_sec_state.authenticated = 1;
+    conn->bhc_sec_state.bonded = 1;
+    ble_hs_unlock();
+
+    ble_gatts_bonding_restored(conn_handle);
+
+    /* Verify notifications sent properly. */
+    ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_1_val,
+                                           ble_gatts_notify_test_chr_1_len);
+    ble_gatts_notify_test_misc_verify_tx_n(ble_gatts_notify_test_chr_2_val,
+                                           ble_gatts_notify_test_chr_2_len);
+
+    /* Ensure notifications enabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_NOTIFY);
+
+    /* Ensure both CCCDs still persisted. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2);
+}
+
+TEST_CASE(ble_gatts_notify_test_bonded_i)
+{
+    struct ble_hs_conn *conn;
+    uint16_t conn_handle;
+    uint16_t flags;
+
+    ble_gatts_notify_test_misc_init(&conn_handle);
+
+    /* Enable bonding. */
+    ble_hs_lock();
+    conn = ble_hs_conn_find(conn_handle);
+    TEST_ASSERT_FATAL(conn != NULL);
+    conn->bhc_sec_state.enc_enabled = 1;
+    conn->bhc_sec_state.authenticated = 1;
+    conn->bhc_sec_state.bonded = 1;
+    ble_hs_unlock();
+
+    /* Enable indications on both characteristics. */
+    ble_gatts_notify_test_misc_enable_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle,
+        BLE_GATTS_CLT_CFG_F_INDICATE);
+    ble_gatts_notify_test_misc_enable_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle,
+        BLE_GATTS_CLT_CFG_F_INDICATE);
+
+    /* Toss both write responses. */
+    ble_hs_test_util_prev_tx_queue_clear();
+
+    /* Ensure both CCCDs got persisted. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2);
+
+    /* Ensure indications read back as enabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE);
+
+    /* Disconnect. */
+    ble_hs_test_util_conn_disconnect(conn_handle);
+
+    /* Ensure both CCCDs still persisted. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2);
+
+    /* Update characteristic 1's value. */
+    ble_gatts_notify_test_chr_1_len = 1;
+    ble_gatts_notify_test_chr_1_val[0] = 0xab;
+    ble_gatts_chr_updated(ble_gatts_notify_test_chr_1_def_handle + 1);
+
+    /* Update characteristic 2's value. */
+    ble_gatts_notify_test_chr_2_len = 16;
+    memcpy(ble_gatts_notify_test_chr_2_val,
+           ((uint8_t[]){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 16);
+    ble_gatts_chr_updated(ble_gatts_notify_test_chr_2_def_handle + 1);
+
+    /* Reconnect; ensure notifications don't get sent while unbonded and that
+     * notifications appear disabled.
+     */
+
+    ble_hs_test_util_create_conn(conn_handle, ((uint8_t[]){2,3,4,5,6,7,8,9}),
+                                 NULL, NULL);
+
+    /* Ensure no indications sent. */
+    TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL);
+
+    /* Ensure notifications disabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == 0);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == 0);
+
+    /* Simulate a successful encryption procedure (bonding restoration). */
+    ble_hs_lock();
+    conn = ble_hs_conn_find(conn_handle);
+    TEST_ASSERT_FATAL(conn != NULL);
+    conn->bhc_sec_state.enc_enabled = 1;
+    conn->bhc_sec_state.authenticated = 1;
+    conn->bhc_sec_state.bonded = 1;
+    ble_hs_unlock();
+
+    ble_gatts_bonding_restored(conn_handle);
+
+    /* Verify first indication sent properly. */
+    ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_1_val,
+                                           ble_gatts_notify_test_chr_1_len);
+
+    /* Verify the second indication doesn't get sent until the first is
+     * confirmed.
+     */
+    ble_hs_test_util_tx_all();
+    TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0);
+
+    /* Receive the confirmation for the first indication. */
+    ble_gatts_notify_test_misc_rx_indicate_rsp(conn_handle);
+
+    /* Verify indication sent properly. */
+    ble_hs_test_util_tx_all();
+    ble_gatts_notify_test_misc_verify_tx_i(ble_gatts_notify_test_chr_2_val,
+                                           ble_gatts_notify_test_chr_2_len);
+
+    /* Receive the confirmation for the second indication. */
+    ble_gatts_notify_test_misc_rx_indicate_rsp(conn_handle);
+
+    /* Verify no pending GATT jobs. */
+    TEST_ASSERT(!ble_gattc_any_jobs());
+
+    /* Ensure notifications enabled. */
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_1_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE);
+    flags = ble_gatts_notify_test_misc_read_notify(
+        conn_handle, ble_gatts_notify_test_chr_2_def_handle);
+    TEST_ASSERT(flags == BLE_GATTS_CLT_CFG_F_INDICATE);
+
+    /* Ensure both CCCDs still persisted. */
+    TEST_ASSERT(ble_hs_test_util_store_num_cccds == 2);
+}
+
 TEST_SUITE(ble_gatts_notify_suite)
 {
     ble_gatts_notify_test_n();
     ble_gatts_notify_test_i();
+
+    ble_gatts_notify_test_bonded_n();
+    ble_gatts_notify_test_bonded_i();
+
+    /* XXX: Test corner cases:
+     *     o Bonding after CCCD configuration.
+     *     o Disconnect prior to rx of indicate ack.
+     *     o Multiple characteristic updates prior to rx of indicate ack.
+     */
 }
 
 int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f98cc567/net/nimble/host/src/test/ble_hs_test_util.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test_util.c 
b/net/nimble/host/src/test/ble_hs_test_util.c
index 810cc19..fb3bf3b 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.c
+++ b/net/nimble/host/src/test/ble_hs_test_util.c
@@ -76,11 +76,9 @@ ble_hs_test_util_prev_tx_dequeue(void)
 
     os_mbuf_free_chain(ble_hs_test_util_prev_tx_cur);
 
-    omp = STAILQ_LAST(&ble_hs_test_util_prev_tx_queue, os_mbuf_pkthdr,
-                      omp_next);
+    omp = STAILQ_FIRST(&ble_hs_test_util_prev_tx_queue);
     if (omp != NULL) {
-        STAILQ_REMOVE(&ble_hs_test_util_prev_tx_queue, omp, os_mbuf_pkthdr,
-                      omp_next);
+        STAILQ_REMOVE_HEAD(&ble_hs_test_util_prev_tx_queue, omp_next);
         ble_hs_test_util_prev_tx_cur = OS_MBUF_PKTHDR_TO_MBUF(omp);
     } else {
         ble_hs_test_util_prev_tx_cur = NULL;
@@ -120,6 +118,7 @@ ble_hs_test_util_prev_tx_queue_sz(void)
 void
 ble_hs_test_util_prev_tx_queue_clear(void)
 {
+    ble_hs_test_util_tx_all();
     while (!STAILQ_EMPTY(&ble_hs_test_util_prev_tx_queue)) {
         ble_hs_test_util_prev_tx_dequeue();
     }
@@ -759,6 +758,7 @@ ble_hs_test_util_set_public_addr(uint8_t *addr)
     memcpy(ble_hs_our_dev.public_addr, addr, 6);
 }
 
+
 void
 ble_hs_test_util_init(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f98cc567/net/nimble/host/src/test/ble_l2cap_sm_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_l2cap_sm_test.c 
b/net/nimble/host/src/test/ble_l2cap_sm_test.c
index 1159028..c58396d 100644
--- a/net/nimble/host/src/test/ble_l2cap_sm_test.c
+++ b/net/nimble/host/src/test/ble_l2cap_sm_test.c
@@ -412,6 +412,21 @@ ble_l2cap_sm_test_util_verify_tx_enc_info(
 }
 
 static void
+ble_l2cap_sm_test_util_verify_tx_sec_req(struct ble_l2cap_sm_sec_req *exp_cmd)
+{
+    struct ble_l2cap_sm_sec_req cmd;
+    struct os_mbuf *om;
+
+    ble_hs_test_util_tx_all();
+
+    om = ble_l2cap_sm_test_util_verify_tx_hdr(BLE_L2CAP_SM_OP_SEC_REQ,
+                                              BLE_L2CAP_SM_SEC_REQ_SZ);
+    ble_l2cap_sm_sec_req_parse(om->om_data, om->om_len, &cmd);
+
+    TEST_ASSERT(cmd.authreq == exp_cmd->authreq);
+}
+
+static void
 ble_l2cap_sm_test_util_verify_tx_pair_fail(
     struct ble_l2cap_sm_pair_fail *exp_cmd)
 {
@@ -914,6 +929,9 @@ ble_l2cap_sm_test_util_peer_lgcy_good(
     if (params->has_sec_req) {
         rc = ble_l2cap_sm_slave_initiate(2);
         TEST_ASSERT(rc == 0);
+
+        /* Ensure we sent the expected security request. */
+        ble_l2cap_sm_test_util_verify_tx_sec_req(&params->sec_req);
     }
 
     /* Receive a pair request from the peer. */

Reply via email to