Skip to content

Commit

Permalink
[test] wiring/no_fixture: move some OOM stress tests into wiring/no_f…
Browse files Browse the repository at this point in the history
…ixture_stress as no_fixture overflows on Electron with test runner framework enabled
  • Loading branch information
avtolstoy committed Jul 12, 2021
1 parent 098fca6 commit 7e11512
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 141 deletions.
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);
}
160 changes: 160 additions & 0 deletions user/tests/wiring/no_fixture_stress/memory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Copyright (c) 2021 Particle Industries, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include "application.h"
#include "unit-test/unit-test.h"
#include "random.h"

// 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);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
suite('No fixture stress');

platform('gen3');
platform('gen3', 'gen2');

0 comments on commit 7e11512

Please sign in to comment.