Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/plugin-ci-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,15 @@ jobs:
exit 1
fi

- name: Run standalone regression tests
run: |
cd ${{ github.workspace }}/cacti/plugins/monitor
if ls tests/test_*.php >/dev/null 2>&1; then
for test_file in tests/test_*.php; do
php "$test_file"
done
fi

- name: Remove the plugins directory exclusion from the .phpstan.neon
run: sed '/plugins/d' -i .phpstan.neon
working-directory: ${{ github.workspace }}/cacti
Expand Down
26 changes: 19 additions & 7 deletions setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ function monitor_device_table_bottom() {
}

function plugin_monitor_uninstall() {
db_execute('DROP TABLE IF EXISTS plugin_monitor_notify_history');
db_execute('DROP TABLE IF EXISTS plugin_monitor_reboot_history');
db_execute('DROP TABLE IF EXISTS plugin_monitor_uptime');
db_execute_prepared('DROP TABLE IF EXISTS plugin_monitor_notify_history', []);
db_execute_prepared('DROP TABLE IF EXISTS plugin_monitor_reboot_history', []);
db_execute_prepared('DROP TABLE IF EXISTS plugin_monitor_uptime', []);
}

function plugin_monitor_page_head() {
Expand Down Expand Up @@ -203,7 +203,12 @@ function monitor_check_upgrade() {

$info = plugin_monitor_version();
$current = $info['version'];
$old = db_fetch_cell('SELECT version FROM plugin_config WHERE directory = "monitor"');
$old = db_fetch_cell_prepared(
'SELECT version
FROM plugin_config
WHERE directory = ?',
['monitor']
);

if ($current != $old) {
monitor_setup_table();
Expand Down Expand Up @@ -319,9 +324,16 @@ function monitor_device_action_execute($action) {
}

function monitor_device_remove($devices) {
db_execute('DELETE FROM plugin_monitor_notify_history WHERE host_id IN(' . implode(',', $devices) . ')');
db_execute('DELETE FROM plugin_monitor_reboot_history WHERE host_id IN(' . implode(',', $devices) . ')');
db_execute('DELETE FROM plugin_monitor_uptime WHERE host_id IN(' . implode(',', $devices) . ')');
if (!cacti_sizeof($devices)) {
return $devices;
}

$devices = array_map('intval', $devices);
$placeholders = implode(',', array_fill(0, cacti_sizeof($devices), '?'));

db_execute_prepared("DELETE FROM plugin_monitor_notify_history WHERE host_id IN($placeholders)", $devices);
db_execute_prepared("DELETE FROM plugin_monitor_reboot_history WHERE host_id IN($placeholders)", $devices);
db_execute_prepared("DELETE FROM plugin_monitor_uptime WHERE host_id IN($placeholders)", $devices);

return $devices;
}
Expand Down
118 changes: 118 additions & 0 deletions tests/test_prepared_statements.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

function assert_contains(string $haystack, string $needle, string $message): void {
if (strpos($haystack, $needle) === false) {
fwrite(STDERR, $message . PHP_EOL);
exit(1);
}
}

function assert_regex(string $pattern, string $subject, string $message): void {
if (!preg_match($pattern, $subject)) {
fwrite(STDERR, $message . PHP_EOL);
exit(1);
}
}

function assert_not_contains(string $haystack, string $needle, string $message): void {
if (strpos($haystack, $needle) !== false) {
fwrite(STDERR, $message . PHP_EOL);
exit(1);
}
}

$setup = file_get_contents(__DIR__ . '/../setup.php');
if ($setup === false) {
fwrite(STDERR, "Unable to read setup.php\n");
exit(1);
}
Comment on lines +24 to +28
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0e8344b: added a CI step in plugin-ci-workflow.yml to execute tests/test_*.php when present.


assert_contains(
$setup,
'db_fetch_cell_prepared(',
'Expected plugin version lookup to use db_fetch_cell_prepared().'
);

assert_regex(
"/SELECT\\s+version\\s+FROM\\s+plugin_config\\s+WHERE\\s+directory\\s*=\\s*\\?/s",
$setup,
'Expected version lookup SQL to query plugin_config with directory placeholder.'
);

assert_regex(
"/db_fetch_cell_prepared\\s*\\(.*\\[\\s*'monitor'\\s*\\]/s",
$setup,
'Expected monitor directory value to be bound as a prepared parameter.'
);

assert_contains(
$setup,
"db_execute_prepared('DROP TABLE IF EXISTS plugin_monitor_notify_history', []);",
'Expected uninstall notify-history drop to use db_execute_prepared() with empty bindings.'
);

assert_contains(
$setup,
"db_execute_prepared('DROP TABLE IF EXISTS plugin_monitor_reboot_history', []);",
'Expected uninstall reboot-history drop to use db_execute_prepared().'
);

assert_contains(
$setup,
"db_execute_prepared('DROP TABLE IF EXISTS plugin_monitor_uptime', []);",
'Expected uninstall uptime drop to use db_execute_prepared().'
);

assert_contains(
$setup,
'$placeholders = implode(\',\', array_fill(0, cacti_sizeof($devices), \'?\'));',
'Expected monitor_device_remove() to build placeholder list for IN clause.'
);
assert_contains(
$setup,
'if (!cacti_sizeof($devices)) {',
'Expected monitor_device_remove() to short-circuit empty device lists.'
);
assert_contains(
$setup,
'array_map(\'intval\', $devices);',
'Expected monitor_device_remove() to normalize device ids before prepared deletes.'
);

assert_contains(
$setup,
'db_execute_prepared("DELETE FROM plugin_monitor_notify_history WHERE host_id IN($placeholders)", $devices);',
'Expected notify history delete to use db_execute_prepared() with placeholders.'
);

assert_contains(
$setup,
'db_execute_prepared("DELETE FROM plugin_monitor_reboot_history WHERE host_id IN($placeholders)", $devices);',
'Expected reboot history delete to use db_execute_prepared() with placeholders.'
);

assert_contains(
$setup,
'db_execute_prepared("DELETE FROM plugin_monitor_uptime WHERE host_id IN($placeholders)", $devices);',
'Expected uptime delete to use db_execute_prepared() with placeholders.'
);

assert_not_contains(
$setup,
'db_execute(\'DELETE FROM plugin_monitor_notify_history WHERE host_id IN(\' . implode(\',\', $devices) . \')\');',
'Raw notify-history delete should not remain.'
);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0e8344b: added negative assertions for reboot and uptime raw-delete patterns as well.

assert_not_contains(
$setup,
'db_execute(\'DELETE FROM plugin_monitor_reboot_history WHERE host_id IN(\' . implode(\',\', $devices) . \')\');',
'Raw reboot-history delete should not remain.'
);

assert_not_contains(
$setup,
'db_execute(\'DELETE FROM plugin_monitor_uptime WHERE host_id IN(\' . implode(\',\', $devices) . \')\');',
'Raw uptime delete should not remain.'
);

echo "OK\n";