22// for details. All rights reserved. Use of this source code is governed by a
33// BSD-style license that can be found in the LICENSE file.
44
5+ import 'dart:convert' ;
56import 'dart:io' ;
67import 'dart:typed_data' ;
78
@@ -12,7 +13,7 @@ import 'package:googleapis/storage/v1.dart' show DetailedApiRequestError;
1213import 'package:logging/logging.dart' ;
1314import 'package:pub_dev/fake/backend/fake_auth_provider.dart' ;
1415import 'package:pub_dev/package/api_export/api_exporter.dart' ;
15- import 'package:pub_dev/shared/datastore .dart' ;
16+ import 'package:pub_dev/shared/configuration .dart' ;
1617import 'package:pub_dev/shared/storage.dart' ;
1718import 'package:pub_dev/shared/utils.dart' ;
1819import 'package:pub_dev/shared/versions.dart' ;
@@ -48,15 +49,19 @@ void main() {
4849 'SHOUT Deleting object from public bucket: "packages/bar-2.0.0.tar.gz".' ,
4950 'SHOUT Deleting object from public bucket: "packages/bar-3.0.0.tar.gz".' ,
5051 ], (fakeTime) async {
51- await storageService.createBucket ('bucket' );
52- final bucket = storageService.bucket ('bucket' );
53- final apiExporter =
54- ApiExporter (dbService, storageService: storageService, bucket: bucket);
52+ // Since we want to verify post-upload tasks triggering API exporter,
53+ // we cannot use an isolated instance, we need to use the same setup.
54+ // However, for better control and consistency, we can remove all the
55+ // existing files from the bucket at the start of this test:
56+ await apiExporter! .stop ();
57+ final bucket =
58+ storageService.bucket (activeConfiguration.exportedApiBucketName! );
59+ await _deleteAll (bucket);
5560
5661 await _testExportedApiSynchronization (
5762 fakeTime,
5863 bucket,
59- apiExporter.synchronizeExportedApi,
64+ apiExporter! .synchronizeExportedApi,
6065 );
6166 });
6267
@@ -68,26 +73,38 @@ void main() {
6873 ],
6974 testProfile: _testProfile,
7075 (fakeTime) async {
71- await storageService.createBucket ('bucket' );
72- final bucket = storageService.bucket ('bucket' );
73- final apiExporter = ApiExporter (dbService,
74- storageService: storageService, bucket: bucket);
76+ // Since we want to verify post-upload tasks triggering API exporter,
77+ // we cannot use an isolated instance, we need to use the same setup.
78+ // However, for better control and consistency, we can remove all the
79+ // existing files from the bucket at the start of this test:
80+ await apiExporter! .stop ();
81+ final bucket =
82+ storageService.bucket (activeConfiguration.exportedApiBucketName! );
83+ await _deleteAll (bucket);
7584
76- await apiExporter.synchronizeExportedApi ();
85+ await apiExporter! .synchronizeExportedApi ();
7786
78- await apiExporter.start ();
87+ await apiExporter! .start ();
7988
8089 await _testExportedApiSynchronization (
8190 fakeTime,
8291 bucket,
8392 () async => await fakeTime.elapse (minutes: 15 ),
8493 );
8594
86- await apiExporter.stop ();
95+ await apiExporter! .stop ();
8796 },
8897 );
8998}
9099
100+ Future <void > _deleteAll (Bucket bucket) async {
101+ await for (final entry in bucket.list (delimiter: '' )) {
102+ if (entry.isObject) {
103+ await bucket.delete (entry.name);
104+ }
105+ }
106+ }
107+
91108Future <void > _testExportedApiSynchronization (
92109 FakeTime fakeTime,
93110 Bucket bucket,
@@ -131,6 +148,10 @@ Future<void> _testExportedApiSynchronization(
131148 await bucket.readBytes ('$runtimeVersion /api/archives/foo-1.0.0.tar.gz' ),
132149 isNotNull,
133150 );
151+ expect (
152+ await bucket.readString ('$runtimeVersion /feed.atom' ),
153+ contains ('v1.0.0 of foo' ),
154+ );
134155 }
135156
136157 _log.info ('## New package' );
@@ -160,6 +181,10 @@ Future<void> _testExportedApiSynchronization(
160181 await bucket.readBytes ('latest/api/archives/foo-1.0.0.tar.gz' ),
161182 isNotNull,
162183 );
184+ expect (
185+ await bucket.readString ('latest/feed.atom' ),
186+ contains ('v1.0.0 of foo' ),
187+ );
163188 // Note. that name completion data won't be updated until search caches
164189 // are purged, so we won't test that it is updated.
165190
@@ -176,6 +201,10 @@ Future<void> _testExportedApiSynchronization(
176201 await bucket.readBytes ('latest/api/archives/bar-2.0.0.tar.gz' ),
177202 isNotNull,
178203 );
204+ expect (
205+ await bucket.readString ('latest/feed.atom' ),
206+ contains ('v2.0.0 of bar' ),
207+ );
179208 }
180209
181210 _log.info ('## New package version' );
@@ -214,6 +243,10 @@ Future<void> _testExportedApiSynchronization(
214243 await bucket.readBytes ('latest/api/archives/bar-3.0.0.tar.gz' ),
215244 isNotNull,
216245 );
246+ expect (
247+ await bucket.readString ('$runtimeVersion /feed.atom' ),
248+ contains ('v3.0.0 of bar' ),
249+ );
217250 }
218251
219252 _log.info ('## Discontinued flipped on' );
@@ -439,7 +472,7 @@ Future<void> _testExportedApiSynchronization(
439472}
440473
441474extension on Bucket {
442- /// Read bytes from bucket, retur null if missing
475+ /// Read bytes from bucket, return null if missing
443476 Future <Uint8List ?> readBytes (String path) async {
444477 try {
445478 return await readAsBytes (path);
@@ -457,4 +490,10 @@ extension on Bucket {
457490 }
458491 return utf8JsonDecoder.convert (gzip.decode (bytes));
459492 }
493+
494+ /// Read bytes from bucket and decode as UTF-8 text.
495+ Future <String > readString (String path) async {
496+ final bytes = await readBytes (path);
497+ return utf8.decode (gzip.decode (bytes! ));
498+ }
460499}
0 commit comments