Completed
Push — master ( f44910...121be2 )
by Greg
02:10
created

BrowserMob::__call()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 2
Metric Value
c 4
b 1
f 2
dl 0
loc 20
rs 9.2
cc 4
eloc 12
nc 4
nop 2
1
<?php
2
namespace Codeception\Extension;
3
4
use Codeception\Module;
5
use Codeception\Exception\ModuleException;
6
use Codeception\Exception\ModuleConfigException;
7
use \PHPBrowserMobProxy_Client as BMP;
8
use \Requests;
9
use \RuntimeException;
10
11
/**
12
 * @method void _open()
13
 * @method void _close()
14
 * @method string _newHar(string $label='')
15
 * @method string _newPage(string $label='')
16
 * @method string _blacklist(string $regexp, integer $status_code)
17
 * @method string _whitelist(string $regexp, integer $status_code)
18
 * @method string _basicAuth(string $domain, string[] $options)
19
 * @method string _headers(string[] $options)
20
 * @method string _responseInterceptor(string $js)
21
 * @method string _requestInterceptor(string $js)
22
 * @method Requests_Response _limits(string[] $options)
23
 * @method Requests_Response _timeouts(string[] $options)
24
 * @method string _remapHosts(string $address, string $ip_address)
25
 * @method string _waitForTrafficToStop(integer $quiet_period, integer $timeout)
26
 * @method string _clearDnsCache()
27
 * @method string _rewriteUrl(string $match, string $replace)
28
 * @method string _retry(integer $retry_count)
29
 */
30
class BrowserMob extends Module
31
{
32
33
    protected $config = ['host', 'port', 'autostart', 'blacklist', 'whitelist', 'limits', 'timeouts', 'redirect', 'retry', 'basicAuth', 'littleproxy'];
34
35
    protected $requiredFields = ['host'];
36
37
    protected $response;
38
39
    private $bmp;
40
41
    /**
42
     * @codeCoverageIgnore
43
     * @ignore Codeception specific
44
     */
45
    public function _initialize()
46
    {
47
        $host = $this->config['host'];
48
        if (isset($this->config['port'])) {
49
            $host = $host.':'.$this->config['port'];
50
        }
51
52
        // test if proxy is available
53
        if (static::__pingProxy($host)) {
54
            $this->bmp = new BMP($host);
55
        } else {
56
            throw new ModuleConfigException(__CLASS__, "Proxy '{$host}' cannot be reached");
57
        }
58
59
        // start a new BrowserMobProxy session
60
        if (isset($this->config['autostart'])) {
61
            if (true === (bool) $this->config['autostart']) {
62
                $this->openProxy();
63
            }
64
        }
65
    }
66
67
    protected static function __pingProxy($url)
68
    {
69
        try {
70
            $response = Requests::get('http://'.$url.'/proxy/');
71
        } catch (\Exception $e) {
72
            throw new ModuleException(__CLASS__, $e->getMessage());
73
        }
74
75
        return $response->success;
76
    }
77
78
    protected function __setProxyCapabilities($capabilities)
79
    {
80
        $response = null;
81
82
        foreach ($capabilities as $config => $data) {
83
            try {
84
                if (false === empty($data)) {
85
                    switch ((string) $config) {
86
                        case 'blacklist':
87
                            foreach ($data['patterns'] as $pattern) {
88
                                $response = $this->_blacklist($pattern, $data['code']);
89
                                if (isset($response->success)) {
90
                                    if (false === $response->success) {
91
                                        break;
92
                                    }
93
                                }
94
                            }
95
                            break;
96
                        case 'whitelist':
97
                            $patterns = implode(',', $data['patterns']);
98
                            $response = $this->_whitelist($patterns, $data['code']);
99
                            if (isset($response->success)) {
100
                                if (false === $response->success) {
101
                                    break;
102
                                }
103
                            }
104
                            break;
105
                        case 'limits':
106
                            $response = $this->_limits($data);
107
                            break;
108
                        case 'timeouts':
109
                            $response = $this->_timeouts($data);
110
                            break;
111
                        case 'redirect':
112
                            foreach ($data as $entry) {
113
                                $response = $this->_remapHosts($entry['address'], $entry['ip']);
114
                                if (isset($response->success)) {
115
                                    if (false === $response->success) {
116
                                        break;
117
                                    }
118
                                }
119
                            }
120
                            break;
121
                        case 'retry':
122
                            $response = $this->_retry($data);
123
                            break;
124
                        case 'basicAuth':
125
                            foreach ($data as $entry) {
126
                                $response = $this->_basicAuth($entry['domain'], $entry['options']);
127
                                if (isset($response->success)) {
128
                                    if (false === $response->success) {
129
                                        break;
130
                                    }
131
                                }
132
                            }
133
                            break;
134
                        default:
135
                            // do nothing
136
                    }
137
                }
138
            } catch (\Exception $e) {
139
                throw new ModuleConfigException(__CLASS__, $e->getMessage());
140
            }
141
142
            if (get_class($response) === 'Request')
143
            {
144
                $this->response = $response;
145
                if (false === $response->success) {
146
                    throw new ModuleConfigException(__CLASS__, "Proxy response error '{$response->status_code}' {$respone->body}");
147
                }
148
            }
149
        }
150
    }
151
152
    public function getProxyPort()
153
    {
154
        return $this->bmp->port;
155
    }
156
157
    public function openProxy($capabilities = null)
158
    {
159
        try {
160
            $this->bmp->open();
161
            if (empty($capabilities)) {
162
                $capabilities = $this->config;
163
            }
164
            $this->__setProxyCapabilities($capabilities);
165
        } catch (\Exception $e) {
166
            throw new ModuleException(__CLASS__, $e->getMessage());
167
        }
168
        return $this->getProxyPort();
169
    }
170
171
    public function closeProxy()
172
    {
173
        try {
174
            $this->bmp->close();
175
        } catch (\Exception $e) {
176
            throw new ModuleException(__CLASS__, $e->getMessage());
177
        }
178
    }
179
180 View Code Duplication
    public function startHar()
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
    {
182
        try {
183
            $this->response = $this->bmp->newHar();
184
        } catch (\Exception $e) {
185
            throw new ModuleException(__CLASS__, $e->getMessage());
186
        }
187
        return $this->response->success;
188
    }
189
190 View Code Duplication
    public function startPage()
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
    {
192
        try {
193
            $this->response = $this->bmp->newPage();
194
        } catch (\Exception $e) {
195
            throw new ModuleException(__CLASS__, $e->getMessage());
196
        }
197
        return $this->response->success;
198
    }
199
200
    public function getHar()
201
    {
202
        return $this->bmp->har;
203
    }
204
205
    // magic function that exposes BrowserMobProxy API pulic methods
206
    public function __call($method, $args)
207
    {
208
        // check if is a command call
209
        if (preg_match('/^_[A-z]+$/', $method)) {
210
            // extract standard method name
211
            $method = preg_filter('/_/', '', $method);
212
            // set call array for calling method
213
            $call = array($this->bmp, $method);
214
            // check if method is callable
215
            if (is_callable($call)) {
216
                $ret = call_user_func_array($call, $args);
217
            } else {
218
                throw new RuntimeException("Method ${method} does not exist or is not callable");
219
            }
220
        } else {
221
            throw new RuntimeException("Method ${method} does not exist or is not callable");
222
        }
223
        $ret = (isset($ret)) ? $ret : null;
224
        return $ret;
225
    }
226
227
}
228