Merge branch 'maint/7.0'
[ninja.git] / test / unit_test / tests / report_Test.php
blob357ace8e8eaec14ceb141de305a8ba3fe30ef3cd
1 <?php
2 class report_Test extends PHPUnit_Framework_TestCase {
3 public function setUp() {
4 $this->auth = Auth::instance(array('session_key' => false))->force_user(new Op5User_AlwaysAuth());
7 public function test_restricted_access() {
8 /* Store old user, so we can reset afterward */
9 $authmod = Auth::instance();
10 $stasheduser = $authmod->get_user();
12 /* Setup limited user, we can't replace the user, but only it's
13 * content. Singleton objects stashes the user object
15 $authmod->force_user($user = new Op5User_AlwaysAuth());
16 $user->set_authorized_for('host_view_all', false);
17 $user->set_authorized_for('service_view_all', false);
18 $user->set_authorized_for('hostgroup_view_all', false);
19 $user->set_authorized_for('servicegroup_view_all', false);
20 $user->username = 'limited';
22 /* Run test */
24 $opts = new Alert_history_options(array('start_time'=>0, 'end_time'=>time()));
25 $querym = new Report_query_builder_Model('report_data', $opts);
27 /* We're not interested in filtering anything, just see the permissions.
28 * Therefore, treat it as an API-call
30 $query = $querym->build_alert_summary_query();
32 /* This string should represent the filter to filter out only allowed
33 * objects
36 $substr = "AND "
37 ."("
38 ."((host_name IN ('monitor')) AND (service_description = ''))"
39 ." OR "
40 ."((host_name, service_description) IN ("
41 ."('host_down_acknowledged', 'service critical'), "
42 ."('host_down_notifications_disabled', 'service ok scheduled'), "
43 ."('monitor', 'Disk usage /'), "
44 ."('monitor', 'Local hardware status'), "
45 ."('monitor', 'MySQL'), "
46 ."('monitor', 'SSH'), "
47 ."('monitor', 'Swap Usage'), "
48 ."('monitor', 'System Load'), "
49 ."('monitor', 'Users'), "
50 ."('monitor', 'Zombie Processes'), "
51 ."('monitor', 'cron process'), "
52 ."('monitor', 'syslogd process')"
53 ."))"
54 .")";
56 $this->assertTrue(strpos($query, $substr) !== false, 'Could not find permission check substring in query');
58 try {
59 $db = Database::instance();
60 $dbr = $db->query('EXPLAIN '.$query);
61 } catch( Kohana_Database_Exception $e ) {
62 $this->fail("Could not run query: ".$e->getMessage());
66 /* Reset user */
67 $authmod->force_user($stasheduser);
70 public function test_overlapping_timeperiods() {
71 $db = Database::instance();
72 $opts = array(
73 'start_time' => strtotime('1999-01-01'),
74 'end_time' => strtotime('2012-01-01'),
75 'rpttimeperiod' => 'weird-stuff');
76 Old_Timeperiod_Model::$precreated = array();
77 $report = Old_Timeperiod_Model::instance($opts);
78 $report->resolve_timeperiods();
79 $this->assertNotEmpty($report->tp_exceptions, 'There should be timeperiod exceptions, based on '.var_export($db->query('SELECT * FROM timeperiod inner join custom_vars on obj_id=id where timeperiod_name="weird-stuff"')->result_array(false), true));
80 // fixme: validate output
83 private function run_and_diag() {
84 $opts = new Avail_options(array('start_time' => 0, 'end_time' => time()));
85 $db = Database::instance();
86 $msg = '';
87 if ($this->auth->authorized_for('host_view_all'))
88 $msg .= ' with host_view_all';
89 if ($this->auth->authorized_for('service_view_all'))
90 $msg .= ' with service_view_all';
92 $out = Livestatus::instance()->getHosts(array('columns' => array('name')));
93 $res = array();
94 foreach ($out as $row) {
95 $res[] = $row['name'];
97 $opts['report_type'] = 'hosts';
98 $opts['objects'] = $res;
99 $result = array();
100 for ($host_state = 1; $host_state <= 7; $host_state++) {
101 $opts['host_states'] = $host_state;
102 for ($service_state = 1; $service_state <= 15; $service_state++) {
103 $opts['service_states'] = $service_state;
104 for ($state_types = 1; $state_types <= 3; $state_types++) {
105 $opts['state_types'] = $state_types;
106 for ($alert_types = 1; $alert_types <= 3; $alert_types++) {
107 $opts['alert_types'] = $alert_types;
108 $rpt = new Report_query_builder_Model('report_data', $opts);
109 $query = $rpt->build_alert_summary_query();
110 $this->assertInternalType('string', $query, "No query returned when $msg for host_state:$host_state;service_state:$service_state;state_type:$state_types;alert_types:$alert_types");
111 $this->assertObjectHasAttribute('select_type', $db->query("EXPLAIN " . $query)->current());
118 public function test_run_summary_test_queries() {
119 $this->auth->set_authorized_for('host_view_all', true);
120 $this->auth->set_authorized_for('service_view_all', true);
121 $this->run_and_diag();
123 $this->auth->set_authorized_for('host_view_all', true);
124 $this->auth->set_authorized_for('service_view_all', false);
125 $this->run_and_diag();
127 $this->auth->set_authorized_for('host_view_all', false);
128 $this->auth->set_authorized_for('service_view_all', true);
129 $this->run_and_diag();
131 $this->auth->set_authorized_for('host_view_all', false);
132 $this->auth->set_authorized_for('service_view_all', false);
133 $this->run_and_diag();
137 * Very important to not change, since the HTTP API
138 * relies on this.
140 function test_event_types()
142 $events = array(
143 Reports_Model::PROCESS_SHUTDOWN => 'monitor_shut_down',
144 Reports_Model::PROCESS_RESTART => 'monitor_restart',
145 Reports_Model::PROCESS_START => 'monitor_start',
146 Reports_Model::SERVICECHECK => 'service_alert',
147 Reports_Model::HOSTCHECK => 'host_alert',
148 Reports_Model::DOWNTIME_START => 'scheduled_downtime_start',
149 Reports_Model::DOWNTIME_STOP => 'scheduled_downtime_stop'
151 foreach($events as $code => $event) {
152 $this->assertEquals($event, Reports_Model::event_type_to_string($code, null, true), sprintf("Unmatching strings: [%s] != [%s]", $event, Reports_Model::event_type_to_string($code, null, true)));
157 * To begin with, test bug #6821
161 * Test bug #8602
163 * Store a filter, with same name as an hostgroup. The hostgroup should be used, and shouldn't be affected by the filter
165 function test_saved_filter_hostgroup_collission() {
167 try {
168 /* Mock a saved query */
169 LSFilter_Saved_Queries_Model::save_query('hostgroup_all', '[hosts] not all', 'global');
171 $the_opts = array(
172 'report_name' => 'TEST_REPORT',
173 'report_type' => 'hostgroups',
174 'hostgroup_name' => array('hostgroup_all'),
175 'report_period' => 'custom',
176 'start_time' => time() - 3600,
177 'end_time' => time(),
179 $opts = new Avail_Options();
180 foreach ($the_opts as $k => $v) {
181 $opts[$k] = $v;
184 /* The hostgroup represents all hosts, the filter represents none, so lets se that we get some hosts */
185 $this->assertNotEmpty($opts->get_report_members());
186 } catch(Exception $e) {
187 /* Just so we can clean up */
188 $db = Database::instance();
189 $dbr = $db->query('DELETE FROM '.LSFilter_Saved_Queries_Model::tablename.' WHERE filter_name="hostgroup_all"');
190 throw $e;
192 /* Clean up... PHP 5.5 is the first to have try {} catch {} finally {do this cleanup}, so copy/paste */
193 $db = Database::instance();
194 $dbr = $db->query('DELETE FROM '.LSFilter_Saved_Queries_Model::tablename.' WHERE filter_name="hostgroup_all"');
198 * Test bug #8602
200 * Store a filter, with same name as an hostgroup. The hostgroup should be used, and shouldn't be affected by the filter
202 function test_saved_filter_servicegroup_collission() {
204 try {
205 /* Mock a saved query */
206 LSFilter_Saved_Queries_Model::save_query('servicegroup_all', '[services] not all', 'global');
208 $the_opts = array(
209 'report_name' => 'TEST_REPORT',
210 'report_type' => 'servicegroups',
211 'servicegroup_name' => array('servicegroup_all'),
212 'report_period' => 'custom',
213 'start_time' => time() - 3600,
214 'end_time' => time(),
216 $opts = new Avail_Options();
217 foreach ($the_opts as $k => $v) {
218 $opts[$k] = $v;
221 /* The hostgroup represents all hosts, the filter represents none, so lets se that we get some hosts */
222 $this->assertNotEmpty($opts->get_report_members());
223 } catch(Exception $e) {
224 /* Just so we can clean up */
225 $db = Database::instance();
226 $dbr = $db->query('DELETE FROM '.LSFilter_Saved_Queries_Model::tablename.' WHERE filter_name="servicegroup_all"');
227 throw $e;
229 /* Clean up... PHP 5.5 is the first to have try {} catch {} finally {do this cleanup}, so copy/paste */
230 $db = Database::instance();
231 $dbr = $db->query('DELETE FROM '.LSFilter_Saved_Queries_Model::tablename.' WHERE filter_name="servicegroup_all"');
235 * The expectation is that - like regular reports - CSV reports should have
236 * one line per host if it's a host report, one per service if it's a
237 * service report, one per host if it's a hostgroup report, one per
238 * service if it's a servicegroup report.
240 * Unless it's a SLA, then we want one line per month always, unless it's a
241 * multi-group-thingy, then we want one line per month and group - for the
242 * record, I'm object to this whole specialcase-multigroup-logic.
244 * When a host belongs to two groups, we will print it once per group. This is
245 * funny, but anything else becomes weird.
247 * We also need to remember to test the single-obj-case vs multi-obj-case,
248 * because those have a tendency to be tricky.
250 * Because all those cases are boring to test, and the CSV output is easy
251 * to test, let's automate!
253 * We don't care about output, but almost anything that can go wrong will
254 * print errors on lines, which we implicitly catch here, so we should be OK
256 function test_csv()
258 $month = date('n') - 1;
259 if ($month < 1)
260 $month += 12;
261 $Avail_opts = array('output_format' => 'csv', 'report_period' => 'last7days');
262 $Sla_opts = array('output_format' => 'csv', 'report_period' => 'lastmonth', 'months' => array($month => 9));
263 $Avail_tests = array(
264 'single host' => array(
265 'obj' => array('report_type' => 'hosts', 'objects' => array('host_pending')),
266 'expected' => 2
268 'multi host' => array(
269 'obj' => array('report_type' => 'hosts', 'objects' => array('host_pending', 'host_up')),
270 'expected' => 3
272 'single service' => array(
273 'obj' => array('report_type' => 'services', 'objects' => array('host_pending;service critical')),
274 'expected' => 2
276 'multi service, same host' => array(
277 'obj' => array('report_type' => 'services', 'objects' => array('host_pending;service critical', 'host_pending;service ok')),
278 'expected' => 3
280 'multi service, different host' => array(
281 'obj' => array('report_type' => 'services', 'objects' => array('host_pending;service critical', 'host_up;service ok')),
282 'expected' => 3
284 'single hostgroup with two members' => array(
285 'obj' => array('report_type' => 'hostgroups', 'objects' => array('hostgroup_acknowledged')),
286 'expected' => 3
288 'multi hostgroups' => array(
289 'obj' => array('report_type' => 'hostgroups', 'objects' => array('hostgroup_acknowledged', 'hostgroup_all')),
290 'expected' => 26
292 'single servicegroup, 88 members' => array(
293 'obj' => array('report_type' => 'servicegroups', 'objects' => array('servicegroup_pending')),
294 'expected' => 89,
296 'multi servicegroups' => array(
297 'obj' => array('report_type' => 'servicegroups', 'objects' => array('servicegroup_pending', 'servicegroup_ok')),
298 'expected' => 111,
301 // @TODO: This is totally stupid and should be extended by setting report_period and months in
302 // obj below - but that becomes boring due to the current month (and thus its report period) being fluid
303 $Sla_tests = array(
304 'single host' => array(
305 'obj' => array('report_type' => 'hosts', 'objects' => array('host_pending')),
306 'expected' => 2
308 'multi host' => array(
309 'obj' => array('report_type' => 'hosts', 'objects' => array('host_pending', 'host_up')),
310 'expected' => 2
312 'single service' => array(
313 'obj' => array('report_type' => 'services', 'objects' => array('host_pending;service critical')),
314 'expected' => 2
316 'multi service, same host' => array(
317 'obj' => array('report_type' => 'services', 'objects' => array('host_pending;service critical', 'host_pending;service ok')),
318 'expected' => 2
320 'multi service, different host' => array(
321 'obj' => array('report_type' => 'services', 'objects' => array('host_pending;service critical', 'host_up;service ok')),
322 'expected' => 2
324 'single hostgroup with two members' => array(
325 'obj' => array('report_type' => 'hostgroups', 'objects' => array('hostgroup_acknowledged')),
326 'expected' => 2
328 'multi hostgroups' => array(
329 'obj' => array('report_type' => 'hostgroups', 'objects' => array('hostgroup_acknowledged', 'hostgroup_all')),
330 'expected' => 3
332 'single servicegroup, 88 members' => array(
333 'obj' => array('report_type' => 'servicegroups', 'objects' => array('servicegroup_pending')),
334 'expected' => 2,
336 'multi servicegroups' => array(
337 'obj' => array('report_type' => 'servicegroups', 'objects' => array('servicegroup_pending', 'servicegroup_ok')),
338 'expected' => 3,
341 foreach (array('Avail', 'Sla') as $report_type) {
342 foreach (${$report_type.'_tests'} as $test_name => $details) {
343 $ctrl_class = $report_type.'_Controller';
344 $opt_class = $report_type.'_options';
345 $ctrl = new $ctrl_class();
346 $ctrl->auto_render = false;
347 $option = new $opt_class();
348 $this->assertTrue($option->set_options(${$report_type.'_opts'}), "Setting initial options for $report_type $test_name should be fine");
349 foreach ($details['obj'] as $k => $v) {
350 $this->assertTrue($option->set($k, $v), "Setting $k for $report_type $test_name should work");
352 $ctrl->generate($option);
353 $out = $ctrl->template->render();
355 $this->assertEquals(count(explode("\n", trim($out))), $details['expected'], "Unexpected number of lines generated for $report_type $test_name, output was: $out");
356 $this->assertSame(strpos($out, '""'), false, "Expected no empty parameters for $report_type $test_name, found in $out");
357 if ($report_type != 'Sla' || $option['report_type'] != 'services') # Because that case has comma-separated host-and-description names. Obviously.
358 $this->assertSame(strpos($out, ';'), false, "Expected no semi-colons in output for $report_type $test_name, found in $out");
363 function test_discover_sla_options() {
364 $input = array(
365 'report_period' => 'custom',
366 'start_year' => 2013,
367 'start_month' => 2,
368 'end_year' => 2013,
369 'end_month' => 2
371 $output = Sla_options::discover_options($input);
372 $this->assertEquals(date('Y-m-d H:i:s', $output['start_time']), '2013-02-01 00:00:00', 'We should start on the first of Febuary');
373 $this->assertEquals(date('Y-m-d H:i:s', $output['end_time']), '2013-02-28 23:59:59', 'We should end on the last of Febuary');