-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
332 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,326 @@ | ||
/************************************************************\ | ||
* Copyright 2019 Lawrence Livermore National Security, LLC | ||
* (c.f. AUTHORS, NOTICE.LLNS, COPYING) | ||
* | ||
* This file is part of the Flux resource manager framework. | ||
* For details, see https://github.com/flux-framework. | ||
* | ||
* SPDX-License-Identifier: LGPL-3.0 | ||
\************************************************************/ | ||
|
||
#if HAVE_CONFIG_H | ||
#include "config.h" | ||
#endif | ||
#include <sys/param.h> | ||
#include <unistd.h> | ||
#include <jansson.h> | ||
#include <flux/core.h> | ||
|
||
#include "src/common/libtap/tap.h" | ||
#include "src/broker/boot_config.h" | ||
|
||
|
||
static void | ||
create_test_file (const char *dir, char *prefix, char *path, size_t pathlen, | ||
const char *contents) | ||
{ | ||
int fd; | ||
if (snprintf (path, | ||
pathlen, | ||
"%s/%s.XXXXXX.toml", | ||
dir ? dir : "/tmp", | ||
prefix) >= pathlen) | ||
BAIL_OUT ("snprintf overflow"); | ||
fd = mkstemps (path, 5); | ||
if (fd < 0) | ||
BAIL_OUT ("mkstemp %s: %s", path, strerror (errno)); | ||
if (write (fd, contents, strlen (contents)) != strlen (contents)) | ||
BAIL_OUT ("write %s: %s", path, strerror (errno)); | ||
if (close (fd) < 0) | ||
BAIL_OUT ("close %s: %s", path, strerror (errno)); | ||
} | ||
|
||
static void | ||
create_test_dir (char *dir, int dirlen) | ||
{ | ||
const char *tmpdir = getenv ("TMPDIR"); | ||
if (snprintf (dir, | ||
dirlen, | ||
"%s/cf.XXXXXXX", | ||
tmpdir ? tmpdir : "/tmp") >= dirlen) | ||
BAIL_OUT ("snprintf overflow"); | ||
if (!mkdtemp (dir)) | ||
BAIL_OUT ("mkdtemp %s: %s", dir, strerror (errno)); | ||
setenv ("FLUX_CONF_DIR", dir, 1); | ||
} | ||
|
||
static char *t1 = \ | ||
"[bootstrap]\n" \ | ||
"default_port = 42\n" \ | ||
"default_bind = \"tcp://en0:%p\"\n" \ | ||
"default_connect = \"tcp://x%h:%p\"\n" \ | ||
"hosts = [\n" \ | ||
" { host = \"foo0\" },\n" \ | ||
" { host = \"foo1\" },\n" \ | ||
" { host = \"foo2\" },\n" \ | ||
"]\n"; | ||
|
||
void test_parse (const char *dir) | ||
{ | ||
char path[PATH_MAX + 1]; | ||
flux_t *h; | ||
struct boot_conf conf; | ||
uint32_t rank; | ||
char uri[MAX_URI + 1]; | ||
|
||
if (!(h = flux_open ("loop://", 0))) | ||
BAIL_OUT ("can't continue without loop handle"); | ||
|
||
create_test_file (dir, "boot", path, sizeof (path), t1); | ||
ok (boot_config_parse (h, &conf) == 0, | ||
"boot_conf_parse worked and set default_port correctly"); | ||
|
||
ok (conf.default_port == 42, | ||
"set default_port correctly"); | ||
ok (!strcmp (conf.default_bind, "tcp://en0:42"), | ||
"and set default_bind correctly (with %%p substitution)"); | ||
ok (!strcmp (conf.default_connect, "tcp://x%h:42"), | ||
"and set default_connect correctly (with %%p substitution)"); | ||
|
||
ok (boot_config_getrankbyname (&conf, "foo0", &rank) == 0 | ||
&& rank == 0, | ||
"boot_config_getrankbyname found first entry"); | ||
ok (boot_config_getrankbyname (&conf, "foo1", &rank) == 0 | ||
&& rank == 1, | ||
"boot_config_getrankbyname found second entry"); | ||
ok (boot_config_getrankbyname (&conf, "foo2", &rank) == 0 | ||
&& rank == 2, | ||
"boot_config_getrankbyname found third entry"); | ||
ok (boot_config_getrankbyname (&conf, "notfound", &rank) < 0, | ||
"boot_config_getrankbyname fails on unknown entry"); | ||
|
||
ok (boot_config_getbindbyrank (&conf, 0, uri, sizeof (uri)) == 0 | ||
&& !strcmp (uri, "tcp://en0:42"), | ||
"boot_config_getbindbyrank 0 works with expected value"); | ||
ok (boot_config_getbindbyrank (&conf, 1, uri, sizeof (uri)) == 0 | ||
&& !strcmp (uri, "tcp://en0:42"), | ||
"boot_config_getbindbyrank 1 works with expected value"); | ||
ok (boot_config_getbindbyrank (&conf, 2, uri, sizeof (uri)) == 0 | ||
&& !strcmp (uri, "tcp://en0:42"), | ||
"boot_config_getbindbyrank 2 works with expected value"); | ||
ok (boot_config_getbindbyrank (&conf, 3, uri, sizeof (uri)) < 0, | ||
"boot_config_getbindbyrank 3 fails"); | ||
|
||
ok (boot_config_geturibyrank (&conf, 0, uri, sizeof (uri)) == 0 | ||
&& !strcmp (uri, "tcp://xfoo0:42"), | ||
"boot_config_geturibyrank 0 works with expected value"); | ||
ok (boot_config_geturibyrank (&conf, 1, uri, sizeof (uri)) == 0 | ||
&& !strcmp (uri, "tcp://xfoo1:42"), | ||
"boot_config_geturibyrank 1 works with expected value"); | ||
ok (boot_config_geturibyrank (&conf, 2, uri, sizeof (uri)) == 0 | ||
&& !strcmp (uri, "tcp://xfoo2:42"), | ||
"boot_config_geturibyrank 2 works with expected value"); | ||
ok (boot_config_geturibyrank (&conf, 3, uri, sizeof (uri)) < 0, | ||
"boot_config_geturibyrank 3 fails"); | ||
|
||
if (unlink (path) < 0) | ||
BAIL_OUT ("could not cleanup test file %s", path); | ||
|
||
flux_close (h); | ||
} | ||
|
||
void test_overflow_bind (const char *dir) | ||
{ | ||
char path[PATH_MAX + 1]; | ||
flux_t *h; | ||
struct boot_conf conf; | ||
char t[MAX_URI*2]; | ||
|
||
if (!(h = flux_open ("loop://", 0))) | ||
BAIL_OUT ("can't continue without loop handle"); | ||
|
||
if (snprintf (t, | ||
sizeof (t), | ||
"[bootstrap]\ndefault_bind=\"%*s\"\nhosts=[\"foo\"]\n", | ||
MAX_URI+2, "foo") >= sizeof (t)) | ||
BAIL_OUT ("snprintf overflow"); | ||
create_test_file (dir, "boot", path, sizeof (path), t); | ||
|
||
ok (boot_config_parse (h, &conf) < 0, | ||
"boot_conf_parse caught default_bind overflow"); | ||
|
||
if (unlink (path) < 0) | ||
BAIL_OUT ("could not cleanup test file %s", path); | ||
|
||
flux_close (h); | ||
} | ||
|
||
void test_overflow_connect (const char *dir) | ||
{ | ||
char path[PATH_MAX + 1]; | ||
flux_t *h; | ||
struct boot_conf conf; | ||
char t[MAX_URI*2]; | ||
|
||
if (!(h = flux_open ("loop://", 0))) | ||
BAIL_OUT ("can't continue without loop handle"); | ||
|
||
if (snprintf (t, | ||
sizeof (t), | ||
"[bootstrap]\ndefault_connect=\"%*s\"\nhosts=[\"foo\"]\n", | ||
MAX_URI+2, "foo") >= sizeof (t)) | ||
BAIL_OUT ("snprintf overflow"); | ||
create_test_file (dir, "boot", path, sizeof (path), t); | ||
|
||
ok (boot_config_parse (h, &conf) < 0, | ||
"boot_conf_parse caught default_connect overflow"); | ||
|
||
if (unlink (path) < 0) | ||
BAIL_OUT ("could not cleanup test file %s", path); | ||
|
||
flux_close (h); | ||
} | ||
|
||
static char *t2 = \ | ||
"[bootstrap]\n" \ | ||
"hosts = [\n" \ | ||
" 42,\n" \ | ||
"]\n"; | ||
|
||
void test_bad_hosts_entry (const char *dir) | ||
{ | ||
char path[PATH_MAX + 1]; | ||
flux_t *h; | ||
struct boot_conf conf; | ||
char uri[MAX_URI + 1]; | ||
uint32_t rank; | ||
|
||
if (!(h = flux_open ("loop://", 0))) | ||
BAIL_OUT ("can't continue without loop handle"); | ||
|
||
create_test_file (dir, "boot", path, sizeof (path), t2); | ||
|
||
if (boot_config_parse (h, &conf) < 0) | ||
BAIL_OUT ("boot_config_parse unexpectedly failed"); | ||
ok (boot_config_getrankbyname (&conf, "bar", &rank) < 0, | ||
"boot_config_getrankbyname fails wrong type host entry"); | ||
ok (boot_config_getbindbyrank (&conf, 0, uri, sizeof(uri)) < 0, | ||
"boot_config_getbindbyrank fails wrong type host entry"); | ||
ok (boot_config_geturibyrank (&conf, 0, uri, sizeof(uri)) < 0, | ||
"boot_config_geturibyrank fails wrong type host entry"); | ||
|
||
if (unlink (path) < 0) | ||
BAIL_OUT ("could not cleanup test file %s", path); | ||
|
||
flux_close (h); | ||
} | ||
|
||
static char *t3 = \ | ||
"[bootstrap]\n" \ | ||
"hosts = [\n" \ | ||
" { host = \"foo\" },\n" \ | ||
"]\n"; | ||
|
||
void test_missing_info (const char *dir) | ||
{ | ||
char path[PATH_MAX + 1]; | ||
flux_t *h; | ||
struct boot_conf conf; | ||
char uri[MAX_URI + 1]; | ||
uint32_t rank; | ||
|
||
if (!(h = flux_open ("loop://", 0))) | ||
BAIL_OUT ("can't continue without loop handle"); | ||
|
||
create_test_file (dir, "boot", path, sizeof (path), t3); | ||
|
||
if (boot_config_parse (h, &conf) < 0) | ||
BAIL_OUT ("boot_config_parse unexpectedly failed"); | ||
ok (boot_config_getrankbyname (&conf, "foo", &rank) == 0 | ||
&& rank == 0, | ||
"boot_config_getrankbyname found entry"); | ||
ok (boot_config_getbindbyrank (&conf, 0, uri, sizeof(uri)) < 0, | ||
"boot_config_getbindbyrank fails due to missing bind uri"); | ||
ok (boot_config_geturibyrank (&conf, 0, uri, sizeof(uri)) < 0, | ||
"boot_config_geturibyrank fails due to missing connect uri"); | ||
|
||
if (unlink (path) < 0) | ||
BAIL_OUT ("could not cleanup test file %s", path); | ||
|
||
flux_close (h); | ||
} | ||
|
||
void test_format (void) | ||
{ | ||
char buf[MAX_URI + 1]; | ||
|
||
ok (boot_config_format_uri (buf, sizeof (buf), "abcd", NULL, 0) == 0 | ||
&& !strcmp (buf, "abcd"), | ||
"format: plain string copy works"); | ||
ok (boot_config_format_uri (buf, sizeof (buf), "abcd:%p", NULL, 42) == 0 | ||
&& !strcmp (buf, "abcd:42"), | ||
"format: %%p substitution works end string"); | ||
ok (boot_config_format_uri (buf, sizeof (buf), "a%pb", NULL, 42) == 0 | ||
&& !strcmp (buf, "a42b"), | ||
"format: %%p substitution works mid string"); | ||
ok (boot_config_format_uri (buf, sizeof (buf), "%p:abcd", NULL, 42) == 0 | ||
&& !strcmp (buf, "42:abcd"), | ||
"format: %%p substitution works begin string"); | ||
ok (boot_config_format_uri (buf, sizeof (buf), "%h", NULL, 0) == 0 | ||
&& !strcmp (buf, "%h"), | ||
"format: %%h passes through when host=NULL"); | ||
ok (boot_config_format_uri (buf, sizeof (buf), "%h", "foo", 0) == 0 | ||
&& !strcmp (buf, "foo"), | ||
"format: %%h substitution works"); | ||
ok (boot_config_format_uri (buf, sizeof (buf), "%%", NULL, 0) == 0 | ||
&& !strcmp (buf, "%"), | ||
"format: %%%% literal works"); | ||
ok (boot_config_format_uri (buf, sizeof (buf), "a%X", NULL, 0) == 0 | ||
&& !strcmp (buf, "a%X"), | ||
"format: unknown token passes through"); | ||
|
||
ok (boot_config_format_uri (buf, 5, "abcd", NULL, 0) == 0 | ||
&& !strcmp (buf, "abcd"), | ||
"format: copy abcd to buf[5] works"); | ||
ok (boot_config_format_uri (buf, 4, "abcd", NULL, 0) < 0, | ||
"format: copy abcd to buf[4] fails"); | ||
|
||
ok (boot_config_format_uri (buf, 5, "a%p", NULL, 123) == 0 | ||
&& !strcmp (buf, "a123"), | ||
"format: %%p substitution into exact size buf works"); | ||
ok (boot_config_format_uri (buf, 4, "a%p", NULL, 123) < 0, | ||
"format: %%p substitution overflow detected"); | ||
|
||
ok (boot_config_format_uri (buf, 5, "a%h", "abc", 0) == 0 | ||
&& !strcmp (buf, "aabc"), | ||
"format: %%h substitution into exact size buf works"); | ||
ok (boot_config_format_uri (buf, 4, "a%h", "abc", 0) < 0, | ||
"format: %%h substitution overflow detected"); | ||
} | ||
|
||
int main (int argc, char **argv) | ||
{ | ||
char dir[PATH_MAX + 1]; | ||
|
||
plan (NO_PLAN); | ||
|
||
test_format (); | ||
|
||
create_test_dir (dir, sizeof (dir)); | ||
|
||
test_parse (dir); | ||
test_overflow_bind (dir); | ||
test_overflow_connect (dir); | ||
test_bad_hosts_entry (dir); | ||
test_missing_info (dir); | ||
|
||
if (rmdir (dir) < 0) | ||
BAIL_OUT ("could not cleanup test dir %s", dir); | ||
|
||
done_testing (); | ||
return 0; | ||
} | ||
|
||
/* | ||
* vi:ts=4 sw=4 expandtab | ||
*/ |