blob: e50bf1135a99894bfae054fb9fbfeac7a9d4a49f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string.h>
#include <errno.h>
#include "testutil/testutil.h"
#include "nimble/ble.h"
#include "host/ble_hs_test.h"
#include "host/ble_gatt.h"
#include "ble_hs_test_util.h"
#define BLE_GATT_WRITE_TEST_MAX_ATTRS 128
static int ble_gatt_write_test_cb_called;
static uint8_t ble_gatt_write_test_attr_value[BLE_ATT_ATTR_MAX_LEN];
static struct ble_gatt_error ble_gatt_write_test_error;
static struct ble_hs_test_util_flat_attr
ble_gatt_write_test_attrs[BLE_GATT_WRITE_TEST_MAX_ATTRS];
static int ble_gatt_write_test_num_attrs;
static void
ble_gatt_write_test_init(void)
{
int i;
ble_hs_test_util_init();
ble_gatt_write_test_cb_called = 0;
ble_gatt_write_test_num_attrs = 0;
for (i = 0; i < sizeof ble_gatt_write_test_attr_value; i++) {
ble_gatt_write_test_attr_value[i] = i;
}
}
static int
ble_gatt_write_test_cb_good(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg)
{
int *attr_len;
attr_len = arg;
TEST_ASSERT(error != NULL);
TEST_ASSERT(conn_handle == 2);
ble_gatt_write_test_error = *error;
if (attr_len != NULL) {
TEST_ASSERT(error->status == 0);
TEST_ASSERT(attr->handle == 100);
}
ble_gatt_write_test_cb_called = 1;
return 0;
}
static void
ble_gatt_write_test_rx_rsp(uint16_t conn_handle)
{
uint8_t op;
int rc;
op = BLE_ATT_OP_WRITE_RSP;
rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
&op, 1);
TEST_ASSERT(rc == 0);
}
static void
ble_gatt_write_test_rx_prep_rsp(uint16_t conn_handle, uint16_t attr_handle,
uint16_t offset,
const void *attr_data, uint16_t attr_data_len)
{
struct ble_att_prep_write_cmd rsp;
uint8_t buf[512];
int rc;
rsp.bapc_handle = attr_handle;
rsp.bapc_offset = offset;
ble_att_prep_write_rsp_write(buf, sizeof buf, &rsp);
memcpy(buf + BLE_ATT_PREP_WRITE_CMD_BASE_SZ, attr_data, attr_data_len);
rc = ble_hs_test_util_l2cap_rx_payload_flat(
conn_handle, BLE_L2CAP_CID_ATT, buf,
BLE_ATT_PREP_WRITE_CMD_BASE_SZ + attr_data_len);
TEST_ASSERT(rc == 0);
}
static void
ble_gatt_write_test_rx_exec_rsp(uint16_t conn_handle)
{
uint8_t op;
int rc;
op = BLE_ATT_OP_EXEC_WRITE_RSP;
rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT,
&op, 1);
TEST_ASSERT(rc == 0);
}
static void
ble_gatt_write_test_misc_long_good(int attr_len)
{
uint16_t mtu;
int off;
int len;
int rc;
ble_gatt_write_test_init();
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
mtu = ble_att_mtu(2);
rc = ble_hs_test_util_gatt_write_long_flat(
2, 100, ble_gatt_write_test_attr_value, attr_len,
ble_gatt_write_test_cb_good, &attr_len);
TEST_ASSERT(rc == 0);
off = 0;
while (off < attr_len) {
len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
if (off + len > attr_len) {
len = attr_len - off;
}
/* Send the pending ATT Prep Write Command. */
ble_hs_test_util_verify_tx_prep_write(
100, off, ble_gatt_write_test_attr_value + off, len);
/* Receive Prep Write response. */
ble_gatt_write_test_rx_prep_rsp(
2, 100, off, ble_gatt_write_test_attr_value + off, len);
/* Verify callback hasn't gotten called. */
TEST_ASSERT(!ble_gatt_write_test_cb_called);
off += len;
}
/* Verify execute write request sent. */
ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE);
/* Receive Exec Write response. */
ble_gatt_write_test_rx_exec_rsp(2);
/* Verify callback got called. */
TEST_ASSERT(ble_gatt_write_test_cb_called);
}
typedef void ble_gatt_write_test_long_fail_fn(uint16_t conn_handle,
int off, int len);
static void
ble_gatt_write_test_misc_long_bad(int attr_len,
ble_gatt_write_test_long_fail_fn *cb)
{
uint16_t mtu;
int fail_now;
int off;
int len;
int rc;
ble_gatt_write_test_init();
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
mtu = ble_att_mtu(2);
rc = ble_hs_test_util_gatt_write_long_flat(
2, 100, ble_gatt_write_test_attr_value, attr_len,
ble_gatt_write_test_cb_good, NULL);
TEST_ASSERT(rc == 0);
fail_now = 0;
off = 0;
while (off < attr_len) {
len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
if (off + len > attr_len) {
len = attr_len - off;
}
/* Send the pending ATT Prep Write Command. */
ble_hs_test_util_verify_tx_prep_write(
100, off, ble_gatt_write_test_attr_value + off, len);
/* Receive Prep Write response. */
len = BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
if (off + len >= attr_len) {
len = attr_len - off;
fail_now = 1;
}
if (!fail_now) {
ble_gatt_write_test_rx_prep_rsp(
2, 100, off, ble_gatt_write_test_attr_value + off, len);
} else {
cb(2, off, len);
break;
}
/* Verify callback hasn't gotten called. */
TEST_ASSERT(!ble_gatt_write_test_cb_called);
off += len;
}
/* Verify callback was called. */
TEST_ASSERT(ble_gatt_write_test_cb_called);
TEST_ASSERT(ble_gatt_write_test_error.status == BLE_HS_EBADDATA);
TEST_ASSERT(ble_gatt_write_test_error.att_handle == 0);
}
static void
ble_gatt_write_test_misc_long_fail_handle(uint16_t conn_handle,
int off, int len)
{
ble_gatt_write_test_rx_prep_rsp(
conn_handle, 99, off, ble_gatt_write_test_attr_value + off,
len);
}
static void
ble_gatt_write_test_misc_long_fail_offset(uint16_t conn_handle,
int off, int len)
{
ble_gatt_write_test_rx_prep_rsp(
conn_handle, 100, off + 1, ble_gatt_write_test_attr_value + off,
len);
}
static void
ble_gatt_write_test_misc_long_fail_value(uint16_t conn_handle,
int off, int len)
{
ble_gatt_write_test_rx_prep_rsp(
conn_handle, 100, off, ble_gatt_write_test_attr_value + off + 1,
len);
}
static void
ble_gatt_write_test_misc_long_fail_length(uint16_t conn_handle,
int off, int len)
{
ble_gatt_write_test_rx_prep_rsp(
conn_handle, 100, off, ble_gatt_write_test_attr_value + off,
len - 1);
}
static int
ble_gatt_write_test_reliable_cb_good(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attrs,
uint8_t num_attrs, void *arg)
{
int i;
TEST_ASSERT_FATAL(num_attrs <= BLE_GATT_WRITE_TEST_MAX_ATTRS);
TEST_ASSERT(conn_handle == 2);
ble_gatt_write_test_num_attrs = num_attrs;
for (i = 0; i < num_attrs; i++) {
ble_hs_test_util_attr_to_flat(ble_gatt_write_test_attrs + i,
attrs + i);
}
ble_gatt_write_test_cb_called = 1;
return 0;
}
static void
ble_gatt_write_test_misc_reliable_good(
struct ble_hs_test_util_flat_attr *flat_attrs)
{
const struct ble_hs_test_util_flat_attr *attr;
struct ble_gatt_attr attrs[16];
uint16_t mtu;
int num_attrs;
int attr_idx;
int len;
int off;
int rc;
int i;
ble_gatt_write_test_init();
for (num_attrs = 0; flat_attrs[num_attrs].handle != 0; num_attrs++) {
TEST_ASSERT_FATAL(num_attrs < sizeof attrs / sizeof attrs[0]);
ble_hs_test_util_attr_from_flat(attrs + num_attrs,
flat_attrs + num_attrs);
}
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
mtu = ble_att_mtu(2);
rc = ble_gattc_write_reliable(2, attrs, num_attrs,
ble_gatt_write_test_reliable_cb_good, NULL);
TEST_ASSERT(rc == 0);
attr_idx = 0;
off = 0;
while (attr_idx < num_attrs) {
attr = flat_attrs + attr_idx;
len = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
if (off + len > attr->value_len) {
len = attr->value_len - off;
}
/* Send the pending ATT Prep Write Command. */
ble_hs_test_util_verify_tx_prep_write(attr->handle, off,
attr->value + off, len);
/* Receive Prep Write response. */
ble_gatt_write_test_rx_prep_rsp(2, attr->handle, off,
attr->value + off, len);
/* Verify callback hasn't gotten called. */
TEST_ASSERT(!ble_gatt_write_test_cb_called);
off += len;
if (off >= attr->value_len) {
attr_idx++;
off = 0;
}
}
/* Verify execute write request sent. */
ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE);
/* Receive Exec Write response. */
ble_gatt_write_test_rx_exec_rsp(2);
/* Verify callback got called. */
TEST_ASSERT(ble_gatt_write_test_cb_called);
TEST_ASSERT(ble_gatt_write_test_num_attrs == num_attrs);
for (i = 0; i < num_attrs; i++) {
rc = ble_hs_test_util_flat_attr_cmp(
ble_gatt_write_test_attrs + i, flat_attrs + i);
TEST_ASSERT(rc == 0);
}
}
TEST_CASE(ble_gatt_write_test_no_rsp)
{
int attr_len;
int rc;
ble_gatt_write_test_init();
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
attr_len = 4;
rc = ble_hs_test_util_gatt_write_no_rsp_flat(
2, 100, ble_gatt_write_test_attr_value, attr_len);
TEST_ASSERT(rc == 0);
/* Send the pending ATT Write Command. */
/* No response expected; verify callback not called. */
TEST_ASSERT(!ble_gatt_write_test_cb_called);
}
TEST_CASE(ble_gatt_write_test_rsp)
{
int attr_len;
ble_gatt_write_test_init();
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
attr_len = 4;
ble_hs_test_util_gatt_write_flat(2, 100, ble_gatt_write_test_attr_value,
attr_len, ble_gatt_write_test_cb_good,
&attr_len);
/* Send the pending ATT Write Command. */
/* Response not received yet; verify callback not called. */
TEST_ASSERT(!ble_gatt_write_test_cb_called);
/* Receive write response. */
ble_gatt_write_test_rx_rsp(2);
/* Verify callback got called. */
TEST_ASSERT(ble_gatt_write_test_cb_called);
}
TEST_CASE(ble_gatt_write_test_long_good)
{
/*** 1 prep write req/rsp. */
ble_gatt_write_test_misc_long_good(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ);
/*** 2 prep write reqs/rsps. */
ble_gatt_write_test_misc_long_good(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1);
/*** Maximum reqs/rsps. */
ble_gatt_write_test_misc_long_good(BLE_ATT_ATTR_MAX_LEN);
}
TEST_CASE(ble_gatt_write_test_long_bad_handle)
{
/*** 1 prep write req/rsp. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ,
ble_gatt_write_test_misc_long_fail_handle);
/*** 2 prep write reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1,
ble_gatt_write_test_misc_long_fail_handle);
/*** Maximum reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_ATTR_MAX_LEN,
ble_gatt_write_test_misc_long_fail_handle);
}
TEST_CASE(ble_gatt_write_test_long_bad_offset)
{
/*** 1 prep write req/rsp. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ,
ble_gatt_write_test_misc_long_fail_offset);
/*** 2 prep write reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1,
ble_gatt_write_test_misc_long_fail_offset);
/*** Maximum reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_ATTR_MAX_LEN,
ble_gatt_write_test_misc_long_fail_offset);
}
TEST_CASE(ble_gatt_write_test_long_bad_value)
{
/*** 1 prep write req/rsp. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ,
ble_gatt_write_test_misc_long_fail_value);
/*** 2 prep write reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1,
ble_gatt_write_test_misc_long_fail_value);
/*** Maximum reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_ATTR_MAX_LEN,
ble_gatt_write_test_misc_long_fail_value);
}
TEST_CASE(ble_gatt_write_test_long_bad_length)
{
/*** 1 prep write req/rsp. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ,
ble_gatt_write_test_misc_long_fail_length);
/*** 2 prep write reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ + 1,
ble_gatt_write_test_misc_long_fail_length);
/*** Maximum reqs/rsps. */
ble_gatt_write_test_misc_long_bad(
BLE_ATT_ATTR_MAX_LEN,
ble_gatt_write_test_misc_long_fail_length);
}
TEST_CASE(ble_gatt_write_test_reliable_good)
{
/*** 1 attribute. */
ble_gatt_write_test_misc_reliable_good(
((struct ble_hs_test_util_flat_attr[]) { {
.handle = 100,
.value_len = 2,
.value = { 1, 2 },
}, {
0
} }));
/*** 2 attributes. */
ble_gatt_write_test_misc_reliable_good(
((struct ble_hs_test_util_flat_attr[]) { {
.handle = 100,
.value_len = 2,
.value = { 1,2 },
}, {
.handle = 113,
.value_len = 6,
.value = { 5,6,7,8,9,10 },
}, {
0
} }));
/*** 3 attributes. */
ble_gatt_write_test_misc_reliable_good(
((struct ble_hs_test_util_flat_attr[]) { {
.handle = 100,
.value_len = 2,
.value = { 1,2 },
}, {
.handle = 113,
.value_len = 6,
.value = { 5,6,7,8,9,10 },
}, {
.handle = 144,
.value_len = 1,
.value = { 0xff },
}, {
0
} }));
/*** Long attributes. */
ble_gatt_write_test_misc_reliable_good(
((struct ble_hs_test_util_flat_attr[]) { {
.handle = 100,
.value_len = 20,
.value = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 },
}, {
.handle = 144,
.value_len = 20,
.value = { 11,12,13,14,15,16,17,18,19,110,
111,112,113,114,115,116,117,118,119,120 },
}, {
0
} }));
}
TEST_CASE(ble_gatt_write_test_long_queue_full)
{
int off;
int len;
int rc;
int i;
ble_gatt_write_test_init();
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
rc = ble_hs_test_util_gatt_write_long_flat(
2, 100, ble_gatt_write_test_attr_value, 128,
ble_gatt_write_test_cb_good, NULL);
TEST_ASSERT(rc == 0);
off = 0;
for (i = 0; i < 2; i++) {
/* Verify prep write request was sent. */
TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() != NULL);
/* Receive Prep Write response. */
len = BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
ble_gatt_write_test_rx_prep_rsp(
2, 100, off, ble_gatt_write_test_attr_value + off, len);
/* Verify callback hasn't gotten called. */
TEST_ASSERT(!ble_gatt_write_test_cb_called);
off += len;
}
/* Verify prep write request was sent. */
TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() != NULL);
/* Receive queue full error. */
ble_hs_test_util_rx_att_err_rsp(2, BLE_ATT_OP_PREP_WRITE_REQ,
BLE_ATT_ERR_PREPARE_QUEUE_FULL, 100);
/* Verify callback was called. */
TEST_ASSERT(ble_gatt_write_test_cb_called);
TEST_ASSERT(ble_gatt_write_test_error.status ==
BLE_HS_ATT_ERR(BLE_ATT_ERR_PREPARE_QUEUE_FULL));
TEST_ASSERT(ble_gatt_write_test_error.att_handle == 100);
/* Verify clear queue command got sent. */
ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_CANCEL);
}
TEST_CASE(ble_gatt_write_test_long_oom)
{
static const struct ble_hs_test_util_flat_attr attr = {
.handle = 34,
.value = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20,
},
.value_len = 20,
};
struct os_mbuf *oms;
int32_t ticks_until;
int chunk_sz;
int off;
int rc;
ble_gatt_write_test_init();
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
/* Initiate a write long procedure. */
off = 0;
rc = ble_hs_test_util_gatt_write_long_flat(
2, attr.handle, attr.value, attr.value_len,
ble_gatt_write_test_cb_good, NULL);
TEST_ASSERT_FATAL(rc == 0);
chunk_sz = ble_att_mtu(2) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
ble_hs_test_util_verify_tx_prep_write(attr.handle, off,
attr.value + off, chunk_sz);
/* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
oms = ble_hs_test_util_mbuf_alloc_all_but(1);
ble_gatt_write_test_rx_prep_rsp(2, attr.handle, off, attr.value + off,
chunk_sz);
off += chunk_sz;
/* Ensure no follow-up request got sent. It should not have gotten sent
* due to mbuf exhaustion.
*/
ble_hs_test_util_prev_tx_queue_clear();
TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
/* Verify that we will resume the stalled GATT procedure in one second. */
ticks_until = ble_gattc_timer();
TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
/* Verify the procedure proceeds after mbufs become available. */
rc = os_mbuf_free_chain(oms);
TEST_ASSERT_FATAL(rc == 0);
os_time_advance(ticks_until);
ble_gattc_timer();
chunk_sz = attr.value_len - off;
ble_hs_test_util_verify_tx_prep_write(attr.handle, off,
attr.value + off, chunk_sz);
/* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
oms = ble_hs_test_util_mbuf_alloc_all_but(1);
ble_gatt_write_test_rx_prep_rsp(
2, attr.handle, off, attr.value + off, chunk_sz);
off += chunk_sz;
/* Ensure no follow-up request got sent. It should not have gotten sent
* due to mbuf exhaustion.
*/
ble_hs_test_util_prev_tx_queue_clear();
TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
/* Verify that we will resume the stalled GATT procedure in one second. */
ticks_until = ble_gattc_timer();
TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
/* Verify that procedure completes when mbufs are available. */
rc = os_mbuf_free_chain(oms);
TEST_ASSERT_FATAL(rc == 0);
os_time_advance(ticks_until);
ble_gattc_timer();
/* Verify execute write request sent. */
ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE);
/* Receive Exec Write response. */
ble_gatt_write_test_rx_exec_rsp(2);
/* Verify callback got called. */
TEST_ASSERT(ble_gatt_write_test_cb_called);
TEST_ASSERT(!ble_gattc_any_jobs());
}
TEST_CASE(ble_gatt_write_test_reliable_oom)
{
static const struct ble_hs_test_util_flat_attr attr = {
.handle = 34,
.value = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20,
},
.value_len = 20,
};
struct ble_gatt_attr mattr;
struct os_mbuf *oms;
int32_t ticks_until;
int chunk_sz;
int off;
int rc;
ble_gatt_write_test_init();
ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}),
NULL, NULL);
/* Initiate a write reliable procedure. */
ble_hs_test_util_attr_from_flat(&mattr, &attr);
off = 0;
rc = ble_gattc_write_reliable(2, &mattr, 1,
ble_gatt_write_test_reliable_cb_good, NULL);
TEST_ASSERT_FATAL(rc == 0);
chunk_sz = ble_att_mtu(2) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
ble_hs_test_util_verify_tx_prep_write(attr.handle, off,
attr.value + off, chunk_sz);
/* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
oms = ble_hs_test_util_mbuf_alloc_all_but(1);
ble_gatt_write_test_rx_prep_rsp(2, attr.handle, off, attr.value + off,
chunk_sz);
off += chunk_sz;
/* Ensure no follow-up request got sent. It should not have gotten sent
* due to mbuf exhaustion.
*/
ble_hs_test_util_prev_tx_queue_clear();
TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
/* Verify that we will resume the stalled GATT procedure in one second. */
ticks_until = ble_gattc_timer();
TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
/* Verify the procedure proceeds after mbufs become available. */
rc = os_mbuf_free_chain(oms);
TEST_ASSERT_FATAL(rc == 0);
os_time_advance(ticks_until);
ble_gattc_timer();
chunk_sz = attr.value_len - off;
ble_hs_test_util_verify_tx_prep_write(attr.handle, off,
attr.value + off, chunk_sz);
/* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */
oms = ble_hs_test_util_mbuf_alloc_all_but(1);
ble_gatt_write_test_rx_prep_rsp(
2, attr.handle, off, attr.value + off, chunk_sz);
off += chunk_sz;
/* Ensure no follow-up request got sent. It should not have gotten sent
* due to mbuf exhaustion.
*/
ble_hs_test_util_prev_tx_queue_clear();
TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue_pullup() == NULL);
/* Verify that we will resume the stalled GATT procedure in one second. */
ticks_until = ble_gattc_timer();
TEST_ASSERT(ticks_until == os_time_ms_to_ticks32(MYNEWT_VAL(BLE_GATT_RESUME_RATE)));
/* Verify that procedure completes when mbufs are available. */
rc = os_mbuf_free_chain(oms);
TEST_ASSERT_FATAL(rc == 0);
os_time_advance(ticks_until);
ble_gattc_timer();
/* Verify execute write request sent. */
ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE);
/* Receive Exec Write response. */
ble_gatt_write_test_rx_exec_rsp(2);
/* Verify callback got called. */
TEST_ASSERT(ble_gatt_write_test_cb_called);
TEST_ASSERT(!ble_gattc_any_jobs());
}
TEST_SUITE(ble_gatt_write_test_suite)
{
tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL);
ble_gatt_write_test_no_rsp();
ble_gatt_write_test_rsp();
ble_gatt_write_test_long_good();
ble_gatt_write_test_long_bad_handle();
ble_gatt_write_test_long_bad_offset();
ble_gatt_write_test_long_bad_value();
ble_gatt_write_test_long_bad_length();
ble_gatt_write_test_long_queue_full();
ble_gatt_write_test_reliable_good();
ble_gatt_write_test_long_oom();
ble_gatt_write_test_reliable_oom();
}
int
ble_gatt_write_test_all(void)
{
ble_gatt_write_test_suite();
return tu_any_failed;
}