Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tests.c Source File

tests.c

00001 /*
00002  * Testing framework for the events library
00003  *
00004  * Copyright (c) 2016 Christopher Haster
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 #include "equeue.h"
00019 #include <unistd.h>
00020 #include <stdio.h>
00021 #include <setjmp.h>
00022 #include <stdint.h>
00023 #include <stdlib.h>
00024 #include <pthread.h>
00025 
00026 
00027 // Testing setup
00028 static jmp_buf test_buf;
00029 static int test_line;
00030 static int test_failure;
00031 
00032 #define test_assert(test) ({                                                \
00033     if (!(test)) {                                                          \
00034         test_line = __LINE__;                                               \
00035         longjmp(test_buf, 1);                                               \
00036     }                                                                       \
00037 })
00038 
00039 #define test_run(func, ...) ({                                              \
00040     printf("%s: ...", #func);                                               \
00041     fflush(stdout);                                                         \
00042                                                                             \
00043     if (!setjmp(test_buf)) {                                                \
00044         func(__VA_ARGS__);                                                  \
00045         printf("\r%s: \e[32mpassed\e[0m\n", #func);                         \
00046     } else {                                                                \
00047         printf("\r%s: \e[31mfailed\e[0m at line %d\n", #func, test_line);   \
00048         test_failure = true;                                                \
00049     }                                                                       \
00050 })
00051 
00052 
00053 // Test functions
00054 void pass_func(void *eh) {
00055 }
00056 
00057 void simple_func(void *p) {
00058     (*(int *)p)++;
00059 }
00060 
00061 void sloth_func(void *p) {
00062     usleep(10000);
00063     (*(int *)p)++;
00064 }
00065 
00066 struct indirect {
00067     int *touched;
00068     uint8_t buffer[7];
00069 };
00070 
00071 void indirect_func(void *p) {
00072     struct indirect *i = (struct indirect*)p;
00073     (*i->touched)++;
00074 }
00075 
00076 struct timing {
00077     unsigned tick;
00078     unsigned delay;
00079 };
00080 
00081 void timing_func(void *p) {
00082     struct timing *timing = (struct timing*)p;
00083     unsigned tick = equeue_tick();
00084 
00085     unsigned t1 = timing->delay;
00086     unsigned t2 = tick - timing->tick;
00087     test_assert(t1 > t2 - 10 && t1 < t2 + 10);
00088 
00089     timing->tick = tick;
00090 }
00091 
00092 struct fragment {
00093     equeue_t *q;
00094     size_t size;
00095     struct timing timing;
00096 };
00097 
00098 void fragment_func(void *p) {
00099     struct fragment *fragment = (struct fragment*)p;
00100     timing_func(&fragment->timing);
00101 
00102     struct fragment *nfragment = equeue_alloc(fragment->q, fragment->size);
00103     test_assert(nfragment);
00104 
00105     *nfragment = *fragment;
00106     equeue_event_delay(nfragment, fragment->timing.delay);
00107 
00108     int id = equeue_post(nfragment->q, fragment_func, nfragment);
00109     test_assert(id);
00110 }
00111 
00112 struct cancel {
00113     equeue_t *q;
00114     int id;
00115 };
00116 
00117 void cancel_func(void *p) {
00118     struct cancel *cancel = (struct cancel *)p;
00119     equeue_cancel(cancel->q, cancel->id);
00120 }
00121 
00122 struct nest {
00123     equeue_t *q;
00124     void (*cb)(void *);
00125     void *data;
00126 };
00127 
00128 void nest_func(void *p) {
00129     struct nest *nest = (struct nest *)p;
00130     equeue_call(nest->q, nest->cb, nest->data);
00131 
00132     usleep(10000);
00133 }
00134 
00135 
00136 // Simple call tests
00137 void simple_call_test(void) {
00138     equeue_t q;
00139     int err = equeue_create(&q, 2048);
00140     test_assert(!err);
00141 
00142     bool touched = false;
00143     equeue_call(&q, simple_func, &touched);
00144     equeue_dispatch(&q, 0);
00145     test_assert(touched);
00146 
00147     equeue_destroy(&q);
00148 }
00149 
00150 void simple_call_in_test(void) {
00151     equeue_t q;
00152     int err = equeue_create(&q, 2048);
00153     test_assert(!err);
00154 
00155     bool touched = false;
00156     int id = equeue_call_in(&q, 10, simple_func, &touched);
00157     test_assert(id);
00158 
00159     equeue_dispatch(&q, 15);
00160     test_assert(touched);
00161 
00162     equeue_destroy(&q);
00163 }
00164 
00165 void simple_call_every_test(void) {
00166     equeue_t q;
00167     int err = equeue_create(&q, 2048);
00168     test_assert(!err);
00169 
00170     bool touched = false;
00171     int id = equeue_call_every(&q, 10, simple_func, &touched);
00172     test_assert(id);
00173 
00174     equeue_dispatch(&q, 15);
00175     test_assert(touched);
00176 
00177     equeue_destroy(&q);
00178 }
00179 
00180 void simple_post_test(void) {
00181     equeue_t q;
00182     int err = equeue_create(&q, 2048);
00183     test_assert(!err);
00184 
00185     int touched = false;
00186     struct indirect *i = equeue_alloc(&q, sizeof(struct indirect));
00187     test_assert(i);
00188 
00189     i->touched = &touched;
00190     int id = equeue_post(&q, indirect_func, i);
00191     test_assert(id);
00192 
00193     equeue_dispatch(&q, 0);
00194     test_assert(*i->touched);
00195 
00196     equeue_destroy(&q);
00197 }
00198 
00199 // Misc tests
00200 void destructor_test(void) {
00201     equeue_t q;
00202     int err = equeue_create(&q, 2048);
00203     test_assert(!err);
00204 
00205     int touched;
00206     struct indirect *e;
00207     int ids[3];
00208 
00209     touched = 0;
00210     for (int i = 0; i < 3; i++) {
00211         e = equeue_alloc(&q, sizeof(struct indirect));
00212         test_assert(e);
00213 
00214         e->touched = &touched;
00215         equeue_event_dtor(e, indirect_func);
00216         int id = equeue_post(&q, pass_func, e);
00217         test_assert(id);
00218     }
00219 
00220     equeue_dispatch(&q, 0);
00221     test_assert(touched == 3);
00222 
00223     touched = 0;
00224     for (int i = 0; i < 3; i++) {
00225         e = equeue_alloc(&q, sizeof(struct indirect));
00226         test_assert(e);
00227 
00228         e->touched = &touched;
00229         equeue_event_dtor(e, indirect_func);
00230         ids[i] = equeue_post(&q, pass_func, e);
00231         test_assert(ids[i]);
00232     }
00233 
00234     for (int i = 0; i < 3; i++) {
00235         equeue_cancel(&q, ids[i]);
00236     }
00237 
00238     equeue_dispatch(&q, 0);
00239     test_assert(touched == 3);
00240 
00241     touched = 0;
00242     for (int i = 0; i < 3; i++) {
00243         e = equeue_alloc(&q, sizeof(struct indirect));
00244         test_assert(e);
00245 
00246         e->touched = &touched;
00247         equeue_event_dtor(e, indirect_func);
00248         int id = equeue_post(&q, pass_func, e);
00249         test_assert(id);
00250     }
00251 
00252     equeue_destroy(&q);
00253     test_assert(touched == 3);
00254 }
00255 
00256 void allocation_failure_test(void) {
00257     equeue_t q;
00258     int err = equeue_create(&q, 2048);
00259     test_assert(!err);
00260 
00261     void *p = equeue_alloc(&q, 4096);
00262     test_assert(!p);
00263 
00264     for (int i = 0; i < 100; i++) {
00265         p = equeue_alloc(&q, 0);
00266     }
00267     test_assert(!p);
00268 
00269     equeue_destroy(&q);
00270 }
00271 
00272 void cancel_test(int N) {
00273     equeue_t q;
00274     int err = equeue_create(&q, 2048);
00275     test_assert(!err);
00276 
00277     bool touched = false;
00278     int *ids = malloc(N*sizeof(int));
00279 
00280     for (int i = 0; i < N; i++) {
00281         ids[i] = equeue_call(&q, simple_func, &touched);
00282     }
00283 
00284     for (int i = N-1; i >= 0; i--) {
00285         equeue_cancel(&q, ids[i]);
00286     }
00287 
00288     free(ids);
00289 
00290     equeue_dispatch(&q, 0);
00291     test_assert(!touched);
00292 
00293     equeue_destroy(&q);
00294 }
00295 
00296 void cancel_inflight_test(void) {
00297     equeue_t q;
00298     int err = equeue_create(&q, 2048);
00299     test_assert(!err);
00300 
00301     bool touched = false;
00302 
00303     int id = equeue_call(&q, simple_func, &touched);
00304     equeue_cancel(&q, id);
00305 
00306     equeue_dispatch(&q, 0);
00307     test_assert(!touched);
00308 
00309     id = equeue_call(&q, simple_func, &touched);
00310     equeue_cancel(&q, id);
00311 
00312     equeue_dispatch(&q, 0);
00313     test_assert(!touched);
00314 
00315     struct cancel *cancel = equeue_alloc(&q, sizeof(struct cancel));
00316     test_assert(cancel);
00317     cancel->q = &q;
00318     cancel->id = 0;
00319 
00320     id = equeue_post(&q, cancel_func, cancel);
00321     test_assert(id);
00322 
00323     cancel->id = equeue_call(&q, simple_func, &touched);
00324 
00325     equeue_dispatch(&q, 0);
00326     test_assert(!touched);
00327 
00328     equeue_destroy(&q);
00329 }
00330 
00331 void cancel_unnecessarily_test(void) {
00332     equeue_t q;
00333     int err = equeue_create(&q, 2048);
00334     test_assert(!err);
00335 
00336     int id = equeue_call(&q, pass_func, 0);
00337     for (int i = 0; i < 5; i++) {
00338         equeue_cancel(&q, id);
00339     }
00340 
00341     id = equeue_call(&q, pass_func, 0);
00342     equeue_dispatch(&q, 0);
00343     for (int i = 0; i < 5; i++) {
00344         equeue_cancel(&q, id);
00345     }
00346 
00347     bool touched = false;
00348     equeue_call(&q, simple_func, &touched);
00349     for (int i = 0; i < 5; i++) {
00350         equeue_cancel(&q, id);
00351     }
00352 
00353     equeue_dispatch(&q, 0);
00354     test_assert(touched);
00355 
00356     equeue_destroy(&q);
00357 }
00358 
00359 void loop_protect_test(void) {
00360     equeue_t q;
00361     int err = equeue_create(&q, 2048);
00362     test_assert(!err);
00363 
00364     bool touched = false;
00365     equeue_call_every(&q, 0, simple_func, &touched);
00366 
00367     equeue_dispatch(&q, 0);
00368     test_assert(touched);
00369 
00370     touched = false;
00371     equeue_call_every(&q, 1, simple_func, &touched);
00372 
00373     equeue_dispatch(&q, 0);
00374     test_assert(touched);
00375 
00376     equeue_destroy(&q);
00377 }
00378 
00379 void break_test(void) {
00380     equeue_t q;
00381     int err = equeue_create(&q, 2048);
00382     test_assert(!err);
00383 
00384     bool touched = false;
00385     equeue_call_every(&q, 0, simple_func, &touched);
00386 
00387     equeue_break(&q);
00388     equeue_dispatch(&q, -1);
00389     test_assert(touched);
00390 
00391     equeue_destroy(&q);
00392 }
00393 
00394 void period_test(void) {
00395     equeue_t q;
00396     int err = equeue_create(&q, 2048);
00397     test_assert(!err);
00398 
00399     int count = 0;
00400     equeue_call_every(&q, 10, simple_func, &count);
00401 
00402     equeue_dispatch(&q, 55);
00403     test_assert(count == 5);
00404 
00405     equeue_destroy(&q);
00406 }
00407 
00408 void nested_test(void) {
00409     equeue_t q;
00410     int err = equeue_create(&q, 2048);
00411     test_assert(!err);
00412 
00413     int touched = 0;
00414     struct nest *nest = equeue_alloc(&q, sizeof(struct nest));
00415     test_assert(nest);
00416     nest->q = &q;
00417     nest->cb = simple_func;
00418     nest->data = &touched;
00419 
00420     int id = equeue_post(&q, nest_func, nest);
00421     test_assert(id);
00422 
00423     equeue_dispatch(&q, 5);
00424     test_assert(touched == 0);
00425 
00426     equeue_dispatch(&q, 5);
00427     test_assert(touched == 1);
00428 
00429     touched = 0;
00430     nest = equeue_alloc(&q, sizeof(struct nest));
00431     test_assert(nest);
00432     nest->q = &q;
00433     nest->cb = simple_func;
00434     nest->data = &touched;
00435 
00436     id = equeue_post(&q, nest_func, nest);
00437     test_assert(id);
00438 
00439     equeue_dispatch(&q, 20);
00440     test_assert(touched == 1);
00441 
00442     equeue_destroy(&q);
00443 }
00444 
00445 void sloth_test(void) {
00446     equeue_t q;
00447     int err = equeue_create(&q, 2048);
00448     test_assert(!err);
00449 
00450     int touched = 0;
00451     int id = equeue_call(&q, sloth_func, &touched);
00452     test_assert(id);
00453 
00454     id = equeue_call_in(&q, 5, simple_func, &touched);
00455     test_assert(id);
00456 
00457     id = equeue_call_in(&q, 15, simple_func, &touched);
00458     test_assert(id);
00459 
00460     equeue_dispatch(&q, 20);
00461     test_assert(touched == 3);
00462 
00463     equeue_destroy(&q);
00464 }
00465 
00466 void *multithread_thread(void *p) {
00467     equeue_t *q = (equeue_t *)p;
00468     equeue_dispatch(q, -1);
00469     return 0;
00470 }
00471 
00472 void multithread_test(void) {
00473     equeue_t q;
00474     int err = equeue_create(&q, 2048);
00475     test_assert(!err);
00476 
00477     int touched = 0;
00478     equeue_call_every(&q, 1, simple_func, &touched);
00479 
00480     pthread_t thread;
00481     err = pthread_create(&thread, 0, multithread_thread, &q);
00482     test_assert(!err);
00483 
00484     usleep(10000);
00485     equeue_break(&q);
00486     err = pthread_join(thread, 0);
00487     test_assert(!err);
00488 
00489     test_assert(touched);
00490 
00491     equeue_destroy(&q);
00492 }
00493 
00494 void background_func(void *p, int ms) {
00495     *(unsigned *)p = ms;
00496 }
00497 
00498 void background_test(void) {
00499     equeue_t q;
00500     int err = equeue_create(&q, 2048);
00501     test_assert(!err);
00502 
00503     int id = equeue_call_in(&q, 20, pass_func, 0);
00504     test_assert(id);
00505 
00506     unsigned ms;
00507     equeue_background(&q, background_func, &ms);
00508     test_assert(ms == 20);
00509 
00510     id = equeue_call_in(&q, 10, pass_func, 0);
00511     test_assert(id);
00512     test_assert(ms == 10);
00513 
00514     id = equeue_call(&q, pass_func, 0);
00515     test_assert(id);
00516     test_assert(ms == 0);
00517 
00518     equeue_dispatch(&q, 0);
00519     test_assert(ms == 10);
00520 
00521     equeue_destroy(&q);
00522     test_assert(ms == -1);
00523 }
00524 
00525 void chain_test(void) {
00526     equeue_t q1;
00527     int err = equeue_create(&q1, 2048);
00528     test_assert(!err);
00529 
00530     equeue_t q2;
00531     err = equeue_create(&q2, 2048);
00532     test_assert(!err);
00533 
00534     equeue_chain(&q2, &q1);
00535 
00536     int touched = 0;
00537 
00538     int id1 = equeue_call_in(&q1, 20, simple_func, &touched);
00539     int id2 = equeue_call_in(&q2, 20, simple_func, &touched);
00540     test_assert(id1 && id2);
00541 
00542     id1 = equeue_call(&q1, simple_func, &touched);
00543     id2 = equeue_call(&q2, simple_func, &touched);
00544     test_assert(id1 && id2);
00545 
00546     id1 = equeue_call_in(&q1, 5, simple_func, &touched);
00547     id2 = equeue_call_in(&q2, 5, simple_func, &touched);
00548     test_assert(id1 && id2);
00549 
00550     equeue_cancel(&q1, id1);
00551     equeue_cancel(&q2, id2);
00552 
00553     id1 = equeue_call_in(&q1, 10, simple_func, &touched);
00554     id2 = equeue_call_in(&q2, 10, simple_func, &touched);
00555     test_assert(id1 && id2);
00556 
00557     equeue_dispatch(&q1, 30);
00558 
00559     test_assert(touched == 6);
00560 
00561     equeue_destroy(&q1);
00562     equeue_destroy(&q2);
00563 }
00564 
00565 void unchain_test(void) {
00566     equeue_t q1;
00567     int err = equeue_create(&q1, 2048);
00568     test_assert(!err);
00569 
00570     equeue_t q2;
00571     err = equeue_create(&q2, 2048);
00572     test_assert(!err);
00573 
00574     equeue_chain(&q2, &q1);
00575 
00576     int touched = 0;
00577     int id1 = equeue_call(&q1, simple_func, &touched);
00578     int id2 = equeue_call(&q2, simple_func, &touched);
00579     test_assert(id1 && id2);
00580 
00581     equeue_dispatch(&q1, 0);
00582     test_assert(touched == 2);
00583 
00584     equeue_chain(&q2, 0);
00585     equeue_chain(&q1, &q2);
00586 
00587     id1 = equeue_call(&q1, simple_func, &touched);
00588     id2 = equeue_call(&q2, simple_func, &touched);
00589     test_assert(id1 && id2);
00590 
00591     equeue_dispatch(&q2, 0);
00592     test_assert(touched == 4);
00593 
00594     equeue_destroy(&q1);
00595     equeue_destroy(&q2);
00596 }
00597 
00598 // Barrage tests
00599 void simple_barrage_test(int N) {
00600     equeue_t q;
00601     int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing)));
00602     test_assert(!err);
00603 
00604     for (int i = 0; i < N; i++) {
00605         struct timing *timing = equeue_alloc(&q, sizeof(struct timing));
00606         test_assert(timing);
00607 
00608         timing->tick = equeue_tick();
00609         timing->delay = (i+1)*100;
00610         equeue_event_delay(timing, timing->delay);
00611         equeue_event_period(timing, timing->delay);
00612 
00613         int id = equeue_post(&q, timing_func, timing);
00614         test_assert(id);
00615     }
00616 
00617     equeue_dispatch(&q, N*100);
00618 
00619     equeue_destroy(&q);
00620 }
00621 
00622 void fragmenting_barrage_test(int N) {
00623     equeue_t q;
00624     int err = equeue_create(&q,
00625             2*N*(EQUEUE_EVENT_SIZE+sizeof(struct fragment)+N*sizeof(int)));
00626     test_assert(!err);
00627 
00628     for (int i = 0; i < N; i++) {
00629         size_t size = sizeof(struct fragment) + i*sizeof(int);
00630         struct fragment *fragment = equeue_alloc(&q, size);
00631         test_assert(fragment);
00632 
00633         fragment->q = &q;
00634         fragment->size = size;
00635         fragment->timing.tick = equeue_tick();
00636         fragment->timing.delay = (i+1)*100;
00637         equeue_event_delay(fragment, fragment->timing.delay);
00638 
00639         int id = equeue_post(&q, fragment_func, fragment);
00640         test_assert(id);
00641     }
00642 
00643     equeue_dispatch(&q, N*100);
00644 
00645     equeue_destroy(&q);
00646 }
00647 
00648 struct ethread {
00649     pthread_t thread;
00650     equeue_t *q;
00651     int ms;
00652 };
00653 
00654 static void *ethread_dispatch(void *p) {
00655     struct ethread *t = (struct ethread*)p;
00656     equeue_dispatch(t->q, t->ms);
00657     return 0;
00658 }
00659 
00660 void multithreaded_barrage_test(int N) {
00661     equeue_t q;
00662     int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing)));
00663     test_assert(!err);
00664 
00665     struct ethread t;
00666     t.q = &q;
00667     t.ms = N*100;
00668     err = pthread_create(&t.thread, 0, ethread_dispatch, &t);
00669     test_assert(!err);
00670 
00671     for (int i = 0; i < N; i++) {
00672         struct timing *timing = equeue_alloc(&q, sizeof(struct timing));
00673         test_assert(timing);
00674 
00675         timing->tick = equeue_tick();
00676         timing->delay = (i+1)*100;
00677         equeue_event_delay(timing, timing->delay);
00678         equeue_event_period(timing, timing->delay);
00679 
00680         int id = equeue_post(&q, timing_func, timing);
00681         test_assert(id);
00682     }
00683 
00684     err = pthread_join(t.thread, 0);
00685     test_assert(!err);
00686 
00687     equeue_destroy(&q);
00688 }
00689 
00690 
00691 int main() {
00692     printf("beginning tests...\n");
00693 
00694     test_run(simple_call_test);
00695     test_run(simple_call_in_test);
00696     test_run(simple_call_every_test);
00697     test_run(simple_post_test);
00698     test_run(destructor_test);
00699     test_run(allocation_failure_test);
00700     test_run(cancel_test, 20);
00701     test_run(cancel_inflight_test);
00702     test_run(cancel_unnecessarily_test);
00703     test_run(loop_protect_test);
00704     test_run(break_test);
00705     test_run(period_test);
00706     test_run(nested_test);
00707     test_run(sloth_test);
00708     test_run(background_test);
00709     test_run(chain_test);
00710     test_run(unchain_test);
00711     test_run(multithread_test);
00712     test_run(simple_barrage_test, 20);
00713     test_run(fragmenting_barrage_test, 20);
00714     test_run(multithreaded_barrage_test, 20);
00715 
00716     printf("done!\n");
00717     return test_failure;
00718 }