Skip to content

Commit 6ff5597

Browse files
committed
NO-ISSUE: Add tests covering the openapi-generator 7.22.0 regeneration
Cover the code paths that change with the 7.22.0 regeneration so the diff is verified: - InsightApi / LiffApi / ManageAudienceApi: request shape (method/path/query/ body keys) and response deserialization - handleResponseWithDataType(): happy path + malformed-JSON -> ApiException - mTLS wiring: Configuration cert/key getters/setters and createHttpClientOption forwarding RequestOptions::CERT / SSL_KEY - ObjectSerializer: unit tests for the shared serialization helper
1 parent 0dc5b45 commit 6ff5597

4 files changed

Lines changed: 862 additions & 0 deletions

File tree

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
<?php
2+
3+
/**
4+
* Copyright 2026 LINE Corporation
5+
*
6+
* LINE Corporation licenses this file to you under the Apache License,
7+
* version 2.0 (the "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at:
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15+
* License for the specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
namespace LINE\Tests\Clients\Insight\Api;
20+
21+
use GuzzleHttp\ClientInterface;
22+
use GuzzleHttp\Psr7\Query;
23+
use GuzzleHttp\Psr7\Request;
24+
use GuzzleHttp\Psr7\Response;
25+
use GuzzleHttp\RequestOptions;
26+
use LINE\Clients\Insight\Api\InsightApi;
27+
use LINE\Clients\Insight\Configuration;
28+
use LINE\Clients\Insight\Model\GetFriendsDemographicsResponse;
29+
use LINE\Clients\Insight\Model\GetMessageEventResponse;
30+
use LINE\Clients\Insight\Model\GetNumberOfFollowersResponse;
31+
use LINE\Clients\Insight\Model\GetNumberOfMessageDeliveriesResponse;
32+
use LINE\Clients\Insight\Model\GetStatisticsPerUnitResponse;
33+
use Mockery;
34+
use PHPUnit\Framework\TestCase;
35+
use Psr\Http\Message\UriInterface;
36+
37+
/**
38+
* Characterization tests for the auto-generated InsightApi client.
39+
*
40+
* These tests pin the request shape (HTTP method, URL path and query parameter
41+
* keys) that the OpenAPI generator currently produces. They are intentionally
42+
* strict about query keys so that a future openapi-generator bump that changes
43+
* the serialization (e.g. camelCase vs snake_case, like the form-param
44+
* regression fixed in #810/#823) is caught before release.
45+
*/
46+
class InsightApiTest extends TestCase
47+
{
48+
private function assertQueryEquals(array $expected, UriInterface $uri): void
49+
{
50+
$this->assertSame($expected, Query::parse($uri->getQuery()), 'Query parameters mismatch');
51+
}
52+
53+
public function testGetFriendsDemographics(): void
54+
{
55+
$client = Mockery::mock(ClientInterface::class);
56+
$client->shouldReceive('send')
57+
->with(
58+
Mockery::on(function (Request $request) {
59+
$this->assertEquals('GET', $request->getMethod());
60+
$this->assertEquals(
61+
'https://api.line.me/v2/bot/insight/demographic',
62+
(string)$request->getUri()
63+
);
64+
return true;
65+
}),
66+
[]
67+
)
68+
->once()
69+
->andReturn(new Response(
70+
status: 200,
71+
headers: [],
72+
body: json_encode(['available' => true, 'genders' => []]),
73+
));
74+
$api = new InsightApi($client);
75+
$response = $api->getFriendsDemographics();
76+
$this->assertInstanceOf(GetFriendsDemographicsResponse::class, $response);
77+
$this->assertTrue($response->getAvailable());
78+
}
79+
80+
public function testGetNumberOfFollowers(): void
81+
{
82+
$client = Mockery::mock(ClientInterface::class);
83+
$client->shouldReceive('send')
84+
->with(
85+
Mockery::on(function (Request $request) {
86+
$this->assertEquals('GET', $request->getMethod());
87+
$uri = $request->getUri();
88+
$this->assertEquals('/v2/bot/insight/followers', $uri->getPath());
89+
$this->assertQueryEquals(['date' => '20260601'], $uri);
90+
return true;
91+
}),
92+
[]
93+
)
94+
->once()
95+
->andReturn(new Response(
96+
status: 200,
97+
headers: [],
98+
body: json_encode([
99+
'status' => 'ready',
100+
'followers' => 100,
101+
'targetedReaches' => 90,
102+
'blocks' => 5,
103+
]),
104+
));
105+
$api = new InsightApi($client);
106+
$response = $api->getNumberOfFollowers(date: '20260601');
107+
$this->assertInstanceOf(GetNumberOfFollowersResponse::class, $response);
108+
$this->assertEquals('ready', $response->getStatus());
109+
$this->assertEquals(100, $response->getFollowers());
110+
$this->assertEquals(5, $response->getBlocks());
111+
}
112+
113+
public function testGetNumberOfMessageDeliveries(): void
114+
{
115+
$client = Mockery::mock(ClientInterface::class);
116+
$client->shouldReceive('send')
117+
->with(
118+
Mockery::on(function (Request $request) {
119+
$this->assertEquals('GET', $request->getMethod());
120+
$uri = $request->getUri();
121+
$this->assertEquals('/v2/bot/insight/message/delivery', $uri->getPath());
122+
$this->assertQueryEquals(['date' => '20260601'], $uri);
123+
return true;
124+
}),
125+
[]
126+
)
127+
->once()
128+
->andReturn(new Response(
129+
status: 200,
130+
headers: [],
131+
body: json_encode(['status' => 'ready', 'broadcast' => 50]),
132+
));
133+
$api = new InsightApi($client);
134+
$response = $api->getNumberOfMessageDeliveries(date: '20260601');
135+
$this->assertInstanceOf(GetNumberOfMessageDeliveriesResponse::class, $response);
136+
$this->assertEquals('ready', $response->getStatus());
137+
$this->assertEquals(50, $response->getBroadcast());
138+
}
139+
140+
public function testGetMessageEvent(): void
141+
{
142+
$client = Mockery::mock(ClientInterface::class);
143+
$client->shouldReceive('send')
144+
->with(
145+
Mockery::on(function (Request $request) {
146+
$this->assertEquals('GET', $request->getMethod());
147+
$uri = $request->getUri();
148+
$this->assertEquals('/v2/bot/insight/message/event', $uri->getPath());
149+
// The LINE Insight API uses the camelCase "requestId" query key.
150+
$this->assertQueryEquals(['requestId' => 'abcdef'], $uri);
151+
return true;
152+
}),
153+
[]
154+
)
155+
->once()
156+
->andReturn(new Response(
157+
status: 200,
158+
headers: [],
159+
body: json_encode(['overview' => ['requestId' => 'abcdef']]),
160+
));
161+
$api = new InsightApi($client);
162+
$response = $api->getMessageEvent(requestId: 'abcdef');
163+
$this->assertInstanceOf(GetMessageEventResponse::class, $response);
164+
}
165+
166+
public function testGetStatisticsPerUnit(): void
167+
{
168+
$client = Mockery::mock(ClientInterface::class);
169+
$client->shouldReceive('send')
170+
->with(
171+
Mockery::on(function (Request $request) {
172+
$this->assertEquals('GET', $request->getMethod());
173+
$uri = $request->getUri();
174+
$this->assertEquals('/v2/bot/insight/message/event/aggregation', $uri->getPath());
175+
// All three query keys are camelCase in the spec and must be preserved.
176+
$this->assertQueryEquals([
177+
'customAggregationUnit' => 'promotion_a',
178+
'from' => '20260601',
179+
'to' => '20260630',
180+
], $uri);
181+
return true;
182+
}),
183+
[]
184+
)
185+
->once()
186+
->andReturn(new Response(
187+
status: 200,
188+
headers: [],
189+
body: json_encode(['overview' => [], 'messages' => [], 'clicks' => []]),
190+
));
191+
$api = new InsightApi($client);
192+
$response = $api->getStatisticsPerUnit(
193+
customAggregationUnit: 'promotion_a',
194+
from: '20260601',
195+
to: '20260630',
196+
);
197+
$this->assertInstanceOf(GetStatisticsPerUnitResponse::class, $response);
198+
}
199+
200+
public function testMutualTlsOptionsArePassedWhenConfigured(): void
201+
{
202+
// The 7.22.0 regeneration adds mTLS support: createHttpClientOption()
203+
// forwards Configuration::getCertFile()/getKeyFile() as Guzzle
204+
// RequestOptions::CERT / SSL_KEY. This pins that wiring.
205+
$config = new Configuration();
206+
$config->setCertFile('/path/to/client-cert.pem');
207+
$config->setKeyFile('/path/to/client-key.pem');
208+
$this->assertEquals('/path/to/client-cert.pem', $config->getCertFile());
209+
$this->assertEquals('/path/to/client-key.pem', $config->getKeyFile());
210+
211+
$client = Mockery::mock(ClientInterface::class);
212+
$client->shouldReceive('send')
213+
->with(
214+
Mockery::type(Request::class),
215+
Mockery::on(function (array $options) {
216+
$this->assertSame('/path/to/client-cert.pem', $options[RequestOptions::CERT] ?? null);
217+
$this->assertSame('/path/to/client-key.pem', $options[RequestOptions::SSL_KEY] ?? null);
218+
return true;
219+
})
220+
)
221+
->once()
222+
->andReturn(new Response(
223+
status: 200,
224+
headers: [],
225+
body: json_encode(['available' => true]),
226+
));
227+
$api = new InsightApi($client, $config);
228+
$response = $api->getFriendsDemographics();
229+
$this->assertInstanceOf(GetFriendsDemographicsResponse::class, $response);
230+
}
231+
232+
public function testThrowsApiExceptionOnMalformedJsonResponse(): void
233+
{
234+
// The 7.22.0 regeneration extracts response handling into
235+
// handleResponseWithDataType(); this pins the invariant that a 2xx
236+
// response with an undecodable body still surfaces as an ApiException.
237+
$client = Mockery::mock(ClientInterface::class);
238+
$client->shouldReceive('send')
239+
->once()
240+
->andReturn(new Response(
241+
status: 200,
242+
headers: [],
243+
body: 'this is not valid json {',
244+
));
245+
$api = new InsightApi($client);
246+
$this->expectException(\LINE\Clients\Insight\ApiException::class);
247+
$api->getNumberOfFollowers(date: '20260601');
248+
}
249+
250+
public function testGetStatisticsPerUnitRejectsInvalidUnit(): void
251+
{
252+
$client = Mockery::mock(ClientInterface::class);
253+
$api = new InsightApi($client);
254+
$this->expectException(\InvalidArgumentException::class);
255+
// "customAggregationUnit" must match /^[a-zA-Z0-9_]{1,30}$/.
256+
$api->getStatisticsPerUnit(
257+
customAggregationUnit: 'invalid unit!',
258+
from: '20260601',
259+
to: '20260630',
260+
);
261+
}
262+
263+
public function testGetNumberOfMessageDeliveriesRejectsInvalidDate(): void
264+
{
265+
$client = Mockery::mock(ClientInterface::class);
266+
$api = new InsightApi($client);
267+
$this->expectException(\InvalidArgumentException::class);
268+
// "date" must match /^[0-9]{8}$/.
269+
$api->getNumberOfMessageDeliveries(date: '2026-06-01');
270+
}
271+
272+
protected function tearDown(): void
273+
{
274+
Mockery::close();
275+
parent::tearDown();
276+
}
277+
}

0 commit comments

Comments
 (0)