diff --git a/lib/advio.c b/lib/advio.c index 8c7205643..ae95fd094 100644 --- a/lib/advio.c +++ b/lib/advio.c @@ -171,7 +171,19 @@ static int advio_xferinfo(void *p, curl_off_t dl_total_bytes, curl_off_t dl_byte int aislocal(const char *uri) { - return access(uri, F_OK) != -1; + char *sep; + const char *supported_schemas[] = { "file", "http", "https", "tftp", "ftp", "scp", "sftp", "smb", "smbs" }; + + sep = strstr(uri, "://"); + if (!sep) + return 1; /* no schema, we assume its a local file */ + + for (int i = 0; i < ARRAY_LEN(supported_schemas); i++) { + if (!strncmp(supported_schemas[i], uri, sep - uri)) + return 0; + } + + return -1; /* none of the supported schemas match. this is an invalid uri */ } AFILE * afopen(const char *uri, const char *mode) diff --git a/lib/periodic_task.c b/lib/task.c similarity index 81% rename from lib/periodic_task.c rename to lib/task.c index 7fcde99cc..d6e46ee16 100644 --- a/lib/periodic_task.c +++ b/lib/task.c @@ -26,22 +26,23 @@ #include "utils.h" -#include "periodic_task.h" +#include "task.h" #include "timing.h" #if PERIODIC_TASK_IMPL == TIMERFD #include #endif -int periodic_task_init(struct periodic_task *t, double rate) +int task_init(struct task *t, double rate, int clock) { - t->period = time_from_double(1.0 / rate); + t->clock = clock; + t->period = rate ? time_from_double(1.0 / rate) : (struct timespec) { 0, 0 }; #if PERIODIC_TASK_IMPL == CLOCK_NANOSLEEP || PERIODIC_TASK_IMPL == NANOSLEEP struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - + clock_gettime(t->clock, &now); + t->next_period = time_add(&now, &t->period); #elif PERIODIC_TASK_IMPL == TIMERFD int ret; @@ -51,7 +52,7 @@ int periodic_task_init(struct periodic_task *t, double rate) .it_value = t->period }; - t->fd = timerfd_create(CLOCK_MONOTONIC, 0); + t->fd = timerfd_create(t->clock, 0); if (t->fd < 0) return -1; @@ -65,7 +66,7 @@ int periodic_task_init(struct periodic_task *t, double rate) return 0; } -int periodic_task_destroy(struct periodic_task *t) +int task_destroy(struct task *t) { #if PERIODIC_TASK_IMPL == TIMERFD return close(t->fd); @@ -86,17 +87,17 @@ static int time_lt(const struct timespec *lhs, const struct timespec *rhs) } #endif -uint64_t periodic_task_wait_until_next_period(struct periodic_task *t) +uint64_t task_wait_until_next_period(struct task *t) { uint64_t runs; int ret; #if PERIODIC_TASK_IMPL == CLOCK_NANOSLEEP || PERIODIC_TASK_IMPL == NANOSLEEP - ret = periodic_task_wait_until(t, &t->next_period); + ret = task_wait_until(t, &t->next_period); struct timespec now; - ret = clock_gettime(CLOCK_MONOTONIC, &now); + ret = clock_gettime(t->clock, &now); if (ret) return 0; @@ -115,18 +116,18 @@ uint64_t periodic_task_wait_until_next_period(struct periodic_task *t) } -int periodic_task_wait_until(struct periodic_task *t, const struct timespec *until) +int task_wait_until(struct task *t, const struct timespec *until) { int ret; #if PERIODIC_TASK_IMPL == CLOCK_NANOSLEEP -retry: ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, until, NULL); +retry: ret = clock_nanosleep(t->clock, TIMER_ABSTIME, until, NULL); if (ret == EINTR) goto retry; #elif PERIODIC_TASK_IMPL == NANOSLEEP struct timespec now, delta; - ret = clock_gettime(CLOCK_MONOTONIC, &now); + ret = clock_gettime(t->clock, &now); if (ret) return ret; @@ -147,10 +148,10 @@ retry: ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, until, NULL); ret = read(t->fd, &runs, sizeof(runs)); if (ret < 0) - return 0; + return ret; #else #error "Invalid period task implementation" #endif - return ret; + return 0; } \ No newline at end of file diff --git a/tests/unit/advio.c b/tests/unit/advio.c index aa8790a3e..ec43aec22 100644 --- a/tests/unit/advio.c +++ b/tests/unit/advio.c @@ -28,12 +28,26 @@ #include #include #include -#include +#include /** This URI points to a Sciebo share which contains some test files. * The Sciebo share is read/write accessible via WebDAV. */ #define BASE_URI "https://1Nrd46fZX8HbggT:badpass@rwth-aachen.sciebo.de/public.php/webdav/node/tests" +Test(advio, islocal) +{ + int ret; + + ret = aislocal("/var/log/villas/dta.dat"); + cr_assert_eq(ret, 1); + + ret = aislocal("http://www.google.de"); + cr_assert_eq(ret, 0); + + ret = aislocal("torrent://www.google.de"); + cr_assert_eq(ret, -1); +} + Test(advio, local) { AFILE *af; @@ -81,7 +95,7 @@ Test(advio, download_large) af = afopen(BASE_URI "/download-large" , "r"); cr_assert(af, "Failed to download file"); - ret = io_format_villas_fscan(af->file, &smp, 1, NULL); + ret = villas_fscan(af->file, &smp, 1, NULL); cr_assert_eq(ret, 1); cr_assert_eq(smp->sequence, 0); diff --git a/tests/unit/io.c b/tests/unit/io.c index 68cae73e1..13d1585f7 100644 --- a/tests/unit/io.c +++ b/tests/unit/io.c @@ -78,7 +78,7 @@ ParameterizedTestParameters(io, highlevel) "json", "msg", "gtnet", - "gtnet-fake", + "gtnet-fake" }; return cr_make_param_array(char[32], formats, ARRAY_LEN(formats)); @@ -125,6 +125,7 @@ ParameterizedTest(char *fmt, io, highlevel) strncpy(dir, "/tmp/villas.XXXXXX", sizeof(dir)); mkdtemp(dir); +// ret = asprintf(&fn, "file://%s/file", dir); ret = asprintf(&fn, "%s/file", dir); cr_assert_gt(ret, 0); @@ -134,16 +135,16 @@ ParameterizedTest(char *fmt, io, highlevel) ret = io_init(&io, f, IO_FORMAT_ALL); cr_assert_eq(ret, 0); - ret = io_open(&io, fn, "w+"); + ret = io_open(&io, fn); cr_assert_eq(ret, 0); ret = io_print(&io, smps, NUM_SAMPLES); cr_assert_eq(ret, NUM_SAMPLES); + + ret = io_flush(&io); + cr_assert_eq(ret, 0); - ret = io_close(&io); - cr_assert_eq(ret, 0); - -#if 1 /* Show the file contents */ +#if 0 /* Show the file contents */ char cmd[128]; if (!strcmp(fmt, "json") || !strcmp(fmt, "villas")) snprintf(cmd, sizeof(cmd), "cat %s", fn); @@ -152,10 +153,13 @@ ParameterizedTest(char *fmt, io, highlevel) system(cmd); #endif - ret = io_open(&io, fn, "r"); - cr_assert_eq(ret, 0); + if (io.mode == IO_MODE_ADVIO) + adownload(io.advio.input, 0); + + io_rewind(&io); cnt = io_scan(&io, smpt, NUM_SAMPLES); + cr_assert_gt(cnt, 0, "Failed to read samples back"); /* The RAW format has certain limitations: * - limited accuracy if smaller datatypes are used @@ -165,7 +169,7 @@ ParameterizedTest(char *fmt, io, highlevel) */ if (f->sscan == raw_sscan) { cr_assert_eq(cnt, 1); - cr_assert_eq(smpt[0]->length, smpt[0]->capacity); + cr_assert_eq(smpt[0]->length, smpt[0]->capacity, "Expected values: %d, Received values: %d", smpt[0]->capacity, smpt[0]->length); if (io.flags & RAW_FAKE) { } diff --git a/tests/unit/main.c b/tests/unit/main.c index adeec8a33..8d514869b 100644 --- a/tests/unit/main.c +++ b/tests/unit/main.c @@ -36,16 +36,16 @@ int main(int argc, char *argv[]) struct log log; ret = log_init(&log, V, LOG_ALL); - if (ret) { + if (ret) error("Failed to initialize logging sub-system"); - return ret; - } + + ret = log_start(&log); + if (ret) + error("Failed to start logging sub-system"); ret = memory_init(DEFAULT_NR_HUGEPAGES); - if (ret) { + if (ret) error("Failed to initialize memory sub-system"); - return ret; - } /* Run criterion tests */ tests = criterion_initialize(); diff --git a/tests/unit/task.c b/tests/unit/task.c new file mode 100644 index 000000000..5bc9943f1 --- /dev/null +++ b/tests/unit/task.c @@ -0,0 +1,88 @@ +/** Unit tests for periodic tasks + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include + +#include + +#include "task.h" +#include "timing.h" + +Test(task, rate, .timeout = 10) +{ + int ret; + double rate = 5, waited; + struct timespec start, end; + struct task task; + + ret = task_init(&task, rate, CLOCK_MONOTONIC); + cr_assert_eq(ret, 0); + + int i; + for (i = 0; i < 10; i++) { + clock_gettime(CLOCK_MONOTONIC, &start); + + task_wait_until_next_period(&task); + + clock_gettime(CLOCK_MONOTONIC, &end); + + waited = time_delta(&start, &end); + + if (fabs(waited - 1.0 / rate) > 10e-3) + break; + } + + if (i < 10) + cr_assert_float_eq(waited, 1.0 / rate, 1e-2, "We slept for %f instead of %f secs in round %d", waited, 1.0 / rate, i); + + ret = task_destroy(&task); + cr_assert_eq(ret, 0); +} + +Test(task, wait_until, .timeout = 5) +{ + int ret; + struct task task; + struct timespec start, end, diff, future; + + ret = task_init(&task, 1, CLOCK_REALTIME); + cr_assert_eq(ret, 0); + + double waitfor = 3.423456789; + + start = time_now(); + diff = time_from_double(waitfor); + future = time_add(&start, &diff); + + ret = task_wait_until(&task, &future); + + end = time_now(); + + cr_assert_eq(ret, 0); + + double waited = time_delta(&start, &end); + + cr_assert_float_eq(waited, waitfor, 1e-2, "We slept for %f instead of %f secs", waited, waitfor); + + ret = task_destroy(&task); + cr_assert_eq(ret, 0); +} \ No newline at end of file diff --git a/tests/unit/timing.c b/tests/unit/timing.c index f6825ce54..69adfdc6e 100644 --- a/tests/unit/timing.c +++ b/tests/unit/timing.c @@ -89,58 +89,4 @@ Test(timing, time_to_from_double) double dbl = time_to_double(&ts); cr_assert_float_eq(dbl, ref, 1e-9); -} - -Test(timing, timerfd_create_rate, .timeout = 20) -{ - struct timespec start, end; - - double rate = 5, waited; - - int tfd = timerfd_create_rate(rate); - - cr_assert(tfd > 0); - - timerfd_wait(tfd); - - int i; - for (i = 0; i < 10; i++) { - start = time_now(); - - timerfd_wait(tfd); - - end = time_now(); - waited = time_delta(&start, &end); - - if (fabs(waited - 1.0 / rate) > 10e-3) - break; - } - - if (i < 10) - cr_assert_float_eq(waited, 1.0 / rate, 1e-2, "We slept for %f instead of %f secs in round %d", waited, 1.0 / rate, i); - - close(tfd); -} - -Test(timing, timerfd_wait_until, .timeout = 10) -{ - int tfd = timerfd_create(CLOCK_REALTIME, 0); - - cr_assert(tfd > 0); - - double waitfor = 2.423456789; - - struct timespec start = time_now(); - struct timespec diff = time_from_double(waitfor); - struct timespec future = time_add(&start, &diff); - - timerfd_wait_until(tfd, &future); - - struct timespec end = time_now(); - - double waited = time_delta(&start, &end); - - cr_assert_float_eq(waited, waitfor, 1e-2, "We slept for %f instead of %f secs", waited, waitfor); - - close(tfd); } \ No newline at end of file