1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SmartGamma\Behat\PactExtension\Infrastructure; |
4
|
|
|
|
5
|
|
|
use GuzzleHttp\Exception\ClientException; |
6
|
|
|
use GuzzleHttp\Psr7\Uri; |
7
|
|
|
use PhpPact\Broker\Service\BrokerHttpClient; |
8
|
|
|
use PhpPact\Consumer\InteractionBuilder; |
9
|
|
|
use PhpPact\Http\GuzzleClient; |
10
|
|
|
use PhpPact\Standalone\MockService\MockServerConfig; |
11
|
|
|
use PhpPact\Standalone\MockService\MockServerEnvConfig; |
12
|
|
|
use PhpPact\Standalone\MockService\Service\MockServerHttpService; |
13
|
|
|
use SmartGamma\Behat\PactExtension\Infrastructure\Factory\InteractionBuilderFactory; |
14
|
|
|
use SmartGamma\Behat\PactExtension\Infrastructure\Factory\MockServerFactory; |
15
|
|
|
use SmartGamma\Behat\PactExtension\Infrastructure\Factory\MockServerHttpServiceFactory; |
16
|
|
|
use SmartGamma\Behat\PactExtension\Infrastructure\Interaction\InteractionCompositor; |
17
|
|
|
use SmartGamma\Behat\PactExtension\Infrastructure\Interaction\InteractionRequestDTO; |
18
|
|
|
use SmartGamma\Behat\PactExtension\Infrastructure\Interaction\InteractionResponseDTO; |
19
|
|
|
|
20
|
|
|
class Pact |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* @var MockServerFactory |
24
|
|
|
*/ |
25
|
|
|
private $mockServerFactory; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var InteractionBuilderFactory |
29
|
|
|
*/ |
30
|
|
|
private $interactionBuilderFactory; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var |
34
|
|
|
*/ |
35
|
|
|
private $mockServerHttpServiceFactory; |
36
|
|
|
|
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var InteractionCompositor |
40
|
|
|
*/ |
41
|
|
|
private $interactionCompositor; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var array |
45
|
|
|
*/ |
46
|
|
|
private $config = []; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var array |
50
|
|
|
*/ |
51
|
|
|
private $providersConfig = []; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var string |
55
|
|
|
*/ |
56
|
|
|
private $tag; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var array |
60
|
|
|
*/ |
61
|
|
|
private $servers = []; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var array |
65
|
|
|
*/ |
66
|
|
|
private $mockServerConfigs = []; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @var MockServerHttpService[] |
70
|
|
|
*/ |
71
|
|
|
private $mockServerHttpServices = []; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @var array |
75
|
|
|
*/ |
76
|
|
|
private $startedServers = []; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @var array |
80
|
|
|
*/ |
81
|
|
|
private $builders = []; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Pact constructor. |
85
|
|
|
* |
86
|
|
|
* @param MockServerFactory $mockServerFactory |
87
|
|
|
* @param InteractionBuilderFactory $interactionBuilderFactory |
88
|
|
|
* @param InteractionCompositor $interactionCompositor |
89
|
|
|
* @param array $config |
90
|
|
|
* @param array $providersConfig |
91
|
|
|
*/ |
92
|
8 |
|
public function __construct( |
93
|
|
|
MockServerFactory $mockServerFactory, |
94
|
|
|
InteractionBuilderFactory $interactionBuilderFactory, |
95
|
|
|
MockServerHttpServiceFactory $mockServerHttpServiceFactory, |
96
|
|
|
InteractionCompositor $interactionCompositor, |
97
|
|
|
array $config, |
98
|
|
|
array $providersConfig |
99
|
|
|
) |
100
|
|
|
{ |
101
|
8 |
|
$this->mockServerFactory = $mockServerFactory; |
102
|
8 |
|
$this->interactionBuilderFactory = $interactionBuilderFactory; |
103
|
8 |
|
$this->mockServerHttpServiceFactory = $mockServerHttpServiceFactory; |
104
|
8 |
|
$this->interactionCompositor = $interactionCompositor; |
105
|
8 |
|
$this->config = $config; |
106
|
8 |
|
$this->providersConfig = $providersConfig; |
107
|
8 |
|
$this->tag = $this->getPactTag(); |
108
|
8 |
|
$this->registerMockServerConfigs(); |
109
|
8 |
|
$this->registerMockServerHttpServices(); |
110
|
8 |
|
$this->registerServers(); |
111
|
8 |
|
$this->registerBuilders(); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
|
115
|
8 |
|
private function registerMockServerConfigs(): void |
116
|
|
|
{ |
117
|
8 |
|
foreach ($this->providersConfig as $providerName => $providerConfig) { |
118
|
8 |
|
$this->mockServerConfigs[$providerName] = $this->createMockServerConfig($providerConfig); |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|
122
|
8 |
|
private function registerMockServerHttpServices(): void |
123
|
|
|
{ |
124
|
8 |
|
foreach ($this->mockServerConfigs as $providerName => $mockServerConfig) { |
125
|
8 |
|
$this->mockServerHttpServices[$providerName] = $this->mockServerHttpServiceFactory->create($mockServerConfig); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
8 |
|
private function registerServers(): void |
130
|
|
|
{ |
131
|
8 |
|
foreach ($this->mockServerConfigs as $providerName => $mockServerConfig) { |
132
|
8 |
|
$this->servers[$providerName] = $this->mockServerFactory->create($mockServerConfig); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
|
137
|
8 |
|
private function registerBuilders(): void |
138
|
|
|
{ |
139
|
8 |
|
foreach ($this->mockServerConfigs as $providerName => $mockServerConfig) { |
140
|
8 |
|
$this->builders[$providerName] = $this->interactionBuilderFactory->create($mockServerConfig); |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* @param array $providerConfig |
146
|
|
|
* |
147
|
|
|
* @return MockServerConfig |
148
|
|
|
*/ |
149
|
8 |
|
private function createMockServerConfig(array $providerConfig): MockServerConfig |
150
|
|
|
{ |
151
|
8 |
|
$config = new MockServerConfig(); |
152
|
|
|
$config |
153
|
8 |
|
->setHost($providerConfig['PACT_MOCK_SERVER_HOST']) |
154
|
8 |
|
->setPort($providerConfig['PACT_MOCK_SERVER_PORT']) |
155
|
8 |
|
->setProvider($providerConfig['PACT_PROVIDER_NAME']) |
156
|
8 |
|
->setConsumer($this->config['PACT_CONSUMER_NAME']) |
157
|
8 |
|
->setPactDir($this->config['PACT_OUTPUT_DIR']) |
158
|
8 |
|
->setCors($this->config['PACT_CORS']) |
159
|
8 |
|
->setHealthCheckTimeout($this->config['PACT_MOCK_SERVER_HEALTH_CHECK_TIMEOUT']) |
160
|
8 |
|
->setPactSpecificationVersion(MockServerEnvConfig::DEFAULT_SPECIFICATION_VERSION); |
161
|
|
|
|
162
|
8 |
|
return $config; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* @param string $consumerVersion |
167
|
|
|
* |
168
|
|
|
* @return bool |
169
|
|
|
*/ |
170
|
2 |
|
public function finalize(string $consumerVersion): bool |
|
|
|
|
171
|
|
|
{ |
172
|
2 |
|
foreach ($this->mockServerConfigs as $providerName => $mockServerConfig) { |
173
|
2 |
|
if (!isset($this->startedServers[$providerName])) { |
174
|
1 |
|
echo 'Ignoring ' . $providerName . ' as it was not started in the suite'; |
175
|
1 |
|
continue; |
176
|
|
|
} |
177
|
|
|
|
178
|
1 |
|
if (!isset($this->config['PACT_BROKER_URI'])) { |
179
|
|
|
echo 'PACT_BROKER_URI environment variable was not set. Skipping PACT file upload for:' . $providerName; |
180
|
|
|
continue; |
181
|
|
|
} |
182
|
|
|
|
183
|
1 |
|
$json = $this->getPactJson($providerName); |
184
|
1 |
|
$this->publishToBroker($mockServerConfig, $json, $consumerVersion); |
185
|
|
|
} |
186
|
|
|
|
187
|
2 |
|
return true; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* @param string $providerName |
192
|
|
|
* |
193
|
|
|
* @return string |
194
|
|
|
*/ |
195
|
1 |
|
private function getPactJson(string $providerName): string |
196
|
|
|
{ |
197
|
1 |
|
$this->mockServerHttpServices[$providerName]->verifyInteractions(); |
198
|
|
|
|
199
|
1 |
|
return $this->mockServerHttpServices[$providerName]->getPactJson(); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @param MockServerConfig $config |
204
|
|
|
* @param string $json |
205
|
|
|
* @param string $consumerVersion |
206
|
|
|
*/ |
207
|
1 |
|
private function publishToBroker(MockServerConfig $config, string $json, string $consumerVersion): void |
208
|
|
|
{ |
209
|
1 |
|
$clientConfig = []; |
210
|
1 |
|
if (isset($this->config['PACT_BROKER_HTTP_AUTH_USER']) |
211
|
1 |
|
&& isset($this->config['PACT_BROKER_HTTP_AUTH_PASS'])) { |
212
|
|
|
$clientConfig = [ |
213
|
|
|
'auth' => [ |
214
|
|
|
$this->config['PACT_BROKER_HTTP_AUTH_USER'], |
215
|
|
|
$this->config['PACT_BROKER_HTTP_AUTH_PASS'], |
216
|
|
|
], |
217
|
|
|
]; |
218
|
|
|
} |
219
|
|
|
|
220
|
1 |
|
$pactBrokerUri = $this->config['PACT_BROKER_URI']; |
221
|
1 |
|
$brokerHttpService = new BrokerHttpClient(new GuzzleClient($clientConfig), new Uri($pactBrokerUri)); |
222
|
|
|
try { |
223
|
1 |
|
$brokerHttpService->publishJson($json, $consumerVersion); |
224
|
|
|
$brokerHttpService->tag($config->getConsumer(), $consumerVersion, $this->tag); |
225
|
|
|
echo 'Pact file has been uploaded to the Broker successfully with version ' . $consumerVersion . ' by tag:' . $this->tag; |
226
|
1 |
|
} catch (ClientException $e) { |
227
|
1 |
|
echo 'Error: ' . $e->getMessage(); |
228
|
|
|
} |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* @return string |
233
|
|
|
*/ |
234
|
8 |
|
private function getPactTag(): string |
235
|
|
|
{ |
236
|
8 |
|
if (!($tag = \getenv('PACT_CONSUMER_TAG'))) { |
237
|
8 |
|
$tag = $this->resolvePactTag($this->getCurrentGitBranch()); |
238
|
|
|
} |
239
|
|
|
|
240
|
8 |
|
return $tag; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* @return string |
245
|
|
|
*/ |
246
|
8 |
|
private function getCurrentGitBranch(): string |
247
|
|
|
{ |
248
|
8 |
|
$branch = 'none'; |
249
|
8 |
|
if (is_dir(__DIR__ . '/.git')) { |
250
|
|
|
$output = exec('git symbolic-ref HEAD'); |
251
|
|
|
$parts = explode('/', $output); |
252
|
|
|
$branch = end($parts); |
253
|
|
|
} |
254
|
|
|
|
255
|
8 |
|
return $branch; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* @param string $branch |
260
|
|
|
* |
261
|
|
|
* @return string |
262
|
|
|
*/ |
263
|
8 |
|
private function resolvePactTag(string $branch) |
264
|
|
|
{ |
265
|
8 |
|
return \in_array($branch, ['develop', 'master'], true) ? 'master' : $branch; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* @param string $providerName |
270
|
|
|
* |
271
|
|
|
* @return int |
272
|
|
|
*/ |
273
|
3 |
|
public function startServer(string $providerName): int |
274
|
|
|
{ |
275
|
3 |
|
if (isset($this->startedServers[$providerName])) { |
276
|
1 |
|
return $this->startedServers[$providerName]; |
277
|
|
|
} |
278
|
|
|
|
279
|
3 |
|
$pid = $this->servers[$providerName]->start(); |
280
|
3 |
|
$this->startedServers[$providerName] = $pid; |
281
|
|
|
|
282
|
3 |
|
return $pid; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* @return bool |
287
|
|
|
*/ |
288
|
1 |
|
public function verifyInteractions(): bool |
|
|
|
|
289
|
|
|
{ |
290
|
1 |
|
foreach ($this->startedServers as $providerName => $val) { |
291
|
|
|
$this->builders[$providerName]->verify(); |
292
|
|
|
$this->mockServerHttpServices[$providerName]->deleteAllInteractions(); |
293
|
|
|
} |
294
|
|
|
|
295
|
1 |
|
return true; |
296
|
|
|
} |
297
|
|
|
|
298
|
1 |
|
public function registerInteraction(InteractionRequestDTO $requestDTO, InteractionResponseDTO $responseDTO, string $providerState): void |
299
|
|
|
{ |
300
|
1 |
|
$providerName = $requestDTO->getProviderName(); |
301
|
|
|
|
302
|
1 |
|
$request = $this->interactionCompositor->createRequestFromDTO($requestDTO); |
303
|
1 |
|
$response = $this->interactionCompositor->createResponseFromDTO($responseDTO); |
304
|
|
|
|
305
|
1 |
|
$this->builders[$providerName] |
306
|
1 |
|
->given($providerState) |
307
|
1 |
|
->uponReceiving($requestDTO->getDescription()) |
308
|
1 |
|
->with($request) |
309
|
1 |
|
->willRespondWith($response); |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
/** |
313
|
|
|
* @return string |
314
|
|
|
*/ |
315
|
1 |
|
public function getConsumerVersion(): string |
316
|
|
|
{ |
317
|
1 |
|
return $this->config['PACT_CONSUMER_VERSION']; |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
|
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.