blob: 812789ccdaee42e3eb1038dcd7b04b3c538f3745 [file] [log] [blame]
/*
*
* PACrunner - Proxy configuration daemon
*
* Copyright (C) 2010-2012 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib.h>
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
#include <CUnit/Automated.h>
#include <CUnit/Console.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include "pacrunner.h"
enum test_suite_part {
SUITE_TITLE = 0,
SUITE_PAC = 1,
SUITE_SERVERS = 2,
SUITE_EXCLUDES = 3,
SUITE_BROWSER_ONLY = 4,
SUITE_DOMAINS = 5,
SUITE_CONFIG = 6,
SUITE_TESTS = 7,
SUITE_NOTHING = 8,
};
enum cu_test_mode {
CU_MODE_BASIC = 0,
CU_MODE_AUTO = 1,
CU_MODE_CONSOLE = 2,
};
struct pacrunner_test_suite {
gchar *title;
gchar *pac;
gchar **servers;
gchar **excludes;
gboolean browser_only;
gchar **domains;
bool config_result;
gchar **tests;
};
static struct pacrunner_test_suite *test_suite;
static bool verbose = false;
static struct pacrunner_proxy *proxy, *proxy2 = NULL, *proxy3 = NULL;
static bool test_config;
static void free_pacrunner_test_suite(struct pacrunner_test_suite *suite)
{
if (!suite)
return;
g_free(suite->title);
g_free(suite->pac);
g_strfreev(suite->servers);
g_strfreev(suite->excludes);
g_strfreev(suite->domains);
g_strfreev(suite->tests);
g_free(suite);
}
static gchar **_g_strappendv(gchar **str_array, const gchar *str)
{
int length = 0;
gchar **result;
gchar *copy;
if (!str)
return NULL;
if (str_array)
length = g_strv_length(str_array);
result = g_try_malloc0(sizeof(gchar *) * (length + 2));
if (!result)
return NULL;
copy = g_strdup(str);
if (!copy) {
g_free(result);
return NULL;
}
if (str_array) {
memmove(result, str_array, length * sizeof(gchar *));
memset(str_array, 0, length * sizeof(gchar *));
}
result[length] = copy;
return result;
}
static void print_test_suite(struct pacrunner_test_suite *suite)
{
gchar **line;
if (!suite)
return;
printf("\nSuite: %s\n", suite->title);
printf("\nPAC:\n%s\n", suite->pac);
printf("\nServers:\n");
if (suite->servers) {
for (line = suite->servers; *line; line++)
printf("%s\n", *line);
} else
printf("(none)\n");
printf("\nExcludes:\n");
if (suite->excludes) {
for (line = suite->excludes; *line; line++)
printf("%s\n", *line);
} else
printf("(none)\n");
printf("\nBrowser Only: %s\n",
suite->browser_only ? "TRUE" : "FALSE");
printf("\nDomains:\n");
if (suite->domains) {
for (line = suite->domains; *line; line++)
printf("%s\n", *line);
} else
printf("(none)\n");
printf("\nConfig result: %s\n",
suite->config_result ? "Valid" : "Invalid");
printf("\nTests:\n");
if (suite->tests) {
short test = 0;
for (line = suite->tests; *line; line++) {
if (test == 0) {
printf("%s --> ", *line);
test++;
} else {
printf("%s\n", *line);
test = 0;
}
}
printf("\n");
} else
printf("(none)\n");
}
static struct pacrunner_test_suite *read_test_suite(const char *path)
{
enum test_suite_part part = SUITE_NOTHING;
struct pacrunner_test_suite *suite;
gchar *content = NULL;
gchar **lines = NULL;
gchar **array;
gchar **line;
suite = g_try_malloc0(sizeof(struct pacrunner_test_suite));
if (!suite)
goto error;
if (!g_file_get_contents(path, &content, NULL, NULL))
goto error;
if (strlen(content) <= 0)
goto error;
lines = g_strsplit(content, "\n", 0);
if (!lines)
goto error;
for (line = lines; *line; line++) {
if (strlen(*line) == 0)
continue;
if (*line[0] == '#')
continue;
if (*line[0] != '[') {
switch (part) {
case SUITE_TITLE:
if (suite->title)
goto error;
suite->title = g_strdup(*line);
if (!suite->title)
goto error;
break;
case SUITE_PAC:
if (!suite->pac)
suite->pac = g_strdup_printf("%s\n",
*line);
else {
gchar *oldpac = suite->pac;
suite->pac = g_strdup_printf("%s%s\n",
oldpac, *line);
g_free(oldpac);
}
if (!suite->pac)
goto error;
break;
case SUITE_SERVERS:
array = _g_strappendv(suite->servers, *line);
if (!array)
goto error;
g_free(suite->servers);
suite->servers = array;
break;
case SUITE_EXCLUDES:
array = _g_strappendv(suite->excludes, *line);
if (!array)
goto error;
g_free(suite->excludes);
suite->excludes = array;
break;
case SUITE_BROWSER_ONLY:
if (strncmp(*line, "TRUE", 4) == 0)
suite->browser_only = TRUE;
else
suite->browser_only = FALSE;
break;
case SUITE_DOMAINS:
array = _g_strappendv(suite->domains, *line);
if (!array)
goto error;
g_free(suite->domains);
suite->domains = array;
break;
case SUITE_CONFIG:
if (strncmp(*line, "VALID", 5) == 0)
suite->config_result = true;
else
suite->config_result = false;
break;
case SUITE_TESTS:
array = _g_strappendv(suite->tests, *line);
if (!array)
goto error;
g_free(suite->tests);
suite->tests = array;
break;
case SUITE_NOTHING:
default:
break;
}
continue;
}
if (strncmp(*line, "[title]", 7) == 0)
part = SUITE_TITLE;
else if (strncmp(*line, "[pac]", 5) == 0)
part = SUITE_PAC;
else if (strncmp(*line, "[servers]", 9) == 0)
part = SUITE_SERVERS;
else if (strncmp(*line, "[excludes]", 10) == 0)
part = SUITE_EXCLUDES;
else if (strncmp(*line, "[browseronly]", 13) == 0)
part = SUITE_BROWSER_ONLY;
else if (strncmp(*line, "[domains]", 9) == 0)
part = SUITE_DOMAINS;
else if (strncmp(*line, "[config]", 8) == 0)
part = SUITE_CONFIG;
else if (strncmp(*line, "[tests]", 7) == 0)
part = SUITE_TESTS;
}
if (verbose)
print_test_suite(suite);
if (!suite->title || (suite->tests
&& g_strv_length(suite->tests) % 2 != 0)
|| (!suite->servers && !suite->pac))
goto error;
g_free(content);
g_strfreev(lines);
return suite;
error:
g_free(content);
g_strfreev(lines);
free_pacrunner_test_suite(suite);
return NULL;
}
static int test_suite_init(void)
{
proxy = pacrunner_proxy_create("eth0");
if (!proxy)
return -1;
return 0;
}
static int test_suite_cleanup(void)
{
if (test_config) {
if (pacrunner_proxy_disable(proxy) != 0)
return -1;
}
pacrunner_proxy_unref(proxy);
return 0;
}
static void test_pac_config(void)
{
if (pacrunner_proxy_set_auto(proxy, NULL, test_suite->pac) == 0)
test_config = true;
CU_ASSERT_TRUE(test_suite->config_result == test_config);
}
static void test_manual_config(void)
{
if (pacrunner_proxy_set_manual(proxy, test_suite->servers,
test_suite->excludes) == 0)
test_config = true;
CU_ASSERT_TRUE(test_suite->config_result == test_config);
}
static void test_proxy_domain(void)
{
int val = 0;
if (pacrunner_proxy_set_domains(proxy, test_suite->domains,
test_suite->browser_only) != 0)
val = -1;
proxy2 = pacrunner_proxy_create("eth1");
if (proxy2) {
char *servers[] = {
"http://proxy2.com",
"https://secproxy2.com",
NULL};
char *domains[] = {
"intel.com",
"domain2.com",
"192.168.4.0/16",
NULL};
if (pacrunner_proxy_set_manual(proxy2, servers, NULL) != 0)
val = -1;
/* BrowserOnly = TRUE */
if (pacrunner_proxy_set_domains(proxy2, domains, TRUE) != 0)
val = -1;
}
proxy3 = pacrunner_proxy_create("wl0");
if (proxy3) {
char *servers[] = {
"socks4://server.one.com",
"socks5://server.two.com",
NULL};
char *domains[] = {
"redhat.com",
"domain3.com",
"fe80:96db::/32",
NULL};
if (pacrunner_proxy_set_manual(proxy3, servers, NULL) != 0)
val = -1;
/* BrowserOnly = FALSE */
if (pacrunner_proxy_set_domains(proxy3, domains, FALSE) != 0)
val = -1;
}
CU_ASSERT_TRUE(val == 0);
}
static void test_proxy_requests(void)
{
gchar **test_strings;
bool verify;
gchar *result;
gchar **test;
gchar *msg;
if (!test_config)
return;
if (verbose)
printf("\n");
for (test = test_suite->tests; *test; test = test + 2) {
gchar *test_result = *(test+1);
test_strings = g_strsplit(*test, " ", 2);
if (!test_strings || g_strv_length(test_strings) != 2) {
g_strfreev(test_strings);
continue;
}
result = pacrunner_proxy_lookup(test_strings[0],
test_strings[1]);
g_strfreev(test_strings);
verify = false;
if (strncmp(test_result, "DIRECT", 6) == 0) {
if (!result ||
strncmp(result, "DIRECT", 6) == 0)
verify = true;
} else {
if (g_strcmp0(result, test_result) == 0)
verify = true;
}
if (verbose) {
if (verify)
msg = g_strdup_printf(
"\tTEST: %s -> %s verified",
*test, test_result);
else
msg = g_strdup_printf(
"\tTEST: %s -> %s FAILED (%s)",
*test, test_result,
!result ? "DIRECT" : result);
printf("%s\n", msg);
g_free(msg);
}
if (result)
g_free(result);
CU_ASSERT_TRUE(verify);
}
}
static void run_test_suite(const char *test_file_path, enum cu_test_mode mode)
{
CU_pTestRegistry cu_registry;
CU_pSuite cu_suite;
if (!test_file_path)
return;
test_suite = read_test_suite(test_file_path);
if (!test_suite) {
if (verbose)
printf("Invalid suite\n");
return;
}
if (verbose)
printf("Valid suite\n");
cu_registry = CU_create_new_registry();
cu_registry = CU_set_registry(cu_registry);
CU_destroy_existing_registry(&cu_registry);
cu_suite = CU_add_suite(test_suite->title, test_suite_init,
test_suite_cleanup);
if (test_suite->pac)
CU_add_test(cu_suite, "PAC config test", test_pac_config);
else
CU_add_test(cu_suite, "Manual config test",
test_manual_config);
CU_add_test(cu_suite, "Proxy Domain test", test_proxy_domain);
if (test_suite->config_result && test_suite->tests)
CU_add_test(cu_suite, "Proxy requests test",
test_proxy_requests);
test_config = false;
if (proxy2)
pacrunner_proxy_unref(proxy2);
if (proxy3)
pacrunner_proxy_unref(proxy3);
switch (mode) {
case CU_MODE_BASIC:
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
break;
case CU_MODE_AUTO:
CU_set_output_filename(test_file_path);
CU_list_tests_to_file();
CU_automated_run_tests();
break;
case CU_MODE_CONSOLE:
CU_console_run_tests();
break;
default:
break;
}
free_pacrunner_test_suite(test_suite);
test_suite = NULL;
}
static void find_and_run_test_suite(GDir *test_dir,
const char *test_path,
const char *file_path,
enum cu_test_mode mode)
{
const gchar *test_file;
gchar *test_file_path;
if (!test_dir && !test_path)
return;
if (CU_initialize_registry() != CUE_SUCCESS) {
printf("%s\n", CU_get_error_msg());
return;
}
if (test_dir) {
for (test_file = g_dir_read_name(test_dir); test_file;
test_file = g_dir_read_name(test_dir)) {
test_file_path = g_strdup_printf("%s/%s",
test_path, test_file);
if (!test_file_path)
return;
run_test_suite(test_file_path, mode);
g_free(test_file_path);
}
} else {
if (test_path)
test_file_path = g_strdup_printf("%s/%s",
test_path, file_path);
else
test_file_path = g_strdup(file_path);
run_test_suite(test_file_path, mode);
g_free(test_file_path);
}
CU_cleanup_registry();
}
static GDir *open_test_dir(gchar **test_path)
{
GDir *test_dir;
if (!test_path || !*test_path)
return NULL;
test_dir = g_dir_open(*test_path, 0, NULL);
if (!test_dir && !g_path_is_absolute(*test_path)) {
gchar *current, *path;
current = g_get_current_dir();
path = g_strdup_printf("%s/%s", current, *test_path);
g_free(*test_path);
g_free(current);
*test_path = path;
test_dir = g_dir_open(*test_path, 0, NULL);
if (!test_dir)
return NULL;
}
return test_dir;
}
static void print_usage()
{
printf("Usage: test-pacrunner <options>\n"
"\t--dir, -d directory: specify a directory where test"
" suites are found\n"
"\t--file, -f file: specify a test suite file\n"
"\t--help, -h: print this help\n"
"\t--mode, -m CUnit mode: basic (default), auto, console\n"
"\t--verbose, -v: verbose output mode\n");
}
static struct option test_options[] = {
{"dir", 1, 0, 'd'},
{"file", 1, 0, 'f'},
{"help", 0, 0, 'h'},
{"mode", 1, 0, 'm'},
{"verbose", 0, 0, 'v'},
{ NULL }
};
int main(int argc, char *argv[])
{
enum cu_test_mode mode = CU_MODE_BASIC;
gchar *test_path = NULL;
gchar *file_path = NULL;
GDir *test_dir = NULL;
int opt_index = 0;
int c;
if (argc < 2)
goto error;
while ((c = getopt_long(argc, argv, "d:hm:v",
test_options, &opt_index)) != -1) {
switch (c) {
case 'd':
if (file_path)
goto error;
test_path = g_strdup(optarg);
break;
case 'f':
if (test_path)
goto error;
file_path = g_strdup(optarg);
break;
case 'h':
print_usage();
return EXIT_SUCCESS;
break;
case 'm':
if (strncmp(optarg, "basic", 5) == 0)
mode = CU_MODE_BASIC;
else if (strncmp(optarg, "auto", 4) == 0)
mode = CU_MODE_AUTO;
else if (strncmp(optarg, "console", 6) == 0)
mode = CU_MODE_CONSOLE;
break;
case 'v':
verbose = true;
break;
case '?':
default:
goto error;
}
}
if (!test_path && !file_path)
goto error;
if (test_path) {
test_dir = open_test_dir(&test_path);
if (!test_dir) {
g_free(test_path);
return EXIT_FAILURE;
}
}
if (file_path)
test_path = g_get_current_dir();
__pacrunner_proxy_init();
__pacrunner_js_init();
__pacrunner_manual_init();
__pacrunner_plugin_init(NULL, NULL);
find_and_run_test_suite(test_dir, test_path, file_path, mode);
__pacrunner_plugin_cleanup();
__pacrunner_manual_cleanup();
__pacrunner_js_cleanup();
__pacrunner_proxy_cleanup();
g_free(test_path);
if (test_dir)
g_dir_close(test_dir);
return EXIT_SUCCESS;
error:
print_usage();
return EXIT_FAILURE;
}