Show outdated and discontinued in listing in get (#2844)

For a pubspec.yaml
```
name: blah 
environment:
  sdk: '>=2.7.0 <3.0.0'

dependencies: 
  package_config:
  _dummy_pkg: <0.0.4
  retry: ^2.0.0
```
Will now have this output for pub get (the second run highlights outdated and discontinued packages):

```
> dart pub get
Resolving dependencies... (1.0s)
+ _dummy_pkg 0.0.3 (discontinued)
+ charcode 1.1.3
+ package_config 1.9.3
+ path 1.7.0
+ retry 2.0.0 (3.0.1 available)
Changed 5 dependencies!
```

Second invocation (with a pubspec.lock in place):

```
> dart pub get
Resolving dependencies... 
  _dummy_pkg 0.0.3 (discontinued)
  retry 2.0.0 (3.0.1 available)
Got dependencies!
```
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index 69a2b33..55a56b3 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -427,8 +427,9 @@
   /// This automatically downloads the package to the system-wide cache as well
   /// if it requires network access to retrieve (specifically, if the package's
   /// source is a [CachedSource]).
-  Future _get(PackageId id) {
-    return http.withDependencyType(root.dependencyType(id.name), () async {
+  Future<void> _get(PackageId id) async {
+    return await http.withDependencyType(root.dependencyType(id.name),
+        () async {
       if (id.isRoot) return;
 
       var source = cache.source(id.source);
diff --git a/lib/src/solver.dart b/lib/src/solver.dart
index 18b4174..e88796a 100644
--- a/lib/src/solver.dart
+++ b/lib/src/solver.dart
@@ -24,8 +24,8 @@
 /// If [unlock] is given, then only packages listed in [unlock] will be unlocked
 /// from [lockFile]. This is useful for a upgrading specific packages only.
 ///
-/// If [unlock] is empty [SolveType.GET] interprets this as lock everything,
-/// while [SolveType.UPGRADE] and [SolveType.DOWNGRADE] interprets an empty
+/// If [unlock] is empty [SolveType.get] interprets this as lock everything,
+/// while [SolveType.upgrade] and [SolveType.downgrade] interprets an empty
 /// [unlock] as unlock everything.
 Future<SolveResult> resolveVersions(
   SolveType type,
@@ -55,8 +55,8 @@
 /// If [unlock] is given, only packages listed in [unlock] will be unlocked
 /// from [lockFile]. This is useful for a upgrading specific packages only.
 ///
-/// If [unlock] is empty [SolveType.GET] interprets this as lock everything,
-/// while [SolveType.UPGRADE] and [SolveType.DOWNGRADE] interprets an empty
+/// If [unlock] is empty [SolveType.get] interprets this as lock everything,
+/// while [SolveType.upgrade] and [SolveType.downgrade] interprets an empty
 /// [unlock] as unlock everything.
 Future<SolveResult> tryResolveVersions(
   SolveType type,
diff --git a/lib/src/solver/package_lister.dart b/lib/src/solver/package_lister.dart
index 087c958..5851e0e 100644
--- a/lib/src/solver/package_lister.dart
+++ b/lib/src/solver/package_lister.dart
@@ -427,7 +427,7 @@
   _RootSource(this._package);
 
   @override
-  Future<List<PackageId>> getVersions(PackageRef ref) {
+  Future<List<PackageId>> getVersions(PackageRef ref, {Duration maxAge}) {
     assert(ref.isRoot);
     return Future.value([PackageId.root(_package)]);
   }
@@ -443,7 +443,8 @@
   @override
   SystemCache get systemCache => throw _unsupported;
   @override
-  Future<List<PackageId>> doGetVersions(PackageRef ref) => throw _unsupported;
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) =>
+      throw _unsupported;
   @override
   Future<Pubspec> doDescribe(PackageId id) => throw _unsupported;
   @override
diff --git a/lib/src/solver/report.dart b/lib/src/solver/report.dart
index 27c368f..39f005f 100644
--- a/lib/src/solver/report.dart
+++ b/lib/src/solver/report.dart
@@ -44,8 +44,8 @@
   /// Displays a report of the results of the version resolution relative to
   /// the previous lock file.
   Future<void> show() async {
-    _reportChanges();
-    _reportOverrides();
+    await _reportChanges();
+    await _reportOverrides();
   }
 
   /// Displays a one-line message summarizing what changes were made (or would
@@ -95,15 +95,16 @@
 
   /// Displays a report of all of the previous and current dependencies and
   /// how they have changed.
-  void _reportChanges() {
+  Future<void> _reportChanges() async {
     _output.clear();
 
     // Show the new set of dependencies ordered by name.
     var names = _result.packages.map((id) => id.name).toList();
     names.remove(_root.name);
     names.sort();
-    names.forEach(_reportPackage);
-
+    for (final name in names) {
+      await _reportPackage(name);
+    }
     // Show any removed ones.
     var removed = _previousLockFile.packages.keys.toSet();
     removed.removeAll(names);
@@ -111,7 +112,7 @@
     if (removed.isNotEmpty) {
       _output.writeln('These packages are no longer being depended on:');
       for (var name in ordered(removed)) {
-        _reportPackage(name, alwaysShow: true);
+        await _reportPackage(name, alwaysShow: true);
       }
     }
 
@@ -119,46 +120,20 @@
   }
 
   /// Displays a warning about the overrides currently in effect.
-  void _reportOverrides() {
+  Future<void> _reportOverrides() async {
     _output.clear();
 
     if (_root.dependencyOverrides.isNotEmpty) {
       _output.writeln('Warning: You are using these overridden dependencies:');
 
       for (var name in ordered(_root.dependencyOverrides.keys)) {
-        _reportPackage(name, alwaysShow: true, highlightOverride: false);
+        await _reportPackage(name, alwaysShow: true, highlightOverride: false);
       }
 
       log.warning(_output);
     }
   }
 
-  /// Displays a warning about any discontinued packages directly depended upon.
-  Future<void> reportDiscontinued() async {
-    final directDependencies = _result.packages
-        .where((id) => _root.dependencyType(id.name) != DependencyType.none);
-    final statuses = await Future.wait(
-      directDependencies.map(
-        (id) async => Pair(
-          id,
-          // We allow data to be up to 3 days old to not spend too much network
-          // time for packages that were not unlocked.
-          await _cache.source(id.source).status(id, Duration(days: 3)),
-        ),
-      ),
-    );
-    for (final statusPair in statuses) {
-      final id = statusPair.first;
-      final status = statusPair.last;
-      if (statusPair.last.isDiscontinued ?? false) {
-        final suffix = status.discontinuedReplacedBy == null
-            ? ''
-            : ' it has been replaced by package ${status.discontinuedReplacedBy}';
-        log.warning('Package ${id.name} has been discontinued$suffix.');
-      }
-    }
-  }
-
   /// Displays a two-line message, number of outdated packages and an
   /// instruction to run `pub outdated` if outdated packages are detected.
   void reportOutdated() {
@@ -190,8 +165,8 @@
   /// If [alwaysShow] is true, the package is reported even if it didn't change,
   /// regardless of [_type]. If [highlightOverride] is true (or absent), writes
   /// "(override)" next to overridden packages.
-  void _reportPackage(String name,
-      {bool alwaysShow = false, bool highlightOverride = true}) {
+  Future<void> _reportPackage(String name,
+      {bool alwaysShow = false, bool highlightOverride = true}) async {
     var newId = _dependencies[name];
     var oldId = _previousLockFile.packages[name];
     var id = newId ?? oldId;
@@ -235,8 +210,46 @@
       // Unchanged.
       icon = '  ';
     }
+    String message;
+    // See if there are any newer versions of the package that we were
+    // unable to upgrade to.
+    if (newId != null && _type != SolveType.DOWNGRADE) {
+      var versions = _result.availableVersions[newId.name];
 
-    if (_type == SolveType.GET && !(alwaysShow || changed || addedOrRemoved)) {
+      var newerStable = false;
+      var newerUnstable = false;
+
+      for (var version in versions) {
+        if (version > newId.version) {
+          if (version.isPreRelease) {
+            newerUnstable = true;
+          } else {
+            newerStable = true;
+          }
+        }
+      }
+      final status =
+          await _cache.source(id.source).status(id, Duration(days: 3));
+      if (status.isDiscontinued) {
+        if (status.discontinuedReplacedBy == null) {
+          message = '(discontinued)';
+        } else {
+          message =
+              '(discontinued replaced by ${status.discontinuedReplacedBy})';
+        }
+      } else if (newerStable) {
+        // If there are newer stable versions, only show those.
+        message = '(${maxAll(versions, Version.prioritize)} available)';
+      } else if (
+          // Only show newer prereleases for versions where a prerelease is
+          // already chosen.
+          newId.version.isPreRelease && newerUnstable) {
+        message = '(${maxAll(versions)} available)';
+      }
+    }
+
+    if (_type == SolveType.GET &&
+        !(alwaysShow || changed || addedOrRemoved || message != null)) {
       return;
     }
 
@@ -257,37 +270,7 @@
       _output.write(" ${log.magenta('(overridden)')}");
     }
 
-    // See if there are any newer versions of the package that we were
-    // unable to upgrade to.
-    if (newId != null && _type != SolveType.DOWNGRADE) {
-      var versions = _result.availableVersions[newId.name];
-
-      var newerStable = false;
-      var newerUnstable = false;
-
-      for (var version in versions) {
-        if (version > newId.version) {
-          if (version.isPreRelease) {
-            newerUnstable = true;
-          } else {
-            newerStable = true;
-          }
-        }
-      }
-
-      // If there are newer stable versions, only show those.
-      String message;
-      if (newerStable) {
-        message = '(${maxAll(versions, Version.prioritize)} available)';
-      } else if (
-          // Only show newer prereleases for versions where a prerelease is
-          // already chosen.
-          newId.version.isPreRelease && newerUnstable) {
-        message = '(${maxAll(versions)} available)';
-      }
-
-      if (message != null) _output.write(' ${log.cyan(message)}');
-    }
+    if (message != null) _output.write(' ${log.cyan(message)}');
 
     _output.writeln();
   }
diff --git a/lib/src/solver/result.dart b/lib/src/solver/result.dart
index 0f33833..5b1022b 100644
--- a/lib/src/solver/result.dart
+++ b/lib/src/solver/result.dart
@@ -108,7 +108,6 @@
     final report =
         SolveReport(type, _sources, _root, _previousLockFile, this, cache);
     report.summarize(dryRun: dryRun);
-    await report.reportDiscontinued();
     if (type == SolveType.UPGRADE) {
       report.reportOutdated();
     }
diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart
index 67d4fe0..10f2126 100644
--- a/lib/src/solver/version_solver.dart
+++ b/lib/src/solver/version_solver.dart
@@ -6,6 +6,7 @@
 import 'dart:math' as math;
 
 import 'package:collection/collection.dart';
+import 'package:pub/src/source/hosted.dart';
 import 'package:pub_semver/pub_semver.dart';
 
 import '../exceptions.dart';
@@ -414,7 +415,7 @@
         _lockFile,
         decisions,
         pubspecs,
-        _getAvailableVersions(decisions),
+        await _getAvailableVersions(decisions),
         _solution.attemptedSolutions);
   }
 
@@ -424,17 +425,24 @@
   /// The version list may not always be complete. If the package is the root
   /// package, or if it's a package that we didn't unlock while solving because
   /// we weren't trying to upgrade it, we will just know the current version.
-  Map<String, List<Version>> _getAvailableVersions(List<PackageId> packages) {
+  Future<Map<String, List<Version>>> _getAvailableVersions(
+      List<PackageId> packages) async {
     var availableVersions = <String, List<Version>>{};
     for (var package in packages) {
       var cached = _packageListers[package.toRef()]?.cachedVersions;
-      // If the version list was never requested, just use the one known
-      // version.
-      var versions = cached == null
-          ? [package.version]
-          : cached.map((id) => id.version).toList();
+      // If the version list was never requested, use versions from cached
+      // version listings if the package is "hosted".
+      // TODO(sigurdm): This has a smell. The Git source should have a
+      // reasonable behavior here (we should be able to call getVersions in a
+      // way that doesn't fetch.
+      var ids = cached ??
+          (package.source is HostedSource
+              ? (await _systemCache
+                  .source(package.source)
+                  .getVersions(package.toRef(), maxAge: Duration(days: 3)))
+              : [package]);
 
-      availableVersions[package.name] = versions;
+      availableVersions[package.name] = ids.map((id) => id.version).toList();
     }
 
     return availableVersions;
diff --git a/lib/src/source.dart b/lib/src/source.dart
index e82075c..fcfe2fe 100644
--- a/lib/src/source.dart
+++ b/lib/src/source.dart
@@ -157,7 +157,9 @@
   /// uses [describe] to get that version.
   ///
   /// Sources should not override this. Instead, they implement [doGetVersions].
-  Future<List<PackageId>> getVersions(PackageRef ref) {
+  ///
+  /// If [maxAge] is given answers can be taken from cache - up to that age old.
+  Future<List<PackageId>> getVersions(PackageRef ref, {Duration maxAge}) {
     if (ref.isRoot) {
       throw ArgumentError('Cannot get versions for the root package.');
     }
@@ -165,7 +167,7 @@
       throw ArgumentError('Package $ref does not use source ${source.name}.');
     }
 
-    return doGetVersions(ref);
+    return doGetVersions(ref, maxAge);
   }
 
   /// Get the IDs of all versions that match [ref].
@@ -180,7 +182,7 @@
   ///
   /// This method is effectively protected: subclasses must implement it, but
   /// external code should not call this. Instead, call [getVersions].
-  Future<List<PackageId>> doGetVersions(PackageRef ref);
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge);
 
   /// A cache of pubspecs described by [describe].
   final _pubspecs = <PackageId, Pubspec>{};
diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart
index cc7d18a..3a3e18d 100644
--- a/lib/src/source/git.dart
+++ b/lib/src/source/git.dart
@@ -225,7 +225,7 @@
   }
 
   @override
-  Future<List<PackageId>> doGetVersions(PackageRef ref) async {
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async {
     return await _pool.withResource(() async {
       await _ensureRepoCache(ref);
       var path = _repoCachePath(ref);
diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart
index d6baab8..a6a4c17 100644
--- a/lib/src/source/hosted.dart
+++ b/lib/src/source/hosted.dart
@@ -339,9 +339,14 @@
   /// Downloads a list of all versions of a package that are available from the
   /// site.
   @override
-  Future<List<PackageId>> doGetVersions(PackageRef ref) async {
-    final versions = await _scheduler.schedule(ref);
-    return versions.keys.toList();
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async {
+    Map<PackageId, _VersionInfo> versionListing;
+    if (maxAge != null) {
+      // Do we have a cached version response on disk?
+      versionListing ??= await _cachedVersionListingResponse(ref, maxAge);
+    }
+    versionListing ??= await _scheduler.schedule(ref);
+    return versionListing.keys.toList();
   }
 
   /// Parses [description] into its server and package name components, then
@@ -647,7 +652,7 @@
 
   /// Gets the list of all versions of [ref] that are in the system cache.
   @override
-  Future<List<PackageId>> doGetVersions(PackageRef ref) async {
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async {
     var parsed = source._parseDescription(ref.description);
     var server = parsed.last;
     log.io('Finding versions of ${ref.name} in '
@@ -694,6 +699,9 @@
     final versionListing =
         await _cachedVersionListingResponse(id.toRef(), maxAge);
 
+    if (versionListing == null) {
+      return PackageStatus();
+    }
     final listing = versionListing[id];
     // If we don't have the specific version we return the empty response.
     //
diff --git a/lib/src/source/path.dart b/lib/src/source/path.dart
index 1d06496..a84b92f 100644
--- a/lib/src/source/path.dart
+++ b/lib/src/source/path.dart
@@ -163,7 +163,7 @@
   BoundPathSource(this.source, this.systemCache);
 
   @override
-  Future<List<PackageId>> doGetVersions(PackageRef ref) async {
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async {
     // There's only one package ID for a given path. We just need to find the
     // version.
     var pubspec = _loadPubspec(ref);
diff --git a/lib/src/source/sdk.dart b/lib/src/source/sdk.dart
index ec201f2..c2d4edf 100644
--- a/lib/src/source/sdk.dart
+++ b/lib/src/source/sdk.dart
@@ -70,7 +70,7 @@
   BoundSdkSource(this.source, this.systemCache);
 
   @override
-  Future<List<PackageId>> doGetVersions(PackageRef ref) async {
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async {
     var pubspec = _loadPubspec(ref);
     var id = PackageId(ref.name, source, pubspec.version, ref.description);
     memoizePubspec(id, pubspec);
diff --git a/lib/src/source/unknown.dart b/lib/src/source/unknown.dart
index a9ae1f2..53b9a42 100644
--- a/lib/src/source/unknown.dart
+++ b/lib/src/source/unknown.dart
@@ -61,7 +61,7 @@
   _BoundUnknownSource(this.source, this.systemCache);
 
   @override
-  Future<List<PackageId>> doGetVersions(PackageRef ref) =>
+  Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) =>
       throw UnsupportedError(
           "Cannot get package versions from unknown source '${source.name}'.");
 
diff --git a/test/get/hosted/warn_about_discontinued_test.dart b/test/get/hosted/warn_about_discontinued_test.dart
index 6e4764f..2b0afc5 100644
--- a/test/get/hosted/warn_about_discontinued_test.dart
+++ b/test/get/hosted/warn_about_discontinued_test.dart
@@ -34,7 +34,12 @@
     deleteEntry(fooVersionsCache);
     deleteEntry(transitiveVersionsCache);
     // We warn only about the direct dependency here:
-    await pubGet(warning: 'Package foo has been discontinued.');
+    await pubGet(output: '''
+Resolving dependencies...
+  foo 1.2.3 (discontinued)
+  transitive 1.0.0 (discontinued)
+Got dependencies!
+''');
     expect(fileExists(fooVersionsCache), isTrue);
     final c = json.decode(readTextFile(fooVersionsCache));
     // Make the cache artificially old.
@@ -43,28 +48,39 @@
     writeTextFile(fooVersionsCache, json.encode(c));
     globalPackageServer
         .add((builder) => builder.discontinue('foo', replacementText: 'bar'));
-    await pubGet(
-        warning:
-            'Package foo has been discontinued it has been replaced by package bar.');
+    await pubGet(output: '''
+Resolving dependencies...
+  foo 1.2.3 (discontinued replaced by bar)
+  transitive 1.0.0 (discontinued)
+Got dependencies!''');
     final c2 = json.decode(readTextFile(fooVersionsCache));
     // Make a bad cached value to test that responses are actually from cache.
     c2['isDiscontinued'] = false;
     writeTextFile(fooVersionsCache, json.encode(c2));
-    await pubGet(warning: isEmpty);
+    await pubGet(output: '''
+Resolving dependencies...
+  transitive 1.0.0 (discontinued)
+Got dependencies!''');
     // Repairing the cache should reset the package listing caches.
     await runPub(args: ['cache', 'repair']);
-    await pubGet(
-        warning:
-            'Package foo has been discontinued it has been replaced by package bar.');
+    await pubGet(output: '''
+Resolving dependencies...
+  foo 1.2.3 (discontinued replaced by bar)
+  transitive 1.0.0 (discontinued)
+Got dependencies!''');
     // Test that --offline won't try to access the server for retrieving the
     // status.
     await serveErrors();
-    await pubGet(
-        args: ['--offline'],
-        warning:
-            'Package foo has been discontinued it has been replaced by package bar.');
+    await pubGet(args: ['--offline'], output: '''
+Resolving dependencies...
+  foo 1.2.3 (discontinued replaced by bar)
+  transitive 1.0.0 (discontinued)
+Got dependencies!''');
     deleteEntry(fooVersionsCache);
     deleteEntry(transitiveVersionsCache);
-    await pubGet(args: ['--offline']);
+    await pubGet(args: ['--offline'], output: '''
+Resolving dependencies...
+Got dependencies!
+''');
   });
 }
diff --git a/test/list_package_dirs/lists_dependency_directories_test.dart b/test/list_package_dirs/lists_dependency_directories_test.dart
index a9862bb..20fcf46 100644
--- a/test/list_package_dirs/lists_dependency_directories_test.dart
+++ b/test/list_package_dirs/lists_dependency_directories_test.dart
@@ -26,12 +26,11 @@
 
     await pubGet();
 
-    await
-        // Note: Using canonicalize here because pub gets the path to the
-        // entrypoint package from the working directory, which has had symlinks
-        // resolve. On Mac, "/tmp" is actually a symlink to "/private/tmp", so we
-        // need to accommodate that.
-        await runPub(args: [
+    // Note: Using canonicalize here because pub gets the path to the
+    // entrypoint package from the working directory, which has had symlinks
+    // resolve. On Mac, "/tmp" is actually a symlink to "/private/tmp", so we
+    // need to accommodate that.
+    await runPub(args: [
       'list-package-dirs',
       '--format=json'
     ], outputJson: {
diff --git a/test/test_pub.dart b/test/test_pub.dart
index beff0ce..0e8bbd4 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -123,7 +123,7 @@
 ///
 /// If [exitCode] is given, expects the command to exit with that code.
 // TODO(rnystrom): Clean up other tests to call this when possible.
-Future pubCommand(RunCommand command,
+Future<void> pubCommand(RunCommand command,
     {Iterable<String> args,
     output,
     error,
@@ -155,14 +155,14 @@
       environment: environment);
 }
 
-Future pubAdd(
+Future<void> pubAdd(
         {Iterable<String> args,
         output,
         error,
         warning,
         int exitCode,
-        Map<String, String> environment}) =>
-    pubCommand(RunCommand.add,
+        Map<String, String> environment}) async =>
+    await pubCommand(RunCommand.add,
         args: args,
         output: output,
         error: error,
@@ -170,14 +170,14 @@
         exitCode: exitCode,
         environment: environment);
 
-Future pubGet(
+Future<void> pubGet(
         {Iterable<String> args,
         output,
         error,
         warning,
         int exitCode,
-        Map<String, String> environment}) =>
-    pubCommand(RunCommand.get,
+        Map<String, String> environment}) async =>
+    await pubCommand(RunCommand.get,
         args: args,
         output: output,
         error: error,
@@ -185,14 +185,14 @@
         exitCode: exitCode,
         environment: environment);
 
-Future pubUpgrade(
+Future<void> pubUpgrade(
         {Iterable<String> args,
         output,
         error,
         warning,
         int exitCode,
-        Map<String, String> environment}) =>
-    pubCommand(RunCommand.upgrade,
+        Map<String, String> environment}) async =>
+    await pubCommand(RunCommand.upgrade,
         args: args,
         output: output,
         error: error,
@@ -200,14 +200,14 @@
         exitCode: exitCode,
         environment: environment);
 
-Future pubDowngrade(
+Future<void> pubDowngrade(
         {Iterable<String> args,
         output,
         error,
         warning,
         int exitCode,
-        Map<String, String> environment}) =>
-    pubCommand(RunCommand.downgrade,
+        Map<String, String> environment}) async =>
+    await pubCommand(RunCommand.downgrade,
         args: args,
         output: output,
         error: error,
@@ -215,14 +215,14 @@
         exitCode: exitCode,
         environment: environment);
 
-Future pubRemove(
+Future<void> pubRemove(
         {Iterable<String> args,
         output,
         error,
         warning,
         int exitCode,
-        Map<String, String> environment}) =>
-    pubCommand(RunCommand.remove,
+        Map<String, String> environment}) async =>
+    await pubCommand(RunCommand.remove,
         args: args,
         output: output,
         error: error,
@@ -295,7 +295,7 @@
 ///
 /// If [environment] is given, any keys in it will override the environment
 /// variables passed to the spawned process.
-Future runPub(
+Future<void> runPub(
     {List<String> args,
     output,
     error,
@@ -349,7 +349,7 @@
 ///
 /// Ensures that the right output is shown and then enters "y" to confirm the
 /// upload.
-Future confirmPublish(TestProcess pub) async {
+Future<void> confirmPublish(TestProcess pub) async {
   // TODO(rnystrom): This is overly specific and inflexible regarding different
   // test packages. Should validate this a little more loosely.
   await expectLater(
@@ -577,7 +577,7 @@
 ///
 /// [hosted] is a list of package names to version strings for dependencies on
 /// hosted packages.
-Future createLockFile(String package,
+Future<void> createLockFile(String package,
     {Iterable<String> sandbox, Map<String, String> hosted}) async {
   var cache = SystemCache(rootDir: _pathInSandbox(cachePath));
 
@@ -592,7 +592,7 @@
 
 /// Like [createLockFile], but creates only a `.packages` file without a
 /// lockfile.
-Future createPackagesFile(String package,
+Future<void> createPackagesFile(String package,
     {Iterable<String> sandbox, Map<String, String> hosted}) async {
   var cache = SystemCache(rootDir: _pathInSandbox(cachePath));
   var lockFile =
diff --git a/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart b/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
index ccafebc..7a232d0 100644
--- a/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
+++ b/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
@@ -9,8 +9,8 @@
 
 void main() {
   test(
-      'does not show how many newer versions are available for '
-      'packages that are locked and not being upgraded', () async {
+      'Shows newer versions available for packages that are locked and not being upgraded',
+      () async {
     await servePackages((builder) {
       builder.serve('not_upgraded', '1.0.0');
       builder.serve('not_upgraded', '2.0.0');
@@ -31,7 +31,7 @@
     // Only upgrade "upgraded".
     await pubUpgrade(args: ['upgraded'], output: RegExp(r'''
 Resolving dependencies\.\.\..*
-  not_upgraded 1\.0\.0
+  not_upgraded 1\.0\.0 \(2\.0\.0 available\)
 . upgraded 2\.0\.0 \(was 1\.0\.0\)
 ''', multiLine: true), environment: {'PUB_ALLOW_PRERELEASE_SDK': 'false'});
   });