Passed
Push — master ( cfee49...a646e4 )
by Mariano
01:12
created

Phiremock::createExpectation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * This file is part of Phiremock.
4
 *
5
 * Phiremock is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Lesser General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * Phiremock is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with Phiremock.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
namespace Mcustiel\Phiremock\Client;
20
21
use Laminas\Diactoros\Request as PsrRequest;
22
use Laminas\Diactoros\Uri;
23
use Mcustiel\Phiremock\Client\Connection\Host;
24
use Mcustiel\Phiremock\Client\Connection\Port;
25
use Mcustiel\Phiremock\Client\Utils\ConditionsBuilder;
26
use Mcustiel\Phiremock\Client\Utils\ExpectationBuilder;
27
use Mcustiel\Phiremock\Common\Http\RemoteConnectionInterface;
28
use Mcustiel\Phiremock\Common\StringStream;
29
use Mcustiel\Phiremock\Common\Utils\ArrayToExpectationConverter;
30
use Mcustiel\Phiremock\Common\Utils\ExpectationToArrayConverter;
31
use Mcustiel\Phiremock\Common\Utils\ScenarioStateInfoToArrayConverter;
32
use Mcustiel\Phiremock\Domain\Expectation;
33
use Mcustiel\Phiremock\Domain\HttpResponse;
34
use Mcustiel\Phiremock\Domain\Options\ScenarioName;
35
use Mcustiel\Phiremock\Domain\Options\ScenarioState;
36
use Mcustiel\Phiremock\Domain\Response;
37
use Mcustiel\Phiremock\Domain\ScenarioStateInfo;
38
use Psr\Http\Message\ResponseInterface;
39
40
class Phiremock
41
{
42
    const API_EXPECTATIONS_URL = '/__phiremock/expectations';
43
    const API_EXECUTIONS_URL = '/__phiremock/executions';
44
    const API_SCENARIOS_URL = '/__phiremock/scenarios';
45
    const API_RESET_URL = '/__phiremock/reset';
46
47
    /** @var RemoteConnectionInterface */
48
    private $connection;
49
50
    /** @var ArrayToExpectationConverter */
51
    private $arrayToExpectationConverter;
52
53
    /** @var ExpectationToArrayConverter */
54
    private $expectationToArrayConverter;
55
56
    /** @var ScenarioStateInfoToArrayConverter */
57
    private $scenarioStateInfoToArrayConverter;
58
59
    /** @var Host */
60
    private $host;
61
62
    /** @var Port */
63
    private $port;
64
65
    public function __construct(
66
        Host $host,
67
        Port $port,
68
        RemoteConnectionInterface $remoteConnection,
69
        ExpectationToArrayConverter $expectationToArrayConverter,
70
        ArrayToExpectationConverter $arrayToExpectationConverter,
71
        ScenarioStateInfoToArrayConverter $scenarioStateInfoToArrayConverter
72
    ) {
73
        $this->host = $host;
74
        $this->port = $port;
75
        $this->connection = $remoteConnection;
76
        $this->expectationToArrayConverter = $expectationToArrayConverter;
77
        $this->arrayToExpectationConverter = $arrayToExpectationConverter;
78
        $this->scenarioStateInfoToArrayConverter = $scenarioStateInfoToArrayConverter;
79
    }
80
81
    /** Creates an expectation with a response for a given request. */
82
    public function createExpectation(Expectation $expectation): void
83
    {
84
        $body = @json_encode($this->expectationToArrayConverter->convert($expectation));
85
        if (json_last_error() !== JSON_ERROR_NONE) {
86
            throw new \RuntimeException('Error generating json body for request: ' . json_last_error_msg());
87
        }
88
        $this->createExpectationFromJson($body);
89
    }
90
91
    /** Creates an expectation from a json configuration */
92
    public function createExpectationFromJson(string $body): void
93
    {
94
        $uri = $this->createBaseUri()->withPath(self::API_EXPECTATIONS_URL);
95
        $request = (new PsrRequest())
96
            ->withUri($uri)
97
            ->withMethod('post')
98
            ->withHeader('Content-Type', 'application/json')
99
            ->withBody(new StringStream($body));
100
        $this->ensureIsExpectedResponse(201, $this->connection->send($request));
101
    }
102
103
    /** Restores pre-defined expectations and resets scenarios and requests counter. */
104
    public function reset(): void
105
    {
106
        $uri = $this->createBaseUri()->withPath(self::API_RESET_URL);
107
        $request = (new PsrRequest())->withUri($uri)->withMethod('post');
108
109
        $this->ensureIsExpectedResponse(200, $this->connection->send($request));
110
    }
111
112
    /** Clears all the currently configured expectations. */
113
    public function clearExpectations(): void
114
    {
115
        $uri = $this->createBaseUri()->withPath(self::API_EXPECTATIONS_URL);
116
        $request = (new PsrRequest())->withUri($uri)->withMethod('delete');
117
118
        $this->ensureIsExpectedResponse(200, $this->connection->send($request));
119
    }
120
121
    /** @return \Mcustiel\Phiremock\Domain\Expectation[] */
122
    public function listExpectations(): array
123
    {
124
        $uri = $this->createBaseUri()->withPath(self::API_EXPECTATIONS_URL);
125
        $request = (new PsrRequest())->withUri($uri)->withMethod('get');
126
        $response = $this->connection->send($request);
127
128
        $this->ensureIsExpectedResponse(200, $response);
129
130
        $arraysList = json_decode($response->getBody()->__toString(), true);
131
        $expectationsList = [];
132
133
        foreach ($arraysList as $expectationArray) {
134
            $expectationsList[] = $this->arrayToExpectationConverter
135
                ->convert($expectationArray);
136
        }
137
        return $expectationsList;
138
    }
139
140
    /** @return int */
141
    public function countExecutions(?ConditionsBuilder $requestBuilder = null): int
142
    {
143
        $uri = $this->createBaseUri()->withPath(self::API_EXECUTIONS_URL);
144
145
        $request = (new PsrRequest())
146
            ->withUri($uri)
147
            ->withMethod('post')
148
            ->withHeader('Content-Type', 'application/json');
149
        if ($requestBuilder !== null) {
150
            $requestBuilderResult = $requestBuilder->build();
151
            $expectation = new Expectation(
152
                $requestBuilderResult->getRequestConditions(),
153
                HttpResponse::createEmpty(),
154
                $requestBuilderResult->getScenarioName()
155
            );
156
            $jsonBody = json_encode($this->expectationToArrayConverter->convert($expectation));
157
            $request = $request->withBody(
158
                new StringStream(
159
                    $jsonBody
160
                )
161
            );
162
        }
163
164
        $response = $this->connection->send($request);
165
166
        $this->ensureIsExpectedResponse(200, $response);
167
        $json = json_decode($response->getBody()->__toString());
168
169
        return $json->count;
170
    }
171
172
    /** @return array */
173
    public function listExecutions(?ConditionsBuilder $requestBuilder = null): array
174
    {
175
        $uri = $this->createBaseUri()->withPath(self::API_EXECUTIONS_URL);
176
177
        $request = (new PsrRequest())
178
            ->withUri($uri)
179
            ->withMethod('put')
180
            ->withHeader('Content-Type', 'application/json');
181
        if ($requestBuilder !== null) {
182
            $requestBuilderResult = $requestBuilder->build();
183
            $expectation = new Expectation(
184
                $requestBuilderResult->getRequestConditions(),
185
                HttpResponse::createEmpty(),
186
                $requestBuilderResult->getScenarioName()
187
            );
188
            $request = $request->withBody(
189
                new StringStream(
190
                    json_encode($this->expectationToArrayConverter->convert($expectation))
191
                )
192
            );
193
        }
194
195
        $response = $this->connection->send($request);
196
        $this->ensureIsExpectedResponse(200, $response);
197
        return json_decode($response->getBody()->__toString(), true);
198
    }
199
200
    /** Sets scenario state. */
201
    public function setScenarioState(string $scenarioName, string $scenarioState): void
202
    {
203
        $scenarioStateInfo = new ScenarioStateInfo(
204
            new ScenarioName($scenarioName),
205
            new ScenarioState($scenarioState)
206
        );
207
        $uri = $this->createBaseUri()->withPath(self::API_SCENARIOS_URL);
208
        $request = (new PsrRequest())
209
            ->withUri($uri)
210
            ->withMethod('put')
211
            ->withHeader('Content-Type', 'application/json')
212
            ->withBody(
213
                new StringStream(
214
                    json_encode(
215
                        $this->scenarioStateInfoToArrayConverter->convert($scenarioStateInfo)
216
                    )
217
                )
218
            );
219
220
        $response = $this->connection->send($request);
221
        $this->ensureIsExpectedResponse(200, $response);
222
    }
223
224
    /** Resets all the scenarios to start state. */
225
    public function resetScenarios(): void
226
    {
227
        $uri = $this->createBaseUri()->withPath(self::API_SCENARIOS_URL);
228
        $request = (new PsrRequest())->withUri($uri)->withMethod('delete');
229
230
        $this->ensureIsExpectedResponse(200, $this->connection->send($request));
231
    }
232
233
    /** Resets all the requests counters to 0. */
234
    public function resetRequestsCounter(): void
235
    {
236
        $uri = $this->createBaseUri()->withPath(self::API_EXECUTIONS_URL);
237
        $request = (new PsrRequest())->withUri($uri)->withMethod('delete');
238
239
        $this->ensureIsExpectedResponse(200, $this->connection->send($request));
240
    }
241
242
    /**
243
     * Inits the fluent interface to create an expectation.
244
     *
245
     * @return \Mcustiel\Phiremock\Client\Utils\ExpectationBuilder
246
     */
247
    public static function on(ConditionsBuilder $requestBuilder): ExpectationBuilder
248
    {
249
        return new ExpectationBuilder($requestBuilder);
250
    }
251
252
    /**
253
     * Shortcut.
254
     *
255
     * @param string $method
256
     * @param string $url
257
     *
258
     * @return \Mcustiel\Phiremock\Client\Utils\ExpectationBuilder
259
     */
260
    public static function onRequest(string $method, string $url): ExpectationBuilder
261
    {
262
        return new ExpectationBuilder(
263
            ConditionsBuilder::create($method, $url)
264
        );
265
    }
266
267
    private function createBaseUri(): Uri
268
    {
269
        return (new Uri())
270
            ->withScheme('http')
271
            ->withHost($this->host->asString())
272
            ->withPort($this->port->asInt());
273
    }
274
275
    /**
276
     * @throws \RuntimeException
277
     */
278
    private function ensureIsExpectedResponse(int $statusCode, ResponseInterface $response)
279
    {
280
        $responseStatusCode = $response->getStatusCode();
281
        if ($responseStatusCode !== $statusCode) {
282
            if ($responseStatusCode >= 500) {
283
                $errors = json_decode($response->getBody()->__toString(), true)['details'];
284
285
                throw new \RuntimeException('An error occurred creating the expectation: ' . ($errors ? var_export($errors, true) : '') . $response->getBody()->__toString());
286
            }
287
288
            if ($responseStatusCode >= 400) {
289
                throw new \RuntimeException('Request error while creating the expectation');
290
            }
291
            throw new \RuntimeException('Unexpected response while creating the expectation');
292
        }
293
    }
294
}
295