/* This file is part of GNUnet. Copyright (C) 2003, 2004, 2005, 2006, 2007 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file util/test_configuration.c * @brief Test that the configuration module works. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" /* Test Configuration Diffs Options */ enum { EDIT_NOTHING, EDIT_SECTION, EDIT_ALL, ADD_NEW_SECTION, ADD_NEW_ENTRY, REMOVE_SECTION, REMOVE_ENTRY, COMPARE, PRINT }; static struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_CONFIGURATION_Handle *cfg_default; struct DiffsCBData { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONFIGURATION_Handle *cfgDiffs; const char *section; int callBackOption; int status; }; static void initDiffsCBData(struct DiffsCBData *cbData) { cbData->section = NULL; cbData->cfg = NULL; cbData->cfgDiffs = NULL; cbData->callBackOption = -1; cbData->status = 0; } /** * callback function for modifying * and comparing configuration */ static void diffsCallBack(void *cls, const char *section, const char *option, const char *value) { struct DiffsCBData *cbData = cls; int cbOption = cbData->callBackOption; switch (cbOption) { case EDIT_SECTION: if (NULL == cbData->section) cbData->section = section; if (strcmp(cbData->section, section) == 0) { GNUNET_CONFIGURATION_set_value_string(cbData->cfg, section, option, "new-value"); GNUNET_CONFIGURATION_set_value_string(cbData->cfgDiffs, section, option, "new-value"); } break; case EDIT_ALL: GNUNET_CONFIGURATION_set_value_string(cbData->cfg, section, option, "new-value"); GNUNET_CONFIGURATION_set_value_string(cbData->cfgDiffs, section, option, "new-value"); break; case ADD_NEW_ENTRY: { static int hit = 0; if (hit == 0) { hit = 1; GNUNET_CONFIGURATION_set_value_string(cbData->cfg, section, "new-key", "new-value"); GNUNET_CONFIGURATION_set_value_string(cbData->cfgDiffs, section, "new-key", "new-value"); } break; } case COMPARE: { int ret; char *diffValue; diffValue = NULL; ret = GNUNET_CONFIGURATION_get_value_string(cbData->cfgDiffs, section, option, &diffValue); if (NULL != diffValue) { if (ret == GNUNET_SYSERR || strcmp(diffValue, value) != 0) cbData->status = 1; } else cbData->status = 1; GNUNET_free_non_null(diffValue); break; } #if 0 case PRINT: if (NULL == cbData->section) { cbData->section = section; printf("\nSection: %s\n", section); } else if (strcmp(cbData->section, section) != 0) { cbData->section = section; printf("\nSection: %s\n", section); } printf("%s = %s\n", option, value); #endif default: break; } } static struct GNUNET_CONFIGURATION_Handle * editConfiguration(struct GNUNET_CONFIGURATION_Handle *cfg, int option) { struct DiffsCBData diffsCB; initDiffsCBData(&diffsCB); diffsCB.cfgDiffs = GNUNET_CONFIGURATION_create(); switch (option) { case EDIT_SECTION: case EDIT_ALL: case ADD_NEW_ENTRY: diffsCB.callBackOption = option; diffsCB.cfg = cfg; GNUNET_CONFIGURATION_iterate(cfg, diffsCallBack, &diffsCB); break; case EDIT_NOTHING: /* Do nothing */ break; case ADD_NEW_SECTION: { int i; char *key; for (i = 0; i < 5; i++) { GNUNET_asprintf(&key, "key%d", i); GNUNET_CONFIGURATION_set_value_string(cfg, "new-section", key, "new-value"); GNUNET_CONFIGURATION_set_value_string(diffsCB.cfgDiffs, "new-section", key, "new-value"); GNUNET_free(key); } break; } case REMOVE_SECTION: break; case REMOVE_ENTRY: break; default: break; } return diffsCB.cfgDiffs; } /** * Checking configuration diffs */ static int checkDiffs(struct GNUNET_CONFIGURATION_Handle *cfg_default, int option) { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONFIGURATION_Handle *cfgDiffs; struct DiffsCBData cbData; int ret; char *diffsFileName; initDiffsCBData(&cbData); cfg = GNUNET_CONFIGURATION_create(); /* load defaults */ GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_load(cfg, NULL)); /* Modify configuration and save it */ cfgDiffs = editConfiguration(cfg, option); diffsFileName = GNUNET_DISK_mktemp("gnunet-test-configurations-diffs.conf"); if (diffsFileName == NULL) { GNUNET_break(0); GNUNET_CONFIGURATION_destroy(cfg); GNUNET_CONFIGURATION_destroy(cfgDiffs); return 1; } GNUNET_CONFIGURATION_write_diffs(cfg_default, cfg, diffsFileName); GNUNET_CONFIGURATION_destroy(cfg); /* Compare the dumped configuration with modifications done */ cfg = GNUNET_CONFIGURATION_create(); GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_parse(cfg, diffsFileName)); if (0 != remove(diffsFileName)) GNUNET_log_strerror_file(GNUNET_ERROR_TYPE_WARNING, "remove", diffsFileName); cbData.callBackOption = COMPARE; cbData.cfgDiffs = cfgDiffs; GNUNET_CONFIGURATION_iterate(cfg, diffsCallBack, &cbData); if (1 == (ret = cbData.status)) { fprintf(stderr, "%s", "Incorrect Configuration Diffs: Diffs may contain data not actually edited\n"); goto housekeeping; } cbData.cfgDiffs = cfg; GNUNET_CONFIGURATION_iterate(cfgDiffs, diffsCallBack, &cbData); if ((ret = cbData.status) == 1) fprintf(stderr, "%s", "Incorrect Configuration Diffs: Data may be missing in diffs\n"); housekeeping: #if 0 cbData.section = NULL; cbData.callBackOption = PRINT; printf("\nExpected Diffs:\n"); GNUNET_CONFIGURATION_iterate(cfgDiffs, diffsCallBack, &cbData); cbData.section = NULL; printf("\nActual Diffs:\n"); GNUNET_CONFIGURATION_iterate(cfg, diffsCallBack, &cbData); #endif GNUNET_CONFIGURATION_destroy(cfg); GNUNET_CONFIGURATION_destroy(cfgDiffs); GNUNET_free(diffsFileName); return ret; } static int testConfig() { char *c; unsigned long long l; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "test", "b", &c)) return 1; if (0 != strcmp("b", c)) { fprintf(stderr, "Got `%s'\n", c); GNUNET_free(c); return 2; } GNUNET_free(c); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, "test", "five", &l)) { GNUNET_break(0); return 3; } if (5 != l) { GNUNET_break(0); return 4; } GNUNET_CONFIGURATION_set_value_string(cfg, "more", "c", "YES"); if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno(cfg, "more", "c")) { GNUNET_break(0); return 5; } GNUNET_CONFIGURATION_set_value_number(cfg, "NUMBERS", "TEN", 10); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "NUMBERS", "TEN", &c)) { GNUNET_break(0); return 6; } if (0 != strcmp(c, "10")) { GNUNET_free(c); GNUNET_break(0); return 7; } GNUNET_free(c); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename(cfg, "last", "test", &c)) { GNUNET_break(0); return 8; } if (0 != strcmp(c, "/hello/world")) { GNUNET_break(0); GNUNET_free(c); return 9; } GNUNET_free(c); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(cfg, "last", "size", &l)) { GNUNET_break(0); return 10; } if (l != 512 * 1024) { GNUNET_break(0); return 11; } return 0; } static const char *want[] = { "/Hello", "/File Name", "/World", NULL, NULL, }; static int check(void *data, const char *fn) { int *idx = data; if (0 == strcmp(want[*idx], fn)) { (*idx)++; return GNUNET_OK; } GNUNET_break(0); return GNUNET_SYSERR; } static int testConfigFilenames() { int idx; idx = 0; if (3 != GNUNET_CONFIGURATION_iterate_value_filenames(cfg, "FILENAMES", "test", &check, &idx)) { GNUNET_break(0); return 8; } if (idx != 3) return 16; if (GNUNET_OK != GNUNET_CONFIGURATION_remove_value_filename(cfg, "FILENAMES", "test", "/File Name")) { GNUNET_break(0); return 24; } if (GNUNET_NO != GNUNET_CONFIGURATION_remove_value_filename(cfg, "FILENAMES", "test", "/File Name")) { GNUNET_break(0); return 32; } if (GNUNET_NO != GNUNET_CONFIGURATION_remove_value_filename(cfg, "FILENAMES", "test", "Stuff")) { GNUNET_break(0); return 40; } if (GNUNET_NO != GNUNET_CONFIGURATION_append_value_filename(cfg, "FILENAMES", "test", "/Hello")) { GNUNET_break(0); return 48; } if (GNUNET_NO != GNUNET_CONFIGURATION_append_value_filename(cfg, "FILENAMES", "test", "/World")) { GNUNET_break(0); return 56; } if (GNUNET_YES != GNUNET_CONFIGURATION_append_value_filename(cfg, "FILENAMES", "test", "/File 1")) { GNUNET_break(0); return 64; } if (GNUNET_YES != GNUNET_CONFIGURATION_append_value_filename(cfg, "FILENAMES", "test", "/File 2")) { GNUNET_break(0); return 72; } idx = 0; want[1] = "/World"; want[2] = "/File 1"; want[3] = "/File 2"; if (4 != GNUNET_CONFIGURATION_iterate_value_filenames(cfg, "FILENAMES", "test", &check, &idx)) { GNUNET_break(0); return 80; } if (idx != 4) { GNUNET_break(0); return 88; } return 0; } int main(int argc, char *argv[]) { int failureCount = 0; char *c; GNUNET_log_setup("test_configuration", "WARNING", NULL); cfg = GNUNET_CONFIGURATION_create(); GNUNET_assert(cfg != NULL); if (GNUNET_OK != GNUNET_CONFIGURATION_parse(cfg, "test_configuration_data.conf")) { fprintf(stderr, "%s", "Failed to parse configuration file\n"); GNUNET_CONFIGURATION_destroy(cfg); return 1; } failureCount += testConfig(); if (failureCount > 0) goto error; failureCount = testConfigFilenames(); if (failureCount > 0) goto error; if (GNUNET_OK != GNUNET_CONFIGURATION_write(cfg, "/tmp/gnunet-test.conf")) { fprintf(stderr, "%s", "Failed to write configuration file\n"); GNUNET_CONFIGURATION_destroy(cfg); return 1; } GNUNET_CONFIGURATION_destroy(cfg); GNUNET_assert(0 == unlink("/tmp/gnunet-test.conf")); cfg = GNUNET_CONFIGURATION_create(); if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg, "test_configuration_data.conf")) { GNUNET_break(0); GNUNET_CONFIGURATION_destroy(cfg); return 1; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg, "TESTING", "WEAKRANDOM", &c)) { GNUNET_break(0); GNUNET_CONFIGURATION_destroy(cfg); return 1; } if (0 != strcmp(c, "YES")) { GNUNET_break(0); GNUNET_free(c); GNUNET_CONFIGURATION_destroy(cfg); return 1; } GNUNET_free(c); GNUNET_CONFIGURATION_destroy(cfg); /* Testing configuration diffs */ cfg_default = GNUNET_CONFIGURATION_create(); if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_default, NULL)) { GNUNET_break(0); GNUNET_CONFIGURATION_destroy(cfg_default); return 1; } /* Nothing changed in the new configuration */ failureCount += checkDiffs(cfg_default, EDIT_NOTHING); /* Modify all entries of the last section */ failureCount += checkDiffs(cfg_default, EDIT_SECTION); /* Add a new section */ failureCount += checkDiffs(cfg_default, ADD_NEW_SECTION); /* Add a new entry to the last section */ failureCount += checkDiffs(cfg_default, ADD_NEW_ENTRY); /* Modify all entries in the configuration */ failureCount += checkDiffs(cfg_default, EDIT_ALL); GNUNET_CONFIGURATION_destroy(cfg_default); error: if (failureCount != 0) { fprintf(stderr, "Test failed: %u\n", failureCount); return 1; } return 0; }