Skip to content

Commit

Permalink
Merge pull request #2337 from particle-iot/socket_errors_test/ch82443
Browse files Browse the repository at this point in the history
On-device tests for #2335
  • Loading branch information
avtolstoy authored Jul 12, 2021
2 parents c4c5236 + 7e11512 commit 51983d4
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 149 deletions.
2 changes: 2 additions & 0 deletions system/inc/system_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ enum SystemEventsParam {
// Cloud connection status
cloud_status_disconnected = 0,
cloud_status_connecting = 1,
cloud_status_handshake = 2,
cloud_status_session_resume = 3,
cloud_status_connected = 8,
cloud_status_disconnecting = 9,

Expand Down
1 change: 1 addition & 0 deletions system/src/system_cloud_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ int system_internet_test(void* reserved);
int system_multicast_announce_presence(void* reserved);
int system_cloud_set_inet_family_keepalive(int af, unsigned int value, int flags);
int system_cloud_get_inet_family_keepalive(int af, unsigned int* value);
sock_handle_t system_cloud_get_socket_handle();

#ifdef __cplusplus
}
Expand Down
6 changes: 6 additions & 0 deletions system/src/system_cloud_connection_compat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,10 @@ void HAL_NET_notify_socket_closed(sock_handle_t socket)
}
}

sock_handle_t system_cloud_get_socket_handle()
{
return s_state.socket;
}


#endif /* !HAL_USE_SOCKET_HAL_POSIX && HAL_USE_SOCKET_HAL_COMPAT */
5 changes: 5 additions & 0 deletions system/src/system_cloud_connection_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,9 @@ int system_cloud_is_connected(void* reserved)
return s_state.socket >= 0 ? 0 : -1;
}

sock_handle_t system_cloud_get_socket_handle()
{
return s_state.socket;
}

#endif /* HAL_USE_SOCKET_HAL_POSIX */
8 changes: 8 additions & 0 deletions system/src/system_cloud_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1152,11 +1152,19 @@ int Spark_Handshake(bool presence_announce)
#endif // HAL_PLATFORM_MUXER_MAY_NEED_DELAY_IN_TX

if (err == protocol::SESSION_RESUMED) {
// XXX: ideally this event should be generated before we perform the handshake
// but the current semantic of indicating after the handshake/session-resumption are done
// also deserves a chance.
system_notify_event(cloud_status, cloud_status_session_resume);
session_resumed = true;
} else if (err != 0) {
return spark_protocol_to_system_error(err);
}
if (!session_resumed) {
// XXX: ideally this event should be generated before we perform the handshake
// but the current semantic of indicating after the handshake/session-resumption are done
// also deserves a chance.
system_notify_event(cloud_status, cloud_status_handshake);
char buf[CLAIM_CODE_SIZE + 1];
if (!HAL_Get_Claim_Code(buf, sizeof(buf)) && buf[0] != 0 && (uint8_t)buf[0] != 0xff) {
LOG(INFO,"Send spark/device/claim/code event for code %s", buf);
Expand Down
3 changes: 3 additions & 0 deletions system/src/system_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,9 @@ void* system_internal(int item, void* reserved)
return mutex_usb_serial();
}
#endif
case 3: {
return reinterpret_cast<void*>(system_cloud_get_socket_handle());
}
default:
return nullptr;
}
Expand Down
108 changes: 108 additions & 0 deletions user/tests/wiring/no_fixture/cloud.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
#include "application.h"
#include "unit-test/unit-test.h"
#include "scope_guard.h"

namespace {

struct HandshakeState {
volatile int handshakeType = -1;
bool operator()() {
return handshakeType != -1;
}
void reset() {
handshakeType = -1;
}
};

HandshakeState handshakeState;

}

test(CLOUD_01_Particle_Connect_Does_Not_Block_In_SemiAutomatic_Mode) {
Particle.disconnect();
Expand All @@ -18,3 +35,94 @@ test(CLOUD_01_Particle_Connect_Does_Not_Block_In_SemiAutomatic_Mode) {
test(CLOUD_03_Restore_System_Mode) {
set_system_mode(AUTOMATIC);
}

#if HAL_PLATFORM_CLOUD_UDP
test(CLOUD_04_socket_errors_do_not_cause_a_full_handshake) {
const int GET_CLOUD_SOCKET_HANDLE_INTERNAL_ID = 3;

Particle.connect();
assertTrue(waitFor(Particle.connected, 120000));

sock_handle_t cloudSock = (sock_handle_t)system_internal(GET_CLOUD_SOCKET_HANDLE_INTERNAL_ID, nullptr);
assertTrue(socket_handle_valid(cloudSock));

auto evHandler = [](system_event_t event, int param, void* ctx) {
if (event == cloud_status) {
if (param == cloud_status_handshake || param == cloud_status_session_resume) {
if (handshakeState.handshakeType == -1) {
handshakeState.handshakeType = param;
}
}
}
};

handshakeState.reset();
System.on(cloud_status, evHandler);
SCOPE_GUARD({
System.off(cloud_status, evHandler);
});
// Pull the rug, this should cause a socket error on recv/send
#if HAL_USE_SOCKET_HAL_POSIX
assertEqual(0, sock_close(cloudSock));
#else
assertEqual(0, socket_close(cloudSock));
#endif // HAL_USE_SOCKET_HAL_POSIX
// Force a publish just in case
(void)Particle.publish("test", "test");
assertTrue(waitFor(handshakeState, 120000));
assertEqual((int)handshakeState.handshakeType, (int)cloud_status_session_resume);
assertTrue(waitFor(Particle.connected, 60000));
}

#if HAL_PLATFORM_CELLULAR
test(CLOUD_05_loss_of_cellular_network_connectivity_does_not_cause_full_handshake) {
Particle.connect();
assertTrue(waitFor(Particle.connected, 120000));

auto evHandler = [](system_event_t event, int param, void* ctx) {
if (event == cloud_status) {
if (param == cloud_status_handshake || param == cloud_status_session_resume) {
if (handshakeState.handshakeType == -1) {
handshakeState.handshakeType = param;
}
}
}
};

handshakeState.reset();
System.on(cloud_status, evHandler);
SCOPE_GUARD({
System.off(cloud_status, evHandler);
});
// Pull the rug, this should cause a socket error on recv/send
#if HAL_PLATFORM_NCP_AT
assertEqual((int)RESP_OK, Cellular.command("AT+CFUN=0,0\r\n"));
// Force a publish just in case
(void)Particle.publish("test", "test");
assertEqual((int)RESP_OK, Cellular.command("AT+CFUN=1,0\r\n"));
#else
CellularDevice devInfo = {};
devInfo.size = sizeof(devInfo);
assertEqual(0, cellular_device_info(&devInfo, nullptr));
// Electrons don't take too well to being switched to minimum functionality mode
// and perform a reset. Deactivating internal context or disconnecting (COPS=2) seems
// to work better.
if (devInfo.dev == DEV_SARA_R410) {
assertEqual((int)RESP_OK, Cellular.command("AT+COPS=2,0\r\n"));
// Force a publish just in case
(void)Particle.publish("test", "test");
assertEqual((int)RESP_OK, Cellular.command("AT+COPS=0,0\r\n"));
} else {
assertEqual((int)RESP_OK, Cellular.command("AT+UPSDA=0,4\r\n"));
// Force a publish just in case
(void)Particle.publish("test", "test");
assertEqual((int)RESP_OK, Cellular.command("AT+UPSDA=0,3\r\n"));
}
#endif // HAL_PLATFORM_NCP_AT
assertTrue(waitFor(handshakeState, 120000));
assertEqual((int)handshakeState.handshakeType, (int)cloud_status_session_resume);
assertTrue(waitFor(Particle.connected, 60000));
}

#endif // HAL_PLATFORM_CELLULAR
#endif // HAL_PLATFORM_CLOUD_UDP
140 changes: 0 additions & 140 deletions user/tests/wiring/no_fixture/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,143 +131,3 @@ test(SYSTEM_05_button_mirror_disable)
#endif // defined(BUTTON1_MIRROR_SUPPORTED)

#endif // !HAL_PLATFORM_NRF52840

// platform supports out of memory notifiation

bool oomEventReceived = false;
size_t oomSizeReceived = 0;
void handle_oom(system_event_t event, int param, void*) {
// Serial is not thread-safe
// Serial.printlnf("got event %d %d", event, param);
if (out_of_memory==event) {
oomEventReceived = true;
oomSizeReceived = param;
}
};

void register_oom() {
oomEventReceived = false;
oomSizeReceived = 0;
System.on(out_of_memory, handle_oom);
}

void unregister_oom() {
System.off(out_of_memory, handle_oom);
}

test(SYSTEM_06_out_of_memory)
{
// Disconnect from the cloud and network just in case
Particle.disconnect();
Network.disconnect();

const size_t size = 1024*1024*1024;
register_oom();
auto ptr = malloc(size);
(void)ptr;
Particle.process();
unregister_oom();

assertTrue(oomEventReceived);
assertEqual(oomSizeReceived, size);
}

test(SYSTEM_07_fragmented_heap) {
struct Block {
Block() {
// Write garbage data to more easily corrupt the RAM
// in case of issues like static RAM / heap overlap or
// just simple heap corruption
Random rng;
rng.gen(data, sizeof(data));
next = nullptr;
}
char data[508];
Block* next;
};
register_oom();

Block* next = nullptr;

// exhaust memory
for (;;) {
Block* b = new Block();
if (!b) {
break;
} else {
b->next = next;
next = b;
}
}

assertTrue(oomEventReceived);
assertEqual(oomSizeReceived, sizeof(Block));

runtime_info_t info;
info.size = sizeof(info);
HAL_Core_Runtime_Info(&info, nullptr);

// we can't really say about the free heap but the block size should be less
assertLessOrEqual(info.largest_free_block_heap, sizeof(Block));
size_t low_heap = info.freeheap;

// free every 2nd block
Block* head = next;
int count = 0;
for (;head;) {
Block* free = head->next;
if (free) {
// skip the next block
head->next = free->next;
delete free;
count++;
head = head->next;
} else {
head = nullptr;
}
}

HAL_Core_Runtime_Info(&info, nullptr);
const size_t half_fragment_block_size = info.largest_free_block_heap;
const size_t half_fragment_free = info.freeheap;

unregister_oom();
register_oom();
const size_t BLOCKS_TO_MALLOC = 3;
Block* b = new Block[BLOCKS_TO_MALLOC]; // no room for 3 blocks, memory is clearly fragmented
delete[] b;

// free the remaining blocks
for (;next;) {
Block* b = next;
next = b->next;
delete b;
}

assertMoreOrEqual(half_fragment_block_size, sizeof(Block)); // there should definitely be one block available
assertLessOrEqual(half_fragment_block_size, BLOCKS_TO_MALLOC*sizeof(Block)-1); // we expect malloc of 3 blocks to fail, so this better allow up to that size less 1
assertMoreOrEqual(half_fragment_free, low_heap+(sizeof(Block)*count));

assertTrue(oomEventReceived);
assertMoreOrEqual(oomSizeReceived, sizeof(Block)*BLOCKS_TO_MALLOC);
}

test(SYSTEM_08_out_of_memory_not_raised_for_0_size_malloc)
{
const size_t size = 0;
register_oom();
auto ptr = malloc(size);
(void)ptr;
Particle.process();
unregister_oom();

assertFalse(oomEventReceived);
}

test(SYSTEM_09_out_of_memory_restore_state)
{
// Restore connection to the cloud and network
Network.connect();
Particle.connect();
waitFor(Particle.connected, 6*60*1000);
}
15 changes: 7 additions & 8 deletions user/tests/wiring/no_fixture_long_running/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@

namespace {

struct NetworkState {
volatile bool disconnected = false;
};
NetworkState networkState;

template <typename T, typename DT>
T divRoundClosest(T n, DT d) {
return ((n + (d / 2)) / d);
Expand Down Expand Up @@ -76,15 +81,9 @@ test(NETWORK_01_LargePacketsDontCauseIssues_ResolveMtu) {
waitFor(Network.ready, WAIT_TIMEOUT);
assertTrue(Network.ready());

struct State {
volatile bool disconnected;
};
State state = {};

auto evHandler = [](system_event_t event, int param, void* ctx) {
State* state = static_cast<State*>(ctx);
if (event == network_status && param == network_status_disconnected) {
state->disconnected = true;
networkState.disconnected = true;
}
};

Expand Down Expand Up @@ -164,7 +163,7 @@ test(NETWORK_01_LargePacketsDontCauseIssues_ResolveMtu) {
if (millis() - start < MINIMUM_TEST_TIME) {
delay(millis() - start);
}
assertFalse((bool)state.disconnected);
assertFalse((bool)networkState.disconnected);
#if PLATFORM_ID != PLATFORM_BORON && PLATFORM_ID != PLATFORM_BSOM
assertMoreOrEqual((mtu - IPV4_PLUS_UDP_HEADER_LENGTH), MBEDTLS_SSL_MAX_CONTENT_LEN);
#else
Expand Down
Loading

0 comments on commit 51983d4

Please sign in to comment.