1<?php
2
3namespace Tests\Icinga\Module\Director\Objects;
4
5use Icinga\Module\Director\IcingaConfig\IcingaConfig;
6use Icinga\Module\Director\Objects\IcingaHost;
7use Icinga\Module\Director\Objects\IcingaService;
8use Icinga\Module\Director\Test\BaseTestCase;
9
10class IcingaServiceTest extends BaseTestCase
11{
12    protected $testHostName = '___TEST___host';
13
14    protected $testServiceName = '___TEST___service';
15
16    protected $createdServices = array();
17
18    public function testUnstoredHostCanBeLazySet()
19    {
20        $service = $this->service();
21        $service->display_name = 'Something else';
22        $service->host = 'not yet';
23        $this->assertEquals(
24            'not yet',
25            $service->host
26        );
27    }
28
29    /**
30     * @expectedException \RuntimeException
31     */
32    public function testFailsToStoreWithMissingLazyRelations()
33    {
34        if ($this->skipForMissingDb()) {
35            return;
36        }
37
38        $db = $this->getDb();
39        $service = $this->service();
40        $service->display_name = 'Something else';
41        $service->host = 'not yet';
42        $service->store($db);
43        $service->delete();
44    }
45
46    public function testAcceptsAssignRules()
47    {
48        $service = $this->service();
49        $service->object_type = 'apply';
50        $service->assign_filter = 'host.address="127.*"';
51    }
52
53    /**
54     * @expectedException \LogicException
55     */
56    public function testRefusesAssignRulesWhenNotBeingAnApply()
57    {
58        $service = $this->service();
59        $service->assign_filter = 'host.address=127.*';
60    }
61
62    public function testAcceptsAndRendersFlatAssignRules()
63    {
64        if ($this->skipForMissingDb()) {
65            return;
66        }
67
68        $db = $this->getDb();
69
70        $service = $this->service();
71
72        // Service apply rule rendering requires access to settings:
73        $service->setConnection($db);
74        $service->object_type = 'apply';
75        $service->assign_filter = 'host.address="127.*"|host.vars.env="test"';
76
77        $this->assertEquals(
78            $this->loadRendered('service1'),
79            (string) $service
80        );
81
82        $this->assertEquals(
83            'host.address="127.*"|host.vars.env="test"',
84            $service->assign_filter
85        );
86    }
87
88    public function testAcceptsAndRendersStructuredAssignRules()
89    {
90        if ($this->skipForMissingDb()) {
91            return;
92        }
93
94        $db = $this->getDb();
95
96        $service = $this->service();
97        // Service apply rule rendering requires access to settings:
98        $service->setConnection($db);
99        $service->object_type = 'apply';
100        $service->assign_filter = 'host.address="127.*"|host.vars.env="test"';
101
102        $this->assertEquals(
103            $this->loadRendered('service1'),
104            (string) $service
105        );
106
107        $this->assertEquals(
108            'host.address="127.*"|host.vars.env="test"',
109            $service->assign_filter = 'host.address="127.*"|host.vars.env="test"'
110        );
111    }
112
113    public function testPersistsAssignRules()
114    {
115        if ($this->skipForMissingDb()) {
116            return;
117        }
118
119        $db = $this->getDb();
120
121        $service = $this->service();
122        $service->object_type = 'apply';
123        $service->assign_filter = 'host.address="127.*"|host.vars.env="test"';
124
125        $service->store($db);
126
127        $service = IcingaService::loadWithAutoIncId($service->id, $db);
128        $this->assertEquals(
129            $this->loadRendered('service1'),
130            (string) $service
131        );
132
133        $this->assertEquals(
134            'host.address="127.*"|host.vars.env="test"',
135            $service->assign_filter
136        );
137
138        $service->delete();
139    }
140
141    public function testRendersToTheCorrectZone()
142    {
143        if ($this->skipForMissingDb()) {
144            return;
145        }
146
147        $db = $this->getDb();
148        $service = $this->service()->setConnection($db);
149
150        $config = new IcingaConfig($db);
151        $service->renderToConfig($config);
152        $masterzone = $db->getMasterZoneName();
153        $this->assertEquals(
154            array('zones.d/' . $masterzone . '/services.conf'),
155            $config->getFileNames()
156        );
157    }
158
159    public function testVariablesInPropertiesAndCustomVariables()
160    {
161        if ($this->skipForMissingDb()) {
162            return;
163        }
164
165        $db = $this->getDb();
166
167        $service = $this->service('___TEST___service_$not_replaced$');
168        $service->setConnection($db);
169        $service->object_type = 'apply';
170        $service->display_name = 'Service: $host.vars.replaced$';
171        $service->assign_filter = 'host.address="127.*"';
172        $service->{'vars.custom_var'} = '$host.vars.replaced$';
173
174        $this->assertEquals(
175            $this->loadRendered('service3'),
176            (string) $service
177        );
178    }
179
180    public function testVariablesAreNotReplacedForNonApplyObjects()
181    {
182        if ($this->skipForMissingDb()) {
183            return;
184        }
185
186        $db = $this->getDb();
187
188        $host = $this->host();
189        $host->store($db);
190
191        $service = $this->service('___TEST___service_$not_replaced$');
192        $service->object_type = 'object';
193        $service->host_id = $host->get('id');
194        $service->display_name = 'Service: $host.vars.not_replaced$';
195        $service->{'vars.custom_var'} = '$host.vars.not_replaced$';
196        $service->store($db);
197
198        $service = IcingaService::loadWithAutoIncId($service->id, $db);
199        $this->assertEquals(
200            $this->loadRendered('service4'),
201            (string) $service
202        );
203    }
204
205    public function testApplyForRendersInVariousModes()
206    {
207        if ($this->skipForMissingDb()) {
208            return;
209        }
210
211        $db = $this->getDb();
212
213        $service = $this->service()->setConnection($db);
214        $service->object_type = 'apply';
215        $service->apply_for = 'host.vars.test1';
216        $service->assign_filter = 'host.vars.env="test"';
217        $this->assertEquals(
218            $this->loadRendered('service5'),
219            (string) $service
220        );
221
222        $service->object_name = '___TEST$config$___service $host.var.bla$';
223        $this->assertEquals(
224            $this->loadRendered('service6'),
225            (string) $service
226        );
227
228        $service->object_name = '';
229        $this->assertEquals(
230            $this->loadRendered('service7'),
231            (string) $service
232        );
233    }
234
235    protected function host()
236    {
237        return IcingaHost::create(array(
238            'object_name'  => $this->testHostName,
239            'object_type'  => 'object',
240            'address'      => '127.0.0.1',
241        ));
242    }
243
244    protected function service($objectName = null)
245    {
246        if ($objectName === null) {
247            $objectName = $this->testServiceName;
248        }
249        $this->createdServices[] = $objectName;
250        return IcingaService::create(array(
251            'object_name'  => $objectName,
252            'object_type'  => 'object',
253            'display_name' => 'Whatever service',
254            'vars'         => array(
255                'test1' => 'string',
256                'test2' => 17,
257                'test3' => false,
258                'test4' => (object) array(
259                    'this' => 'is',
260                    'a' => array(
261                        'dict',
262                        'ionary'
263                    )
264                )
265            )
266        ));
267    }
268
269    protected function loadRendered($name)
270    {
271        return file_get_contents(__DIR__ . '/rendered/' . $name . '.out');
272    }
273
274    public function tearDown()
275    {
276        if ($this->hasDb()) {
277            $db = $this->getDb();
278            $kill = array($this->testHostName);
279            foreach ($kill as $name) {
280                if (IcingaHost::exists($name, $db)) {
281                    IcingaHost::load($name, $db)->delete();
282                }
283            }
284
285            $kill = $this->createdServices;
286            foreach ($kill as $name) {
287                if (IcingaService::exists(array($name), $db)) {
288                    IcingaService::load($name, $db)->delete();
289                }
290            }
291        }
292    }
293}
294