From 2ec4163bcbbcfa6c025b32cdbdbd3adf8c7a84f2 Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Sun, 26 Dec 2010 21:31:33 -0500
Subject: [PATCH] [INI] Tests for access and changes

Patch adds two functions. One tests permissions,
another validates if the file has changed or not.
---
 ini/ini_parse_ut.c |  248 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 248 insertions(+), 0 deletions(-)

diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
index f0a95527aa315b559e5c6fa42740fe4a3ba4e4b3..f5b1c2c5b4e82de2baf29955901da28afc082cbb 100644
--- a/ini/ini_parse_ut.c
+++ b/ini/ini_parse_ut.c
@@ -625,10 +625,256 @@ int merge_section_test(void)
                   resname, checkname, error));
 
     return error;
+}
+
+int startup_test(void)
+{
+    int error = EOK;
+    struct ini_cfgfile *file_ctx = NULL;
+    struct ini_cfgobj *ini_config = NULL;
+    char **error_list = NULL;
+    char filename[PATH_MAX];
+    char *srcdir;
+
+    srcdir = getenv("srcdir");
+    sprintf(filename, "%s/ini/ini.d/foo.conf",
+                      (srcdir == NULL) ? "." : srcdir);
+
+    INIOUT(printf("<==== Startup test ====>\n"));
+
+    /* Open config file */
+    error = ini_config_file_open(filename,
+                                 INI_STOP_ON_NONE,
+                                 0,
+                                 INI_META_STATS,
+                                 &file_ctx);
+    if (error) {
+        printf("Failed to open file for reading. Error %d.\n",  error);
+        return error;
+    }
+
+    /* We will check just permissions here. */
+    error = ini_config_access_check(file_ctx,
+                                INI_ACCESS_CHECK_MODE, /* add uid & gui flags
+                                                        * in real case
+                                                        */
+                                0, /* <- will be real uid in real case */
+                                0, /* <- will be real gid in real case */
+                                0440, /* Checking for r--r----- */
+                                0);
+    /* This check is expected to fail since
+     * the actual permissions on the test file are: rw-rw-r--
+     */
+
+    if (!error) {
+        printf("Expected error got success!\n");
+        ini_config_file_destroy(file_ctx);
+        return EACCES;
+    }
+
+    error = ini_config_access_check(
+                        file_ctx,
+                        INI_ACCESS_CHECK_MODE, /* add uid & gui flags
+                                                * in real case
+                                                */
+                        0, /* <- will be real uid in real case */
+                        0, /* <- will be real gid in real case */
+                        0664, /* Checkling for rw-rw-r-- */
+                        0);
+
+    if (error) {
+        printf("Access check failed %d!\n", error);
+        ini_config_file_destroy(file_ctx);
+        return EACCES;
+    }
+
+
+    /* Create config object */
+    error = ini_config_create(&ini_config);
+    if (error) {
+        printf("Failed to create collection. Error %d.\n", error);
+        ini_config_file_destroy(file_ctx);
+        return error;
+    }
+
+    error = ini_config_parse(file_ctx,
+                             ini_config);
+    if (error) {
+        INIOUT(printf("Failed to parse configuration. Error %d.\n", error));
+
+        if (ini_config_error_count(file_ctx)) {
+            INIOUT(printf("Errors detected while parsing: %s\n",
+                   ini_config_get_filename(file_ctx)));
+            ini_config_get_errors(file_ctx, &error_list);
+            INIOUT(ini_print_errors(stdout, error_list));
+            ini_config_free_errors(error_list);
+        }
+        /* We do not return here intentionally */
+    }
+
+    ini_config_file_destroy(file_ctx);
+
+    INIOUT(col_debug_collection(ini_config->cfg, COL_TRAVERSE_DEFAULT));
+
+    ini_config_destroy(ini_config);
+
+    return 0;
+}
+
+int reload_test(void)
+{
+    int error = EOK;
+    struct ini_cfgfile *file_ctx = NULL;
+    struct ini_cfgfile *file_ctx_new = NULL;
+    char infile[PATH_MAX];
+    char outfile[PATH_MAX];
+    char command[PATH_MAX * 3];
+    char *srcdir;
+    char *builddir;
+    int changed = 0;
+
+    INIOUT(printf("<==== Reload test ====>\n"));
+
+    srcdir = getenv("srcdir");
+    sprintf(infile, "%s/ini/ini.d/foo.conf",
+                      (srcdir == NULL) ? "." : srcdir);
+    builddir = getenv("builddir");
+    sprintf(outfile, "%s/foo.conf",
+                      (builddir == NULL) ? "." : builddir);
+    sprintf(command, "cp %s %s", infile, outfile);
+    errno = 0;
+    if(system(command)) {
+        error = errno;
+        printf("Failed to run copy command %d.\n",  error);
+        return error;
+    }
+
+    /* Open config file */
+    error = ini_config_file_open(outfile,
+                                 INI_STOP_ON_NONE,
+                                 0,
+                                 INI_META_STATS,
+                                 &file_ctx);
+    if (error) {
+        printf("Failed to open file for reading. Error %d.\n",  error);
+        return error;
+    }
+
+    error = ini_config_access_check(
+                    file_ctx,
+                    INI_ACCESS_CHECK_MODE, /* add uid & gui flags
+                                            * in real case
+                                            */
+                    0, /* <- will be real uid in real case */
+                    0, /* <- will be real gid in real case */
+                    0664, /* Checkling for rw-rw-r-- */
+                    0);
+
+    if (error) {
+        printf("Access check failed %d!\n", error);
+        ini_config_file_destroy(file_ctx);
+        return EACCES;
+    }
+
+    /* ... Create config object and read configuration - not shown here.
+     *     See other examples ... */
+
+    /* Now close file but leave the context around */
+    ini_config_file_close(file_ctx);
+
+    /* Some time passed and we received a signal to reload... */
+    error = ini_config_file_reopen(file_ctx, &file_ctx_new);
+    if (error) {
+        printf("Failed to open file for reading. Error %d.\n",  error);
+        ini_config_file_destroy(file_ctx);
+        return error;
+    }
+
+    changed = 0;
+    error = ini_config_changed(file_ctx,
+                               file_ctx_new,
+                               &changed);
+    if (error) {
+        printf("Failed to compare files. Error %d.\n",  error);
+        ini_config_file_destroy(file_ctx);
+        ini_config_file_destroy(file_ctx_new);
+        return error;
+    }
+
+    /* Check if file changed */
+    if (changed) {
+        printf("File changed when it shouldn't. This is unexpected error.\n");
+        ini_config_file_destroy(file_ctx);
+        ini_config_file_destroy(file_ctx_new);
+        return EINVAL;
+    }
+
+    /* Close file */
+    ini_config_file_destroy(file_ctx_new);
 
+    /* Emulate as if file changed */
+    errno = 0;
+    if (unlink(outfile)) {
+        error = errno;
+        printf("Failed to delete file %d.\n",  error);
+        ini_config_file_destroy(file_ctx);
+        return error;
+    }
+
+    sleep(1);
+
+    errno = 0;
+    if (system(command)) {
+        error = errno;
+        printf("Failed to run copy command %d.\n",  error);
+        ini_config_file_destroy(file_ctx);
+        return error;
+    }
+
+    /* Read again */
+    file_ctx_new = NULL;
+    error = ini_config_file_reopen(file_ctx, &file_ctx_new);
+    if (error) {
+        printf("Failed to open file for reading. Error %d.\n",  error);
+        ini_config_file_destroy(file_ctx);
+        return error;
+    }
 
+    changed = 0;
+    error = ini_config_changed(file_ctx,
+                               file_ctx_new,
+                               &changed);
+    if (error) {
+        printf("Failed to compare files. Error %d.\n",  error);
+        ini_config_file_destroy(file_ctx);
+        ini_config_file_destroy(file_ctx_new);
+        return error;
+    }
+
+    /* Check if file changed */
+    if (!changed) {
+        printf("File did not change when it should. This is an error.\n");
+        ini_config_file_destroy(file_ctx);
+        ini_config_file_destroy(file_ctx_new);
+        return EINVAL;
+    }
+
+    /* We do not need original context any more. */
+    ini_config_file_destroy(file_ctx);
+
+    /* New context is now original context */
+    file_ctx = file_ctx_new;
+
+    /* ... Create config object and read configuration - not shown here.
+     *     See other examples ... */
+
+    ini_config_file_destroy(file_ctx);
+
+    return 0;
 }
 
+
+
 /* Main function of the unit test */
 int main(int argc, char *argv[])
 {
@@ -637,6 +883,8 @@ int main(int argc, char *argv[])
                         read_again_test,
                         merge_values_test,
                         merge_section_test,
+                        startup_test,
+                        reload_test,
                         NULL };
     test_fn t;
     int i = 0;
-- 
1.5.5.6

