From cdc864eebbd09b56a8ec26cff3513ed986c6e213 Mon Sep 17 00:00:00 2001 From: Istvan Soos Date: Thu, 24 Oct 2024 16:50:44 +0200 Subject: [PATCH 1/3] Starting PackageStorage - moving all bucket-methods to a single place. --- app/lib/admin/actions/moderate_package.dart | 3 +- .../actions/moderate_package_versions.dart | 3 +- app/lib/package/backend.dart | 9 + app/lib/package/package_storage.dart | 175 ++++++++++++++++++ .../maintenance/update_public_bucket.dart | 157 ---------------- app/lib/tool/neat_task/pub_dev_tasks.dart | 4 +- app/test/admin/moderate_package_test.dart | 5 +- .../admin/moderate_package_version_test.dart | 5 +- .../update_public_bucket_test.dart | 99 ++++------ 9 files changed, 231 insertions(+), 229 deletions(-) create mode 100644 app/lib/package/package_storage.dart delete mode 100644 app/lib/tool/maintenance/update_public_bucket.dart diff --git a/app/lib/admin/actions/moderate_package.dart b/app/lib/admin/actions/moderate_package.dart index fdfa94d867..7cf10f8669 100644 --- a/app/lib/admin/actions/moderate_package.dart +++ b/app/lib/admin/actions/moderate_package.dart @@ -8,7 +8,6 @@ import '../../package/backend.dart'; import '../../package/models.dart'; import '../../shared/datastore.dart'; import '../../task/backend.dart'; -import '../../tool/maintenance/update_public_bucket.dart'; import 'actions.dart'; final moderatePackage = AdminAction( @@ -83,7 +82,7 @@ Note: the action may take a longer time to complete as the public archive bucket }); // retract or re-populate public archive files - await updatePublicArchiveBucket( + await packageBackend.packageStorage.updatePublicArchiveBucket( package: package, ageCheckThreshold: Duration.zero, deleteIfOlder: Duration.zero, diff --git a/app/lib/admin/actions/moderate_package_versions.dart b/app/lib/admin/actions/moderate_package_versions.dart index 7f8ef70438..630eb5cb1e 100644 --- a/app/lib/admin/actions/moderate_package_versions.dart +++ b/app/lib/admin/actions/moderate_package_versions.dart @@ -11,7 +11,6 @@ import '../../scorecard/backend.dart'; import '../../shared/datastore.dart'; import '../../shared/versions.dart'; import '../../task/backend.dart'; -import '../../tool/maintenance/update_public_bucket.dart'; import '../backend.dart'; import '../models.dart'; @@ -116,7 +115,7 @@ Set the moderated flag on a package version (updating the flag and the timestamp }); // retract or re-populate public archive files - await updatePublicArchiveBucket( + await packageBackend.packageStorage.updatePublicArchiveBucket( package: package, ageCheckThreshold: Duration.zero, deleteIfOlder: Duration.zero, diff --git a/app/lib/package/backend.dart b/app/lib/package/backend.dart index 4cfd0b2266..924fd74108 100644 --- a/app/lib/package/backend.dart +++ b/app/lib/package/backend.dart @@ -17,6 +17,7 @@ import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:pool/pool.dart'; import 'package:pub_dev/package/api_export/export_api_to_bucket.dart'; +import 'package:pub_dev/package/package_storage.dart'; import 'package:pub_dev/service/async_queue/async_queue.dart'; import 'package:pub_dev/service/rate_limit/rate_limit.dart'; import 'package:pub_dev/shared/versions.dart'; @@ -91,6 +92,14 @@ class PackageBackend { /// - `packages/$package-$version.tar.gz` (package archive) final Bucket _publicBucket; + /// The storage handling for the archive files. + late final packageStorage = PackageStorage( + db, + _storage, + _canonicalBucket, + _publicBucket, + ); + @visibleForTesting int maxVersionsPerPackage = _defaultMaxVersionsPerPackage; diff --git a/app/lib/package/package_storage.dart b/app/lib/package/package_storage.dart new file mode 100644 index 0000000000..07259eb914 --- /dev/null +++ b/app/lib/package/package_storage.dart @@ -0,0 +1,175 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:gcloud/storage.dart'; +import 'package:logging/logging.dart'; +import 'package:pub_dev/package/backend.dart'; +import 'package:pub_dev/package/models.dart'; +import 'package:pub_dev/shared/datastore.dart'; +import 'package:pub_dev/shared/storage.dart'; + +final _logger = Logger('package_storage'); + +class PackageStorage { + final DatastoreDB _dbService; + final Storage _storage; + + /// The Cloud Storage bucket to use for canonical package archives. + /// The following files are present: + /// - `packages/$package-$version.tar.gz` (package archive) + final Bucket _canonicalBucket; + + /// The Cloud Storage bucket to use for public package archives. + /// The following files are present: + /// - `packages/$package-$version.tar.gz` (package archive) + final Bucket _publicBucket; + + PackageStorage( + this._dbService, + this._storage, + this._canonicalBucket, + this._publicBucket, + ); + + /// Updates the public package archive: + /// - copies missing archive objects from canonical to public bucket, + /// - deletes leftover objects from public bucket + /// + /// Return the number of objects that were updated. + Future updatePublicArchiveBucket({ + String? package, + Duration ageCheckThreshold = const Duration(days: 1), + Duration deleteIfOlder = const Duration(days: 7), + }) async { + _logger.info('Scanning PackageVersions for public bucket updates...'); + + var updatedCount = 0; + var toBeDeletedCount = 0; + final deleteObjects = {}; + + final objectNamesInPublicBucket = {}; + + Package? lastPackage; + final pvStream = package == null + ? _dbService.query().run() + : packageBackend.streamVersionsOfPackage(package); + await for (final pv in pvStream) { + if (lastPackage?.name != pv.package) { + lastPackage = await packageBackend.lookupPackage(pv.package); + } + final isModerated = lastPackage!.isModerated || pv.isModerated; + + final objectName = tarballObjectName(pv.package, pv.version!); + final publicInfo = await _publicBucket.tryInfo(objectName); + + if (isModerated) { + if (publicInfo != null) { + deleteObjects.add(objectName); + } + continue; + } + + if (publicInfo == null) { + _logger + .warning('Updating missing object in public bucket: $objectName'); + try { + await _storage.copyObject( + _canonicalBucket.absoluteObjectName(objectName), + _publicBucket.absoluteObjectName(objectName), + ); + final newInfo = await _publicBucket.info(objectName); + await updateContentDispositionToAttachment(newInfo, _publicBucket); + updatedCount++; + } on Exception catch (e, st) { + _logger.shout( + 'Failed to copy $objectName from canonical to public bucket', + e, + st, + ); + } + } + objectNamesInPublicBucket.add(objectName); + } + + final filterForNamePrefix = + package == null ? 'packages/' : tarballObjectNamePackagePrefix(package); + await for (final entry in _publicBucket.list(prefix: filterForNamePrefix)) { + // Skip non-objects. + if (!entry.isObject) { + continue; + } + // Skip objects that were matched in the previous step. + if (objectNamesInPublicBucket.contains(entry.name)) { + continue; + } + if (deleteObjects.contains(entry.name)) { + continue; + } + + final publicInfo = await _publicBucket.tryInfo(entry.name); + if (publicInfo == null) { + _logger.warning( + 'Failed to get info for public bucket object "${entry.name}".'); + continue; + } + + await updateContentDispositionToAttachment(publicInfo, _publicBucket); + + // Skip recently updated objects. + if (publicInfo.age < ageCheckThreshold) { + // Ignore recent files. + continue; + } + + final canonicalInfo = await _canonicalBucket.tryInfo(entry.name); + if (canonicalInfo != null) { + // Warn if both the canonical and the public bucket has the same object, + // but it wasn't matched through the [PackageVersion] query above. + if (canonicalInfo.age < ageCheckThreshold) { + // Ignore recent files. + continue; + } + _logger.severe( + 'Object without matching PackageVersion in canonical and public buckets: "${entry.name}".'); + continue; + } else { + // The object in the public bucket has no matching file in the canonical bucket. + // We can assume it is stale and can delete it. + if (publicInfo.age <= deleteIfOlder) { + _logger.shout( + 'Object from public bucket will be deleted: "${entry.name}".'); + toBeDeletedCount++; + } else { + deleteObjects.add(entry.name); + } + } + } + + for (final objectName in deleteObjects) { + _logger.shout('Deleting object from public bucket: "$objectName".'); + await _publicBucket.delete(objectName); + } + + return PublicBucketUpdateStat( + archivesUpdated: updatedCount, + archivesToBeDeleted: toBeDeletedCount, + archivesDeleted: deleteObjects.length, + ); + } +} + +class PublicBucketUpdateStat { + final int archivesUpdated; + final int archivesToBeDeleted; + final int archivesDeleted; + + PublicBucketUpdateStat({ + required this.archivesUpdated, + required this.archivesToBeDeleted, + required this.archivesDeleted, + }); + + bool get isAllZero => + archivesUpdated == 0 && archivesToBeDeleted == 0 && archivesDeleted == 0; +} diff --git a/app/lib/tool/maintenance/update_public_bucket.dart b/app/lib/tool/maintenance/update_public_bucket.dart deleted file mode 100644 index 51232d89ee..0000000000 --- a/app/lib/tool/maintenance/update_public_bucket.dart +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:gcloud/storage.dart'; -import 'package:logging/logging.dart'; -import 'package:pub_dev/package/backend.dart'; -import 'package:pub_dev/package/models.dart'; -import 'package:pub_dev/shared/configuration.dart'; -import 'package:pub_dev/shared/datastore.dart'; -import 'package:pub_dev/shared/storage.dart'; - -final _logger = Logger('update_public_buckets'); - -class PublicBucketUpdateStat { - final int archivesUpdated; - final int archivesToBeDeleted; - final int archivesDeleted; - - PublicBucketUpdateStat({ - required this.archivesUpdated, - required this.archivesToBeDeleted, - required this.archivesDeleted, - }); - - bool get isAllZero => - archivesUpdated == 0 && archivesToBeDeleted == 0 && archivesDeleted == 0; -} - -/// Updates the public package archive: -/// - copies missing archive objects from canonical to public bucket, -/// - deletes leftover objects from public bucket -/// -/// Return the number of objects that were updated. -Future updatePublicArchiveBucket({ - String? package, - Duration ageCheckThreshold = const Duration(days: 1), - Duration deleteIfOlder = const Duration(days: 7), -}) async { - _logger.info('Scanning PackageVersions for public bucket updates...'); - - var updatedCount = 0; - var toBeDeletedCount = 0; - final deleteObjects = {}; - final canonicalBucket = - storageService.bucket(activeConfiguration.canonicalPackagesBucketName!); - final publicBucket = - storageService.bucket(activeConfiguration.publicPackagesBucketName!); - - final objectNamesInPublicBucket = {}; - - Package? lastPackage; - final pvStream = package == null - ? dbService.query().run() - : packageBackend.streamVersionsOfPackage(package); - await for (final pv in pvStream) { - if (lastPackage?.name != pv.package) { - lastPackage = await packageBackend.lookupPackage(pv.package); - } - final isModerated = lastPackage!.isModerated || pv.isModerated; - - final objectName = tarballObjectName(pv.package, pv.version!); - final publicInfo = await publicBucket.tryInfo(objectName); - - if (isModerated) { - if (publicInfo != null) { - deleteObjects.add(objectName); - } - continue; - } - - if (publicInfo == null) { - _logger.warning('Updating missing object in public bucket: $objectName'); - try { - await storageService.copyObject( - canonicalBucket.absoluteObjectName(objectName), - publicBucket.absoluteObjectName(objectName), - ); - final newInfo = await publicBucket.info(objectName); - await updateContentDispositionToAttachment(newInfo, publicBucket); - updatedCount++; - } on Exception catch (e, st) { - _logger.shout( - 'Failed to copy $objectName from canonical to public bucket', - e, - st, - ); - } - } - objectNamesInPublicBucket.add(objectName); - } - - final filterForNamePrefix = - package == null ? 'packages/' : tarballObjectNamePackagePrefix(package); - await for (final entry in publicBucket.list(prefix: filterForNamePrefix)) { - // Skip non-objects. - if (!entry.isObject) { - continue; - } - // Skip objects that were matched in the previous step. - if (objectNamesInPublicBucket.contains(entry.name)) { - continue; - } - if (deleteObjects.contains(entry.name)) { - continue; - } - - final publicInfo = await publicBucket.tryInfo(entry.name); - if (publicInfo == null) { - _logger.warning( - 'Failed to get info for public bucket object "${entry.name}".'); - continue; - } - - await updateContentDispositionToAttachment(publicInfo, publicBucket); - - // Skip recently updated objects. - if (publicInfo.age < ageCheckThreshold) { - // Ignore recent files. - continue; - } - - final canonicalInfo = await canonicalBucket.tryInfo(entry.name); - if (canonicalInfo != null) { - // Warn if both the canonical and the public bucket has the same object, - // but it wasn't matched through the [PackageVersion] query above. - if (canonicalInfo.age < ageCheckThreshold) { - // Ignore recent files. - continue; - } - _logger.severe( - 'Object without matching PackageVersion in canonical and public buckets: "${entry.name}".'); - continue; - } else { - // The object in the public bucket has no matching file in the canonical bucket. - // We can assume it is stale and can delete it. - if (publicInfo.age <= deleteIfOlder) { - _logger.shout( - 'Object from public bucket will be deleted: "${entry.name}".'); - toBeDeletedCount++; - } else { - deleteObjects.add(entry.name); - } - } - } - - for (final objectName in deleteObjects) { - _logger.shout('Deleting object from public bucket: "$objectName".'); - await publicBucket.delete(objectName); - } - - return PublicBucketUpdateStat( - archivesUpdated: updatedCount, - archivesToBeDeleted: toBeDeletedCount, - archivesDeleted: deleteObjects.length, - ); -} diff --git a/app/lib/tool/neat_task/pub_dev_tasks.dart b/app/lib/tool/neat_task/pub_dev_tasks.dart index c521dcdc61..6414fe904d 100644 --- a/app/lib/tool/neat_task/pub_dev_tasks.dart +++ b/app/lib/tool/neat_task/pub_dev_tasks.dart @@ -30,7 +30,6 @@ import '../../task/global_lock.dart'; import '../../tool/backfill/backfill_new_fields.dart'; import '../maintenance/remove_orphaned_likes.dart'; import '../maintenance/update_package_likes.dart'; -import '../maintenance/update_public_bucket.dart'; import 'datastore_status_provider.dart'; final _logger = Logger('pub_dev_tasks'); @@ -114,7 +113,8 @@ void _setupGenericPeriodicTasks() { _daily( name: 'sync-public-bucket-from-canonical-bucket', isRuntimeVersioned: false, - task: updatePublicArchiveBucket, + task: () async => + await packageBackend.packageStorage.updatePublicArchiveBucket(), ); // Exports the package name completion data to a bucket. diff --git a/app/test/admin/moderate_package_test.dart b/app/test/admin/moderate_package_test.dart index 6de46959fa..71aef8abf4 100644 --- a/app/test/admin/moderate_package_test.dart +++ b/app/test/admin/moderate_package_test.dart @@ -22,7 +22,6 @@ import 'package:pub_dev/search/backend.dart'; import 'package:pub_dev/shared/configuration.dart'; import 'package:pub_dev/shared/datastore.dart'; import 'package:pub_dev/shared/storage.dart'; -import 'package:pub_dev/tool/maintenance/update_public_bucket.dart'; import 'package:test/test.dart'; import '../admin/models_test.dart'; @@ -315,13 +314,13 @@ void main() { await expectStatusCode(404); // another check after background tasks are running - await updatePublicArchiveBucket(); + await packageBackend.packageStorage.updatePublicArchiveBucket(); await expectStatusCode(404); await _moderate('oxygen', state: false, caseId: mc.caseId); await expectStatusCode(200); // another check after background tasks are running - await updatePublicArchiveBucket(); + await packageBackend.packageStorage.updatePublicArchiveBucket(); final restoredBytes = await expectStatusCode(200); expect(restoredBytes, bytes); }); diff --git a/app/test/admin/moderate_package_version_test.dart b/app/test/admin/moderate_package_version_test.dart index 5d23ee8236..e44b1ffcc1 100644 --- a/app/test/admin/moderate_package_version_test.dart +++ b/app/test/admin/moderate_package_version_test.dart @@ -22,7 +22,6 @@ import 'package:pub_dev/shared/datastore.dart'; import 'package:pub_dev/shared/exceptions.dart'; import 'package:pub_dev/shared/storage.dart'; import 'package:pub_dev/task/backend.dart'; -import 'package:pub_dev/tool/maintenance/update_public_bucket.dart'; import 'package:test/test.dart'; import '../frontend/handlers/_utils.dart'; @@ -207,13 +206,13 @@ void main() { await expectStatusCode(200, version: '1.2.0'); // another check after background tasks are running - await updatePublicArchiveBucket(); + await packageBackend.packageStorage.updatePublicArchiveBucket(); await expectStatusCode(404); await expectStatusCode(200, version: '1.2.0'); await _moderate('oxygen', '1.0.0', state: false); await expectStatusCode(200); - await updatePublicArchiveBucket(); + await packageBackend.packageStorage.updatePublicArchiveBucket(); final restoredBytes = await expectStatusCode(200); expect(restoredBytes, bytes); }); diff --git a/app/test/tool/maintenance/update_public_bucket_test.dart b/app/test/tool/maintenance/update_public_bucket_test.dart index d14aaaceb8..d110359dc8 100644 --- a/app/test/tool/maintenance/update_public_bucket_test.dart +++ b/app/test/tool/maintenance/update_public_bucket_test.dart @@ -3,17 +3,29 @@ // BSD-style license that can be found in the LICENSE file. import 'package:gcloud/storage.dart'; +import 'package:pub_dev/package/backend.dart'; +import 'package:pub_dev/package/package_storage.dart'; import 'package:pub_dev/shared/configuration.dart'; -import 'package:pub_dev/tool/maintenance/update_public_bucket.dart'; import 'package:test/test.dart'; import '../../shared/test_services.dart'; void main() { group('update public bucket', () { + Future _updatePublicArchiveBucket({ + String? package, + Duration? ageCheckThreshold, + Duration? deleteIfOlder, + }) async { + return await packageBackend.packageStorage.updatePublicArchiveBucket( + package: package, + ageCheckThreshold: ageCheckThreshold ?? Duration.zero, + deleteIfOlder: deleteIfOlder ?? const Duration(days: 7), + ); + } + testWithProfile('no update', fn: () async { - final changes = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes = await _updatePublicArchiveBucket(); expect(changes.isAllZero, isTrue); }); @@ -22,14 +34,12 @@ void main() { storageService.bucket(activeConfiguration.publicPackagesBucketName!); await bucket.delete('packages/oxygen-1.0.0.tar.gz'); - final changes = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes = await _updatePublicArchiveBucket(); expect(changes.archivesUpdated, 1); expect(changes.archivesToBeDeleted, 0); expect(changes.archivesDeleted, 0); - final changes2 = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes2 = await _updatePublicArchiveBucket(); expect(changes2.isAllZero, isTrue); }); @@ -39,22 +49,15 @@ void main() { storageService.bucket(activeConfiguration.publicPackagesBucketName!); await bucket.delete('packages/oxygen-1.0.0.tar.gz'); - final changes = await updatePublicArchiveBucket( - package: 'oxygen', - ageCheckThreshold: Duration.zero, - ); + final changes = await _updatePublicArchiveBucket(package: 'oxygen'); expect(changes.archivesUpdated, 1); expect(changes.archivesToBeDeleted, 0); expect(changes.archivesDeleted, 0); - final changes2 = await updatePublicArchiveBucket( - package: 'oxygen', - ageCheckThreshold: Duration.zero, - ); + final changes2 = await _updatePublicArchiveBucket(package: 'oxygen'); expect(changes2.isAllZero, isTrue); - final changes3 = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes3 = await _updatePublicArchiveBucket(); expect(changes3.isAllZero, isTrue); }); @@ -64,21 +67,14 @@ void main() { storageService.bucket(activeConfiguration.publicPackagesBucketName!); await bucket.delete('packages/oxygen-1.0.0.tar.gz'); - final changes = await updatePublicArchiveBucket( - package: 'neon', - ageCheckThreshold: Duration.zero, - ); + final changes = await _updatePublicArchiveBucket(package: 'neon'); expect(changes.isAllZero, isTrue); - final changes2 = await updatePublicArchiveBucket( - package: 'neon', - ageCheckThreshold: Duration.zero, - ); + final changes2 = await _updatePublicArchiveBucket(package: 'neon'); expect(changes2.isAllZero, isTrue); // eventual update - final changes3 = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes3 = await _updatePublicArchiveBucket(); expect(changes3.archivesUpdated, 1); expect(changes3.archivesToBeDeleted, 0); expect(changes3.archivesDeleted, 0); @@ -90,19 +86,18 @@ void main() { await bucket.writeBytes('packages/oxygen-0.0.99.tar.gz', [1]); // recent file gets ignored - final recent = await updatePublicArchiveBucket(); + final recent = await _updatePublicArchiveBucket( + ageCheckThreshold: Duration(days: 1)); expect(recent.isAllZero, isTrue); // non-recent file will get deleted - final changes = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes = await _updatePublicArchiveBucket(); expect(changes.archivesUpdated, 0); expect(changes.archivesToBeDeleted, 1); expect(changes.archivesDeleted, 0); // non-recent file is deleted - final changes2 = await updatePublicArchiveBucket( - ageCheckThreshold: Duration.zero, + final changes2 = await _updatePublicArchiveBucket( deleteIfOlder: Duration.zero, ); expect(changes2.archivesUpdated, 0); @@ -110,8 +105,7 @@ void main() { expect(changes2.archivesDeleted, 1); // second round should report 0 deleted - final changes3 = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes3 = await _updatePublicArchiveBucket(); expect(changes3.isAllZero, isTrue); }); @@ -121,22 +115,19 @@ void main() { await bucket.writeBytes('packages/oxygen-0.0.99.tar.gz', [1]); // recent file gets ignored - final recent = await updatePublicArchiveBucket(package: 'oxygen'); + final recent = await _updatePublicArchiveBucket( + ageCheckThreshold: Duration(days: 1)); expect(recent.isAllZero, isTrue); // non-recent file will get deleted - final changes = await updatePublicArchiveBucket( - package: 'oxygen', - ageCheckThreshold: Duration.zero, - ); + final changes = await _updatePublicArchiveBucket(package: 'oxygen'); expect(changes.archivesUpdated, 0); expect(changes.archivesToBeDeleted, 1); expect(changes.archivesDeleted, 0); // non-recent file is deleted - final changes2 = await updatePublicArchiveBucket( + final changes2 = await _updatePublicArchiveBucket( package: 'oxygen', - ageCheckThreshold: Duration.zero, deleteIfOlder: Duration.zero, ); expect(changes2.archivesUpdated, 0); @@ -144,15 +135,11 @@ void main() { expect(changes2.archivesDeleted, 1); // second round should report 0 deleted - final changes3 = await updatePublicArchiveBucket( - package: 'oxygen', - ageCheckThreshold: Duration.zero, - ); + final changes3 = await _updatePublicArchiveBucket(package: 'oxygen'); expect(changes3.isAllZero, isTrue); // no further changes - final changes4 = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes4 = await _updatePublicArchiveBucket(); expect(changes4.isAllZero, isTrue); }); @@ -162,30 +149,22 @@ void main() { await bucket.writeBytes('packages/oxygen-0.0.99.tar.gz', [1]); // no matching file - final recent = await updatePublicArchiveBucket(package: 'neon'); + final recent = await _updatePublicArchiveBucket(package: 'neon'); expect(recent.isAllZero, isTrue); // no matching files - final changes = await updatePublicArchiveBucket( - package: 'neon', - ageCheckThreshold: Duration.zero, - ); + final changes = await _updatePublicArchiveBucket(package: 'neon'); expect(changes.isAllZero, isTrue); - final changes2 = await updatePublicArchiveBucket( + final changes2 = await _updatePublicArchiveBucket( package: 'neon', - ageCheckThreshold: Duration.zero, deleteIfOlder: Duration.zero, ); expect(changes2.isAllZero, isTrue); - final changes3 = await updatePublicArchiveBucket( - package: 'neon', - ageCheckThreshold: Duration.zero, - ); + final changes3 = await _updatePublicArchiveBucket(package: 'neon'); expect(changes3.isAllZero, isTrue); // changes will be picked up without filter - final changes4 = - await updatePublicArchiveBucket(ageCheckThreshold: Duration.zero); + final changes4 = await _updatePublicArchiveBucket(); expect(changes4.isAllZero, isFalse); }); }); From e098ac50ed7ce8c31fa38260b351f79b25fc0165 Mon Sep 17 00:00:00 2001 From: Istvan Soos Date: Thu, 24 Oct 2024 17:06:34 +0200 Subject: [PATCH 2/3] Also move test file --- .../{tool/maintenance => package}/update_public_bucket_test.dart | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/test/{tool/maintenance => package}/update_public_bucket_test.dart (100%) diff --git a/app/test/tool/maintenance/update_public_bucket_test.dart b/app/test/package/update_public_bucket_test.dart similarity index 100% rename from app/test/tool/maintenance/update_public_bucket_test.dart rename to app/test/package/update_public_bucket_test.dart From 21d661a3cafe8d20e75f0320986fce5af310872a Mon Sep 17 00:00:00 2001 From: Istvan Soos Date: Thu, 24 Oct 2024 17:37:09 +0200 Subject: [PATCH 3/3] fixing test import url --- app/test/package/update_public_bucket_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/test/package/update_public_bucket_test.dart b/app/test/package/update_public_bucket_test.dart index d110359dc8..89626a5518 100644 --- a/app/test/package/update_public_bucket_test.dart +++ b/app/test/package/update_public_bucket_test.dart @@ -8,7 +8,7 @@ import 'package:pub_dev/package/package_storage.dart'; import 'package:pub_dev/shared/configuration.dart'; import 'package:test/test.dart'; -import '../../shared/test_services.dart'; +import '../shared/test_services.dart'; void main() { group('update public bucket', () {