Phiremock::createExpectation()   A
last analyzed

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\Connection\Scheme;
26
use Mcustiel\Phiremock\Client\Utils\ConditionsBuilder;
27
use Mcustiel\Phiremock\Client\Utils\ExpectationBuilder;
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\ScenarioStateInfo;
37
use Mcustiel\Phiremock\Domain\Version;
38
use Psr\Http\Client\ClientExceptionInterface;
39
use Psr\Http\Client\ClientInterface;
40
use Psr\Http\Message\ResponseInterface;
41
use RuntimeException;
42
43
class Phiremock
44
{
45
    const API_EXPECTATIONS_URL = '/__phiremock/expectations';
46
    const API_EXECUTIONS_URL = '/__phiremock/executions';
47
    const API_SCENARIOS_URL = '/__phiremock/scenarios';
48
    const API_RESET_URL = '/__phiremock/reset';
49
50
    /** @var ClientInterface */
51
    private $connection;
52
53
    /** @var ArrayToExpectationConverter */
54
    private $arrayToExpectationConverter;
55
56
    /** @var ExpectationToArrayConverter */
57
    private $expectationToArrayConverter;
58
59
    /** @var ScenarioStateInfoToArrayConverter */
60
    private $scenarioStateInfoToArrayConverter;
61
62
    /** @var Host */
63
    private $host;
64
65
    /** @var Port */
66
    private $port;
67
68
    /** @var Scheme */
69
    private $scheme;
70
71
    public function __construct(
72
        Host $host,
73
        Port $port,
74
        ClientInterface $remoteConnection,
75
        ExpectationToArrayConverter $expectationToArrayConverter,
76
        ArrayToExpectationConverter $arrayToExpectationConverter,
77
        ScenarioStateInfoToArrayConverter $scenarioStateInfoToArrayConverter,
78
        ?Scheme $scheme = null
79
    ) {
80
        $this->host = $host;
81
        $this->port = $port;
82
        $this->connection = $remoteConnection;
83
        $this->expectationToArrayConverter = $expectationToArrayConverter;
84
        $this->arrayToExpectationConverter = $arrayToExpectationConverter;
85
        $this->scenarioStateInfoToArrayConverter = $scenarioStateInfoToArrayConverter;
86
        $this->scheme = $scheme ?? Scheme::createHttp();
87
    }
88
89
    /**
90
     * Creates an expectation with a response for a given request.
91
     * @throws ClientExceptionInterface
92
     */
93
    public function createExpectation(Expectation $expectation): void
94
    {
95
        $body = @json_encode($this->expectationToArrayConverter->convert($expectation));
96
        if (json_last_error() !== JSON_ERROR_NONE) {
97
            throw new RuntimeException('Error generating json body for request: ' . json_last_error_msg());
98
        }
99
        $this->createExpectationFromJson($body);
0 ignored issues
show
Bug introduced by
It seems like $body can also be of type false; however, parameter $body of Mcustiel\Phiremock\Clien...teExpectationFromJson() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

99
        $this->createExpectationFromJson(/** @scrutinizer ignore-type */ $body);
Loading history...
100
    }
101
102
    /**
103
     * Creates an expectation from a json configuration
104
     * @throws ClientExceptionInterface
105
     */
106
    public function createExpectationFromJson(string $body): void
107
    {
108
        $uri = $this->createBaseUri()->withPath(self::API_EXPECTATIONS_URL);
109
        $request = (new PsrRequest())
110
            ->withUri($uri)
111
            ->withMethod('POST')
112
            ->withHeader('Content-Type', 'application/json')
113
            ->withBody(new StringStream($body));
114
        $this->ensureIsExpectedResponse(201, $this->connection->sendRequest($request));
115
    }
116
117
    /**
118
     * Restores pre-defined expectations and resets scenarios and requests counter.
119
     * @throws ClientExceptionInterface
120
     */
121
    public function reset(): void
122
    {
123
        $uri = $this->createBaseUri()->withPath(self::API_RESET_URL);
124
        $request = (new PsrRequest())->withUri($uri)->withMethod('POST');
125
126
        $this->ensureIsExpectedResponse(200, $this->connection->sendRequest($request));
127
    }
128
129
    /**
130
     * Clears all the currently configured expectations.
131
     * @throws ClientExceptionInterface
132
     */
133
    public function clearExpectations(): void
134
    {
135
        $uri = $this->createBaseUri()->withPath(self::API_EXPECTATIONS_URL);
136
        $request = (new PsrRequest())->withUri($uri)->withMethod('DELETE');
137
138
        $this->ensureIsExpectedResponse(200, $this->connection->sendRequest($request));
139
    }
140
141
    /**
142
     * @throws ClientExceptionInterface
143
     * @return Expectation[]
144
     */
145
    public function listExpectations(): array
146
    {
147
        $uri = $this->createBaseUri()->withPath(self::API_EXPECTATIONS_URL);
148
        $request = (new PsrRequest())->withUri($uri)->withMethod('GET');
149
        $response = $this->connection->sendRequest($request);
150
151
        $this->ensureIsExpectedResponse(200, $response);
152
153
        $arraysList = json_decode($response->getBody()->__toString(), true);
154
        $expectationsList = [];
155
156
        foreach ($arraysList as $expectationArray) {
157
            $expectationsList[] = $this->arrayToExpectationConverter
158
                ->convert($expectationArray);
159
        }
160
        return $expectationsList;
161
    }
162
163
    /** @throws ClientExceptionInterface */
164
    public function countExecutions(?ConditionsBuilder $requestBuilder = null): int
165
    {
166
        $uri = $this->createBaseUri()->withPath(self::API_EXECUTIONS_URL);
167
168
        $request = (new PsrRequest())
169
            ->withUri($uri)
170
            ->withMethod('POST')
171
            ->withHeader('Content-Type', 'application/json');
172
        if ($requestBuilder !== null) {
173
            $requestBuilderResult = $requestBuilder->build();
174
            $expectation = new Expectation(
175
                $requestBuilderResult->getRequestConditions(),
176
                HttpResponse::createEmpty(),
177
                $requestBuilderResult->getScenarioName(),
178
                null,
179
                new Version('2')
180
            );
181
            $jsonBody = json_encode($this->expectationToArrayConverter->convert($expectation));
182
            $request = $request->withBody(
183
                new StringStream(
184
                    $jsonBody
185
                )
186
            );
187
        }
188
189
        $response = $this->connection->sendRequest($request);
190
191
        $this->ensureIsExpectedResponse(200, $response);
192
        $json = json_decode($response->getBody()->__toString());
193
194
        return $json->count;
195
    }
196
197
    /** @throws ClientExceptionInterface */
198
    public function listExecutions(?ConditionsBuilder $requestBuilder = null): array
199
    {
200
        $uri = $this->createBaseUri()->withPath(self::API_EXECUTIONS_URL);
201
202
        $request = (new PsrRequest())
203
            ->withUri($uri)
204
            ->withMethod('PUT')
205
            ->withHeader('Content-Type', 'application/json');
206
        if ($requestBuilder !== null) {
207
            $requestBuilderResult = $requestBuilder->build();
208
            $expectation = new Expectation(
209
                $requestBuilderResult->getRequestConditions(),
210
                HttpResponse::createEmpty(),
211
                $requestBuilderResult->getScenarioName(),
212
                null,
213
                new Version('2')
214
            );
215
            $request = $request->withBody(
216
                new StringStream(
217
                    json_encode($this->expectationToArrayConverter->convert($expectation))
218
                )
219
            );
220
        }
221
222
        $response = $this->connection->sendRequest($request);
223
        $this->ensureIsExpectedResponse(200, $response);
224
        return json_decode($response->getBody()->__toString());
225
    }
226
227
    /**
228
     * Sets scenario state.
229
     * @throws ClientExceptionInterface
230
     */
231
    public function setScenarioState(string $scenarioName, string $scenarioState): void
232
    {
233
        $scenarioStateInfo = new ScenarioStateInfo(
234
            new ScenarioName($scenarioName),
235
            new ScenarioState($scenarioState)
236
        );
237
        $uri = $this->createBaseUri()->withPath(self::API_SCENARIOS_URL);
238
        $request = (new PsrRequest())
239
            ->withUri($uri)
240
            ->withMethod('PUT')
241
            ->withHeader('Content-Type', 'application/json')
242
            ->withBody(
243
                new StringStream(
244
                    json_encode(
245
                        $this->scenarioStateInfoToArrayConverter->convert($scenarioStateInfo)
246
                    )
247
                )
248
            );
249
250
        $response = $this->connection->sendRequest($request);
251
        $this->ensureIsExpectedResponse(200, $response);
252
    }
253
254
    /**
255
     * Resets all the scenarios to start state.
256
     * @throws ClientExceptionInterface
257
     */
258
    public function resetScenarios(): void
259
    {
260
        $uri = $this->createBaseUri()->withPath(self::API_SCENARIOS_URL);
261
        $request = (new PsrRequest())->withUri($uri)->withMethod('DELETE');
262
263
        $this->ensureIsExpectedResponse(200, $this->connection->sendRequest($request));
264
    }
265
266
    /**
267
     * Resets all the requests counters to 0.
268
     * @throws ClientExceptionInterface
269
     */
270
    public function resetRequestsCounter(): void
271
    {
272
        $uri = $this->createBaseUri()->withPath(self::API_EXECUTIONS_URL);
273
        $request = (new PsrRequest())->withUri($uri)->withMethod('DELETE');
274
275
        $this->ensureIsExpectedResponse(200, $this->connection->sendRequest($request));
276
    }
277
278
    /**
279
     * Inits the fluent interface to create an expectation.
280
     *
281
     * @return ExpectationBuilder
282
     */
283
    public static function on(ConditionsBuilder $requestBuilder): ExpectationBuilder
284
    {
285
        return new ExpectationBuilder($requestBuilder);
286
    }
287
288
    /** Shortcut. */
289
    public static function onRequest(string $method, string $url): ExpectationBuilder
290
    {
291
        return new ExpectationBuilder(
292
            ConditionsBuilder::create($method, $url)
293
        );
294
    }
295
296
    private function createBaseUri(): Uri
297
    {
298
        return (new Uri())
299
            ->withScheme($this->scheme->asString())
300
            ->withHost($this->host->asString())
301
            ->withPort($this->port->asInt());
302
    }
303
304
    /** @throws RuntimeException */
305
    private function ensureIsExpectedResponse(int $statusCode, ResponseInterface $response): void
306
    {
307
        $responseStatusCode = $response->getStatusCode();
308
        if ($responseStatusCode !== $statusCode) {
309
            if ($responseStatusCode >= 500) {
310
                $errors = json_decode($response->getBody()->__toString(), true)['details'];
311
312
                throw new RuntimeException('An error occurred creating the expectation: ' . ($errors ? var_export($errors, true) : '') . $response->getBody()->__toString());
313
            }
314
315
            if ($responseStatusCode >= 400) {
316
                throw new RuntimeException('Request error while creating the expectation');
317
            }
318
            throw new RuntimeException('Unexpected response while creating the expectation');
319
        }
320
    }
321
}
322