toContain($table); } }); it('hands api_plugin_db_table_create a scalar primary key while keeping the array form for db_update_table', function () { // api_plugin_db_table_create() interpolates data['primary'] straight into // PRIMARY KEY (`...`) down to the 1.2.29 compat floor, so an array would // render as PRIMARY KEY (`Array`) and fail the create on a fresh install. // db_update_table() needs the array form, so the canonical definitions keep it. monitor_setup_table(); $creates = array_filter($GLOBALS['__test_db_calls'], function ($call) { return $call['fn'] === 'api_plugin_db_table_create'; }); expect($creates)->not->toBeEmpty(); foreach ($creates as $call) { expect($call['data']['primary'])->toBeString(); } expect(monitor_notify_history_table_data()['primary'])->toBeArray() ->and(monitor_uptime_table_data()['primary'])->toBeArray(); }); it('does not keep plugin ownership of the user-owned dashboards table', function () { monitor_setup_table(); $disowned = array_filter($GLOBALS['__test_db_calls'], function ($call) { return $call['fn'] === 'db_execute' && stripos($call['sql'], 'DELETE FROM plugin_db_changes') !== false && stripos($call['sql'], 'plugin_monitor_dashboards') !== false; }); expect($disowned)->not->toBeEmpty(); }); it('launches poller_monitor.php in the background on the primary poller', function () { $GLOBALS['__test_config_options']['path_php_binary'] = '/usr/bin/php'; monitor_poller_bottom(); expect($GLOBALS['__test_exec_calls'])->toHaveCount(1); expect($GLOBALS['__test_exec_calls'][0]['command'])->toBe('/usr/bin/php'); expect($GLOBALS['__test_exec_calls'][0]['args'])->toContain('poller_monitor.php'); }); it('does nothing on a non-primary poller', function () { $GLOBALS['config']['poller_id'] = 2; monitor_poller_bottom(); expect($GLOBALS['__test_exec_calls'])->toBeEmpty(); }); it('parses a legacy dashboard url into the properties vars structure', function () { $props = monitor_url_to_properties('monitor.php?refresh=60&grouping=site&site=-1&rfilter='); expect($props)->toBe([ 'vars' => [ 'refresh' => '60', 'grouping' => 'site', 'site' => '-1', 'rfilter' => '', ], ]); }); it('migrates legacy dashboard urls into properties and drops the url column', function () { monitor_test_reset_db_mocks(); $GLOBALS['__test_db_calls'] = array(); monitor_test_mock_db('db_table_exists', 'plugin_monitor_dashboards', true); monitor_test_mock_db('db_column_exists', fn ($key) => $key === 'plugin_monitor_dashboards.url', true); monitor_test_mock_db('db_fetch_assoc', 'plugin_monitor_dashboards', [ ['id' => 1, 'url' => 'monitor.php?grouping=site&view=tiles'], ]); monitor_migrate_dashboard_properties(); $updates = array_values(array_filter($GLOBALS['__test_db_calls'], fn ($c) => $c['fn'] === 'db_execute_prepared')); $removed = array_filter($GLOBALS['__test_db_calls'], fn ($c) => $c['fn'] === 'db_remove_column' && $c['column'] === 'url'); expect($removed)->not->toBeEmpty(); expect($updates)->not->toBeEmpty(); expect($updates[0]['params'][0])->toContain('"grouping":"site"'); }); it('skips dashboard migration when the url column is already gone', function () { monitor_test_reset_db_mocks(); $GLOBALS['__test_db_calls'] = array(); monitor_test_mock_db('db_table_exists', 'plugin_monitor_dashboards', true); monitor_test_mock_db('db_column_exists', fn ($key) => $key === 'plugin_monitor_dashboards.properties', true); monitor_migrate_dashboard_properties(); $removed = array_filter($GLOBALS['__test_db_calls'], fn ($c) => $c['fn'] === 'db_remove_column'); expect($removed)->toBeEmpty(); });