Skip to content

Commit 72f8d2b

Browse files
committed
Request chunking and better testing helpers
1 parent 8ea19d2 commit 72f8d2b

13 files changed

+320
-124
lines changed

src/Client.php

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
namespace Torchlight;
77

8+
use Illuminate\Http\Client\Pool;
89
use Illuminate\Support\Arr;
910
use Illuminate\Support\Collection;
10-
use Illuminate\Support\Facades\Cache;
1111
use Illuminate\Support\Facades\Http;
1212
use Throwable;
1313
use Torchlight\Exceptions\ConfigurationException;
@@ -42,26 +42,35 @@ public function highlight($blocks)
4242

4343
protected function request(Collection $blocks)
4444
{
45-
$blocks = $this->collectionOfBlocks($blocks);
46-
47-
$host = Torchlight::config('host', 'https://api.torchlight.dev');
45+
$error = false;
4846

4947
try {
50-
$response = Http::timeout(5)
51-
->withToken($this->getToken())
52-
->post($host . '/highlight', [
53-
'blocks' => $this->blocksAsRequestParam($blocks)->values()->toArray(),
54-
])
55-
->json();
48+
$response = $this->collectionOfBlocks($blocks)
49+
->chunk(Torchlight::config('request_chunk_size', 15))
50+
->pipe(function ($chunks) {
51+
return collect($this->requestChunks($chunks));
52+
})
53+
->map(function ($response) use (&$error) {
54+
if ($response instanceof Throwable) {
55+
$error = $response;
56+
57+
return [];
58+
}
59+
60+
if ($response->failed()) {
61+
$error = $response->toException();
62+
63+
return [];
64+
}
65+
66+
return Arr::get($response->json(), 'blocks', []);
67+
})
68+
->flatten(1);
5669
} catch (Throwable $e) {
57-
$response = [
58-
'error' => $e->getMessage()
59-
];
70+
$this->throwUnlessProduction($e);
6071
}
6172

62-
$this->potentiallyThrowRequestException($response);
63-
64-
$response = collect(Arr::get($response, 'blocks', []))->keyBy('id');
73+
$response = collect($response)->keyBy('id');
6574

6675
$blocks->each(function (Block $block) use ($response) {
6776
$blockFromResponse = Arr::get($response, "{$block->id()}", []);
@@ -84,9 +93,28 @@ protected function request(Collection $blocks)
8493
// Only store the ones we got back from the API.
8594
$this->setCacheFromBlocks($blocks, $response->keys());
8695

96+
$this->potentiallyThrowRequestException($error);
97+
8798
return $blocks;
8899
}
89100

101+
protected function requestChunks($chunks)
102+
{
103+
return Http::pool(function (Pool $pool) use ($chunks) {
104+
$host = Torchlight::config('host', 'https://api.torchlight.dev');
105+
$timeout = Torchlight::config('request_timeout', 5);
106+
107+
$chunks->each(function ($blocks) use ($pool, $host, $timeout) {
108+
$pool->timeout($timeout)
109+
->baseUrl($host)
110+
->withToken($this->getToken())
111+
->post('highlight', [
112+
'blocks' => $this->blocksAsRequestParam($blocks)->values()->toArray(),
113+
]);
114+
});
115+
});
116+
}
117+
90118
protected function collectionOfBlocks($blocks)
91119
{
92120
return collect($blocks)->each(function ($block) {
@@ -109,10 +137,10 @@ protected function getToken()
109137
return $token;
110138
}
111139

112-
protected function potentiallyThrowRequestException($response)
140+
protected function potentiallyThrowRequestException($exception)
113141
{
114-
if ($error = Arr::get($response, 'error')) {
115-
$this->throwUnlessProduction(new RequestException($error));
142+
if ($exception) {
143+
$this->throwUnlessProduction(new RequestException($exception->getMessage()));
116144
}
117145
}
118146

tests/BaseTest.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,106 @@
55

66
namespace Torchlight\Tests;
77

8+
use Exception;
9+
use GuzzleHttp\Exception\ConnectException;
10+
use GuzzleHttp\Exception\TransferException;
11+
use GuzzleHttp\Promise\FulfilledPromise;
12+
use http\Client\Response;
13+
use Illuminate\Http\Client\ConnectionException;
14+
use Illuminate\Http\Client\Request;
15+
use Illuminate\Support\Arr;
16+
use Illuminate\Support\Facades\Http;
817
use Orchestra\Testbench\TestCase;
18+
use Throwable;
19+
use Torchlight\Block;
920
use Torchlight\TorchlightServiceProvider;
1021

1122
abstract class BaseTest extends TestCase
1223
{
24+
protected $apiFaked = false;
25+
26+
protected $fakeResponseBlocks = [];
27+
28+
protected function setUp(): void
29+
{
30+
parent::setUp();
31+
}
32+
1333
protected function getPackageProviders($app)
1434
{
1535
return [
1636
TorchlightServiceProvider::class
1737
];
1838
}
39+
40+
protected function fakeApi()
41+
{
42+
$this->apiFaked = true;
43+
44+
$this->fakeResponseBlocks = [];
45+
46+
Http::fake([
47+
'api.torchlight.dev/*' => function (Request $request) {
48+
$response = [];
49+
50+
foreach ($request->data()['blocks'] as $block) {
51+
if (!Arr::has($this->fakeResponseBlocks, $block['id'])) {
52+
throw new TransferException('Torchlight block response not set for ' . $block['id']);
53+
}
54+
55+
$fake = $this->fakeResponseBlocks[$block['id']];
56+
57+
if (is_array($fake)) {
58+
$highlighted = "<div class='highlighted'>" . $block['code'] . "</div>";
59+
60+
$response[] = array_merge($block, [
61+
'classes' => 'torchlight',
62+
'styles' => 'background-color: #000000;',
63+
'wrapped' => "<pre><code>$highlighted</code></pre>",
64+
'highlighted' => $highlighted,
65+
], $fake);
66+
}
67+
68+
if ($fake === ConnectException::class) {
69+
throw new ConnectException('Connection timed out', $request->toPsrRequest());
70+
}
71+
72+
if ($fake instanceof Response || $fake instanceof FulfilledPromise) {
73+
return $fake;
74+
}
75+
}
76+
77+
return Http::response([
78+
'duration' => 100,
79+
'engine' => 1,
80+
'blocks' => $response
81+
], 200);
82+
},
83+
]);
84+
}
85+
86+
protected function fakeSuccessfulResponse($id, $response = [])
87+
{
88+
$this->addFake($id, $response);
89+
}
90+
91+
protected function fakeTimeout($id)
92+
{
93+
$this->addFake($id, ConnectException::class);
94+
}
95+
96+
protected function fakeNullResponse($id)
97+
{
98+
$this->addFake($id, Http::response(null, 200));
99+
}
100+
101+
protected function addFake($id, $response)
102+
{
103+
if (!$this->apiFaked) {
104+
$this->fakeApi();
105+
}
106+
107+
$this->fakeResponseBlocks[$id] = $response;
108+
}
109+
19110
}

0 commit comments

Comments
 (0)