BehatConfigManager.php 8.31 KB
Newer Older
Son Nguyen's avatar
Son Nguyen committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
/**
 * @package    mahara
 * @subpackage test/behat
 * @author     Son Nguyen, Catalyst IT Ltd
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
 * @copyright  For copyright information on Mahara, please see the README file distributed with this software.
 * @copyright  portions from Moodle Behat, 2013 David Monllaó
 *
 */


/**
 * Utils to set Behat config
 *
 */

defined('INTERNAL') || die();

require_once(dirname(__DIR__) . '/lib.php');
Son Nguyen's avatar
Son Nguyen committed
21
require_once(__DIR__ . '/util.php');
Son Nguyen's avatar
Son Nguyen committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
require_once(dirname(dirname(dirname(__DIR__))) . '/classes/TestsFinder.php');

/**
 * Behat configuration manager
 *
 * Creates/updates Behat config files getting tests
 * and steps from Mahara codebase
 *
 */
class BehatConfigManager {

    /**
     * Updates a config file
     *
Son Nguyen's avatar
Son Nguyen committed
36
     * Define test suites for mahara core and plugins
Son Nguyen's avatar
Son Nguyen committed
37
     *
Son Nguyen's avatar
Son Nguyen committed
38
39
40
41
42
43
44
     * Default test suite is
     *  - core_features
     *
     * Each test suite should have
     *  - paths of feature files
     *  - contexts
     *  - filters (for plugin test suite, use tags: pluginname)
Son Nguyen's avatar
Son Nguyen committed
45
46
47
     *
     * @return void
     */
Son Nguyen's avatar
Son Nguyen committed
48
    public static function update_config_file() {
Son Nguyen's avatar
Son Nguyen committed
49
50
        global $CFG;

Son Nguyen's avatar
Son Nguyen committed
51
        $configfilepath = BehatTestingUtil::get_behat_config_path();
Son Nguyen's avatar
Son Nguyen committed
52

Son Nguyen's avatar
Son Nguyen committed
53
54
        // Get core_features test suite
        $suites = array();
Son Nguyen's avatar
Son Nguyen committed
55

Son Nguyen's avatar
Son Nguyen committed
56
        $core_paths = array(BehatTestingUtil::get_mahararoot() . self::get_behat_tests_path(). DIRECTORY_SEPARATOR . 'features');
Son Nguyen's avatar
Son Nguyen committed
57
58
59

        // Optionally include features from additional directories.
        if (!empty($CFG->behat_additionalfeatures)) {
Son Nguyen's avatar
Son Nguyen committed
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
            $core_paths = array_merge($core_paths, array_map("realpath", $CFG->behat_additionalfeatures));
        }
        $core_contexts = array(
            'BehatMaharaCoreContext',
            'BehatHooks',
            'BehatGeneral',
            'BehatNavigation',
            'BehatView',
            'BehatDataGenerators',
            'BehatAccount',
            'BehatAdmin',
            'BehatForms',
        );
        $core_filters = array(
            'tags' => '@core'
        );
        $suites['core_features'] = array(
            'paths'    => $core_paths,
            'contexts' => $core_contexts,
            'filters'  => $core_filters,
        );
Son Nguyen's avatar
Son Nguyen committed
81

Son Nguyen's avatar
Son Nguyen committed
82
83
84
85
86
87
88
89
90
91
92
        // Get test suite config for each plugin
        // Gets all the plugins with features and/or contexts.
        $plugins = TestsFinder::get_plugins_with_tests('features');
        if ($plugins) {
            foreach ($plugins as $pluginname => $path) {
                $path = self::clean_path($path) ;
                if (file_exists($path . self::get_behat_tests_path())) {
                    $suites[$pluginname] = array(
                        'paths'    => array($path),
                        'contexts' => array_merge($core_contexts, self::get_plugin_contexts($path)),
                    );
Son Nguyen's avatar
Son Nguyen committed
93
94
                }

Son Nguyen's avatar
Son Nguyen committed
95
96
            }
            $features = array_merge($features, array_values($featurespaths));
Son Nguyen's avatar
Son Nguyen committed
97
98
99
100
        }

        // Behat config file specifing the main context class,
        // the required Behat extensions and Mahara test wwwroot.
Son Nguyen's avatar
Son Nguyen committed
101
        $contents = self::get_config_file_contents($suites);
Son Nguyen's avatar
Son Nguyen committed
102
103

        // Stores the file.
104
        check_dir_exists(dirname($configfilepath), true, true);
Son Nguyen's avatar
Son Nguyen committed
105
        if (!file_put_contents($configfilepath, $contents)) {
Son Nguyen's avatar
Son Nguyen committed
106
            behat_error(BEHAT_MAHARA_EXITCODE_BADPERMISSIONS, 'File ' . $configfilepath . ' can not be created');
Son Nguyen's avatar
Son Nguyen committed
107
108
109
110
111
        }

    }

    /**
Son Nguyen's avatar
Son Nguyen committed
112
     * Gets the list contexts for a plugin
Son Nguyen's avatar
Son Nguyen committed
113
     *
Son Nguyen's avatar
Son Nguyen committed
114
     * @param $pluginpath
Son Nguyen's avatar
Son Nguyen committed
115
116
     * @return array
     */
Son Nguyen's avatar
Son Nguyen committed
117
    public static function get_plugin_contexts($pluginpath) {
Son Nguyen's avatar
Son Nguyen committed
118

Son Nguyen's avatar
Son Nguyen committed
119
        $plugincontexts = array();
Son Nguyen's avatar
Son Nguyen committed
120

Son Nguyen's avatar
Son Nguyen committed
121
122
123
124
125
        // All Behat*.php inside self::get_behat_tests_path() are added contexts.
        $regite = new RegexIterator(new DirectoryIterator($pluginpath . self::get_behat_tests_path()), '|^Behat.*\.php$|');
        foreach ($regite as $file) {
            $key = $file->getBasename('.php');
            $plugincontexts[] = $key;
Son Nguyen's avatar
Son Nguyen committed
126
127
        }

Son Nguyen's avatar
Son Nguyen committed
128
        return $plugincontexts;
Son Nguyen's avatar
Son Nguyen committed
129
130
131
    }

    /**
Son Nguyen's avatar
Son Nguyen committed
132
     * Generate the Behat config file
Son Nguyen's avatar
Son Nguyen committed
133
     *
Son Nguyen's avatar
Son Nguyen committed
134
     * @param array $suites
Son Nguyen's avatar
Son Nguyen committed
135
136
     * @return string
     */
Son Nguyen's avatar
Son Nguyen committed
137
    protected static function get_config_file_contents($suites) {
Son Nguyen's avatar
Son Nguyen committed
138
139
140
        global $CFG;

        // We require here when we are sure behat dependencies are available.
Son Nguyen's avatar
Son Nguyen committed
141
        require_once(TestingUtil::get_mahararoot() . '/external/vendor/autoload.php');
Son Nguyen's avatar
Son Nguyen committed
142
143
144

        // It is possible that it has no value as we don't require a full behat setup to list the step definitions.
        if (empty($CFG->behat_wwwroot)) {
Son Nguyen's avatar
Son Nguyen committed
145
            $CFG->behat_wwwroot = 'http://example.com';
Son Nguyen's avatar
Son Nguyen committed
146
147
        }

Son Nguyen's avatar
Son Nguyen committed
148
        $basedir = $CFG->docroot . 'testing/frameworks/behat';
Son Nguyen's avatar
Son Nguyen committed
149
150
        $config = array(
            'default' => array(
Son Nguyen's avatar
Son Nguyen committed
151
152
                'autoload' => array($basedir . DIRECTORY_SEPARATOR . 'classes'),
                'formatters' => array(
153
154
155
156
                    'progress' => true,
                    'html' => array(
                      'output_path' => '%paths.base%/html_results/'
                    ),
Son Nguyen's avatar
Son Nguyen committed
157
158
                ),
                'extensions' => array(
Son Nguyen's avatar
Son Nguyen committed
159
                    'Behat\MinkExtension' => array(
Son Nguyen's avatar
Son Nguyen committed
160
                        'base_url' => $CFG->behat_wwwroot,
Son Nguyen's avatar
Son Nguyen committed
161
                        'files_path' => get_mahararoot_dir() . '/test/behat/upload_files',
162
163
164
165
                        'javascript_session' => 'selenium2',
                        'selenium2' => array(
                            'browser' => 'chrome',
                            'wd_host' => $CFG->behat_selenium2
Son Nguyen's avatar
Son Nguyen committed
166
                        ),
167
                        'goutte' => null,
Son Nguyen's avatar
Son Nguyen committed
168
                     ),
169
170
171
172
173
174
175
176
                     'emuse\BehatHTMLFormatter\BehatHTMLFormatterExtension' => array(
                       'name' => 'html',
                       'renderer' => 'Twig,Behat2',
                       'file_name' => 'index',
                       'print_args' => 'true',
                       'print_outp' => 'true',
                       'loop_break' => 'true'
                     )
Son Nguyen's avatar
Son Nguyen committed
177
                ),
Son Nguyen's avatar
Son Nguyen committed
178
                'suites' => $suites
Son Nguyen's avatar
Son Nguyen committed
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
            )
        );

        // In case user defined overrides respect them over our default ones.
        if (!empty($CFG->behat_config)) {
            $config = self::merge_config($config, $CFG->behat_config);
        }

        return Symfony\Component\Yaml\Yaml::dump($config, 10, 2);
    }

    /**
     * Overrides default config with local config values
     *
     * array_merge does not merge completely the array's values
     *
     * @param mixed $config The node of the default config
     * @param mixed $localconfig The node of the local config
     * @return mixed The merge result
     */
    protected static function merge_config($config, $localconfig) {

        if (!is_array($config) && !is_array($localconfig)) {
            return $localconfig;
        }

        // Local overrides also deeper default values.
        if (is_array($config) && !is_array($localconfig)) {
            return $localconfig;
        }

        foreach ($localconfig as $key => $value) {

            // If defaults are not as deep as local values let locals override.
            if (!is_array($config)) {
                unset($config);
            }

            // Add the param if it doesn't exists or merge branches.
            if (empty($config[$key])) {
                $config[$key] = $value;
Son Nguyen's avatar
Son Nguyen committed
220
221
            }
            else {
Son Nguyen's avatar
Son Nguyen committed
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
                $config[$key] = self::merge_config($config[$key], $localconfig[$key]);
            }
        }

        return $config;
    }

    /**
     * Cleans the path returned by get_plugins_with_tests() to standarize it
     *
     * @see TestsFinder::get_all_directories_with_tests() it returns the path including /tests/
     * @param string $path
     * @return string The string without the last /tests part
     */
    protected final static function clean_path($path) {

        $path = rtrim($path, DIRECTORY_SEPARATOR);

        $parttoremove = DIRECTORY_SEPARATOR . 'tests';

        $substr = substr($path, strlen($path) - strlen($parttoremove));
        if ($substr == $parttoremove) {
            $path = substr($path, 0, strlen($path) - strlen($parttoremove));
        }

        return rtrim($path, DIRECTORY_SEPARATOR);
    }

    /**
     * The relative path where plugins stores their behat tests
     *
     * @return string
     */
    protected final static function get_behat_tests_path() {
Son Nguyen's avatar
Son Nguyen committed
256
        return DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'behat';
Son Nguyen's avatar
Son Nguyen committed
257
258
259
    }

}