]> git.ozlabs.org Git - petitboot/blobdiff - test/parser/utils.c
lib/process: Add process_get_stdout
[petitboot] / test / parser / utils.c
index 083d916b082fd4cda6ba3af8a59b370ffa9d5b0c..d8499a47689ab2115065a005aca6d5b957755603 100644 (file)
 #include "device-handler.h"
 #include "parser.h"
 #include "resource.h"
+#include "event.h"
+#include "platform.h"
+#include "paths.h"
+#include "parser-conf.h"
 
 #include "parser-test.h"
 
@@ -25,6 +29,10 @@ struct p_item {
 
 struct test_file {
        struct discover_device  *dev;
+       enum {
+               TEST_FILE,
+               TEST_DIR,
+       }                       type;
        const char              *name;
        void                    *data;
        int                     size;
@@ -65,7 +73,7 @@ struct discover_device *test_create_device(struct parser_test *test,
 {
        struct discover_device *dev;
 
-       dev = discover_device_create(test->handler, name);
+       dev = discover_device_create(test->handler, NULL, name);
 
        dev->device->id = talloc_strdup(dev, name);
        dev->device_path = talloc_asprintf(dev, "/dev/%s", name);
@@ -85,19 +93,32 @@ static struct discover_context *test_create_context(struct parser_test *test)
        list_init(&ctx->boot_options);
        ctx->device = test_create_device_simple(test);
        ctx->test_data = test;
+       ctx->handler = test->handler;
        device_handler_add_device(test->handler, ctx->device);
 
        return ctx;
 }
 
-extern struct config *test_config_init(struct parser_test *test);
+/* define our own test platform */
+static bool test_platform_probe(struct platform *p __attribute__((unused)),
+               void *ctx __attribute__((unused)))
+{
+       return true;
+}
+
+struct platform test_platform = {
+       .name = "test",
+       .probe = test_platform_probe,
+};
+
+register_platform(test_platform);
 
 struct parser_test *test_init(void)
 {
        struct parser_test *test;
 
        test = talloc_zero(NULL, struct parser_test);
-       test->config = test_config_init(test);
+       platform_init(NULL);
        test->handler = device_handler_init(NULL, NULL, 0);
        test->ctx = test_create_context(test);
        list_init(&test->files);
@@ -109,20 +130,24 @@ void test_fini(struct parser_test *test)
 {
        device_handler_destroy(test->handler);
        talloc_free(test);
+       platform_fini();
 }
 
 void __test_read_conf_data(struct parser_test *test,
+               struct discover_device *dev, const char *conf_file,
                const char *buf, size_t len)
 {
-       test->conf.size = len;
-       test->conf.buf = talloc_memdup(test, buf, len);
+       test_add_file_data(test, dev, conf_file, buf, len);
 }
 
-void test_read_conf_file(struct parser_test *test, const char *filename)
+void test_read_conf_file(struct parser_test *test, const char *filename,
+               const char *conf_file)
 {
        struct stat stat;
+       size_t size;
        char *path;
        int fd, rc;
+       char *buf;
 
        path = talloc_asprintf(test, "%s/%s", TEST_CONF_BASE, filename);
 
@@ -134,22 +159,18 @@ void test_read_conf_file(struct parser_test *test, const char *filename)
        assert(!rc);
        (void)rc;
 
-       test->conf.size = stat.st_size;
-       test->conf.buf = talloc_array(test, char, test->conf.size + 1);
+       size = stat.st_size;
+       buf = talloc_array(test, char, size + 1);
 
-       rc = read(fd, test->conf.buf, test->conf.size);
-       assert(rc == (ssize_t)test->conf.size);
+       rc = read(fd, buf, size);
+       assert(rc == (ssize_t)size);
 
-       *(char *)(test->conf.buf + test->conf.size) = '\0';
+       *(buf + size) = '\0';
 
        close(fd);
        talloc_free(path);
-}
 
-void test_set_conf_source(struct parser_test *test, const char *url)
-{
-       test->ctx->conf_url = pb_url_parse(test, url);
-       assert(test->ctx->conf_url);
+       test_add_file_data(test, test->ctx->device, conf_file, buf, size);
 }
 
 void test_add_file_data(struct parser_test *test, struct discover_device *dev,
@@ -158,6 +179,7 @@ void test_add_file_data(struct parser_test *test, struct discover_device *dev,
        struct test_file *file;
 
        file = talloc_zero(test, struct test_file);
+       file->type = TEST_FILE;
        file->dev = dev;
        file->name = filename;
        file->data = talloc_memdup(test, data, size);
@@ -165,6 +187,36 @@ void test_add_file_data(struct parser_test *test, struct discover_device *dev,
        list_add(&test->files, &file->list);
 }
 
+void test_add_dir(struct parser_test *test, struct discover_device *dev,
+               const char *dirname)
+{
+       struct test_file *file;
+
+       file = talloc_zero(test, struct test_file);
+       file->type = TEST_DIR;
+       file->dev = dev;
+       file->name = dirname;
+       /* Pick a non-zero size for directories so that "[ -s <dir
+        * path> ]" sees that the file has non-zero size. */
+       file->size = 1;
+       list_add(&test->files, &file->list);
+}
+
+void test_set_event_source(struct parser_test *test)
+{
+        test->ctx->event = talloc_zero(test->ctx, struct event);
+}
+
+void test_set_event_param(struct event *event, const char *name,
+                const char *value)
+{
+        event_set_param(event, name, value);
+}
+
+void test_set_event_device(struct event *event, const char *dev)
+{
+       event->device = talloc_strdup(event, dev);
+}
 
 int parser_request_file(struct discover_context *ctx,
                struct discover_device *dev, const char *filename,
@@ -179,6 +231,8 @@ int parser_request_file(struct discover_context *ctx,
                        continue;
                if (strcmp(file->name, filename))
                        continue;
+               if (file->type != TEST_FILE)
+                       continue;
 
                /* the read_file() interface always adds a trailing null
                 * for string-safety; do the same here */
@@ -193,12 +247,45 @@ int parser_request_file(struct discover_context *ctx,
        return -1;
 }
 
+int parser_stat_path(struct discover_context *ctx,
+               struct discover_device *dev, const char *path,
+               struct stat *statbuf)
+{
+       struct parser_test *test = ctx->test_data;
+       struct test_file *file;
+
+       list_for_each_entry(&test->files, file, list) {
+               if (file->dev != dev)
+                       continue;
+               if (strcmp(file->name, path))
+                       continue;
+
+               statbuf->st_size = (off_t)file->size;
+               switch (file->type) {
+               case TEST_FILE:
+                       statbuf->st_mode = S_IFREG;
+                       break;
+               case TEST_DIR:
+                       statbuf->st_mode = S_IFDIR;
+                       break;
+               default:
+                       fprintf(stderr, "%s: bad test file mode %d!", __func__,
+                               file->type);
+                       exit(EXIT_FAILURE);
+               }
+
+               return 0;
+       }
+
+       return -1;
+}
+
 int parser_replace_file(struct discover_context *ctx,
                struct discover_device *dev, const char *filename,
                char *buf, int len)
 {
        struct parser_test *test = ctx->test_data;
-       struct test_file *f, *file;
+       struct test_file *f, *file = NULL;
 
        list_for_each_entry(&test->files, f, list) {
                if (f->dev != dev)
@@ -221,6 +308,169 @@ int parser_replace_file(struct discover_context *ctx,
        file->size = len;
        return 0;
 }
+
+int parser_scandir(struct discover_context *ctx, const char *dirname,
+                  struct dirent ***files, int (*filter)(const struct dirent *)
+                  __attribute__((unused)),
+                  int (*comp)(const struct dirent **, const struct dirent **)
+                  __attribute__((unused)))
+{
+       struct parser_test *test = ctx->test_data;
+       struct test_file *f;
+       char *filename;
+       struct dirent **dirents = NULL, **new_dirents;
+       int n = 0, namelen;
+
+       list_for_each_entry(&test->files, f, list) {
+               if (f->dev != ctx->device)
+                       continue;
+
+               if (strlen(f->name) <= strlen(dirname))
+                       continue;
+
+               filename = strrchr(f->name, '/');
+               if (!filename)
+                       continue;
+
+               namelen = strlen(filename);
+
+               if (strncmp(f->name, dirname, strlen(f->name) - namelen))
+                       continue;
+
+               if (!dirents) {
+                       dirents = malloc(sizeof(struct dirent *));
+               } else {
+                       new_dirents = realloc(dirents, sizeof(struct dirent *)
+                                             * (n + 1));
+                       if (!new_dirents)
+                               goto err_cleanup;
+
+                       dirents = new_dirents;
+               }
+
+               dirents[n] = malloc(sizeof(struct dirent) + namelen + 1);
+
+               if (!dirents[n])
+                       goto err_cleanup;
+
+               strcpy(dirents[n]->d_name, filename + 1);
+               n++;
+       }
+
+       *files = dirents;
+
+       return n;
+
+err_cleanup:
+       do {
+               free(dirents[n]);
+       } while (n-- > 0);
+
+       free(dirents);
+
+       return -1;
+}
+
+bool parser_is_unique(struct discover_context *ctx, struct discover_device *dev,
+       const char *filename, struct list *found_list)
+{
+       (void)ctx;
+       (void)dev;
+       (void)filename;
+       (void)found_list;
+
+       /* Just let the parser process everything. */
+       return true;
+}
+
+struct load_url_result *load_url_async(void *ctx, struct pb_url *url,
+               load_url_complete async_cb, void *async_data,
+               waiter_cb stdout_cb, void *stdout_data)
+{
+       struct conf_context *conf = async_data;
+       struct parser_test *test = conf->dc->test_data;
+       struct load_url_result *result;
+       char tmp[] = "/tmp/pb-XXXXXX";
+       ssize_t rc = -1, sz = 0;
+       struct test_file *file;
+       int fd;
+
+       /* Ignore the stdout callback for tests */
+       (void)stdout_cb;
+       (void)stdout_data;
+
+       fd = mkstemp(tmp);
+
+       if (fd < 0)
+               return NULL;
+
+       /* Some parsers will expect to need to read a file, so write the
+        * specified file to a temporary file */
+       list_for_each_entry(&test->files, file, list) {
+               if (file->dev)
+                       continue;
+
+               if (strcmp(file->name, url->full))
+                       continue;
+
+               while (sz < file->size) {
+                       rc = write(fd, file->data, file->size);
+                       if (rc < 0) {
+                               fprintf(stderr,
+                                       "Failed to write to tmpfile, %m\n");
+                               break;
+                       }
+                       sz += rc;
+               }
+               break;
+       }
+
+       close(fd);
+
+       result = talloc_zero(ctx, struct load_url_result);
+       if (!result)
+               return NULL;
+
+       result->local = talloc_strdup(result, tmp);
+       result->url = url;
+       if (rc < 0)
+               result->status = LOAD_ERROR;
+       else
+               result->status = result->local ? LOAD_OK : LOAD_ERROR;
+       result->cleanup_local = true;
+
+       async_cb(result, conf);
+
+       return result;
+}
+
+int parser_request_url(struct discover_context *ctx, struct pb_url *url,
+               char **buf, int *len)
+{
+       struct parser_test *test = ctx->test_data;
+       struct test_file *file;
+       char *tmp;
+
+       list_for_each_entry(&test->files, file, list) {
+               if (file->dev)
+                       continue;
+
+               if (strcmp(file->name, url->full))
+                       continue;
+
+               /* the read_file() interface always adds a trailing null
+                * for string-safety; do the same here */
+               tmp = talloc_array(test, char, file->size + 1);
+               memcpy(tmp, file->data, file->size);
+               tmp[file->size] = '\0';
+               *buf = tmp;
+               *len = file->size;
+               return 0;
+       }
+
+       return -1;
+}
+
 int test_run_parser(struct parser_test *test, const char *parser_name)
 {
        struct p_item* i;
@@ -229,7 +479,7 @@ int test_run_parser(struct parser_test *test, const char *parser_name)
                if (strcmp(i->parser->name, parser_name))
                        continue;
                test->ctx->parser = i->parser;
-               return i->parser->parse(test->ctx, test->conf.buf, test->conf.size);
+               return i->parser->parse(test->ctx);
        }
 
        errx(EXIT_FAILURE, "%s: parser '%s' not found", __func__, parser_name);
@@ -267,6 +517,21 @@ void test_hotplug_device(struct parser_test *test, struct discover_device *dev)
                boot_option_resolve(test->handler, opt);
 }
 
+void test_remove_device(struct parser_test *test, struct discover_device *dev)
+{
+       struct discover_boot_option *opt, *tmp;
+
+       if (dev == test->ctx->device) {
+               list_for_each_entry_safe(&test->ctx->boot_options,
+                               opt, tmp, list) {
+                       list_remove(&opt->list);
+                       talloc_free(opt);
+               }
+       }
+
+       device_handler_remove(test->handler, dev);
+}
+
 struct discover_boot_option *get_boot_option(struct discover_context *ctx,
                int idx)
 {