diff --git a/.travis.yml b/.travis.yml index d99954e..ab261ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -253,8 +253,6 @@ connectivity/libraries/ppp connectivity/netsocket features/nanostack features/lwipstack features/frameworks/greentea-client \ features/frameworks/utest features/frameworks/unity components BUILD - python tools/make.py -t GCC_ARM -m NUCLEO_F103RB --source=. --build=BUILD/NUCLEO_F103RB/GCC_ARM -j0 - # Run local equeue tests - - make -C ${EVENTS}/tests/unit test # Run profiling tests - make -C ${EVENTS}/tests/unit prof | tee prof after_success: diff --git a/events/tests/unit/Makefile b/events/tests/unit/Makefile index e8bb503..777d315 100644 --- a/events/tests/unit/Makefile +++ b/events/tests/unit/Makefile @@ -4,7 +4,7 @@ AR = ar SIZE = size -SRC += $(wildcard *.c) +SRC += $(wildcard ../../source/*.c) OBJ := $(SRC:.c=.o) DEP := $(SRC:.c=.d) ASM := $(SRC:.c=.s) @@ -27,13 +27,9 @@ all: $(TARGET) -test: tests.o $(OBJ) - $(CC) $(CFLAGS) $^ $(LFLAGS) -o tests - tests - prof: prof.o $(OBJ) $(CC) $(CFLAGS) $^ $(LFLAGS) -o prof - prof + ./prof asm: $(ASM) @@ -53,7 +49,6 @@ clean: rm -f $(TARGET) - rm -f tests tests.o tests.d rm -f prof prof.o prof.d rm -f $(OBJ) rm -f $(DEP) diff --git a/events/tests/unit/tests.c b/events/tests/unit/tests.c deleted file mode 100644 index efbf7f4..0000000 --- a/events/tests/unit/tests.c +++ /dev/null @@ -1,902 +0,0 @@ -/* - * Testing framework for the events library - * - * Copyright (c) 2016 ARM Limited - * - * Licensed 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 "events/equeue.h" -#include -#include -#include -#include -#include -#include - - -// Testing setup -static jmp_buf test_buf; -static int test_line; -static int test_failure; - -#define test_assert(test) ({ \ - if (!(test)) { \ - test_line = __LINE__; \ - longjmp(test_buf, 1); \ - } \ -}) - -#define test_run(func, ...) ({ \ - printf("%s: ...", #func); \ - fflush(stdout); \ - \ - if (!setjmp(test_buf)) { \ - func(__VA_ARGS__); \ - printf("\r%s: \e[32mpassed\e[0m\n", #func); \ - } else { \ - printf("\r%s: \e[31mfailed\e[0m at line %d\n", #func, test_line); \ - test_failure = true; \ - } \ -}) - - -// Test functions -void pass_func(void *eh) -{ -} - -void simple_func(void *p) -{ - (*(int *)p)++; -} - -void sloth_func(void *p) -{ - usleep(10000); - (*(int *)p)++; -} - -struct indirect { - int *touched; - uint8_t buffer[7]; -}; - -void indirect_func(void *p) -{ - struct indirect *i = (struct indirect *)p; - (*i->touched)++; -} - -struct timing { - unsigned tick; - unsigned delay; -}; - -void timing_func(void *p) -{ - struct timing *timing = (struct timing *)p; - unsigned tick = equeue_tick(); - - unsigned t1 = timing->delay; - unsigned t2 = tick - timing->tick; - test_assert(t1 > t2 - 10 && t1 < t2 + 10); - - timing->tick = tick; -} - -struct fragment { - equeue_t *q; - size_t size; - struct timing timing; -}; - -void fragment_func(void *p) -{ - struct fragment *fragment = (struct fragment *)p; - timing_func(&fragment->timing); - - struct fragment *nfragment = equeue_alloc(fragment->q, fragment->size); - test_assert(nfragment); - - *nfragment = *fragment; - equeue_event_delay(nfragment, fragment->timing.delay); - - int id = equeue_post(nfragment->q, fragment_func, nfragment); - test_assert(id); -} - -struct cancel { - equeue_t *q; - int id; -}; - -void cancel_func(void *p) -{ - struct cancel *cancel = (struct cancel *)p; - equeue_cancel(cancel->q, cancel->id); -} - -struct nest { - equeue_t *q; - void (*cb)(void *); - void *data; -}; - -void nest_func(void *p) -{ - struct nest *nest = (struct nest *)p; - equeue_call(nest->q, nest->cb, nest->data); - - usleep(10000); -} - - -// Simple call tests -void simple_call_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - bool touched = false; - equeue_call(&q, simple_func, &touched); - equeue_dispatch(&q, 0); - test_assert(touched); - - equeue_destroy(&q); -} - -void simple_call_in_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - bool touched = false; - int id = equeue_call_in(&q, 10, simple_func, &touched); - test_assert(id); - - equeue_dispatch(&q, 15); - test_assert(touched); - - equeue_destroy(&q); -} - -void simple_call_every_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - bool touched = false; - int id = equeue_call_every(&q, 10, simple_func, &touched); - test_assert(id); - - equeue_dispatch(&q, 15); - test_assert(touched); - - equeue_destroy(&q); -} - -void simple_post_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int touched = false; - struct indirect *i = equeue_alloc(&q, sizeof(struct indirect)); - test_assert(i); - - i->touched = &touched; - int id = equeue_post(&q, indirect_func, i); - test_assert(id); - - equeue_dispatch(&q, 0); - test_assert(*i->touched); - - equeue_destroy(&q); -} - -// Misc tests -void destructor_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int touched; - struct indirect *e; - int ids[3]; - - touched = 0; - for (int i = 0; i < 3; i++) { - e = equeue_alloc(&q, sizeof(struct indirect)); - test_assert(e); - - e->touched = &touched; - equeue_event_dtor(e, indirect_func); - int id = equeue_post(&q, pass_func, e); - test_assert(id); - } - - equeue_dispatch(&q, 0); - test_assert(touched == 3); - - touched = 0; - for (int i = 0; i < 3; i++) { - e = equeue_alloc(&q, sizeof(struct indirect)); - test_assert(e); - - e->touched = &touched; - equeue_event_dtor(e, indirect_func); - ids[i] = equeue_post(&q, pass_func, e); - test_assert(ids[i]); - } - - for (int i = 0; i < 3; i++) { - equeue_cancel(&q, ids[i]); - } - - equeue_dispatch(&q, 0); - test_assert(touched == 3); - - touched = 0; - for (int i = 0; i < 3; i++) { - e = equeue_alloc(&q, sizeof(struct indirect)); - test_assert(e); - - e->touched = &touched; - equeue_event_dtor(e, indirect_func); - int id = equeue_post(&q, pass_func, e); - test_assert(id); - } - - equeue_destroy(&q); - test_assert(touched == 3); -} - -void allocation_failure_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - void *p = equeue_alloc(&q, 4096); - test_assert(!p); - - for (int i = 0; i < 100; i++) { - p = equeue_alloc(&q, 0); - } - test_assert(!p); - - equeue_destroy(&q); -} - -void cancel_test(int N) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - bool touched = false; - int *ids = malloc(N * sizeof(int)); - - for (int i = 0; i < N; i++) { - ids[i] = equeue_call(&q, simple_func, &touched); - } - - for (int i = N - 1; i >= 0; i--) { - test_assert(equeue_cancel(&q, ids[i])); - } - - free(ids); - - equeue_dispatch(&q, 0); - test_assert(!touched); - - equeue_destroy(&q); -} - -void cancel_inflight_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - bool touched = false; - - int id = equeue_call(&q, simple_func, &touched); - test_assert(equeue_cancel(&q, id)); - - equeue_dispatch(&q, 0); - test_assert(!touched); - - id = equeue_call(&q, simple_func, &touched); - test_assert(equeue_cancel(&q, id)); - - equeue_dispatch(&q, 0); - test_assert(!touched); - - struct cancel *cancel = equeue_alloc(&q, sizeof(struct cancel)); - test_assert(cancel); - cancel->q = &q; - cancel->id = 0; - - id = equeue_post(&q, cancel_func, cancel); - test_assert(id); - - cancel->id = equeue_call(&q, simple_func, &touched); - - equeue_dispatch(&q, 0); - test_assert(!touched); - - equeue_destroy(&q); -} - -void cancel_unnecessarily_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int id = equeue_call(&q, pass_func, 0); - for (int i = 0; i < 5; i++) { - test_assert(equeue_cancel(&q, id) == (i == 0)); - } - - id = equeue_call(&q, pass_func, 0); - equeue_dispatch(&q, 0); - for (int i = 0; i < 5; i++) { - test_assert(!equeue_cancel(&q, id)); - } - - bool touched = false; - equeue_call(&q, simple_func, &touched); - for (int i = 0; i < 5; i++) { - test_assert(!equeue_cancel(&q, id)); - } - - equeue_dispatch(&q, 0); - test_assert(touched); - - equeue_destroy(&q); -} - -void loop_protect_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - bool touched = false; - equeue_call_every(&q, 0, simple_func, &touched); - - equeue_dispatch(&q, 0); - test_assert(touched); - - touched = false; - equeue_call_every(&q, 1, simple_func, &touched); - - equeue_dispatch(&q, 0); - test_assert(touched); - - equeue_destroy(&q); -} - -void break_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - bool touched = false; - equeue_call_every(&q, 0, simple_func, &touched); - - equeue_break(&q); - equeue_dispatch(&q, -1); - test_assert(touched); - - equeue_destroy(&q); -} - -void break_no_windup_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int count = 0; - equeue_call_every(&q, 0, simple_func, &count); - - equeue_break(&q); - equeue_break(&q); - equeue_dispatch(&q, -1); - test_assert(count == 1); - - count = 0; - equeue_dispatch(&q, 55); - test_assert(count > 1); - - equeue_destroy(&q); -} - -void period_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int count = 0; - equeue_call_every(&q, 10, simple_func, &count); - - equeue_dispatch(&q, 55); - test_assert(count == 5); - - equeue_destroy(&q); -} - -void nested_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int touched = 0; - struct nest *nest = equeue_alloc(&q, sizeof(struct nest)); - test_assert(nest); - nest->q = &q; - nest->cb = simple_func; - nest->data = &touched; - - int id = equeue_post(&q, nest_func, nest); - test_assert(id); - - equeue_dispatch(&q, 5); - test_assert(touched == 0); - - equeue_dispatch(&q, 5); - test_assert(touched == 1); - - touched = 0; - nest = equeue_alloc(&q, sizeof(struct nest)); - test_assert(nest); - nest->q = &q; - nest->cb = simple_func; - nest->data = &touched; - - id = equeue_post(&q, nest_func, nest); - test_assert(id); - - equeue_dispatch(&q, 20); - test_assert(touched == 1); - - equeue_destroy(&q); -} - -void sloth_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int touched = 0; - int id = equeue_call(&q, sloth_func, &touched); - test_assert(id); - - id = equeue_call_in(&q, 5, simple_func, &touched); - test_assert(id); - - id = equeue_call_in(&q, 15, simple_func, &touched); - test_assert(id); - - equeue_dispatch(&q, 20); - test_assert(touched == 3); - - equeue_destroy(&q); -} - -void *multithread_thread(void *p) -{ - equeue_t *q = (equeue_t *)p; - equeue_dispatch(q, -1); - return 0; -} - -void multithread_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int touched = 0; - equeue_call_every(&q, 1, simple_func, &touched); - - pthread_t thread; - err = pthread_create(&thread, 0, multithread_thread, &q); - test_assert(!err); - - usleep(10000); - equeue_break(&q); - err = pthread_join(thread, 0); - test_assert(!err); - - test_assert(touched); - - equeue_destroy(&q); -} - -void background_func(void *p, int ms) -{ - *(unsigned *)p = ms; -} - -void background_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - int id = equeue_call_in(&q, 20, pass_func, 0); - test_assert(id); - - unsigned ms; - equeue_background(&q, background_func, &ms); - test_assert(ms == 20); - - id = equeue_call_in(&q, 10, pass_func, 0); - test_assert(id); - test_assert(ms == 10); - - id = equeue_call(&q, pass_func, 0); - test_assert(id); - test_assert(ms == 0); - - equeue_dispatch(&q, 0); - test_assert(ms == 10); - - equeue_destroy(&q); - test_assert(ms == -1); -} - -void chain_test(void) -{ - equeue_t q1; - int err = equeue_create(&q1, 2048); - test_assert(!err); - - equeue_t q2; - err = equeue_create(&q2, 2048); - test_assert(!err); - - equeue_chain(&q2, &q1); - - int touched = 0; - - int id1 = equeue_call_in(&q1, 20, simple_func, &touched); - int id2 = equeue_call_in(&q2, 20, simple_func, &touched); - test_assert(id1 && id2); - - id1 = equeue_call(&q1, simple_func, &touched); - id2 = equeue_call(&q2, simple_func, &touched); - test_assert(id1 && id2); - - id1 = equeue_call_in(&q1, 5, simple_func, &touched); - id2 = equeue_call_in(&q2, 5, simple_func, &touched); - test_assert(id1 && id2); - - test_assert(equeue_cancel(&q1, id1)); - test_assert(equeue_cancel(&q2, id2)); - - id1 = equeue_call_in(&q1, 10, simple_func, &touched); - id2 = equeue_call_in(&q2, 10, simple_func, &touched); - test_assert(id1 && id2); - - equeue_dispatch(&q1, 30); - - test_assert(touched == 6); - - equeue_destroy(&q2); - equeue_destroy(&q1); -} - -void unchain_test(void) -{ - equeue_t q1; - int err = equeue_create(&q1, 2048); - test_assert(!err); - - equeue_t q2; - err = equeue_create(&q2, 2048); - test_assert(!err); - - equeue_chain(&q2, &q1); - - int touched = 0; - int id1 = equeue_call(&q1, simple_func, &touched); - int id2 = equeue_call(&q2, simple_func, &touched); - test_assert(id1 && id2); - - equeue_dispatch(&q1, 0); - test_assert(touched == 2); - - equeue_chain(&q2, 0); - equeue_chain(&q1, &q2); - - id1 = equeue_call(&q1, simple_func, &touched); - id2 = equeue_call(&q2, simple_func, &touched); - test_assert(id1 && id2); - - equeue_dispatch(&q2, 0); - test_assert(touched == 4); - - equeue_destroy(&q1); - equeue_destroy(&q2); -} - -// Barrage tests -void simple_barrage_test(int N) -{ - equeue_t q; - int err = equeue_create(&q, N * (EQUEUE_EVENT_SIZE + sizeof(struct timing))); - test_assert(!err); - - for (int i = 0; i < N; i++) { - struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); - test_assert(timing); - - timing->tick = equeue_tick(); - timing->delay = (i + 1) * 100; - equeue_event_delay(timing, timing->delay); - equeue_event_period(timing, timing->delay); - - int id = equeue_post(&q, timing_func, timing); - test_assert(id); - } - - equeue_dispatch(&q, N * 100); - - equeue_destroy(&q); -} - -void fragmenting_barrage_test(int N) -{ - equeue_t q; - int err = equeue_create(&q, - 2 * N * (EQUEUE_EVENT_SIZE + sizeof(struct fragment) + N * sizeof(int))); - test_assert(!err); - - for (int i = 0; i < N; i++) { - size_t size = sizeof(struct fragment) + i * sizeof(int); - struct fragment *fragment = equeue_alloc(&q, size); - test_assert(fragment); - - fragment->q = &q; - fragment->size = size; - fragment->timing.tick = equeue_tick(); - fragment->timing.delay = (i + 1) * 100; - equeue_event_delay(fragment, fragment->timing.delay); - - int id = equeue_post(&q, fragment_func, fragment); - test_assert(id); - } - - equeue_dispatch(&q, N * 100); - - equeue_destroy(&q); -} - -struct ethread { - pthread_t thread; - equeue_t *q; - int ms; -}; - -static void *ethread_dispatch(void *p) -{ - struct ethread *t = (struct ethread *)p; - equeue_dispatch(t->q, t->ms); - return 0; -} - -void multithreaded_barrage_test(int N) -{ - equeue_t q; - int err = equeue_create(&q, N * (EQUEUE_EVENT_SIZE + sizeof(struct timing))); - test_assert(!err); - - struct ethread t; - t.q = &q; - t.ms = N * 100; - err = pthread_create(&t.thread, 0, ethread_dispatch, &t); - test_assert(!err); - - for (int i = 0; i < N; i++) { - struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); - test_assert(timing); - - timing->tick = equeue_tick(); - timing->delay = (i + 1) * 100; - equeue_event_delay(timing, timing->delay); - equeue_event_period(timing, timing->delay); - - int id = equeue_post(&q, timing_func, timing); - test_assert(id); - } - - err = pthread_join(t.thread, 0); - test_assert(!err); - - equeue_destroy(&q); -} - -struct count_and_queue { - int p; - equeue_t *q; -}; - -void simple_breaker(void *p) -{ - struct count_and_queue *caq = (struct count_and_queue *)p; - equeue_break(caq->q); - usleep(10000); - caq->p++; -} - -void break_request_cleared_on_timeout(void) -{ - equeue_t q; - int err = equeue_create(&q, 2048); - test_assert(!err); - - struct count_and_queue pq; - pq.p = 0; - pq.q = &q; - - int id = equeue_call_every(&q, 10, simple_breaker, &pq); - - equeue_dispatch(&q, 10); - test_assert(pq.p == 1); - - test_assert(equeue_cancel(&q, id)); - - int count = 0; - equeue_call_every(&q, 10, simple_func, &count); - - equeue_dispatch(&q, 55); - test_assert(count > 1); - - equeue_destroy(&q); -} - -void sibling_test(void) -{ - equeue_t q; - int err = equeue_create(&q, 1024); - test_assert(!err); - - int id0 = equeue_call_in(&q, 1, pass_func, 0); - int id1 = equeue_call_in(&q, 1, pass_func, 0); - int id2 = equeue_call_in(&q, 1, pass_func, 0); - - struct equeue_event *e = q.queue; - - for (; e; e = e->next) { - for (struct equeue_event *s = e->sibling; s; s = s->sibling) { - test_assert(!s->next); - } - } - test_assert(equeue_cancel(&q, id0)); - test_assert(equeue_cancel(&q, id1)); - test_assert(equeue_cancel(&q, id2)); - equeue_destroy(&q); -} - -struct user_allocated_event { - struct equeue_event e; - bool touched; -}; - -void user_allocated_event_test() -{ - equeue_t q; - int err = equeue_create(&q, EQUEUE_EVENT_SIZE); - test_assert(!err); - - bool touched = false; - struct user_allocated_event e1 = { { 0, 0, 0, NULL, NULL, NULL, 0, -1, NULL, NULL }, 0 }; - struct user_allocated_event e2 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; - struct user_allocated_event e3 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; - struct user_allocated_event e4 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; - struct user_allocated_event e5 = { { 0, 0, 0, NULL, NULL, NULL, 0, -1, NULL, NULL }, 0 }; - - test_assert(0 != equeue_call(&q, simple_func, &touched)); - test_assert(0 == equeue_call(&q, simple_func, &touched)); - test_assert(0 == equeue_call(&q, simple_func, &touched)); - - equeue_post_user_allocated(&q, simple_func, &e1.e); - equeue_post_user_allocated(&q, simple_func, &e2.e); - equeue_post_user_allocated(&q, simple_func, &e3.e); - equeue_post_user_allocated(&q, simple_func, &e4.e); - equeue_post_user_allocated(&q, simple_func, &e5.e); - test_assert(equeue_cancel_user_allocated(&q, &e3.e)); - - equeue_dispatch(&q, 1); - - test_assert(true == touched); - test_assert(true == e1.touched); - test_assert(true == e2.touched); - test_assert(false == e3.touched); - test_assert(true == e4.touched); - test_assert(true == e5.touched); - - equeue_dispatch(&q, 10); - - test_assert(true == touched); - test_assert(true == e1.touched); - test_assert(true == e2.touched); - test_assert(false == e3.touched); - test_assert(true == e4.touched); - test_assert(true == e5.touched); - - equeue_destroy(&q); -} - -void id_cycle() -{ - equeue_t q; - int err = equeue_create(&q, 10000000); - test_assert(!err); - - for (int i = 0; i < 300; i++) { - int id = equeue_call(&q, pass_func, 0); - test_assert(id != 0); - test_assert(equeue_cancel(&q, id)); - } - - equeue_destroy(&q); -} - -int main() -{ - printf("beginning tests...\n"); - - test_run(simple_call_test); - test_run(simple_call_in_test); - test_run(simple_call_every_test); - test_run(simple_post_test); - test_run(destructor_test); - test_run(allocation_failure_test); - test_run(cancel_test, 20); - test_run(cancel_inflight_test); - test_run(cancel_unnecessarily_test); - test_run(loop_protect_test); - test_run(break_test); - test_run(break_no_windup_test); - test_run(period_test); - test_run(nested_test); - test_run(sloth_test); - test_run(background_test); - test_run(chain_test); - test_run(unchain_test); - test_run(multithread_test); - test_run(simple_barrage_test, 20); - test_run(fragmenting_barrage_test, 20); - test_run(multithreaded_barrage_test, 20); - test_run(break_request_cleared_on_timeout); - test_run(sibling_test); - test_run(user_allocated_event_test); - test_run(id_cycle); - printf("done!\n"); - return test_failure; -}