diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5a0b2943..2fb52a82 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,10 +43,10 @@ jobs: -v /var/run/utmp:/var/run/utmp \ --mount source=tmp-vol,destination=/src,target=/media/ramdisk2 \ ${{ matrix.distro }} \ - /bin/sh -c '${{ matrix.prepare }} && \ - tools/setup && \ - ./configure --enable-libtap && \ - make && \ + /bin/sh -c '${{ matrix.prepare }} > /dev/null && \ + tools/setup > /dev/null && \ + ./configure --enable-libtap > /dev/null && \ + make > /dev/null && \ make test && \ make dist && \ tar zxf monitoring-plugins-*.tar.gz && \ diff --git a/.gitignore b/.gitignore index 4d49c220..730d2e66 100644 --- a/.gitignore +++ b/.gitignore @@ -233,6 +233,7 @@ plugins/check_disk.d/.dirstamp /plugins/tests/test_utils /plugins/tests/test_check_disk /plugins/tests/test_check_swap +/plugins/tests/test_check_snmp /plugins/tests/.deps /plugins/tests/.dirstamp diff --git a/configure.ac b/configure.ac index e4351ad7..ef02bbeb 100644 --- a/configure.ac +++ b/configure.ac @@ -184,7 +184,7 @@ if test "$enable_libtap" = "yes" ; then EXTRA_TEST="test_utils test_tcp test_cmd test_base64" AC_SUBST(EXTRA_TEST) - EXTRA_PLUGIN_TESTS="tests/test_check_swap tests/test_check_disk" + EXTRA_PLUGIN_TESTS="tests/test_check_swap tests/test_check_disk tests/test_check_snmp" AC_SUBST(EXTRA_PLUGIN_TESTS) fi diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am index 7798a72e..9deebdfa 100644 --- a/lib/tests/Makefile.am +++ b/lib/tests/Makefile.am @@ -5,8 +5,7 @@ noinst_PROGRAMS = @EXTRA_TEST@ TESTS = @EXTRA_TEST@ check_PROGRAMS = @EXTRA_TEST@ -AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ - -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins +AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins EXTRA_PROGRAMS = test_utils test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output diff --git a/lib/utils_base.c b/lib/utils_base.c index 28e6dc47..accafa3b 100644 --- a/lib/utils_base.c +++ b/lib/utils_base.c @@ -47,8 +47,6 @@ monitoring_plugin *this_monitoring_plugin = NULL; mp_state_enum timeout_state = STATE_CRITICAL; unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; -bool _np_state_read_file(FILE *state_file); - void np_init(char *plugin_name, int argc, char **argv) { if (this_monitoring_plugin == NULL) { this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin)); diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 2bea8fc0..06467f7a 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -17,7 +17,7 @@ AM_CPPFLAGS = -I.. \ -I$(top_srcdir)/lib \ -I$(top_srcdir)/gl \ -I$(top_srcdir)/intl \ - -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ + -DCHECK_SNMP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ @LDAPINCLUDE@ \ @PGINCLUDE@ \ @SSLINCLUDE@ @@ -53,13 +53,12 @@ EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \ SUBDIRS = picohttpparser -np_test_scripts = tests/test_check_swap.t \ - tests/test_check_snmp.t \ - tests/test_check_disk.t +np_test_scripts = tests/check_swap.t \ + tests/check_snmp.t \ + tests/check_disk.t EXTRA_DIST = t \ tests \ - $(np_test_scripts) \ negate.d \ check_swap.d \ check_ldap.d \ @@ -190,6 +189,8 @@ tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c tests_test_check_snmp_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap tests_test_check_snmp_SOURCES = tests/test_check_snmp.c check_snmp.d/check_snmp_helpers.c +tests_test_check_snmp_LDFLAGS = $(AM_LDFLAGS) -lm `net-snmp-config --libs` +tests_test_check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags` tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap tests_test_check_disk_SOURCES = tests/test_check_disk.c diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c index 09196dc4..034db4c2 100644 --- a/plugins/check_snmp.c +++ b/plugins/check_snmp.c @@ -258,7 +258,7 @@ int main(int argc, char **argv) { np_init((char *)progname, argc, argv); - state_key stateKey = np_enable_state(NULL, 1, progname, argc, argv); + state_key stateKey = check_snmp_enable_state(NULL, 1, progname, argc, (const char **)argv); /* Parse extra opts if any */ argv = np_extra_opts(&argc, argv, progname); @@ -313,15 +313,16 @@ int main(int argc, char **argv) { bool have_previous_state = false; if (config.evaluation_params.calculate_rate) { - state_data *previous_state = np_state_read(stateKey); - if (previous_state == NULL) { + check_snmp_state_read_wrapper recovered = check_snmp_state_read(stateKey); + + if (recovered.errorcode != 0) { // failed to recover state // or no previous state have_previous_state = false; } else { // sanity check recover_state_data_type prev_state_wrapper = - recover_state_data(previous_state->data, (idx_t)previous_state->length); + recover_state_data(recovered.data.data, (idx_t)recovered.data.length); if (prev_state_wrapper.errorcode == OK) { have_previous_state = true; @@ -371,7 +372,7 @@ int main(int argc, char **argv) { gen_state_string(new_state, config.snmp_params.num_of_test_units); if (current_state_wrapper.errorcode == OK) { - np_state_write_string(stateKey, current_time, current_state_wrapper.state_string); + check_snmp_state_write_string(stateKey, current_time, current_state_wrapper.state_string); } else { die(STATE_UNKNOWN, "failed to create state string"); } diff --git a/plugins/check_snmp.d/check_snmp_helpers.c b/plugins/check_snmp.d/check_snmp_helpers.c index 83e94a34..4f67ffc9 100644 --- a/plugins/check_snmp.d/check_snmp_helpers.c +++ b/plugins/check_snmp.d/check_snmp_helpers.c @@ -11,7 +11,7 @@ extern int verbose; -check_snmp_test_unit check_snmp_test_unit_init() { +check_snmp_test_unit check_snmp_test_unit_init(void) { check_snmp_test_unit tmp = { .threshold = mp_thresholds_init(), }; @@ -91,7 +91,7 @@ const char DEFAULT_OUTPUT_DELIMITER[] = " "; const int RANDOM_STATE_DATA_LENGTH_PREDICTION = 8192; -check_snmp_config check_snmp_config_init() { +check_snmp_config check_snmp_config_init(void) { check_snmp_config tmp = { .snmp_params = { @@ -599,7 +599,7 @@ check_snmp_evaluation evaluate_single_unit(response_value response, return result; } -char *_np_state_generate_key(int argc, char **argv); +char *check_snmp_state_generate_key(int argc, const char **argv); /* * If time=NULL, use current time. Create state file, with state format @@ -608,7 +608,12 @@ char *_np_state_generate_key(int argc, char **argv); * two things writing to same key at same time. * Will die with UNKNOWN if errors */ -void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore) { +void check_snmp_state_write_string(state_key stateKey, time_t timestamp, + const char *stringToStore) { + if (stateKey._filename == NULL || strcmp(stateKey._filename, "") == 0) { + die(STATE_UNKNOWN, "%s: empty filename in state file\n", __FUNCTION__); + } + time_t current_time; if (timestamp == 0) { time(¤t_time); @@ -631,7 +636,6 @@ void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToS *p = '\0'; if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) { /* Can't free this! Otherwise error message is wrong! */ - /* np_free(directories); */ die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories); } *p = '/'; @@ -668,7 +672,7 @@ void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToS } fprintf(temp_file_pointer, "# NP State file\n"); - fprintf(temp_file_pointer, "%d\n", NP_STATE_FORMAT_VERSION); + fprintf(temp_file_pointer, "%d\n", CHECK_SNMP_STATE_FORMAT_VERSION); fprintf(temp_file_pointer, "%d\n", stateKey.data_version); fprintf(temp_file_pointer, "%lu\n", current_time); fprintf(temp_file_pointer, "%s\n", stringToStore); @@ -691,10 +695,11 @@ void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToS if (rename(temp_file, stateKey._filename) != 0) { unlink(temp_file); + printf("%s: %s to %s\n", _("Cannot rename state temp file"), temp_file, stateKey._filename); if (temp_file) { free(temp_file); } - die(STATE_UNKNOWN, _("Cannot rename state temp file")); + die(STATE_UNKNOWN, NULL); } if (temp_file) { @@ -705,17 +710,25 @@ void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToS /* * Read the state file */ -bool _np_state_read_file(FILE *state_file, state_key stateKey) { +typedef struct { + int errorcode; + state_data data; +} check_snmp_state_read_file_wrapper; +check_snmp_state_read_file_wrapper check_snmp_state_read_file(FILE *state_file, state_key input_state) { time_t current_time; time(¤t_time); + check_snmp_state_read_file_wrapper result = { + .errorcode = 0, + .data = {}, + }; + /* Note: This introduces a limit of 8192 bytes in the string data */ char *line = (char *)calloc(1, 8192); if (line == NULL) { die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); } - bool status = false; enum { STATE_FILE_VERSION, STATE_DATA_VERSION, @@ -724,7 +737,8 @@ bool _np_state_read_file(FILE *state_file, state_key stateKey) { STATE_DATA_END } expected = STATE_FILE_VERSION; - int failure = 0; + bool failure = false; + bool found_data = false; // if we reach the end but there is not data, we fail while (!failure && (fgets(line, 8192, state_file)) != NULL) { size_t pos = strlen(line); if (line[pos - 1] == '\n') { @@ -738,16 +752,16 @@ bool _np_state_read_file(FILE *state_file, state_key stateKey) { switch (expected) { case STATE_FILE_VERSION: { int i = atoi(line); - if (i != NP_STATE_FORMAT_VERSION) { - failure++; + if (i != CHECK_SNMP_STATE_FORMAT_VERSION) { + failure = true; } else { expected = STATE_DATA_VERSION; } } break; case STATE_DATA_VERSION: { int i = atoi(line); - if (i != stateKey.data_version) { - failure++; + if (i != input_state.data_version) { + failure = true; } else { expected = STATE_DATA_TIME; } @@ -756,20 +770,21 @@ bool _np_state_read_file(FILE *state_file, state_key stateKey) { /* If time > now, error */ time_t data_time = strtoul(line, NULL, 10); if (data_time > current_time) { - failure++; + failure = true; } else { - stateKey.state_data->time = data_time; + result.data.time = data_time; expected = STATE_DATA_TEXT; } } break; case STATE_DATA_TEXT: - stateKey.state_data->data = strdup(line); - if (stateKey.state_data->data == NULL) { + result.data.data = strdup(line); + if (result.data.data == NULL) { die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); } - stateKey.state_data->length = strlen(line); + result.data.length = strlen(line); expected = STATE_DATA_END; - status = true; + result.errorcode = 0; + found_data = true; break; case STATE_DATA_END:; } @@ -778,7 +793,12 @@ bool _np_state_read_file(FILE *state_file, state_key stateKey) { if (line) { free(line); } - return status; + + if (failure || !found_data) { + result.errorcode = 1; + } + + return result; } /* * Will return NULL if no data is available (first run). If key currently @@ -787,32 +807,31 @@ bool _np_state_read_file(FILE *state_file, state_key stateKey) { * If numerically lower, then return as no previous state. die with UNKNOWN * if exceptional error. */ -state_data *np_state_read(state_key stateKey) { +check_snmp_state_read_wrapper check_snmp_state_read(state_key stateKey) { /* Open file. If this fails, no previous state found */ + check_snmp_state_read_wrapper result = { + .data = {}, + .errorcode = 0, + }; + FILE *statefile = fopen(stateKey._filename, "r"); - state_data *this_state_data = (state_data *)calloc(1, sizeof(state_data)); - if (statefile != NULL) { - - if (this_state_data == NULL) { - die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); - } - - this_state_data->data = NULL; - stateKey.state_data = this_state_data; - - if (_np_state_read_file(statefile, stateKey)) { - this_state_data->errorcode = OK; - } else { - this_state_data->errorcode = ERROR; - } - - fclose(statefile); - } else { + if (statefile == NULL) { // Failed to open state file - this_state_data->errorcode = ERROR; + result.errorcode = 1; + return result; } - return stateKey.state_data; + check_snmp_state_read_file_wrapper recovered = check_snmp_state_read_file(statefile, stateKey); + if (recovered.errorcode == 0) { + result.errorcode = OK; + result.data = recovered.data; + } else { + result.errorcode = ERROR; + } + + fclose(statefile); + + return result; } /* @@ -820,7 +839,7 @@ state_data *np_state_read(state_key stateKey) { * envvar NAGIOS_PLUGIN_STATE_DIRECTORY * statically compiled shared state directory */ -char *_np_state_calculate_location_prefix(void) { +char *check_snmp_state_calculate_location_prefix(void) { char *env_dir; /* Do not allow passing MP_STATE_PATH in setuid plugins @@ -837,7 +856,7 @@ char *_np_state_calculate_location_prefix(void) { } } - return NP_STATE_DIR_PREFIX; + return CHECK_SNMP_STATE_DIR_PREFIX; } /* @@ -845,8 +864,8 @@ char *_np_state_calculate_location_prefix(void) { * Sets variables. Generates filename. Returns np_state_key. die with * UNKNOWN if exception */ -state_key np_enable_state(char *keyname, int expected_data_version, const char *plugin_name, - int argc, char **argv) { +state_key check_snmp_enable_state(char *keyname, int expected_data_version, const char *plugin_name, + int argc, const char **argv) { state_key *this_state = (state_key *)calloc(1, sizeof(state_key)); if (this_state == NULL) { die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); @@ -854,7 +873,7 @@ state_key np_enable_state(char *keyname, int expected_data_version, const char * char *temp_keyname = NULL; if (keyname == NULL) { - temp_keyname = _np_state_generate_key(argc, argv); + temp_keyname = check_snmp_state_generate_key(argc, (const char **)argv); } else { temp_keyname = strdup(keyname); if (temp_keyname == NULL) { @@ -873,11 +892,11 @@ state_key np_enable_state(char *keyname, int expected_data_version, const char * this_state->name = temp_keyname; this_state->plugin_name = (char *)plugin_name; this_state->data_version = expected_data_version; - this_state->state_data = NULL; + this_state->state_data = (state_data){}; /* Calculate filename */ char *temp_filename = NULL; - int error = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), + int error = asprintf(&temp_filename, "%s/%lu/%s/%s", check_snmp_state_calculate_location_prefix(), (unsigned long)geteuid(), plugin_name, this_state->name); if (error < 0) { die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); @@ -889,18 +908,17 @@ state_key np_enable_state(char *keyname, int expected_data_version, const char * } /* - * Returns a string to use as a keyname, based on an md5 hash of argv, thus + * Returns a string to use as a keyname, based on the sha256 hash of argv, thus * hopefully a unique key per service/plugin invocation. Use the extra-opts * parse of argv, so that uniqueness in parameters are reflected there. */ -char *_np_state_generate_key(int argc, char **argv) { +char *check_snmp_state_generate_key(int argc, const char **argv) { unsigned char result[256]; #ifdef USE_OPENSSL /* * This code path is chosen if openssl is available (which should be the most common - * scenario). Alternatively, the gnulib implementation/ - * + * scenario). Alternatively, the gnulib implementation is used */ EVP_MD_CTX *ctx = EVP_MD_CTX_new(); diff --git a/plugins/check_snmp.d/check_snmp_helpers.h b/plugins/check_snmp.d/check_snmp_helpers.h index 95b361ac..386c06b8 100644 --- a/plugins/check_snmp.d/check_snmp_helpers.h +++ b/plugins/check_snmp.d/check_snmp_helpers.h @@ -3,9 +3,9 @@ #include "./config.h" #include -check_snmp_test_unit check_snmp_test_unit_init(); +check_snmp_test_unit check_snmp_test_unit_init(void); int check_snmp_set_thresholds(const char *, check_snmp_test_unit[], size_t, bool); -check_snmp_config check_snmp_config_init(); +check_snmp_config check_snmp_config_init(void); typedef struct { oid oid[MAX_OID_LEN]; @@ -48,24 +48,28 @@ check_snmp_evaluation evaluate_single_unit(response_value response, check_snmp_state_entry prev_state, bool have_previous_state); -#define NP_STATE_FORMAT_VERSION 1 +#define CHECK_SNMP_STATE_FORMAT_VERSION 1 -typedef struct state_data_struct { +typedef struct { time_t time; void *data; size_t length; /* Of binary data */ int errorcode; } state_data; -typedef struct state_key_struct { +typedef struct { char *name; char *plugin_name; int data_version; char *_filename; - state_data *state_data; + state_data state_data; } state_key; -state_data *np_state_read(state_key stateKey); -state_key np_enable_state(char *keyname, int expected_data_version, const char *plugin_name, - int argc, char **argv); -void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore); +typedef struct { + int errorcode; + state_data data; +} check_snmp_state_read_wrapper; +check_snmp_state_read_wrapper check_snmp_state_read(state_key stateKey); +state_key check_snmp_enable_state(char *keyname, int expected_data_version, const char *plugin_name, + int argc, const char **argv); +void check_snmp_state_write_string(state_key stateKey, time_t timestamp, const char *stringToStore); diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp_peer.t similarity index 98% rename from plugins/t/check_ntp.t rename to plugins/t/check_ntp_peer.t index 7703bc3b..a03be52b 100644 --- a/plugins/t/check_ntp.t +++ b/plugins/t/check_ntp_peer.t @@ -5,10 +5,11 @@ # use strict; +use warnings; use Test::More; use NPTest; -my @PLUGINS1 = ('check_ntp_peer', 'check_ntp_time'); +my @PLUGINS1 = ('check_ntp_peer'); my @PLUGINS2 = ('check_ntp_peer'); plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2)); diff --git a/plugins/t/check_ntp_time.t b/plugins/t/check_ntp_time.t new file mode 100644 index 00000000..a814c3d6 --- /dev/null +++ b/plugins/t/check_ntp_time.t @@ -0,0 +1,87 @@ +#! /usr/bin/perl -w -I .. +# +# Testing NTP +# +# + +use strict; +use warnings; +use Test::More; +use NPTest; + +my @PLUGINS1 = ('check_ntp_time'); + +plan tests => (12 * scalar(@PLUGINS1)); + +my $res; + +my $ntp_service = getTestParameter( "NP_GOOD_NTP_SERVICE", + "A host providing NTP service", + "pool.ntp.org"); + +my $no_ntp_service = getTestParameter( "NP_NO_NTP_SERVICE", + "A host NOT providing the NTP service", + "localhost" ); + +my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE", + "The hostname of system not responsive to network requests", + "10.0.0.1" ); + +my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID", + "An invalid (not known to DNS) hostname", + "nosuchhost"); + +my $ntp_okmatch1 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/'; +my $ntp_warnmatch1 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/'; +my $ntp_critmatch1 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/'; +my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/'; +my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/'; +my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/'; +my $ntp_noresponse = '/(.*Socket timeout after \d+ seconds.*)|(.*No response from NTP server.*)/'; +my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/'; + + +foreach my $plugin (@PLUGINS1) { + SKIP: { + skip "No NTP server defined", 6 unless $ntp_service; + $res = NPTest->testCmd( + "./$plugin -H $ntp_service -w 1000 -c 2000" + ); + cmp_ok( $res->return_code, '==', 0, "$plugin: Good NTP result (simple check)" ); + like( $res->output, $ntp_okmatch1, "$plugin: Output match OK (simple check)" ); + + $res = NPTest->testCmd( + "./$plugin -H $ntp_service -w 1000: -c 2000" + ); + cmp_ok( $res->return_code, '==', 1, "$plugin: Warning NTP result (simple check)" ); + like( $res->output, $ntp_warnmatch1, "$plugin: Output match WARNING (simple check)" ); + + $res = NPTest->testCmd( + "./$plugin -H $ntp_service -w 1000 -c 2000:" + ); + cmp_ok( $res->return_code, '==', 2, "$plugin: Critical NTP result (simple check)" ); + like( $res->output, $ntp_critmatch1, "$plugin: Output match CRITICAL (simple check)" ); + } + + SKIP: { + skip "No bad NTP server defined", 1 unless $no_ntp_service; + $res = NPTest->testCmd( + "./$plugin -H $no_ntp_service -t 3" + ); + cmp_ok( $res->return_code, '==', 2, "$plugin: No NTP service" ); + like( $res->output, $ntp_noresponse, "$plugin: Output match no NTP service" ); + } + + $res = NPTest->testCmd( + "./$plugin -H $host_nonresponsive -t 3" + ); + cmp_ok( $res->return_code, '==', 2, "$plugin: Server not responding" ); + like( $res->output, $ntp_noresponse, "$plugin: Output match non-responsive" ); + + $res = NPTest->testCmd( + "./$plugin -H $hostname_invalid" + ); + cmp_ok( $res->return_code, '==', 3, "$plugin: Invalid hostname/address" ); + like( $res->output, $ntp_nosuchhost, "$plugin: Output match invalid hostname/address" ); + +} diff --git a/plugins/tests/test_check_disk.t b/plugins/tests/check_disk.t similarity index 55% rename from plugins/tests/test_check_disk.t rename to plugins/tests/check_disk.t index 56354650..a81f447a 100755 --- a/plugins/tests/test_check_disk.t +++ b/plugins/tests/check_disk.t @@ -1,6 +1,9 @@ #!/usr/bin/perl +use strict; +use warnings; + use Test::More; -if (! -e "./test_check_disk") { +if (! -e "./tests/test_check_disk") { plan skip_all => "./test_check_disk not compiled - please enable libtap library to test"; } -exec "./test_check_disk"; +system("./tests/test_check_disk"); diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t index 26d67898..9a238a1d 100755 --- a/plugins/tests/check_snmp.t +++ b/plugins/tests/check_snmp.t @@ -275,3 +275,9 @@ like($res->output, '/.*4.20.*| iso.3.6.1.4.1.8072.3.2.67.19=4.20/', "Test multip $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -w 1"); is($res->return_code, 1, "Test multiply RC + thresholds" ); like($res->output, '/.*4.20.* | iso.3.6.1.4.1.8072.3.2.67.19=4.20+;1/', "Test multiply .1 output + thresholds" ); + +if (! -e "./tests/test_check_snmp") { + plan skip_all => "./test_check_snmp not compiled - please enable libtap library to test"; +} + +system("./tests/test_check_snmp"); diff --git a/plugins/tests/test_check_swap.t b/plugins/tests/check_swap.t similarity index 56% rename from plugins/tests/test_check_swap.t rename to plugins/tests/check_swap.t index 826fae01..91ed8683 100755 --- a/plugins/tests/test_check_swap.t +++ b/plugins/tests/check_swap.t @@ -1,6 +1,9 @@ #!/usr/bin/perl +use strict; +use warnings; + use Test::More; -if (! -e "./test_check_swap") { +if (! -e "./tests/test_check_swap") { plan skip_all => "./test_check_swap not compiled - please enable libtap library to test"; } -exec "./test_check_swap"; +system("./tests/test_check_swap"); diff --git a/plugins/tests/test_check_snmp.c b/plugins/tests/test_check_snmp.c index d71706d0..d562338f 100644 --- a/plugins/tests/test_check_snmp.c +++ b/plugins/tests/test_check_snmp.c @@ -16,153 +16,185 @@ * *****************************************************************************/ -#include "tap.h" +#include "../../tap/tap.h" #include "../../config.h" +#include +#include +#include #include #include #include +#include +#include -#include "utils_base.c" #include "../check_snmp.d/check_snmp_helpers.h" +#include "states.h" -char *_np_state_generate_key(int argc, char **argv); -char *_np_state_calculate_location_prefix(void); +// helpers +int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { + (void)sb; + (void)typeflag; + (void)ftwbuf; -int main(int argc, char **argv) { - char *temp_string = (char *)_np_state_generate_key(argc, argv); - ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), - "Got hash with exe and no parameters") || - diag("You are probably running in wrong directory. Must run as ./test_utils"); + int rv = remove(fpath); + + if (rv) { + perror(fpath); + } + + return rv; +} + +int rmrf(char *path) { return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); } + +char *create_file_path(const char *prefix, const char *end_part) { + char *result = calloc(strlen(prefix) + strlen(end_part) + 1, sizeof(char)); + if (result == NULL) { + die(2, "Failed to allocate memory"); + } + + strcpy(result, prefix); + strcat(result, end_part); + return result; +} + +// declarations to make it compile +int verbose = 0; +void print_usage(void) {} +const char *progname = "test_check_snmp"; + +char *check_snmp_state_generate_key(int argc, char **argv); +char *check_snmp_state_calculate_location_prefix(void); +// + +void test_key_generation(int argc, char **argv) { + char *temp_string = (char *)check_snmp_state_generate_key(argc, argv); + ok(!strcmp(temp_string, "8a5881f5f97e68878b738538d9b864e1c8e3e463"), + "Got hash with exe and no parameters: %s", temp_string); + + if (!strcmp(temp_string, "8dd4ba3c1dcea40bd80fe2e2c73872b669e211banot")) { + diag("You are probably running in wrong directory. Must run as ./tests/test_check_snmp"); + } int fake_argc = 4; char *fake_argv[] = { - "./test_utils", + "./tests/test_check_snmp", "here", "--and", "now", }; - temp_string = (char *)_np_state_generate_key(fake_argc, fake_argv); - ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), - "Got based on expected argv"); + temp_string = (char *)check_snmp_state_generate_key(fake_argc, fake_argv); + ok(!strcmp(temp_string, "cf15afca3c3a45d60056384f64459880ce3dedc5"), + "Got %s based on expected argv", temp_string); +} +void test_state_location_prefix(void) { unsetenv("MP_STATE_PATH"); - temp_string = (char *)_np_state_calculate_location_prefix(); - ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory"); + char *temp_string = (char *)check_snmp_state_calculate_location_prefix(); + ok(!strcmp(temp_string, CHECK_SNMP_STATE_DIR_PREFIX), "Got default directory"); setenv("MP_STATE_PATH", "", 1); - temp_string = (char *)_np_state_calculate_location_prefix(); - ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string"); + temp_string = (char *)check_snmp_state_calculate_location_prefix(); + ok(!strcmp(temp_string, CHECK_SNMP_STATE_DIR_PREFIX), + "Got default directory even with empty string"); setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1); - temp_string = (char *)_np_state_calculate_location_prefix(); + temp_string = (char *)check_snmp_state_calculate_location_prefix(); ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory"); - fake_argc = 1; - fake_argv[0] = "./test_utils"; - state_key temp_state_key1 = np_enable_state(NULL, 51, "check_test", fake_argc, fake_argv); + unsetenv("MP_STATE_PATH"); +} + +void test_enable_state(void) { + const int fake_argc = 1; + const char *fake_argv[1] = {"fake_argv"}; + state_key temp_state_key1 = + check_snmp_enable_state(NULL, 51, "check_test", fake_argc, fake_argv); ok(!strcmp(temp_state_key1.plugin_name, "check_test"), "Got plugin name"); - ok(!strcmp(temp_state_key1.name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), - "Got generated filename"); + ok(!strcmp(temp_state_key1.name, "8dd4ba3c1dcea40bd80fe2e2c73872b669e211ba"), + "Got generated filename: %s", temp_state_key1.name); - state_key temp_state_key2 = - np_enable_state("allowedchars_in_keyname", 77, "check_snmp", fake_argc, fake_argv); + const char *expected_plugin_name = "check_foobar"; + state_key temp_state_key2 = check_snmp_enable_state("allowedchars_in_keyname", 77, + expected_plugin_name, fake_argc, fake_argv); + ok(!strcmp(temp_state_key2.plugin_name, expected_plugin_name), "Got plugin name: %s", + temp_state_key2.plugin_name); + ok(!strcmp(temp_state_key2.name, "allowedchars_in_keyname"), + "Got key name with valid chars: %s", temp_state_key2.name); +} - char state_path[1024]; - sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", - (unsigned long)geteuid()); - ok(!strcmp(temp_state_key2.plugin_name, "check_test"), "Got plugin name"); - ok(!strcmp(temp_state_key2.name, "allowedchars_in_keyname"), "Got key name with valid chars"); - ok(!strcmp(temp_state_key2._filename, state_path), "Got internal filename"); +void test_read_state(state_key test_state, const char test_string[], const char *test_dir, + const char *example_dir) { + check_snmp_state_read_wrapper recovered_state = check_snmp_state_read(test_state); + ok(recovered_state.errorcode == 0, "Got state data now"); - /* Don't do this test just yet. Will die */ - /* - np_enable_state("bad^chars$in@here", 77); - temp_state_key = this_monitoring_plugin->state; - ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced" - ); - */ + if (recovered_state.errorcode != 0) { + diag("Are you running in right directory? No state data could be recovered"); + exit(2); + } - state_key temp_state_key3 = - np_enable_state("funnykeyname", 54, "check_snmp", fake_argc, fake_argv); - sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", - (unsigned long)geteuid()); - ok(!strcmp(temp_state_key3.plugin_name, "check_test"), "Got plugin name"); - ok(!strcmp(temp_state_key3.name, "funnykeyname"), "Got key name"); + ok(recovered_state.data.time == 1234567890, "Got time: %d", recovered_state.data.time); + ok(!strcmp((char *)recovered_state.data.data, test_string), "Data as expected"); - ok(!strcmp(temp_state_key3._filename, state_path), "Got internal filename"); - ok(temp_state_key3.data_version == 54, "Version set"); + test_state.data_version = 53; + recovered_state = check_snmp_state_read(test_state); + ok(recovered_state.errorcode != 0, "Older data version gives error"); + test_state.data_version = 54; - state_data *temp_state_data = np_state_read(temp_state_key3); - ok(temp_state_data == NULL, "Got no state data as file does not exist"); + char *nonexistent_file_path = create_file_path(example_dir, "/nonexistent"); + test_state._filename = nonexistent_file_path; + check_snmp_state_read_wrapper non_existent = check_snmp_state_read(test_state); + ok(non_existent.errorcode != 0, "Missing file gives error"); - /* - temp_fp = fopen("var/statefile", "r"); - if (temp_fp==NULL) - printf("Error opening. errno=%d\n", errno); - printf("temp_fp=%s\n", temp_fp); - ok( _np_state_read_file(temp_fp) == true, "Can read state file" ); - fclose(temp_fp); - */ + char *oldformat_file_path = create_file_path(example_dir, "/oldformat"); + test_state._filename = oldformat_file_path; + check_snmp_state_read_wrapper old_format = check_snmp_state_read(test_state); + ok(old_format.errorcode != 0, "Old file format gives error"); - temp_state_key3._filename = "var/statefile"; - temp_state_data = np_state_read(temp_state_key3); - ok(temp_state_data != NULL, "Got state data now") || - diag("Are you running in right directory? Will get coredump next if not"); - ok(temp_state_data->time == 1234567890, "Got time"); - ok(!strcmp((char *)temp_state_data->data, "String to read"), "Data as expected"); + char *baddate_file_path = create_file_path(example_dir, "/baddate"); + test_state._filename = baddate_file_path; + check_snmp_state_read_wrapper baddate = check_snmp_state_read(test_state); + ok(baddate.errorcode != 0, "Bad date gives error"); - temp_state_key3.data_version = 53; - temp_state_data = np_state_read(temp_state_key3); - ok(temp_state_data == NULL, "Older data version gives NULL"); - temp_state_key3.data_version = 54; + char *missingdataline_file_path = create_file_path(example_dir, "/missingdataline"); + test_state._filename = missingdataline_file_path; + check_snmp_state_read_wrapper missingdataline = check_snmp_state_read(test_state); + ok(missingdataline.errorcode != 0, "Missing data line gives error"); - temp_state_key3._filename = "var/nonexistent"; - temp_state_data = np_state_read(temp_state_key3); - ok(temp_state_data == NULL, "Missing file gives NULL"); + // generate new file to test time proceeding + char *generated_file_path = create_file_path(test_dir, "/generated"); + test_state._filename = generated_file_path; - temp_state_key3._filename = "var/oldformat"; - temp_state_data = np_state_read(temp_state_key3); - ok(temp_state_data == NULL, "Old file format gives NULL"); - - temp_state_key3._filename = "var/baddate"; - temp_state_data = np_state_read(temp_state_key3); - ok(temp_state_data == NULL, "Bad date gives NULL"); - - temp_state_key3._filename = "var/missingdataline"; - temp_state_data = np_state_read(temp_state_key3); - ok(temp_state_data == NULL, "Missing data line gives NULL"); - - unlink("var/generated"); - temp_state_key3._filename = "var/generated"; + char *example_statefile_file_path = create_file_path(example_dir, "/statefile"); time_t current_time = 1234567890; - np_state_write_string(temp_state_key3, current_time, "String to read"); - ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected"); + check_snmp_state_write_string(test_state, current_time, test_string); + char *cmp_execution_string = NULL; + (void)!asprintf(&cmp_execution_string, "cmp %s %s", generated_file_path, + example_statefile_file_path); + ok(system(cmp_execution_string) == 0, "Generated file same as expected"); - unlink("var/generated_directory/statefile"); - unlink("var/generated_directory"); - temp_state_key3._filename = "var/generated_directory/statefile"; + char *generated_dir_test_file_path = + create_file_path(test_dir, "/generated_directory/statefile"); + test_state._filename = generated_dir_test_file_path; current_time = 1234567890; - np_state_write_string(temp_state_key3, current_time, "String to read"); - ok(system("cmp var/generated_directory/statefile var/statefile") == 0, - "Have created directory"); + check_snmp_state_write_string(test_state, current_time, test_string); + (void)!asprintf(&cmp_execution_string, "cmp %s %s", generated_dir_test_file_path, + example_statefile_file_path); + ok(system(cmp_execution_string) == 0, "Have created directory"); - /* This test to check cannot write to dir - can't automate yet */ - /* - unlink("var/generated_bad_dir"); - mkdir("var/generated_bad_dir", S_IRUSR); - np_state_write_string(current_time, "String to read"); - */ - - temp_state_key3._filename = "var/generated"; - time(¤t_time); - np_state_write_string(temp_state_key3, 0, "String to read"); - temp_state_data = np_state_read(temp_state_key3); + test_state._filename = generated_dir_test_file_path; + check_snmp_state_write_string(test_state, 0, test_string); + check_snmp_state_read_wrapper recovered_state_1 = check_snmp_state_read(test_state); + ok(recovered_state_1.errorcode == 0, "recovered state successfully"); /* Check time is set to current_time */ - ok(system("cmp var/generated var/statefile > /dev/null") != 0, - "Generated file should be different this time"); - ok(temp_state_data->time - current_time <= 1, "Has time generated from current time"); + (void)!asprintf(&cmp_execution_string, "cmp %s %s > /dev/null", generated_dir_test_file_path, + example_statefile_file_path); + ok(system(cmp_execution_string) != 0, "Generated file should be different this time"); + + time(¤t_time); + ok(recovered_state_1.data.time - current_time <= 1, "Has time generated from current time"); /* Don't know how to automatically test this. Need to be able to redefine die and catch the * error */ @@ -170,6 +202,59 @@ int main(int argc, char **argv) { temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write"; np_state_write_string(0, "Bad file"); */ +} + +int main(int argc, char **argv) { + // Generate test directory + char *base_path = dirname(argv[0]); + const char test_dir_name[] = "/test"; + + char *test_dir_path = create_file_path(base_path, test_dir_name); + + // remove test directory before using it + rmrf(test_dir_path); + + int result_mkdir = mkdir(test_dir_path, 0700); + + ok(result_mkdir == 0, "Generated test directory: %s", test_dir_path); + + if (result_mkdir != 0) { + // failed to create test directory, rest is useless + diag("Failed to generate test directory. Aborting here. mkdir result was: %s", + strerror(errno)); + exit(2); + } + + test_key_generation(argc, argv); + + test_state_location_prefix(); + + int fake_argc = 1; + const char *fake_argv[1] = {"fake_argv"}; + const char *expected_plugin_name = "fake_pluginname"; + const char *test_state_subpath = "/test_state"; + char *test_state_path = create_file_path(test_dir_path, test_state_subpath); + setenv("MP_STATE_PATH", test_state_path, 1); + + state_key temp_state = + check_snmp_enable_state("funnykeyname", 54, expected_plugin_name, fake_argc, fake_argv); + const char *test_string = "String to read"; + check_snmp_state_write_string(temp_state, 1234567890, test_string); + + ok(!strcmp(temp_state.plugin_name, expected_plugin_name), "Got plugin name: %s", + temp_state.plugin_name); + ok(!strcmp(temp_state.name, "funnykeyname"), "Got key name"); + + check_snmp_state_read_wrapper recoverd_state_data = check_snmp_state_read(temp_state); + ok(recoverd_state_data.errorcode == 0, "Retrieve state data from file '%s'", + temp_state._filename); + + const char *example_dir = "/var/check_snmp"; + char *example_path = create_file_path(base_path, example_dir); + test_read_state(temp_state, test_string, test_dir_path, example_path); np_cleanup(); + + // remove test directory after using it + rmrf(test_dir_path); } diff --git a/plugins/tests/test_check_snmp.t b/plugins/tests/test_check_snmp.t deleted file mode 100755 index 967633e9..00000000 --- a/plugins/tests/test_check_snmp.t +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/perl -use Test::More; -if (! -e "./test_check_snmp") { - plan skip_all => "./test_check_snmp not compiled - please enable libtap library to test"; -} -exec "./test_check_snmp"; diff --git a/plugins/tests/var/check_snmp/baddate b/plugins/tests/var/check_snmp/baddate new file mode 100644 index 00000000..2fda432e --- /dev/null +++ b/plugins/tests/var/check_snmp/baddate @@ -0,0 +1,5 @@ +# NP State file +1 +54 +2147483647 +Date in future!!!! diff --git a/plugins/tests/var/check_snmp/missingdataline b/plugins/tests/var/check_snmp/missingdataline new file mode 100644 index 00000000..d87f73aa --- /dev/null +++ b/plugins/tests/var/check_snmp/missingdataline @@ -0,0 +1,4 @@ +# NP State file +1 +54 +1234567890 diff --git a/plugins/tests/var/check_snmp/oldformat b/plugins/tests/var/check_snmp/oldformat new file mode 100644 index 00000000..102f8c9f --- /dev/null +++ b/plugins/tests/var/check_snmp/oldformat @@ -0,0 +1,5 @@ +# NP State file +0 +54 +1234567890 +String to read diff --git a/plugins/tests/var/check_snmp/statefile b/plugins/tests/var/check_snmp/statefile new file mode 100644 index 00000000..5002139c --- /dev/null +++ b/plugins/tests/var/check_snmp/statefile @@ -0,0 +1,5 @@ +# NP State file +1 +54 +1234567890 +String to read diff --git a/plugins/utils.h b/plugins/utils.h index 68ff1630..9d72cd5b 100644 --- a/plugins/utils.h +++ b/plugins/utils.h @@ -21,7 +21,7 @@ suite of plugins. */ #ifdef NP_EXTRA_OPTS /* Include extra-opts functions if compiled in */ -# include "extra_opts.h" +# include "../lib/extra_opts.h" #else /* else, fake np_extra_opts */ # define np_extra_opts(acptr, av, pr) av