Skip to content

Commit 5390c20

Browse files
committed
modules: transport: Add tests and fix found bugs
- Add tests for all states and transitions - Fix bugs found when adding tests, such as no transition to _BACKOFF state. - Remove private message types for successful and failed connection establishment. These are not needed anymore as the _connect() call happens synchronously in the state machine context. Signed-off-by: Jan Tore Guggedal <jantore.guggedal@nordicsemi.no>
1 parent 4a44252 commit 5390c20

File tree

5 files changed

+106
-69
lines changed

5 files changed

+106
-69
lines changed

app/src/modules/transport/Kconfig.transport

+5-6
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ config APP_TRANSPORT_BACKOFF_INITIAL_SECONDS
1414
Time in between reconnection attempts to the CoAP server.
1515
The timer starts after the last failed attempt.
1616

17-
choice APP_TRANSPORT_BACKOFF_BACKOFF_TYPE
17+
choice APP_TRANSPORT_BACKOFF_TYPE
1818
prompt "Reconnection backoff type"
19-
default APP_TRANSPORT_BACKOFF_BACKOFF_TYPE_LINEAR
19+
default APP_TRANSPORT_BACKOFF_TYPE_LINEAR
2020

21-
config APP_TRANSPORT_BACKOFF_BACKOFF_TYPE_EXPONENTIAL
21+
config APP_TRANSPORT_BACKOFF_TYPE_EXPONENTIAL
2222
bool "Exponential backoff"
2323
help
2424
Exponential backoff doubles the reconnection timeout after each failed attempt.
2525
The maximum reconnection timeout is defined by APP_TRANSPORT_BACKOFF_MAX_SECONDS.
2626

27-
config APP_TRANSPORT_BACKOFF_BACKOFF_TYPE_LINEAR
27+
config APP_TRANSPORT_BACKOFF_TYPE_LINEAR
2828
bool "Linear backoff"
2929
help
3030
Linear backoff adds a fixed amount of time to the reconnection timeout after each failed attempt,
3131
as defined by APP_TRANSPORT_BACKOFF_LINEAR_INCREMENT_SECONDS.
3232

33-
config APP_TRANSPORT_BACKOFF_BACKOFF_TYPE_NONE
33+
config APP_TRANSPORT_BACKOFF_TYPE_NONE
3434
bool "No backoff"
3535
help
3636
No backoff means that the reconnection timeout is constant at the value defined by
@@ -41,7 +41,6 @@ endchoice
4141
config APP_TRANSPORT_BACKOFF_LINEAR_INCREMENT_SECONDS
4242
int "Reconnection backoff time increment"
4343
default 60
44-
depends on APP_TRANSPORT_BACKOFF_BACKOFF_TYPE_LINEAR
4544
help
4645
Time added to the reconnection timeout after each failed attempt in seconds.
4746
The maximum reconnection timeout is defined by APP_TRANSPORT_BACKOFF_MAX_SECONDS.

app/src/modules/transport/transport.c

+7-35
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ ZBUS_CHAN_ADD_OBS(BATTERY_CHAN, transport, 0);
3838

3939
/* Enumerator to be used in privat transport channel */
4040
enum priv_transport_msg {
41-
CLOUD_CONN_SUCCES,
42-
CLOUD_CONN_FAILED,
4341
CLOUD_BACKOFF_EXPIRED,
4442
};
4543

@@ -53,7 +51,7 @@ ZBUS_CHAN_DEFINE(PRIV_TRANSPORT_CHAN,
5351
NULL,
5452
NULL,
5553
ZBUS_OBSERVERS(transport),
56-
CLOUD_CONN_FAILED
54+
CLOUD_BACKOFF_EXPIRED
5755
);
5856

5957
/* Connection attempt backoff timer is run as a delayable work on the system workqueue */
@@ -73,7 +71,6 @@ static void state_disconnected_run(void *o);
7371
static void state_connecting_entry(void *o);
7472

7573
static void state_connecting_attempt_entry(void *o);
76-
static void state_connecting_attempt_run(void *o);
7774

7875
static void state_connecting_backoff_entry(void *o);
7976
static void state_connecting_backoff_run(void *o);
@@ -130,7 +127,7 @@ static const struct smf_state states[] = {
130127
&states[STATE_CONNECTING_ATTEMPT]),
131128

132129
[STATE_CONNECTING_ATTEMPT] = SMF_CREATE_STATE(
133-
state_connecting_attempt_entry, state_connecting_attempt_run, NULL,
130+
state_connecting_attempt_entry, NULL, NULL,
134131
&states[STATE_CONNECTING],
135132
NULL),
136133

@@ -192,7 +189,6 @@ static void connect_to_cloud(void)
192189
{
193190
int err;
194191
char buf[NRF_CLOUD_CLIENT_ID_MAX_LEN];
195-
enum priv_transport_msg conn_result = CLOUD_CONN_SUCCES;
196192

197193
err = nrf_cloud_client_id_get(buf, sizeof(buf));
198194
if (err == 0) {
@@ -206,27 +202,25 @@ static void connect_to_cloud(void)
206202

207203
err = nrf_cloud_coap_connect(APP_VERSION_STRING);
208204
if (err == 0) {
209-
err = zbus_chan_pub(&PRIV_TRANSPORT_CHAN, &conn_result, K_SECONDS(1));
210-
if (err) {
211-
LOG_ERR("zbus_chan_pub, error: %d", err);
212-
SEND_FATAL_ERROR();
213-
}
205+
STATE_SET(transport_state, STATE_CONNECTED);
214206

215207
return;
216208
}
217209

218210
/* Connection failed, retry */
219211
LOG_ERR("nrf_cloud_coap_connect, error: %d", err);
212+
213+
STATE_SET(transport_state, STATE_CONNECTING_BACKOFF);
220214
}
221215

222216
static uint32_t calculate_backoff_time(uint32_t attempts)
223217
{
224218
uint32_t backoff_time = CONFIG_APP_TRANSPORT_BACKOFF_INITIAL_SECONDS;
225219

226220
/* Calculate backoff time */
227-
if (IS_ENABLED(CONFIG_APP_TRANSPORT_BACKOFF_EXPONENTIAL)) {
221+
if (IS_ENABLED(CONFIG_APP_TRANSPORT_BACKOFF_TYPE_EXPONENTIAL)) {
228222
backoff_time = CONFIG_APP_TRANSPORT_BACKOFF_INITIAL_SECONDS << (attempts - 1);
229-
} else if (IS_ENABLED(CONFIG_APP_TRANSPORT_BACKOFF_LINEAR)) {
223+
} else if (IS_ENABLED(CONFIG_APP_TRANSPORT_BACKOFF_TYPE_LINEAR)) {
230224
backoff_time = CONFIG_APP_TRANSPORT_BACKOFF_INITIAL_SECONDS +
231225
((attempts - 1) * CONFIG_APP_TRANSPORT_BACKOFF_LINEAR_INCREMENT_SECONDS);
232226
}
@@ -350,28 +344,6 @@ static void state_connecting_attempt_entry(void *o)
350344
connect_to_cloud();
351345
}
352346

353-
static void state_connecting_attempt_run(void *o)
354-
{
355-
struct state_object *state_object = o;
356-
357-
LOG_DBG("%s", __func__);
358-
359-
if (state_object->chan == &PRIV_TRANSPORT_CHAN) {
360-
enum priv_transport_msg msg = *(enum priv_transport_msg *)state_object->msg_buf;
361-
362-
switch (msg) {
363-
case CLOUD_CONN_SUCCES:
364-
STATE_SET(transport_state, STATE_CONNECTED);
365-
break;
366-
case CLOUD_CONN_FAILED:
367-
STATE_SET(transport_state, STATE_CONNECTING_BACKOFF);
368-
break;
369-
default:
370-
break;
371-
}
372-
}
373-
}
374-
375347
/* Handler for STATE_CONNECTING_BACKOFF */
376348

377349
static void state_connecting_backoff_entry(void *o)

tests/module/transport/CMakeLists.txt

+8-1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,12 @@ target_compile_definitions(app PRIVATE
3535
-DCONFIG_APP_TRANSPORT_MESSAGE_QUEUE_SIZE=5
3636
-DCONFIG_APP_TRANSPORT_EXEC_TIME_SECONDS_MAX=1
3737
-DCONFIG_APP_TRANSPORT_WATCHDOG_TIMEOUT_SECONDS=2
38-
-DCONFIG_APP_TRANSPORT_BACKOFF_SECONDS=3
38+
-DCONFIG_APP_TRANSPORT_BACKOFF_TYPE_LINEAR=1
39+
-DCONFIG_APP_TRANSPORT_BACKOFF_INITIAL_SECONDS=6
40+
-DCONFIG_APP_TRANSPORT_BACKOFF_LINEAR_INCREMENT_SECONDS=6
41+
-DCONFIG_APP_TRANSPORT_BACKOFF_MAX_SECONDS=36
42+
-DCONFIG_APP_NETWORK_SAMPLE_NETWORK_QUALITY=1
43+
-DCONFIG_LTE_LC_CONN_EVAL_MODULE=1
44+
-DCONFIG_LTE_LC_EDRX_MODULE=1
45+
-DCONFIG_LTE_LC_PSM_MODULE=1
3946
)

tests/module/transport/prj.conf

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
CONFIG_UNITY=y
88
CONFIG_LOG=y
9+
CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=n
910

1011
CONFIG_ZBUS=y
1112
CONFIG_ZBUS_OBSERVER_NAME=y

tests/module/transport/src/transport_module_test.c

+85-27
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,41 @@ FAKE_VALUE_FUNC(int, nrf_cloud_coap_connect, const char * const);
1919
FAKE_VALUE_FUNC(int, nrf_cloud_coap_disconnect);
2020
FAKE_VALUE_FUNC(int, nrf_cloud_coap_shadow_device_status_update);
2121
FAKE_VALUE_FUNC(int, nrf_cloud_coap_bytes_send, uint8_t *, size_t, bool);
22+
FAKE_VALUE_FUNC(int, nrf_cloud_coap_sensor_send, const char *, double, int64_t, bool);
23+
FAKE_VALUE_FUNC(int, nrf_cloud_coap_json_message_send, const char *, bool, bool);
24+
25+
/* Forward declarations */
26+
static void dummy_cb(const struct zbus_channel *chan);
27+
static void cloud_chan_cb(const struct zbus_channel *chan);
28+
static void error_cb(const struct zbus_channel *chan);
29+
30+
/* Define unused subscribers */
31+
ZBUS_SUBSCRIBER_DEFINE(app, 1);
32+
ZBUS_SUBSCRIBER_DEFINE(battery, 1);
33+
ZBUS_SUBSCRIBER_DEFINE(environmental, 1);
34+
ZBUS_SUBSCRIBER_DEFINE(fota, 1);
35+
ZBUS_SUBSCRIBER_DEFINE(led, 1);
36+
ZBUS_SUBSCRIBER_DEFINE(location, 1);
37+
ZBUS_LISTENER_DEFINE(trigger, dummy_cb);
38+
ZBUS_LISTENER_DEFINE(cloud, cloud_chan_cb);
39+
ZBUS_LISTENER_DEFINE(error, error_cb);
40+
41+
#define FAKE_DEVICE_ID "test_device"
2242

2343
static K_SEM_DEFINE(cloud_disconnected, 0, 1);
2444
static K_SEM_DEFINE(cloud_connected_ready, 0, 1);
2545
static K_SEM_DEFINE(cloud_connected_paused, 0, 1);
2646
static K_SEM_DEFINE(data_sent, 0, 1);
2747
static K_SEM_DEFINE(fatal_error_received, 0, 1);
2848

49+
static int nrf_cloud_client_id_get_custom_fake(char *buf, size_t len)
50+
{
51+
TEST_ASSERT(len >= sizeof(FAKE_DEVICE_ID));
52+
memcpy(buf, FAKE_DEVICE_ID, sizeof(FAKE_DEVICE_ID));
53+
54+
return 0;
55+
}
56+
2957
static void dummy_cb(const struct zbus_channel *chan)
3058
{
3159
ARG_UNUSED(chan);
@@ -57,24 +85,18 @@ static void error_cb(const struct zbus_channel *chan)
5785
}
5886
}
5987

60-
/* Define unused subscribers */
61-
ZBUS_SUBSCRIBER_DEFINE(app, 1);
62-
ZBUS_SUBSCRIBER_DEFINE(battery, 1);
63-
ZBUS_SUBSCRIBER_DEFINE(environmental, 1);
64-
ZBUS_SUBSCRIBER_DEFINE(fota, 1);
65-
ZBUS_SUBSCRIBER_DEFINE(led, 1);
66-
ZBUS_SUBSCRIBER_DEFINE(location, 1);
67-
ZBUS_LISTENER_DEFINE(trigger, dummy_cb);
68-
ZBUS_LISTENER_DEFINE(cloud, cloud_chan_cb);
69-
ZBUS_LISTENER_DEFINE(error, error_cb);
70-
7188
void setUp(void)
7289
{
7390
const struct zbus_channel *chan;
7491

7592
/* Reset fakes */
7693
RESET_FAKE(task_wdt_feed);
7794
RESET_FAKE(task_wdt_add);
95+
RESET_FAKE(nrf_cloud_client_id_get);
96+
RESET_FAKE(nrf_cloud_coap_json_message_send);
97+
RESET_FAKE(nrf_cloud_coap_connect);
98+
99+
nrf_cloud_client_id_get_fake.custom_fake = nrf_cloud_client_id_get_custom_fake;
78100

79101
/* Clear all channels */
80102
zbus_sub_wait(&location, &chan, K_NO_WAIT);
@@ -95,6 +117,36 @@ void test_initial_transition_to_disconnected(void)
95117
TEST_ASSERT_EQUAL(0, err);
96118
}
97119

120+
void test_connecting_backoff(void)
121+
{
122+
int err;
123+
struct network_msg msg = { .type = NETWORK_CONNECTED, };
124+
uint64_t connect_start_time, connect_duration_sec;
125+
126+
nrf_cloud_coap_connect_fake.return_val = -EAGAIN;
127+
connect_start_time = k_uptime_get();
128+
129+
msg.type = NETWORK_CONNECTED;
130+
131+
err = zbus_chan_pub(&NETWORK_CHAN, &msg, K_SECONDS(1));
132+
TEST_ASSERT_EQUAL(0, err);
133+
134+
/* Transport module needs CPU to run state machine */
135+
k_sleep(K_MSEC(10));
136+
137+
err = k_sem_take(&cloud_connected_ready, K_SECONDS(60));
138+
TEST_ASSERT_EQUAL(-EAGAIN, err);
139+
140+
connect_duration_sec = k_uptime_delta(&connect_start_time) / MSEC_PER_SEC;
141+
142+
/* Check that the connection attempt took at least
143+
* CONFIG_APP_TRANSPORT_BACKOFF_INITIAL_SECONDS
144+
*/
145+
146+
TEST_ASSERT_GREATER_OR_EQUAL(CONFIG_APP_TRANSPORT_BACKOFF_INITIAL_SECONDS,
147+
connect_duration_sec);
148+
}
149+
98150
void test_transition_disconnected_connected_ready(void)
99151
{
100152
int err;
@@ -108,20 +160,23 @@ void test_transition_disconnected_connected_ready(void)
108160

109161
void test_sending_payload(void)
110162
{
163+
int err;
111164
struct payload payload = {
112-
.buffer = "test",
113-
.buffer_len = sizeof(payload.buffer) - 1,
165+
.buffer = "{\"test\": 1}",
166+
.buffer_len = strlen(payload.buffer),
114167
};
115168

116-
zbus_chan_pub(&PAYLOAD_CHAN, &payload, K_NO_WAIT);
169+
err = zbus_chan_pub(&PAYLOAD_CHAN, &payload, K_SECONDS(1));
170+
TEST_ASSERT_EQUAL(0, err);
117171

118172
/* Transport module needs CPU to run state machine */
119-
k_sleep(K_MSEC(100));
173+
k_sleep(K_MSEC(10));
120174

121-
TEST_ASSERT_EQUAL(1, nrf_cloud_coap_bytes_send_fake.call_count);
122-
TEST_ASSERT_EQUAL(0, strncmp(nrf_cloud_coap_bytes_send_fake.arg0_val,
175+
TEST_ASSERT_EQUAL(1, nrf_cloud_coap_json_message_send_fake.call_count);
176+
TEST_ASSERT_EQUAL(0, strncmp(nrf_cloud_coap_json_message_send_fake.arg0_val,
123177
payload.buffer, payload.buffer_len));
124-
TEST_ASSERT_EQUAL(payload.buffer_len, nrf_cloud_coap_bytes_send_fake.arg1_val);
178+
TEST_ASSERT_EQUAL(false, nrf_cloud_coap_json_message_send_fake.arg1_val);
179+
TEST_ASSERT_EQUAL(false, nrf_cloud_coap_json_message_send_fake.arg2_val);
125180
}
126181

127182
void test_connected_ready_to_paused(void)
@@ -143,30 +198,33 @@ void test_connected_paused_to_ready_send_payload(void)
143198
int err;
144199
enum network_msg_type status = NETWORK_CONNECTED;
145200
struct payload payload = {
146-
.buffer = "Another test",
147-
.buffer_len = sizeof(payload.buffer) - 1,
201+
.buffer = "{\"Another\": \"test\"}",
202+
.buffer_len = strlen(payload.buffer),
148203
};
149204

150205
/* Reset call count */
151206
nrf_cloud_coap_bytes_send_fake.call_count = 0;
152207

153-
zbus_chan_pub(&NETWORK_CHAN, &status, K_NO_WAIT);
208+
err = zbus_chan_pub(&NETWORK_CHAN, &status, K_NO_WAIT);
209+
TEST_ASSERT_EQUAL(0, err);
154210

155211
/* Transport module needs CPU to run state machine */
156-
k_sleep(K_MSEC(100));
212+
k_sleep(K_MSEC(10));
157213

158214
err = k_sem_take(&cloud_connected_ready, K_SECONDS(1));
159215
TEST_ASSERT_EQUAL(0, err);
160216

161-
zbus_chan_pub(&PAYLOAD_CHAN, &payload, K_NO_WAIT);
217+
err = zbus_chan_pub(&PAYLOAD_CHAN, &payload, K_NO_WAIT);
218+
TEST_ASSERT_EQUAL(0, err);
162219

163220
/* Transport module needs CPU to run state machine */
164-
k_sleep(K_MSEC(100));
221+
k_sleep(K_MSEC(10));
165222

166-
TEST_ASSERT_EQUAL(1, nrf_cloud_coap_bytes_send_fake.call_count);
167-
TEST_ASSERT_EQUAL(0, strncmp(nrf_cloud_coap_bytes_send_fake.arg0_val,
223+
TEST_ASSERT_EQUAL(1, nrf_cloud_coap_json_message_send_fake.call_count);
224+
TEST_ASSERT_EQUAL(0, strncmp(nrf_cloud_coap_json_message_send_fake.arg0_val,
168225
payload.buffer, payload.buffer_len));
169-
TEST_ASSERT_EQUAL(payload.buffer_len, nrf_cloud_coap_bytes_send_fake.arg1_val);
226+
TEST_ASSERT_EQUAL(false, nrf_cloud_coap_json_message_send_fake.arg1_val);
227+
TEST_ASSERT_EQUAL(false, nrf_cloud_coap_json_message_send_fake.arg2_val);
170228
}
171229

172230
/* This is required to be added to each test. That is because unity's

0 commit comments

Comments
 (0)