fixes tests for samba ad
[tine20] / tests / tine20 / Admin / CliTest.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Admin
6  * @license     http://www.gnu.org/licenses/agpl.html
7  * @copyright   Copyright (c) 2009-2016 Metaways Infosystems GmbH (http://www.metaways.de)
8  * @author      Philipp Schüle <p.schuele@metaways.de>
9  */
10
11 /**
12  * Test class for Tinebase_Admin
13  */
14 class Admin_CliTest extends TestCase
15 {
16     /**
17      * Backend
18      *
19      * @var Admin_Frontend_Cli
20      */
21     protected $_cli;
22     
23     /**
24      * @var array test objects
25      */
26     protected $objects = array();
27
28
29     /**
30      * config groups
31      * 
32      */
33     protected $_testGroup = array();
34     
35     /**
36      * @var Tinebase_Record_RecordSet
37      */
38     protected $_groupsToDelete = null;
39
40     /**
41      * Sets up the fixture.
42      * This method is called before a test is executed.
43      *
44      * @access protected
45      */
46     protected function setUp()
47     {
48         parent::setUp();
49         
50         $this->_cli = new Admin_Frontend_Cli();
51         
52         $this->_usernamesToDelete = array('hmaster', 'hmeister', 'hmoster', 'irmeli', 'testuser', 'm.muster');
53
54         $this->_groupsToDelete = new Tinebase_Record_RecordSet('Tinebase_Model_Group');
55         $testGroups = array('domainuser', 'teacher', 'student');
56         foreach ($testGroups as $group) {
57             try {
58                 $this->_testGroup[$group] = Tinebase_Group::getInstance()->create(new Tinebase_Model_Group(array(
59                     'name' => $group
60                 )));
61             } catch (Exception $e) {
62                 $this->_testGroup[$group] = Tinebase_Group::getInstance()->getGroupByName($group);
63             }
64             $this->_groupsToDelete->addRecord($this->_testGroup[$group]);
65         }
66
67         $this->objects['config'] = '<?xml version="1.0" encoding="UTF-8"?>
68         <config>
69             <dryrun>0</dryrun>
70             <encoding>ISO-8859-1</encoding>
71             <mapping>
72                 <field>
73                     <source>firstname</source>
74                     <destination>accountFirstName</destination>
75                 </field>
76                 <field>
77                     <source>lastname</source>
78                     <destination>accountLastName</destination>
79                 </field>
80                 <field>
81                     <source>loginname</source>
82                     <destination>accountLoginName</destination>
83                 </field>
84                 <field>
85                     <source>password</source>
86                     <destination>password</destination>
87                 </field>
88                 <field>
89                     <source>email</source>
90                     <destination>accountEmailAddress</destination>
91                 </field>
92             </mapping>
93         </config>';
94         
95         $this->objects['configWithHeadline'] = '<?xml version="1.0" encoding="UTF-8"?>
96         <config>
97             <headline>1</headline>
98             <dryrun>0</dryrun>
99             <encoding>ISO-8859-1</encoding>
100             <mapping>
101                 <field>
102                     <source>firstname</source>
103                     <destination>accountFirstName</destination>
104                 </field>
105                 <field>
106                     <source>lastname</source>
107                     <destination>accountLastName</destination>
108                 </field>
109                 <field>
110                     <source>loginname</source>
111                     <destination>accountLoginName</destination>
112                 </field>
113                 <field>
114                     <source>password</source>
115                     <destination>password</destination>
116                 </field>
117                 <field>
118                     <source>email</source>
119                     <destination>accountEmailAddress</destination>
120                 </field>
121             </mapping>
122         </config>';
123         
124         $this->objects['configSemicolon'] = '<?xml version="1.0" encoding="UTF-8"?>
125         <config>
126             <model>Tinebase_Model_FullUser</model>
127             <plugin>Admin_Import_User_Csv</plugin>
128             <type>import</type>
129             <headline>1</headline>
130             <dryrun>0</dryrun>
131             <extension>csv</extension>
132             <delimiter>;</delimiter>
133             <mapping>
134             <field>
135                     <source>firstname</source>
136                     <destination>accountFirstName</destination>
137                 </field>
138                 <field>
139                     <source>lastname</source>
140                     <destination>accountLastName</destination>
141                 </field>
142                 <field>
143                     <source>loginname</source>
144                     <destination>accountLoginName</destination>
145                 </field>
146                 <field>
147                     <source>password</source>
148                     <destination>password</destination>
149                 </field>
150                 <field>
151                     <source>email</source>
152                     <destination>accountEmailAddress</destination>
153                 </field>
154             </mapping>
155         </config>';
156         $this->objects['configEmailuser'] = '<?xml version="1.0" encoding="UTF-8"?>
157         <config>
158             <model>Tinebase_Model_FullUser</model>
159             <plugin>Admin_Import_User_Csv</plugin>
160             <type>import</type>
161             <headline>1</headline>
162             <dryrun>0</dryrun>
163             <extension>csv</extension>
164             <mapping>
165                 <field>
166                     <source>firstname</source>
167                     <destination>accountFirstName</destination>
168                 </field>
169                 <field>
170                     <source>lastname</source>
171                     <destination>accountLastName</destination>
172                 </field>
173                 <field>
174                     <source>loginname</source>
175                     <destination>accountLoginName</destination>
176                 </field>
177                 <field>
178                     <source>password</source>
179                     <destination>password</destination>
180                 </field>
181                 <field>
182                     <source>email</source>
183                     <destination>accountEmailAddress</destination>
184                 </field>
185                 <field>
186                     <source>emailAliases</source> <!-- leerzeichen separator -->
187                     <destination>emailAliases</destination>
188                 </field>
189                 <field>
190                     <source>emailForwards</source>
191                     <destination>emailForwards</destination>
192                 </field>
193             </mapping>
194         </config>';
195           $this->objects['configAdvanced'] = '<?xml version="1.0" encoding="UTF-8"?>
196         <config>
197            <model>Tinebase_Model_FullUser</model>
198            <plugin>Admin_Import_Csv</plugin>
199            <type>import</type>
200            <headline>1</headline>
201            <dryrun>0</dryrun>
202            <delimiter>,</delimiter>
203            <mapping>
204                <field>
205                    <source>firstname</source>
206                    <destination>accountFirstName</destination>
207                </field>
208                <field>
209                    <source>lastname</source>
210                    <destination>accountLastName</destination>
211                </field>
212                <field>
213                    <source>objectname</source>
214                    <destination>accountLoginName</destination>
215                </field>
216                <field>
217                    <source>password</source>
218                    <destination>password</destination>
219                </field>
220                <field>
221                    <source>primary_group_id</source>
222                    <destination>accountPrimaryGroup</destination>
223                </field>
224                <field>
225                    <source>additional_groups</source>
226                    <destination>groups</destination>
227                </field>
228               <field>
229                    <source>accountHomeDirectory</source>
230                    <destination>accountHomeDirectory</destination>
231                </field>
232                <field>
233                    <source>accountHomeDirectoryPrefix</source>
234                    <destination>accountHomeDirectoryPrefix</destination>
235                </field>
236                <field>
237                    <source>accountLoginShell</source>
238                    <destination>accountLoginShell</destination>
239                </field>
240                <field>
241                    <source>homePath</source>
242                    <destination>homePath</destination>
243                </field>
244                <field>
245                    <source>homeDrive</source>
246                    <destination>homeDrive</destination>
247                </field>
248                <field>
249                    <source>logonScript</source>
250                    <destination>logonScript</destination>
251                </field>
252                <field>
253                    <source>profilePath</source>
254                    <destination>profilePath</destination>
255                </field>
256            </mapping>
257         </config>';
258     }
259     
260     /**
261      * Tears down the fixture
262      * This method is called after a test is executed.
263      *
264      * @access protected
265      */
266     protected function tearDown()
267     {
268         $this->_groupIdsToDelete = $this->_groupsToDelete->getArrayOfIds();
269         parent::tearDown();
270     }
271     
272     /**
273      * test to import admin users
274      *
275      */
276     public function testImportUsers()
277     {
278         $out = $this->_importUsers($this->objects['config'], dirname(__FILE__) . '/files/test.csv', 'admin_user_import_csv_test');
279         $this->_checkResult($out);
280     }
281     
282     /**
283      * import users
284      *
285      * @param string $_config xml config
286      * 
287      * @see 0008300: Import User via CLI don't import all fields
288      */
289     protected function _importUsers($_config, $_filename, $_definition)
290     {
291         // create definition / check if exists
292         try {
293             $definition = Tinebase_ImportExportDefinition::getInstance()->getByName($_definition);
294             $definition->plugin_options = $_config;
295         } catch (Tinebase_Exception_NotFound $e) {
296             $definition = Tinebase_ImportExportDefinition::getInstance()->create(new Tinebase_Model_ImportExportDefinition(array(
297                 'application_id'    => Tinebase_Application::getInstance()->getApplicationByName('Admin')->getId(),
298                 'name'              => $_definition,
299                 'type'              => 'import',
300                 'model'             => 'Tinebase_Model_FullUser',
301                 'plugin'            => 'Admin_Import_User_Csv',
302                 'plugin_options'    => $_config
303             )));
304         }
305         
306         $tempFilename = TestServer::replaceEmailDomainInFile($_filename);
307         
308         $opts = new Zend_Console_Getopt('abp:');
309         $opts->setArguments(array($tempFilename, 'definition=' . $_definition));
310         
311         // start import (dry run)
312         ob_start();
313         $this->_cli->importUser($opts);
314         $out = ob_get_clean();
315         
316         return $out;
317     }
318     
319     /**
320      * check import result
321      * 
322      * @param string $out
323      */
324     protected function _checkResult($out, $username = 'hmoster')
325     {
326         // check output
327         if ($username == 'hmoster') {
328             $this->assertEquals("Imported 3 records. Import failed for 0 records. \n", $out);
329         } else {
330             $this->assertEquals("Imported 1 records. Import failed for 2 records. \n", $out);
331         }
332         
333         // check if users (with their data) have been added to tine20
334         $user = Tinebase_User::getInstance()->getFullUserByLoginName($username);
335         if ($username == 'hmoster') {
336             $this->assertEquals('Hins', $user->accountFirstName);
337         }
338         $maildomain = TestServer::getPrimaryMailDomain();
339         $this->assertEquals($username . '@' . $maildomain, $user->accountEmailAddress);
340     }
341
342     /**
343      * test to import admin users
344      */
345     public function testImportUsersWithHeadline()
346     {
347         $out = $this->_importUsers($this->objects['configWithHeadline'], dirname(__FILE__) . '/files/testHeadline.csv', 'admin_user_import_csv_test_headline');
348         $this->_checkResult($out);
349     }
350     
351     /**
352      * testImportUsersWithEmailAndSemicolon
353      * 
354      * @see 0008300: Import User via CLI don't import all fields
355      */
356     public function testImportUsersWithEmailAndSemicolon()
357     {
358         $out = $this->_importUsers($this->objects['configSemicolon'], dirname(__FILE__) . '/files/tine_user3.csv', 'admin_user_import_csv_test_semicolon');
359         $this->_checkResult($out, 'irmeli');
360     }
361     
362     /**
363      * testImportUsersWithEmailUser
364      */
365     public function testImportUsersWithEmailUser()
366     {
367         $userBackend = Tinebase_User::getInstance();
368         $maildomain = TestServer::getPrimaryMailDomain();
369
370         $readFile = fopen(dirname(__FILE__) . '/files/tine_user5.csv', 'r');
371         $writeFile = fopen('test.csv', 'w');
372         $delimiter = ',';
373         $enclosure = '"';
374         
375         while (($row = fgetcsv($readFile)) !== false) {
376             foreach ($row as $colIndex => &$field) {
377                 $field = str_replace('DOMAIN', $maildomain, $field);
378             }
379             fputcsv($writeFile, $row, $delimiter, $enclosure);
380         }
381         
382         fclose($readFile);
383         fclose($writeFile);
384         
385         if (! array_key_exists('Tinebase_EmailUser_Smtp_Postfix', $userBackend->getPlugins())) {
386             $this->markTestSkipped('Postfix SQL plugin not enabled');
387         }
388         
389         $this->_importUsers($this->objects['configEmailuser'], 'test.csv', 'admin_user_import_csv_test_emailuser');
390         $newUser = $userBackend->getFullUserByLoginName('testuser');
391         $this->assertEquals(array('contact@' . $maildomain, 'kontakt@' . $maildomain), $newUser->smtpUser->emailAliases);
392         $this->assertEquals(array('test@' . $maildomain), $newUser->smtpUser->emailForwards);
393         $this->assertTrue($newUser->smtpUser->emailForwardOnly);
394         unlink("test.csv");
395     }
396     
397     /**
398      * testImportUsersAdvanced
399      */
400     public function testImportUsersAdvanced()
401     {
402         $userBackend = Tinebase_User::getInstance();
403         
404         $readFile = fopen(dirname(__FILE__) . '/files/test_teacher.csv', 'r');
405         $writeFile = fopen('test2.csv', 'w');
406         $delimiter = ',';
407         $enclosure = '"';
408         
409         while (($row = fgetcsv($readFile)) !== false) {
410             foreach ($row as $colIndex => &$field) {
411                 $field = str_replace('PRIMARYGROUP', $this->_testGroup['domainuser']->getId(), $field);
412                 $field = str_replace('GROUP1', $this->_testGroup['teacher']->getId(), $field);
413                 $field = str_replace('GROUP2', $this->_testGroup['student']->getId(), $field);
414             }
415             fputcsv($writeFile, $row, $delimiter, $enclosure);
416         }
417         
418         fclose($readFile);
419         fclose($writeFile);
420         
421         $this->_importUsers($this->objects['configAdvanced'], 'test2.csv', 'admin_user_import_csv_test_advanced');
422         $newUser = Tinebase_User::getInstance()->getFullUserByLoginName('m.muster');
423         
424         $newUserMemberships = Tinebase_Group::getInstance()->getGroupMemberships($newUser);
425         $this->assertTrue(in_array($this->_testGroup['domainuser']->getId(), $newUserMemberships),
426         ' not member of the domainuser group (' . $this->_testGroup['domainuser']->getId() . ') ' . print_r($newUserMemberships, TRUE));
427         $this->assertTrue(in_array($this->_testGroup['student']->getId(), $newUserMemberships),
428         ' not member of the student group (' . $this->_testGroup['student']->getId() . ') ' . print_r($newUserMemberships, TRUE));
429         $this->assertTrue(in_array($this->_testGroup['teacher']->getId(), $newUserMemberships),
430         ' not member of the teacher group (' . $this->_testGroup['teacher']->getId() . ') ' . print_r($newUserMemberships, TRUE));
431         
432         $this->assertEquals('/bin/false', $newUser->accountLoginShell);
433         $this->assertEquals('/storage/lehrer/m.muster', $newUser->accountHomeDirectory);
434         
435         if (array_key_exists('Tinebase_User_Plugin_Samba', $userBackend->getPlugins())) {
436             $this->assertEquals('\\fileserver\profiles\m.muster', $newUser->sambaSAM->profilePath);
437         }
438         unlink("test2.csv");
439     }
440     
441     /**
442      * tests if import with members from csv works correctly
443      */
444     public function testImportGroups()
445     {
446         $opts = new Zend_Console_Getopt('abp:');
447         $opts->setArguments(array(dirname(__FILE__) . '/files/import_groups.csv', 'definition=admin_group_import_csv'));
448         
449         // start import (dry run)
450         ob_start();
451         $this->_cli->importGroups($opts);
452         $out = ob_get_clean();
453         $this->assertStringStartsWith('Imported 4 records.', $out);
454         
455         $expected = array('men' => 3, 'women' => 2, 'highperformers' => 2, 'lowperformers' => 3);
456         $this->_testImportGroupsHelper($expected);
457         
458         $opts->setArguments(array(dirname(__FILE__) . '/files/import_groups_update.csv', 'definition=admin_group_import_csv'));
459         ob_start();
460         $this->_cli->importGroups($opts);
461         $out = ob_get_clean();
462         $this->assertStringStartsWith('Imported 0 records.', $out);
463         
464         $expected = array('men' => 3, 'women' => 2,  'lowperformers' => 2, 'highperformers' => 3);
465         $this->_testImportGroupsHelper($expected);
466     }
467     
468     protected function _testImportGroupsHelper($expected)
469     {
470         $be = new Tinebase_Group_Sql();
471         
472         foreach($expected as $name => $count) {
473             $group = $be->getGroupByName($name);
474             $members = $be->getGroupMembers($group);
475         
476             $this->assertEquals($count, count($members), 'Group ' . $name . ' should have ' . $count . ' members!');
477             $this->assertEquals('displayed', $group->visibility, 'Group ' . $name . ' should be visible!');
478         }
479     }
480 }