source: trunk/server/www/app/models/testsuite.php @ 297

Last change on this file since 297 was 297, checked in by sander, 11 years ago

Generate and display jobs and results for test suites

File size: 9.9 KB
Line 
1<?php
2/**
3 * Officeshots.org - Test your office documents in different applications
4 * Copyright (C) 2009 Stichting Lone Wolves
5 * Written by Sander Marechal <s.marechal@jejik.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/**
22 * The Testsuite  model
23 */
24class Testsuite extends AppModel
25{
26        /** @var string Requests can be assigned a specific format, and every format maps to one or more mimetypes */
27        public $belongsTo = array('Gallery');
28
29        /**
30         * Synchronise all testsuite files to the database
31         */
32        public function synchronise()
33        {
34                $suites = $this->find('all');
35                foreach ($suites as &$suite) {
36                        $this->log(sprintf('Synchronising testsuite "%s"', $suite['Testsuite']['name']), LOG_DEBUG);
37                        $this->_syncGallery($suite['Testsuite']['id']);
38                        $this->_syncSource($suite['Testsuite']['id']);
39                }
40        }
41
42        /**
43         * Create or update the gallery belonging to the suite
44         * @param $suite_id The ID of the Testsuite
45         */
46        private function _syncGallery($suite_id)
47        {
48                $this->id = $suite_id;
49                $name     = $this->field('name');
50               
51                $this->Gallery->id = $this->field('gallery_id');
52                $gallery = $this->Gallery->read();
53
54                if ($gallery) {
55                        // Update the gallery
56                        if ($gallery['Gallery']['name'] != $name) {
57                                $this->Gallery->set('name', $name);
58                                $this->Gallery->save();
59                        }
60                } else {
61                        // Create a new gallery
62                        $this->Gallery->create();
63                        $this->Gallery->set(array(
64                                'name' => $name,
65                                'user_id' => Configure::read('Testsuite.user_id'),
66                                'group_id' => Configure::read('Testsuite.group_id'),
67                        ));
68                        $this->Gallery->save();
69
70                        $this->saveField('gallery_id', $this->Gallery->id);
71                       
72                        $this->log(sprintf('Created gallery "%s"', $name), LOG_DEBUG);
73                }
74        }
75
76        /**
77         * Synchronise the files in the source directory
78         * Note: It only adds new files and directories, it does not remove them!
79         *
80         * @param $suite_id The ID of the Testsuite
81         */
82        private function _syncSource($suite_id)
83        {
84                $this->id   = $suite_id;
85                $source     = $this->field('source');
86                $root       = $this->field('root');
87                $gallery_id = $this->field('gallery_id');
88
89                $this->_syncDirectory($source, $root, $gallery_id);
90        }
91
92        /**
93         * Synchronise a directory with a gallery
94         * @param string $path Path to the source directory
95         * @param string $root Root of the target directory
96         * @param int $gallery_id The Gallery that this directory is part of
97         */
98        private function _syncDirectory($path, $root, $gallery_id)
99        {
100                $this->log(sprintf('Synchronising gallery %s (%s to %s)', $gallery_id, $path, $root), LOG_DEBUG);
101
102                // Loop through all the subdirectories
103                $directories = glob(FILES . $path . DS . '*', GLOB_NOSORT | GLOB_ONLYDIR);
104                foreach ($directories as $directory) {
105                        // Skip testDoc directories in the Fellowship
106                        if (strtolower(substr($directory, -7)) == 'testdoc') {
107                                $this->_syncDirectory($path . DS . basename($directory), $root, $gallery_id);
108                                return;
109                        }
110
111                        $gallery_name = basename($directory);
112                        $gallery = $this->Gallery->find('first', array(
113                                'conditions' => array(
114                                        'Gallery.parent_id' => $gallery_id,
115                                        'Gallery.name' => $gallery_name,
116                                ),
117                        ));
118
119                        if ($gallery) {
120                                $this->Gallery->id = $gallery['Gallery']['id'];
121                        } else {
122                                $this->Gallery->create();
123                                $this->Gallery->set(array(
124                                        'name' => $gallery_name,
125                                        'parent_id' => $gallery_id,
126                                        'user_id' => Configure::read('Testsuite.user_id'),
127                                        'group_id' => Configure::read('Testsuite.group_id'),
128                                ));
129                                $this->Gallery->save();
130                               
131                                $this->log(sprintf('Created gallery %s: "%s"', $this->Gallery->id, $gallery_name), LOG_DEBUG);
132                        }
133
134                        $this->_syncDirectory($path . DS . basename($directory), $root . DS . basename($directory), $this->Gallery->id);
135                }
136
137                // Loop through all the files in the directory
138                $files = glob(FILES . $path . DS . '*', GLOB_NOSORT);
139                foreach ($files as $file) {
140                        // Directories have been handled above
141                        if (is_dir($file)) {
142                                continue;
143                        }
144
145                        $this->_syncFile($file, $root, $gallery_id);
146                }
147
148                // If there are no requests or subgalleries, remove this gallery
149                $subgalleryCount = $this->Gallery->childcount($gallery_id, true); // Use direct here. It comes from the database, not $data!
150                $requestCount    = $this->Gallery->requestCount($gallery_id);
151
152                if ($subgalleryCount == 0 && $requestCount == 0) {
153                        $this->Gallery->delete($gallery_id);
154                }
155        }
156
157        /**
158         * Synchronise a file
159         * @param string $path Path to the source file
160         * @param string $root Root of the target directory
161         * @param int $gallery_id The Gallery that this file is part of
162         */
163        private function _syncFile($path, $root, $gallery_id)
164        {
165                $this->log(sprintf('Synchronising %s to %s', $path, $root), LOG_DEBUG);
166
167                $gallery = $this->Gallery->read(null, $gallery_id);
168
169                // Rename the Fellowship testDoc documents to something more sensible
170                $filename = basename($path);
171                if (strtolower(substr($filename, 0, 8)) == 'testdoc.') {
172                        $filename  = $gallery['Gallery']['name'];
173                        $filename .= strrchr($path, '.');
174                }
175
176                // See if a request exists for this file
177                $this->Gallery->Request->bindModel(array('hasOne' => array('GalleriesRequest')));
178                $request = $this->Gallery->Request->find('first', array(
179                        'conditions' => array(
180                                'Request.filename' => $filename,
181                                'GalleriesRequest.gallery_id' => $gallery_id,
182                        ),
183                ));
184
185                if (!$request) {
186                        $stamp = date('Y-m-d H:i:s', filemtime($path));
187
188                        // Create a new request
189                        $this->Gallery->Request->create();
190                        $this->Gallery->Request->set(array(
191                                'user_id' => Configure::read('Testsuite.user_id'),
192                                'ip_address' => 0,
193                                'root' => $root . DS . basename($path),
194                                'path' => $root . DS . basename($path) . DS . 'source',
195                                'priority' => 10,
196                                'state' => Request::STATE_PREPROCESSOR_QUEUED,
197                                'created' => $stamp,
198                                'modified' => $stamp,
199                        ));
200                        $this->Gallery->Request->save();
201
202                        // Add the file to the request
203                        if (!$this->Gallery->Request->setFile($path, $filename)) {
204                                $error = implode("\n", $this->Gallery->Request->Behaviors->File->errors);
205                                $this->log('Adding file failed: ' . $error, LOG_DEBUG);
206                                $this->Gallery->Request->delete();
207                                return;
208                        }
209                        $this->Gallery->Request->save();
210
211                        // Add Validators to the request
212                        $this->Gallery->Request->addValidators();
213
214                        // Schedule the preprocessor for the request
215                        if (!$this->Gallery->Request->defer('run', 'Preprocessor')) {
216                                $this->log('Failed to queue the preprocessor for request ' . $this->Gallery->Request->id);
217                        }
218                       
219                        // Add the request to the gallery
220                        $this->Gallery->addRequest($this->Gallery->Request->id, $gallery_id);
221
222                        // Done
223                        $this->log(sprintf('Created request "%s"', $root . DS . basename($path)), LOG_DEBUG);
224                        return;
225                }
226
227                // See if the request needs updating
228                if (strtotime($request['Request']['modified']) < filemtime($path)) {
229                        $this->Gallery->Request->id = $request['Request']['id'];
230                        $this->Gallery->Request->deleteJobs();
231                        $this->Gallery->Request->setFile($path);
232                        $this->Gallery->Request->set(array(
233                                'modified' => filemtime($path),
234                                'state' => Request::STATE_PREPROCESSOR_QUEUED,
235                        ));
236                        $this->Gallery->Request->save();
237                       
238                        // Add Validators to the request
239                        $this->Gallery->Request->addValidators();
240
241                        // Schedule the preprocessor for the request
242                        if (!$this->Gallery->Request->defer('run', 'Preprocessor')) {
243                                $this->log('Failed to queue the preprocessor for request ' . $this->Gallery->Request->id);
244                        }
245                       
246                        $this->log(sprintf('Updated request %s "%s"', $request['Request']['id'], $filename), LOG_DEBUG);
247                }
248        }
249
250        /**
251         * Add jobs to all the test suite requests for all stable factories
252         */
253        public function addJobs()
254        {
255                // Load the necessary models
256                $this->Worker = ClassRegistry::init('Worker');
257                $this->Request = ClassRegistry::init('Request');
258
259                $workers = $this->Worker->getActive(true);
260                $requests = $this->_getRequests();
261
262                foreach ($requests as $request) {
263                        $this->_addJobs($request, $workers);
264                }
265        }
266
267        /**
268         * Get all requests and jobs that belong to all test suites
269         */
270        private function _getRequests()
271        {
272                $requests = array();
273                $suites = $this->find('all', array('recursive' => -1));
274
275                foreach ($suites as $suite) {
276                        $requests = Set::merge(
277                                $requests,
278                                $this->Gallery->getRequests($suite['Testsuite']['gallery_id'])
279                        );
280                }
281
282                return $requests;
283        }
284
285        /**
286         * Add jobs for $workers to a single request
287         * @param array $workers An array of available workers
288         * @param array $request The request to add the jobs to
289         */
290        private function _addJobs($request, $workers)
291        {
292                $newJobs = array();
293                foreach ($workers as $worker) {
294                        // If the worker does not support this doctype, skip it.
295                        if ($request['Mimetype']['doctype_id'] != $worker['Doctype']['id']) {
296                                continue;
297                        }
298
299                        foreach ($worker['Format'] as $format) {
300                                $match = false;
301
302                                foreach ($request['Job'] as $job) {
303                                        $match = (
304                                                $job['platform_id'] == $worker['Platform']['id']
305                                                && $job['application_id'] == $worker['Application']['id']
306                                                && $job['version'] == $worker['Worker']['version']
307                                                && $job['format_id'] == $format['id']
308                                        );
309
310                                        // If a job already exists we're done checking
311                                        if ($match) {
312                                                break;
313                                        }
314                                }
315
316                                if ($match) {
317                                        continue;
318                                }
319
320                                // If we get here, no suitable job exists and we need to add one
321                                $newJobs[] = array(
322                                        'platform_id' => $worker['Platform']['id'],
323                                        'application_id' => $worker['Application']['id'],
324                                        'version' => $worker['Worker']['version'],
325                                        'format_id' => $format['id'],
326                                );
327                        }
328                }
329               
330                $this->Request->id = $request['Request']['id'];
331                $this->Request->addJobs($newJobs);
332        }
333}
334
335?>
Note: See TracBrowser for help on using the repository browser.