Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
6a75e486
Unverified
Commit
6a75e486
authored
Jun 08, 2021
by
Jonah Williams
Committed by
GitHub
Jun 08, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] remove substantial mocking from version test (#84007)
parent
588b9a3a
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
335 additions
and
514 deletions
+335
-514
version.dart
packages/flutter_tools/lib/src/version.dart
+159
-132
version_test.dart
packages/flutter_tools/test/general.shard/version_test.dart
+176
-382
No files found.
packages/flutter_tools/lib/src/version.dart
View file @
6a75e486
...
...
@@ -7,6 +7,7 @@ import 'package:meta/meta.dart';
import
'base/common.dart'
;
import
'base/file_system.dart'
;
import
'base/io.dart'
;
import
'base/logger.dart'
;
import
'base/process.dart'
;
import
'base/time.dart'
;
import
'cache.dart'
;
...
...
@@ -221,6 +222,38 @@ class FlutterVersion {
}
}
/// Checks if the currently installed version of Flutter is up-to-date, and
/// warns the user if it isn't.
///
/// This function must run while [Cache.lock] is acquired because it reads and
/// writes shared cache files.
Future
<
void
>
checkFlutterVersionFreshness
()
async
{
// Don't perform update checks if we're not on an official channel.
if
(!
kOfficialChannels
.
contains
(
channel
))
{
return
;
}
DateTime
localFrameworkCommitDate
;
try
{
localFrameworkCommitDate
=
DateTime
.
parse
(
_latestGitCommitDate
(
lenient:
false
));
}
on
VersionCheckError
{
// Don't perform the update check if the version check failed.
return
;
}
final
DateTime
?
latestFlutterCommitDate
=
await
_getLatestAvailableFlutterDate
();
await
checkVersionFreshness
(
this
,
clock:
_clock
,
localFrameworkCommitDate:
localFrameworkCommitDate
,
latestFlutterCommitDate:
latestFlutterCommitDate
,
logger:
globals
.
logger
,
cache:
globals
.
cache
,
pauseTime:
timeToPauseToLetUserReadTheMessage
,
);
}
/// The name of the temporary git remote used to check for the latest
/// available Flutter framework version.
///
...
...
@@ -296,45 +329,6 @@ class FlutterVersion {
return
_branch
!;
}
/// The amount of time we wait before pinging the server to check for the
/// availability of a newer version of Flutter.
@visibleForTesting
static
const
Duration
checkAgeConsideredUpToDate
=
Duration
(
days:
3
);
/// We warn the user if the age of their Flutter installation is greater than
/// this duration. The durations are slightly longer than the expected release
/// cadence for each channel, to give the user a grace period before they get
/// notified.
///
/// For example, for the beta channel, this is set to five weeks because
/// beta releases happen approximately every month.
@visibleForTesting
static
Duration
versionAgeConsideredUpToDate
(
String
channel
)
{
switch
(
channel
)
{
case
'stable'
:
return
const
Duration
(
days:
365
~/
2
);
// Six months
case
'beta'
:
return
const
Duration
(
days:
7
*
8
);
// Eight weeks
case
'dev'
:
return
const
Duration
(
days:
7
*
4
);
// Four weeks
default
:
return
const
Duration
(
days:
7
*
3
);
// Three weeks
}
}
/// The amount of time we wait between issuing a warning.
///
/// This is to avoid annoying users who are unable to upgrade right away.
@visibleForTesting
static
const
Duration
maxTimeSinceLastWarning
=
Duration
(
days:
1
);
/// The amount of time we pause for to let the user read the message about
/// outdated Flutter installation.
///
/// This can be customized in tests to speed them up.
@visibleForTesting
static
Duration
timeToPauseToLetUserReadTheMessage
=
const
Duration
(
seconds:
2
);
/// Reset the version freshness information by removing the stamp file.
///
/// New version freshness information will be regenerated when
...
...
@@ -351,67 +345,6 @@ class FlutterVersion {
}
}
/// Checks if the currently installed version of Flutter is up-to-date, and
/// warns the user if it isn't.
///
/// This function must run while [Cache.lock] is acquired because it reads and
/// writes shared cache files.
Future
<
void
>
checkFlutterVersionFreshness
()
async
{
// Don't perform update checks if we're not on an official channel.
if
(!
kOfficialChannels
.
contains
(
channel
))
{
return
;
}
DateTime
localFrameworkCommitDate
;
try
{
localFrameworkCommitDate
=
DateTime
.
parse
(
_latestGitCommitDate
(
lenient:
false
));
}
on
VersionCheckError
{
// Don't perform the update check if the version check failed.
return
;
}
final
Duration
frameworkAge
=
_clock
.
now
().
difference
(
localFrameworkCommitDate
);
final
bool
installationSeemsOutdated
=
frameworkAge
>
versionAgeConsideredUpToDate
(
channel
);
// Get whether there's a newer version on the remote. This only goes
// to the server if we haven't checked recently so won't happen on every
// command.
final
DateTime
?
latestFlutterCommitDate
=
await
_getLatestAvailableFlutterDate
();
final
VersionCheckResult
remoteVersionStatus
=
latestFlutterCommitDate
==
null
?
VersionCheckResult
.
unknown
:
latestFlutterCommitDate
.
isAfter
(
localFrameworkCommitDate
)
?
VersionCheckResult
.
newVersionAvailable
:
VersionCheckResult
.
versionIsCurrent
;
// Do not load the stamp before the above server check as it may modify the stamp file.
final
VersionCheckStamp
stamp
=
await
VersionCheckStamp
.
load
();
final
DateTime
lastTimeWarningWasPrinted
=
stamp
.
lastTimeWarningWasPrinted
??
_clock
.
ago
(
maxTimeSinceLastWarning
*
2
);
final
bool
beenAWhileSinceWarningWasPrinted
=
_clock
.
now
().
difference
(
lastTimeWarningWasPrinted
)
>
maxTimeSinceLastWarning
;
// We show a warning if either we know there is a new remote version, or we couldn't tell but the local
// version is outdated.
final
bool
canShowWarning
=
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
||
(
remoteVersionStatus
==
VersionCheckResult
.
unknown
&&
installationSeemsOutdated
);
if
(
beenAWhileSinceWarningWasPrinted
&&
canShowWarning
)
{
final
String
updateMessage
=
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
?
newVersionAvailableMessage
()
:
versionOutOfDateMessage
(
frameworkAge
);
globals
.
printStatus
(
updateMessage
,
emphasis:
true
);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
stamp
.
store
(
newTimeWarningWasPrinted:
_clock
.
now
(),
),
Future
<
void
>.
delayed
(
timeToPauseToLetUserReadTheMessage
),
]);
}
}
/// log.showSignature=false is a user setting and it will break things,
/// so we want to disable it for every git log call. This is a convenience
/// wrapper that does that.
...
...
@@ -420,32 +353,6 @@ class FlutterVersion {
return
<
String
>[
'git'
,
'-c'
,
'log.showSignature=false'
,
'log'
]
+
args
;
}
@visibleForTesting
static
String
versionOutOfDateMessage
(
Duration
frameworkAge
)
{
String
warning
=
'WARNING: your installation of Flutter is
${frameworkAge.inDays}
days old.'
;
// Append enough spaces to match the message box width.
warning
+=
' '
*
(
74
-
warning
.
length
);
return
'''
╔════════════════════════════════════════════════════════════════════════════╗
║
$warning
║
║ ║
║ To update to the latest version, run "flutter upgrade". ║
╚════════════════════════════════════════════════════════════════════════════╝
'''
;
}
@visibleForTesting
static
String
newVersionAvailableMessage
()
{
return
'''
╔════════════════════════════════════════════════════════════════════════════╗
║ A new version of Flutter is available! ║
║ ║
║ To update to the latest version, run "flutter upgrade". ║
╚════════════════════════════════════════════════════════════════════════════╝
'''
;
}
/// Gets the release date of the latest available Flutter version.
///
/// This method sends a server request if it's been more than
...
...
@@ -455,7 +362,7 @@ class FlutterVersion {
/// unable to reach the server to get the latest version.
Future
<
DateTime
?>
_getLatestAvailableFlutterDate
()
async
{
globals
.
cache
.
checkLockAcquired
();
final
VersionCheckStamp
versionCheckStamp
=
await
VersionCheckStamp
.
load
();
final
VersionCheckStamp
versionCheckStamp
=
await
VersionCheckStamp
.
load
(
globals
.
cache
,
globals
.
logger
);
if
(
versionCheckStamp
.
lastTimeVersionWasChecked
!=
null
)
{
final
Duration
timeSinceLastCheck
=
_clock
.
now
().
difference
(
...
...
@@ -510,8 +417,8 @@ class VersionCheckStamp {
@visibleForTesting
static
const
String
flutterVersionCheckStampFile
=
'flutter_version_check'
;
static
Future
<
VersionCheckStamp
>
load
()
async
{
final
String
?
versionCheckStamp
=
globals
.
cache
.
getStampFor
(
flutterVersionCheckStampFile
);
static
Future
<
VersionCheckStamp
>
load
(
Cache
cache
,
Logger
logger
)
async
{
final
String
?
versionCheckStamp
=
cache
.
getStampFor
(
flutterVersionCheckStampFile
);
if
(
versionCheckStamp
!=
null
)
{
// Attempt to parse stamp JSON.
...
...
@@ -520,11 +427,11 @@ class VersionCheckStamp {
if
(
jsonObject
is
Map
<
String
,
dynamic
>)
{
return
fromJson
(
jsonObject
);
}
else
{
globals
.
printTrace
(
'Warning: expected version stamp to be a Map but found:
$jsonObject
'
);
logger
.
printTrace
(
'Warning: expected version stamp to be a Map but found:
$jsonObject
'
);
}
}
on
Exception
catch
(
error
,
stackTrace
)
{
// Do not crash if JSON is malformed.
globals
.
printTrace
(
'
${error.runtimeType}
:
$error
\n
$stackTrace
'
);
logger
.
printTrace
(
'
${error.runtimeType}
:
$error
\n
$stackTrace
'
);
}
}
...
...
@@ -550,6 +457,7 @@ class VersionCheckStamp {
DateTime
?
newTimeVersionWasChecked
,
DateTime
?
newKnownRemoteVersion
,
DateTime
?
newTimeWarningWasPrinted
,
Cache
?
cache
,
})
async
{
final
Map
<
String
,
String
>
jsonData
=
toJson
();
...
...
@@ -566,7 +474,7 @@ class VersionCheckStamp {
}
const
JsonEncoder
prettyJsonEncoder
=
JsonEncoder
.
withIndent
(
' '
);
globals
.
cache
.
setStampFor
(
flutterVersionCheckStampFile
,
prettyJsonEncoder
.
convert
(
jsonData
));
(
cache
??
globals
.
cache
)
.
setStampFor
(
flutterVersionCheckStampFile
,
prettyJsonEncoder
.
convert
(
jsonData
));
}
Map
<
String
,
String
>
toJson
({
...
...
@@ -837,3 +745,122 @@ enum VersionCheckResult {
/// A newer version is available.
newVersionAvailable
,
}
@visibleForTesting
Future
<
void
>
checkVersionFreshness
(
FlutterVersion
version
,
{
required
DateTime
localFrameworkCommitDate
,
required
DateTime
?
latestFlutterCommitDate
,
required
SystemClock
clock
,
required
Cache
cache
,
required
Logger
logger
,
Duration
pauseTime
=
Duration
.
zero
,
})
async
{
// Don't perform update checks if we're not on an official channel.
if
(!
kOfficialChannels
.
contains
(
version
.
channel
))
{
return
;
}
final
Duration
frameworkAge
=
clock
.
now
().
difference
(
localFrameworkCommitDate
);
final
bool
installationSeemsOutdated
=
frameworkAge
>
versionAgeConsideredUpToDate
(
version
.
channel
);
// Get whether there's a newer version on the remote. This only goes
// to the server if we haven't checked recently so won't happen on every
// command.
final
VersionCheckResult
remoteVersionStatus
=
latestFlutterCommitDate
==
null
?
VersionCheckResult
.
unknown
:
latestFlutterCommitDate
.
isAfter
(
localFrameworkCommitDate
)
?
VersionCheckResult
.
newVersionAvailable
:
VersionCheckResult
.
versionIsCurrent
;
// Do not load the stamp before the above server check as it may modify the stamp file.
final
VersionCheckStamp
stamp
=
await
VersionCheckStamp
.
load
(
cache
,
logger
);
final
DateTime
lastTimeWarningWasPrinted
=
stamp
.
lastTimeWarningWasPrinted
??
clock
.
ago
(
maxTimeSinceLastWarning
*
2
);
final
bool
beenAWhileSinceWarningWasPrinted
=
clock
.
now
().
difference
(
lastTimeWarningWasPrinted
)
>
maxTimeSinceLastWarning
;
// We show a warning if either we know there is a new remote version, or we couldn't tell but the local
// version is outdated.
final
bool
canShowWarning
=
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
||
(
remoteVersionStatus
==
VersionCheckResult
.
unknown
&&
installationSeemsOutdated
);
if
(
beenAWhileSinceWarningWasPrinted
&&
canShowWarning
)
{
final
String
updateMessage
=
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
?
newVersionAvailableMessage
()
:
versionOutOfDateMessage
(
frameworkAge
);
logger
.
printStatus
(
updateMessage
,
emphasis:
true
);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
stamp
.
store
(
newTimeWarningWasPrinted:
clock
.
now
(),
cache:
cache
,
),
Future
<
void
>.
delayed
(
pauseTime
),
]);
}
}
/// The amount of time we wait before pinging the server to check for the
/// availability of a newer version of Flutter.
@visibleForTesting
const
Duration
checkAgeConsideredUpToDate
=
Duration
(
days:
3
);
/// We warn the user if the age of their Flutter installation is greater than
/// this duration. The durations are slightly longer than the expected release
/// cadence for each channel, to give the user a grace period before they get
/// notified.
///
/// For example, for the beta channel, this is set to five weeks because
/// beta releases happen approximately every month.
@visibleForTesting
Duration
versionAgeConsideredUpToDate
(
String
channel
)
{
switch
(
channel
)
{
case
'stable'
:
return
const
Duration
(
days:
365
~/
2
);
// Six months
case
'beta'
:
return
const
Duration
(
days:
7
*
8
);
// Eight weeks
case
'dev'
:
return
const
Duration
(
days:
7
*
4
);
// Four weeks
default
:
return
const
Duration
(
days:
7
*
3
);
// Three weeks
}
}
/// The amount of time we wait between issuing a warning.
///
/// This is to avoid annoying users who are unable to upgrade right away.
@visibleForTesting
const
Duration
maxTimeSinceLastWarning
=
Duration
(
days:
1
);
/// The amount of time we pause for to let the user read the message about
/// outdated Flutter installation.
///
/// This can be customized in tests to speed them up.
@visibleForTesting
Duration
timeToPauseToLetUserReadTheMessage
=
const
Duration
(
seconds:
2
);
@visibleForTesting
String
versionOutOfDateMessage
(
Duration
frameworkAge
)
{
String
warning
=
'WARNING: your installation of Flutter is
${frameworkAge.inDays}
days old.'
;
// Append enough spaces to match the message box width.
warning
+=
' '
*
(
74
-
warning
.
length
);
return
'''
╔════════════════════════════════════════════════════════════════════════════╗
║
$warning
║
║ ║
║ To update to the latest version, run "flutter upgrade". ║
╚════════════════════════════════════════════════════════════════════════════╝
'''
;
}
@visibleForTesting
String
newVersionAvailableMessage
(
)
{
return
'''
╔════════════════════════════════════════════════════════════════════════════╗
║ A new version of Flutter is available! ║
║ ║
║ To update to the latest version, run "flutter upgrade". ║
╚════════════════════════════════════════════════════════════════════════════╝
'''
;
}
packages/flutter_tools/test/general.shard/version_test.dart
View file @
6a75e486
...
...
@@ -6,13 +6,10 @@
import
'dart:convert'
;
import
'package:collection/collection.dart'
show
ListEquality
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/base/process.dart'
;
import
'package:flutter_tools/src/base/time.dart'
;
import
'package:flutter_tools/src/base/utils.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/globals_null_migrated.dart'
as
globals
;
import
'package:flutter_tools/src/version.dart'
;
...
...
@@ -23,17 +20,15 @@ import '../src/context.dart';
import
'../src/fake_process_manager.dart'
;
final
SystemClock
_testClock
=
SystemClock
.
fixed
(
DateTime
(
2015
,
1
,
1
));
final
DateTime
_stampUpToDate
=
_testClock
.
ago
(
FlutterVersion
.
checkAgeConsideredUpToDate
~/
2
);
final
DateTime
_stampOutOfDate
=
_testClock
.
ago
(
FlutterVersion
.
checkAgeConsideredUpToDate
*
2
);
final
DateTime
_stampUpToDate
=
_testClock
.
ago
(
checkAgeConsideredUpToDate
~/
2
);
final
DateTime
_stampOutOfDate
=
_testClock
.
ago
(
checkAgeConsideredUpToDate
*
2
);
void
main
(
)
{
MockProcessManager
mockProcessManager
;
MockCache
mockCache
;
FakeProcessManager
processManager
;
setUp
(()
{
processManager
=
FakeProcessManager
.
empty
();
mockProcessManager
=
MockProcessManager
();
mockCache
=
MockCache
();
});
...
...
@@ -47,17 +42,17 @@ void main() {
for
(
final
String
channel
in
kOfficialChannels
)
{
DateTime
getChannelUpToDateVersion
()
{
return
_testClock
.
ago
(
FlutterVersion
.
versionAgeConsideredUpToDate
(
channel
)
~/
2
);
return
_testClock
.
ago
(
versionAgeConsideredUpToDate
(
channel
)
~/
2
);
}
DateTime
getChannelOutOfDateVersion
()
{
return
_testClock
.
ago
(
FlutterVersion
.
versionAgeConsideredUpToDate
(
channel
)
*
2
);
return
_testClock
.
ago
(
versionAgeConsideredUpToDate
(
channel
)
*
2
);
}
group
(
'
$FlutterVersion
for
$channel
'
,
()
{
setUpAll
(()
{
Cache
.
disableLocking
();
FlutterVersion
.
timeToPauseToLetUserReadTheMessage
=
Duration
.
zero
;
timeToPauseToLetUserReadTheMessage
=
Duration
.
zero
;
});
testUsingContext
(
'prints nothing when Flutter installation looks fresh'
,
()
async
{
...
...
@@ -139,7 +134,7 @@ void main() {
expect
(
flutterVersion
.
getVersionString
(
redactUnknownBranches:
true
),
'
$channel
/1234abcd'
);
expect
(
flutterVersion
.
getBranchName
(
redactUnknownBranches:
true
),
channel
);
_expectVersionMessage
(
''
);
_expectVersionMessage
(
''
,
testLogger
);
expect
(
processManager
.
hasRemainingExpectations
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
...
...
@@ -147,172 +142,159 @@ void main() {
Cache:
()
=>
mockCache
,
});
testUsingContext
(
'prints nothing when Flutter installation looks out-of-date but is actually up-to-date'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelOutOfDateVersion
(),
stamp:
VersionCheckStamp
(
testWithoutContext
(
'prints nothing when Flutter installation looks out-of-date but is actually up-to-date'
,
()
async
{
final
FakeFlutterVersion
flutterVersion
=
FakeFlutterVersion
(
channel
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
VersionCheckStamp
stamp
=
VersionCheckStamp
(
lastTimeVersionWasChecked:
_stampOutOfDate
,
lastKnownRemoteVersion:
getChannelOutOfDateVersion
(),
),
remoteCommitDate:
getChannelOutOfDateVersion
(),
expectSetStamp:
true
,
expectServerPing:
true
,
channel:
channel
,
);
final
FlutterVersion
version
=
globals
.
flutterVersion
;
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
''
);
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
json
.
encode
(
stamp
));
await
checkVersionFreshness
(
flutterVersion
,
cache:
mockCache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelOutOfDateVersion
(),
);
_expectVersionMessage
(
''
,
logger
);
});
testUsingContext
(
'does not ping server when version stamp is up-to-date'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelOutOfDateVersion
(),
stamp:
VersionCheckStamp
(
testWithoutContext
(
'does not ping server when version stamp is up-to-date'
,
()
async
{
final
FakeFlutterVersion
flutterVersion
=
FakeFlutterVersion
(
channel
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
VersionCheckStamp
stamp
=
VersionCheckStamp
(
lastTimeVersionWasChecked:
_stampUpToDate
,
lastKnownRemoteVersion:
getChannelUpToDateVersion
(),
),
expectSetStamp:
true
,
channel:
channel
,
);
final
FlutterVersion
version
=
globals
.
flutterVersion
;
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
FlutterVersion
.
newVersionAvailableMessage
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
json
.
encode
(
stamp
));
await
checkVersionFreshness
(
flutterVersion
,
cache:
mockCache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
_expectVersionMessage
(
newVersionAvailableMessage
(),
logger
);
verify
(
mockCache
.
setStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
,
any
)).
called
(
1
);
});
testUsingContext
(
'does not print warning if printed recently'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelOutOfDateVersion
(),
stamp:
VersionCheckStamp
(
testWithoutContext
(
'does not print warning if printed recently'
,
()
async
{
final
FakeFlutterVersion
flutterVersion
=
FakeFlutterVersion
(
channel
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
VersionCheckStamp
stamp
=
VersionCheckStamp
(
lastTimeVersionWasChecked:
_stampUpToDate
,
lastKnownRemoteVersion:
getChannelUpToDateVersion
(),
),
expectSetStamp:
true
,
channel:
channel
,
lastTimeWarningWasPrinted:
_testClock
.
now
(),
);
final
FlutterVersion
version
=
globals
.
flutterVersion
;
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
FlutterVersion
.
newVersionAvailableMessage
());
expect
((
await
VersionCheckStamp
.
load
()).
lastTimeWarningWasPrinted
,
_testClock
.
now
());
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
json
.
encode
(
stamp
));
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
''
);
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
await
checkVersionFreshness
(
flutterVersion
,
cache:
mockCache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
_expectVersionMessage
(
''
,
logger
);
});
testUsingContext
(
'pings server when version stamp is missing then does not'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelOutOfDateVersion
(),
remoteCommitDate:
getChannelUpToDateVersion
(),
expectSetStamp:
true
,
expectServerPing:
true
,
channel:
channel
,
testWithoutContext
(
'pings server when version stamp is missing'
,
()
async
{
final
FakeFlutterVersion
flutterVersion
=
FakeFlutterVersion
(
channel
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
'{}'
);
await
checkVersionFreshness
(
flutterVersion
,
cache:
mockCache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
final
FlutterVersion
version
=
globals
.
flutterVersion
;
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
FlutterVersion
.
newVersionAvailableMessage
());
// Immediate subsequent check is not expected to ping the server.
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelOutOfDateVersion
(),
stamp:
await
VersionCheckStamp
.
load
(),
channel:
channel
,
);
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
''
);
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
_expectVersionMessage
(
newVersionAvailableMessage
(),
logger
);
verify
(
mockCache
.
setStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
,
any
)).
called
(
1
);
});
testUsingContext
(
'pings server when version stamp is out-of-date'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelOutOfDateVersion
(),
stamp:
VersionCheckStamp
(
testWithoutContext
(
'pings server when version stamp is out-of-date'
,
()
async
{
final
FakeFlutterVersion
flutterVersion
=
FakeFlutterVersion
(
channel
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
VersionCheckStamp
stamp
=
VersionCheckStamp
(
lastTimeVersionWasChecked:
_stampOutOfDate
,
lastKnownRemoteVersion:
_testClock
.
ago
(
const
Duration
(
days:
2
)),
),
remoteCommitDate:
getChannelUpToDateVersion
(),
expectSetStamp:
true
,
expectServerPing:
true
,
channel:
channel
,
);
final
FlutterVersion
version
=
globals
.
flutterVersion
;
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
FlutterVersion
.
newVersionAvailableMessage
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
});
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
json
.
encode
(
stamp
));
testUsingContext
(
'does not print warning when unable to connect to server if not out of date'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelUpToDateVersion
(),
errorOnFetch:
true
,
expectServerPing:
true
,
expectSetStamp:
true
,
channel:
channel
,
await
checkVersionFreshness
(
flutterVersion
,
cache:
mockCache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
final
FlutterVersion
version
=
globals
.
flutterVersion
;
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
''
);
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
_expectVersionMessage
(
newVersionAvailableMessage
(),
logger
);
});
testUsingContext
(
'prints warning when unable to connect to server if really out of date'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
localCommitDate:
getChannelOutOfDateVersion
(),
errorOnFetch:
true
,
expectServerPing:
true
,
expectSetStamp:
true
,
channel:
channel
,
testWithoutContext
(
'does not print warning when unable to connect to server if not out of date'
,
()
async
{
final
FakeFlutterVersion
flutterVersion
=
FakeFlutterVersion
(
channel
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
'{}'
);
await
checkVersionFreshness
(
flutterVersion
,
cache:
mockCache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelUpToDateVersion
(),
latestFlutterCommitDate:
null
,
// Failed to get remote version
);
final
FlutterVersion
version
=
globals
.
flutterVersion
;
await
version
.
checkFlutterVersionFreshness
();
_expectVersionMessage
(
FlutterVersion
.
versionOutOfDateMessage
(
_testClock
.
now
().
difference
(
getChannelOutOfDateVersion
())));
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
_expectVersionMessage
(
''
,
logger
);
});
testWithoutContext
(
'prints warning when unable to connect to server if really out of date'
,
()
async
{
final
FakeFlutterVersion
flutterVersion
=
FakeFlutterVersion
(
channel
);
final
BufferLogger
logger
=
BufferLogger
.
test
();
final
VersionCheckStamp
stamp
=
VersionCheckStamp
(
lastTimeVersionWasChecked:
_stampOutOfDate
,
lastKnownRemoteVersion:
_testClock
.
ago
(
const
Duration
(
days:
2
)),
);
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
json
.
encode
(
stamp
));
await
checkVersionFreshness
(
flutterVersion
,
cache:
mockCache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
null
,
// Failed to get remote version
);
_expectVersionMessage
(
versionOutOfDateMessage
(
_testClock
.
now
().
difference
(
getChannelOutOfDateVersion
())),
logger
);
});
group
(
'
$VersionCheckStamp
for
$channel
'
,
()
{
...
...
@@ -322,118 +304,44 @@ void main() {
expect
(
stamp
.
lastTimeWarningWasPrinted
,
isNull
);
}
testUsingContext
(
'loads blank when stamp file missing'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
channel:
channel
);
_expectDefault
(
await
VersionCheckStamp
.
load
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
testWithoutContext
(
'loads blank when stamp file missing'
,
()
async
{
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
null
);
_expectDefault
(
await
VersionCheckStamp
.
load
(
mockCache
,
BufferLogger
.
test
()));
});
testUsingContext
(
'loads blank when stamp file is malformed JSON'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
stampJson:
'<'
,
channel:
channel
);
_expectDefault
(
await
VersionCheckStamp
.
load
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
testWithoutContext
(
'loads blank when stamp file is malformed JSON'
,
()
async
{
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
'<'
);
_expectDefault
(
await
VersionCheckStamp
.
load
(
mockCache
,
BufferLogger
.
test
()));
});
testUsingContext
(
'loads blank when stamp file is well-formed but invalid JSON'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
stampJson:
'[]'
,
channel:
channel
,
);
_expectDefault
(
await
VersionCheckStamp
.
load
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
testWithoutContext
(
'loads blank when stamp file is well-formed but invalid JSON'
,
()
async
{
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
'[]'
);
_expectDefault
(
await
VersionCheckStamp
.
load
(
mockCache
,
BufferLogger
.
test
()));
});
testUsingContext
(
'loads valid JSON'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
stampJson:
'''
testWithoutContext
(
'loads valid JSON'
,
()
async
{
final
String
value
=
'''
{
"lastKnownRemoteVersion": "
${_testClock.ago(const Duration(days: 1))}
",
"lastTimeVersionWasChecked": "
${_testClock.ago(const Duration(days: 2))}
",
"lastTimeWarningWasPrinted": "
${_testClock.now()}
"
}
'''
,
channel:
channel
,
);
'''
;
when
(
mockCache
.
getStampFor
(
VersionCheckStamp
.
flutterVersionCheckStampFile
))
.
thenReturn
(
value
);
final
VersionCheckStamp
stamp
=
await
VersionCheckStamp
.
load
(
mockCache
,
BufferLogger
.
test
());
final
VersionCheckStamp
stamp
=
await
VersionCheckStamp
.
load
();
expect
(
stamp
.
lastKnownRemoteVersion
,
_testClock
.
ago
(
const
Duration
(
days:
1
)));
expect
(
stamp
.
lastTimeVersionWasChecked
,
_testClock
.
ago
(
const
Duration
(
days:
2
)));
expect
(
stamp
.
lastTimeWarningWasPrinted
,
_testClock
.
now
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
});
testUsingContext
(
'stores version stamp'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
expectSetStamp:
true
,
channel:
channel
,
);
_expectDefault
(
await
VersionCheckStamp
.
load
());
final
VersionCheckStamp
stamp
=
VersionCheckStamp
(
lastKnownRemoteVersion:
_testClock
.
ago
(
const
Duration
(
days:
1
)),
lastTimeVersionWasChecked:
_testClock
.
ago
(
const
Duration
(
days:
2
)),
lastTimeWarningWasPrinted:
_testClock
.
now
(),
);
await
stamp
.
store
();
final
VersionCheckStamp
storedStamp
=
await
VersionCheckStamp
.
load
();
expect
(
storedStamp
.
lastKnownRemoteVersion
,
_testClock
.
ago
(
const
Duration
(
days:
1
)));
expect
(
storedStamp
.
lastTimeVersionWasChecked
,
_testClock
.
ago
(
const
Duration
(
days:
2
)));
expect
(
storedStamp
.
lastTimeWarningWasPrinted
,
_testClock
.
now
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
});
testUsingContext
(
'overwrites individual fields'
,
()
async
{
fakeData
(
mockProcessManager
,
mockCache
,
expectSetStamp:
true
,
channel:
channel
,
);
_expectDefault
(
await
VersionCheckStamp
.
load
());
final
VersionCheckStamp
stamp
=
VersionCheckStamp
(
lastKnownRemoteVersion:
_testClock
.
ago
(
const
Duration
(
days:
10
)),
lastTimeVersionWasChecked:
_testClock
.
ago
(
const
Duration
(
days:
9
)),
lastTimeWarningWasPrinted:
_testClock
.
ago
(
const
Duration
(
days:
8
)),
);
await
stamp
.
store
(
newKnownRemoteVersion:
_testClock
.
ago
(
const
Duration
(
days:
1
)),
newTimeVersionWasChecked:
_testClock
.
ago
(
const
Duration
(
days:
2
)),
newTimeWarningWasPrinted:
_testClock
.
now
(),
);
final
VersionCheckStamp
storedStamp
=
await
VersionCheckStamp
.
load
();
expect
(
storedStamp
.
lastKnownRemoteVersion
,
_testClock
.
ago
(
const
Duration
(
days:
1
)));
expect
(
storedStamp
.
lastTimeVersionWasChecked
,
_testClock
.
ago
(
const
Duration
(
days:
2
)));
expect
(
storedStamp
.
lastTimeWarningWasPrinted
,
_testClock
.
now
());
},
overrides:
<
Type
,
Generator
>{
FlutterVersion:
()
=>
FlutterVersion
(
clock:
_testClock
),
ProcessManager:
()
=>
mockProcessManager
,
Cache:
()
=>
mockCache
,
});
});
}
...
...
@@ -702,130 +610,16 @@ void main() {
});
}
void
_expectVersionMessage
(
String
message
)
{
expect
(
testL
ogger
.
statusText
.
trim
(),
message
.
trim
());
testL
ogger
.
clear
();
void
_expectVersionMessage
(
String
message
,
BufferLogger
logger
)
{
expect
(
l
ogger
.
statusText
.
trim
(),
message
.
trim
());
l
ogger
.
clear
();
}
void
fakeData
(
ProcessManager
pm
,
Cache
cache
,
{
DateTime
localCommitDate
,
DateTime
remoteCommitDate
,
VersionCheckStamp
stamp
,
String
stampJson
,
bool
errorOnFetch
=
false
,
bool
expectSetStamp
=
false
,
bool
expectServerPing
=
false
,
String
channel
=
'master'
,
})
{
ProcessResult
success
(
String
standardOutput
)
{
return
ProcessResult
(
1
,
0
,
standardOutput
,
''
);
}
ProcessResult
failure
(
int
exitCode
)
{
return
ProcessResult
(
1
,
exitCode
,
''
,
'error'
);
}
when
(
cache
.
getStampFor
(
any
)).
thenAnswer
((
Invocation
invocation
)
{
expect
(
invocation
.
positionalArguments
.
single
,
VersionCheckStamp
.
flutterVersionCheckStampFile
);
if
(
stampJson
!=
null
)
{
return
stampJson
;
}
if
(
stamp
!=
null
)
{
return
json
.
encode
(
stamp
.
toJson
());
}
return
null
;
});
when
(
cache
.
setStampFor
(
any
,
any
)).
thenAnswer
((
Invocation
invocation
)
{
expect
(
invocation
.
positionalArguments
.
first
,
VersionCheckStamp
.
flutterVersionCheckStampFile
);
if
(
expectSetStamp
)
{
stamp
=
VersionCheckStamp
.
fromJson
(
castStringKeyedMap
(
json
.
decode
(
invocation
.
positionalArguments
[
1
]
as
String
)));
return
;
}
throw
StateError
(
'Unexpected call to Cache.setStampFor(
${invocation.positionalArguments}
,
${invocation.namedArguments}
)'
);
});
ProcessResult
syncAnswer
(
Invocation
invocation
)
{
bool
argsAre
(
String
a1
,
[
String
a2
,
String
a3
,
String
a4
,
String
a5
,
String
a6
,
String
a7
,
String
a8
,
String
a9
])
{
const
ListEquality
<
String
>
equality
=
ListEquality
<
String
>();
final
List
<
String
>
args
=
invocation
.
positionalArguments
.
single
as
List
<
String
>;
final
List
<
String
>
expectedArgs
=
<
String
>[
a1
,
a2
,
a3
,
a4
,
a5
,
a6
,
a7
,
a8
,
a9
].
where
((
String
arg
)
=>
arg
!=
null
).
toList
();
return
equality
.
equals
(
args
,
expectedArgs
);
}
bool
listArgsAre
(
List
<
String
>
a
)
{
return
Function
.
apply
(
argsAre
,
a
)
as
bool
;
}
if
(
listArgsAre
(
FlutterVersion
.
gitLog
(<
String
>[
'-n'
,
'1'
,
'--pretty=format:%ad'
,
'--date=iso'
])))
{
return
success
(
localCommitDate
.
toString
());
}
else
if
(
argsAre
(
'git'
,
'remote'
))
{
return
success
(
''
);
}
else
if
(
argsAre
(
'git'
,
'remote'
,
'add'
,
'__flutter_version_check__'
,
'https://github.com/flutter/flutter.git'
))
{
return
success
(
''
);
}
else
if
(
argsAre
(
'git'
,
'fetch'
,
'__flutter_version_check__'
,
channel
))
{
if
(!
expectServerPing
)
{
fail
(
'Did not expect server ping'
);
}
return
errorOnFetch
?
failure
(
128
)
:
success
(
''
);
// Careful here! argsAre accepts 9 arguments and FlutterVersion.gitLog adds 4.
}
else
if
(
remoteCommitDate
!=
null
&&
listArgsAre
(
FlutterVersion
.
gitLog
(<
String
>[
'__flutter_version_check__/
$channel
'
,
'-n'
,
'1'
,
'--pretty=format:%ad'
,
'--date=iso'
])))
{
return
success
(
remoteCommitDate
.
toString
());
}
else
if
(
argsAre
(
'git'
,
'fetch'
,
'https://github.com/flutter/flutter.git'
,
'--tags'
))
{
return
success
(
''
);
}
class
MockCache
extends
Mock
implements
Cache
{}
throw
StateError
(
'Unexpected call to ProcessManager.run(
${invocation.positionalArguments}
,
${invocation.namedArguments}
)'
);
}
class
FakeFlutterVersion
extends
Fake
implements
FlutterVersion
{
FakeFlutterVersion
(
this
.
channel
);
when
(
pm
.
runSync
(
any
,
workingDirectory:
anyNamed
(
'workingDirectory'
))).
thenAnswer
(
syncAnswer
);
when
(
pm
.
run
(
any
,
workingDirectory:
anyNamed
(
'workingDirectory'
))).
thenAnswer
((
Invocation
invocation
)
async
{
return
syncAnswer
(
invocation
);
});
when
(
pm
.
runSync
(
<
String
>[
'git'
,
'rev-parse'
,
'--abbrev-ref'
,
'--symbolic'
,
'@{u}'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenReturn
(
ProcessResult
(
101
,
0
,
channel
,
''
));
when
(
pm
.
runSync
(
<
String
>[
'git'
,
'rev-parse'
,
'--abbrev-ref'
,
'HEAD'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenReturn
(
ProcessResult
(
102
,
0
,
'branch'
,
''
));
when
(
pm
.
runSync
(
FlutterVersion
.
gitLog
(<
String
>[
'-n'
,
'1'
,
'--pretty=format:%H'
]),
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenReturn
(
ProcessResult
(
103
,
0
,
'1234abcd'
,
''
));
when
(
pm
.
runSync
(
FlutterVersion
.
gitLog
(<
String
>[
'-n'
,
'1'
,
'--pretty=format:%ar'
]),
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenReturn
(
ProcessResult
(
104
,
0
,
'1 second ago'
,
''
));
when
(
pm
.
runSync
(
<
String
>[
'git'
,
'fetch'
,
'https://github.com/flutter/flutter'
,
'--tags'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenReturn
(
ProcessResult
(
105
,
0
,
''
,
''
));
when
(
pm
.
runSync
(
<
String
>[
'git'
,
'tag'
,
'--points-at'
,
'1234abcd'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenReturn
(
ProcessResult
(
106
,
0
,
''
,
''
));
when
(
pm
.
runSync
(
<
String
>[
'git'
,
'describe'
,
'--match'
,
'*.*.*'
,
'--long'
,
'--tags'
,
'1234abcd'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenReturn
(
ProcessResult
(
107
,
0
,
'v0.1.2-3-1234abcd'
,
''
));
@override
final
String
channel
;
}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
class
MockCache
extends
Mock
implements
Cache
{}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment