Skip to content

Commit 8021b48

Browse files
authored
Integration test to use pub get with the exported API bucket (+ minimal content rewrite) (#8328)
1 parent 031c368 commit 8021b48

File tree

5 files changed

+146
-6
lines changed

5 files changed

+146
-6
lines changed

app/lib/fake/server/fake_server_entrypoint.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:pub_dev/fake/server/fake_search_service.dart';
1414
import 'package:pub_dev/fake/server/fake_storage_server.dart';
1515
import 'package:pub_dev/fake/server/local_server_state.dart';
1616
import 'package:pub_dev/frontend/static_files.dart';
17+
import 'package:pub_dev/package/api_export/api_exporter.dart';
1718
import 'package:pub_dev/shared/configuration.dart';
1819
import 'package:pub_dev/shared/handlers.dart';
1920
import 'package:pub_dev/shared/logging.dart';
@@ -177,6 +178,7 @@ Future<shelf.Response> _testProfile(shelf.Request rq) async {
177178
source: ImportSource.autoGenerated(),
178179
);
179180
final analysis = (map['analysis'] as String?) ?? 'fake';
181+
await apiExporter!.synchronizeExportedApi();
180182
await processTaskFakeLocalOrWorker(analysis);
181183
return shelf.Response.ok('{}');
182184
}

app/lib/fake/server/fake_storage_server.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,14 @@ class FakeStorageServer {
7474
if (exists == null) {
7575
return Response.notFound('404 Not Found');
7676
}
77-
final contentType = lookupMimeType(objectName);
78-
return Response.ok(bucket.read(objectName),
79-
headers: {if (contentType != null) 'Content-Type': contentType});
77+
final contentType =
78+
exists.metadata.contentType ?? lookupMimeType(objectName);
79+
final contentEncoding = exists.metadata.contentEncoding;
80+
81+
return Response.ok(bucket.read(objectName), headers: {
82+
if (contentType != null) 'Content-Type': contentType,
83+
if (contentEncoding != null) 'Content-Encoding': contentEncoding,
84+
});
8085
} else if (request.method == 'POST') {
8186
_logger.info('Uploading: ${request.requestedUri.path}');
8287
final contentHeader = _parse(request.headers['content-type']);

app/test/admin/moderate_package_version_test.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'dart:convert';
6-
import 'dart:io';
76
import 'dart:typed_data';
87

98
import 'package:_pub_shared/data/account_api.dart';
@@ -242,8 +241,8 @@ void main() {
242241
'/$prefix/api/packages/oxygen';
243242
final rs = await http.get(Uri.parse(url));
244243
expect(rs.statusCode, 200);
245-
final data = json.decode(utf8.decode(gzip.decode(rs.bodyBytes)))
246-
as Map<String, dynamic>;
244+
final data =
245+
json.decode(utf8.decode(rs.bodyBytes)) as Map<String, dynamic>;
247246
final versions = (data['versions'] as List)
248247
.map((i) => (i as Map)['version'])
249248
.toSet();

pkg/pub_integration/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ dependencies:
1717

1818
dev_dependencies:
1919
coverage: any # test already depends on it
20+
shelf: ^1.4.0
2021
test: ^1.16.5
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
7+
import 'dart:io';
8+
9+
import 'package:http/http.dart' as http;
10+
import 'package:path/path.dart' as p;
11+
import 'package:pub_integration/src/fake_test_context_provider.dart';
12+
import 'package:shelf/shelf.dart' as shelf;
13+
import 'package:shelf/shelf_io.dart' as shelf_io;
14+
import 'package:test/test.dart';
15+
16+
void main() {
17+
group(
18+
'exported bucket works with pub get',
19+
() {
20+
late final TestContextProvider fakeTestScenario;
21+
final httpClient = http.Client();
22+
late final Directory temp;
23+
late final HttpServer proxy;
24+
25+
setUpAll(() async {
26+
fakeTestScenario = await TestContextProvider.start();
27+
temp = await Directory.systemTemp.createTemp('exported-bucket');
28+
29+
final pubUri = Uri.parse(fakeTestScenario.pubHostedUrl);
30+
final storageUri = pubUri.replace(
31+
port: pubUri.port + 1, path: '/fake-exported-apis/latest');
32+
33+
// read-only proxy server with minimal content rewrite
34+
proxy = await shelf_io.serve((rq) async {
35+
try {
36+
// the proxy url with the appropriate path prefix
37+
final proxyUri = storageUri.replace(pathSegments: [
38+
...storageUri.pathSegments,
39+
...rq.requestedUri.pathSegments
40+
]);
41+
42+
// other requests are proxied
43+
final rs = await http.get(proxyUri);
44+
45+
Map<String, String> copyHeaders(List<String> keys) {
46+
return Map.fromEntries(
47+
rs.headers.entries.where((e) => keys.contains(e.key)));
48+
}
49+
50+
// package listing requests need content rewrite (+ keeping the condition broad for future JSON APIs)
51+
if (rs.statusCode == 200 &&
52+
rq.requestedUri.toString().contains('/api/packages/')) {
53+
return shelf.Response(
54+
rs.statusCode,
55+
body: rs.body.replaceAll(
56+
pubUri.toString(), 'http://localhost:${proxy.port}'),
57+
headers: copyHeaders(['content-type']),
58+
);
59+
}
60+
61+
// otherwise return the result as-is
62+
return shelf.Response(
63+
rs.statusCode,
64+
body: rs.bodyBytes,
65+
headers: copyHeaders(['content-type', 'content-encoding']),
66+
);
67+
} catch (e, st) {
68+
print(e);
69+
print(st);
70+
return shelf.Response.internalServerError();
71+
}
72+
}, InternetAddress.loopbackIPv4, 0);
73+
});
74+
75+
tearDownAll(() async {
76+
await proxy.close();
77+
await temp.delete(recursive: true);
78+
await fakeTestScenario.close();
79+
httpClient.close();
80+
});
81+
82+
test('bulk tests', () async {
83+
final origin = fakeTestScenario.pubHostedUrl;
84+
// init server data
85+
await httpClient.post(
86+
Uri.parse('$origin/fake-test-profile'),
87+
body: json.encode(
88+
{
89+
'testProfile': {
90+
'defaultUser': '[email protected]',
91+
'packages': [
92+
{
93+
'name': 'exported_api_pkg',
94+
'versions': [
95+
{'version': '1.0.0'},
96+
{'version': '1.0.2-dev+2'},
97+
],
98+
},
99+
],
100+
},
101+
},
102+
),
103+
);
104+
105+
// create a local project with dependency on exported_api_pkg:1.0.2-dev+2
106+
final pubspec = File(p.join(temp.path, 'pubspec.yaml'));
107+
await pubspec.writeAsString(json.encode({
108+
'name': 'test_pkg',
109+
'environment': {
110+
'sdk': '>=3.0.0 <4.0.0',
111+
},
112+
'dependencies': {
113+
'exported_api_pkg': '^1.0.1',
114+
},
115+
}));
116+
117+
// run pub get and verify its success
118+
final pr = await Process.run(
119+
'dart',
120+
['pub', 'get', '-v'],
121+
environment: {'PUB_HOSTED_URL': 'http://localhost:${proxy.port}'},
122+
workingDirectory: temp.path,
123+
);
124+
expect(pr.exitCode, 0, reason: [pr.stdout, pr.stderr].join('\n'));
125+
126+
final resolvedFile =
127+
File(p.join(temp.path, '.dart_tool', 'package_config.json'));
128+
expect(resolvedFile.existsSync(), true);
129+
});
130+
},
131+
timeout: Timeout.factor(testTimeoutFactor),
132+
);
133+
}

0 commit comments

Comments
 (0)