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
b96d818c
Unverified
Commit
b96d818c
authored
Dec 03, 2019
by
Jonah Williams
Committed by
GitHub
Dec 03, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove record/replay/bug report functionality from the tool (#45999)
parent
a484db66
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
0 additions
and
584 deletions
+0
-584
file_system.dart
packages/flutter_tools/lib/src/base/file_system.dart
+0
-73
platform.dart
packages/flutter_tools/lib/src/base/platform.dart
+0
-30
process_manager.dart
packages/flutter_tools/lib/src/base/process_manager.dart
+0
-43
flutter_command_runner.dart
.../flutter_tools/lib/src/runner/flutter_command_runner.dart
+0
-80
vmservice.dart
packages/flutter_tools/lib/src/vmservice.dart
+0
-29
vmservice_record_replay.dart
packages/flutter_tools/lib/src/vmservice_record_replay.dart
+0
-294
bug_report_test.dart
...ges/flutter_tools/test/general.shard/bug_report_test.dart
+0
-35
No files found.
packages/flutter_tools/lib/src/base/file_system.dart
View file @
b96d818c
...
@@ -5,18 +5,15 @@
...
@@ -5,18 +5,15 @@
import
'package:file/file.dart'
;
import
'package:file/file.dart'
;
import
'package:file/local.dart'
;
import
'package:file/local.dart'
;
import
'package:file/memory.dart'
;
import
'package:file/memory.dart'
;
import
'package:file/record_replay.dart'
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'common.dart'
show
throwToolExit
;
import
'common.dart'
show
throwToolExit
;
import
'context.dart'
;
import
'context.dart'
;
import
'platform.dart'
;
import
'platform.dart'
;
import
'process.dart'
;
export
'package:file/file.dart'
;
export
'package:file/file.dart'
;
export
'package:file/local.dart'
;
export
'package:file/local.dart'
;
const
String
_kRecordingType
=
'file'
;
const
FileSystem
_kLocalFs
=
LocalFileSystem
();
const
FileSystem
_kLocalFs
=
LocalFileSystem
();
/// Currently active implementation of the file system.
/// Currently active implementation of the file system.
...
@@ -25,33 +22,6 @@ const FileSystem _kLocalFs = LocalFileSystem();
...
@@ -25,33 +22,6 @@ const FileSystem _kLocalFs = LocalFileSystem();
/// with [MemoryFileSystem].
/// with [MemoryFileSystem].
FileSystem
get
fs
=>
context
.
get
<
FileSystem
>()
??
_kLocalFs
;
FileSystem
get
fs
=>
context
.
get
<
FileSystem
>()
??
_kLocalFs
;
/// Gets a [FileSystem] that will record file system activity to the specified
/// base recording [location].
///
/// Activity will be recorded in a subdirectory of [location] named `"file"`.
/// It is permissible for [location] to represent an existing non-empty
/// directory as long as there is no collision with the `"file"` subdirectory.
RecordingFileSystem
getRecordingFileSystem
(
String
location
)
{
final
Directory
dir
=
getRecordingSink
(
location
,
_kRecordingType
);
final
RecordingFileSystem
fileSystem
=
RecordingFileSystem
(
delegate:
_kLocalFs
,
destination:
dir
);
addShutdownHook
(()
async
{
await
fileSystem
.
recording
.
flush
();
},
ShutdownStage
.
SERIALIZE_RECORDING
);
return
fileSystem
;
}
/// Gets a [FileSystem] that replays invocation activity from a previously
/// recorded set of invocations.
///
/// [location] must represent a directory to which file system activity has
/// been recorded (i.e. the result of having been previously passed to
/// [getRecordingFileSystem]), or a [ToolExit] will be thrown.
ReplayFileSystem
getReplayFileSystem
(
String
location
)
{
final
Directory
dir
=
getReplaySource
(
location
,
_kRecordingType
);
return
ReplayFileSystem
(
recording:
dir
);
}
/// Create the ancestor directories of a file path if they do not already exist.
/// Create the ancestor directories of a file path if they do not already exist.
void
ensureDirectoryExists
(
String
filePath
)
{
void
ensureDirectoryExists
(
String
filePath
)
{
final
String
dirPath
=
fs
.
path
.
dirname
(
filePath
);
final
String
dirPath
=
fs
.
path
.
dirname
(
filePath
);
...
@@ -105,49 +75,6 @@ void copyDirectorySync(
...
@@ -105,49 +75,6 @@ void copyDirectorySync(
}
}
}
}
/// Gets a directory to act as a recording destination, creating the directory
/// as necessary.
///
/// The directory will exist in the local file system, be named [basename], and
/// be a child of the directory identified by [dirname].
///
/// If the target directory already exists as a directory, the existing
/// directory must be empty, or a [ToolExit] will be thrown. If the target
/// directory exists as an entity other than a directory, a [ToolExit] will
/// also be thrown.
Directory
getRecordingSink
(
String
dirname
,
String
basename
)
{
final
String
location
=
_kLocalFs
.
path
.
join
(
dirname
,
basename
);
switch
(
_kLocalFs
.
typeSync
(
location
,
followLinks:
false
))
{
case
FileSystemEntityType
.
file
:
case
FileSystemEntityType
.
link
:
throwToolExit
(
'Invalid record-to location:
$dirname
("
$basename
" exists as non-directory)'
);
break
;
case
FileSystemEntityType
.
directory
:
if
(
_kLocalFs
.
directory
(
location
).
listSync
(
followLinks:
false
).
isNotEmpty
)
{
throwToolExit
(
'Invalid record-to location:
$dirname
("
$basename
" is not empty)'
);
}
break
;
case
FileSystemEntityType
.
notFound
:
_kLocalFs
.
directory
(
location
).
createSync
(
recursive:
true
);
}
return
_kLocalFs
.
directory
(
location
);
}
/// Gets a directory that holds a saved recording to be used for the purpose of
/// replay.
///
/// The directory will exist in the local file system, be named [basename], and
/// be a child of the directory identified by [dirname].
///
/// If the target directory does not exist, a [ToolExit] will be thrown.
Directory
getReplaySource
(
String
dirname
,
String
basename
)
{
final
Directory
dir
=
_kLocalFs
.
directory
(
_kLocalFs
.
path
.
join
(
dirname
,
basename
));
if
(!
dir
.
existsSync
())
{
throwToolExit
(
'Invalid replay-from location:
$dirname
("
$basename
" does not exist)'
);
}
return
dir
;
}
/// Canonicalizes [path].
/// Canonicalizes [path].
///
///
/// This function implements the behavior of `canonicalize` from
/// This function implements the behavior of `canonicalize` from
...
...
packages/flutter_tools/lib/src/base/platform.dart
View file @
b96d818c
...
@@ -5,39 +5,9 @@
...
@@ -5,39 +5,9 @@
import
'package:platform/platform.dart'
;
import
'package:platform/platform.dart'
;
import
'context.dart'
;
import
'context.dart'
;
import
'file_system.dart'
;
export
'package:platform/platform.dart'
;
export
'package:platform/platform.dart'
;
const
Platform
_kLocalPlatform
=
LocalPlatform
();
const
Platform
_kLocalPlatform
=
LocalPlatform
();
const
String
_kRecordingType
=
'platform'
;
Platform
get
platform
=>
context
.
get
<
Platform
>()
??
_kLocalPlatform
;
Platform
get
platform
=>
context
.
get
<
Platform
>()
??
_kLocalPlatform
;
/// Serializes the current [platform] to the specified base recording
/// [location].
///
/// Platform metadata will be recorded in a subdirectory of [location] named
/// `"platform"`. It is permissible for [location] to represent an existing
/// non-empty directory as long as there is no collision with the `"platform"`
/// subdirectory.
///
/// Returns the existing platform.
Platform
getRecordingPlatform
(
String
location
)
{
final
Directory
dir
=
getRecordingSink
(
location
,
_kRecordingType
);
final
File
file
=
_getPlatformManifest
(
dir
);
file
.
writeAsStringSync
(
platform
.
toJson
(),
flush:
true
);
return
platform
;
}
FakePlatform
getReplayPlatform
(
String
location
)
{
final
Directory
dir
=
getReplaySource
(
location
,
_kRecordingType
);
final
File
file
=
_getPlatformManifest
(
dir
);
final
String
json
=
file
.
readAsStringSync
();
return
FakePlatform
.
fromJson
(
json
);
}
File
_getPlatformManifest
(
Directory
dir
)
{
final
String
path
=
dir
.
fileSystem
.
path
.
join
(
dir
.
path
,
'MANIFEST.txt'
);
return
dir
.
fileSystem
.
file
(
path
);
}
packages/flutter_tools/lib/src/base/process_manager.dart
View file @
b96d818c
...
@@ -2,54 +2,11 @@
...
@@ -2,54 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:async'
;
import
'package:process/process.dart'
;
import
'package:process/process.dart'
;
import
'package:process/record_replay.dart'
;
import
'common.dart'
;
import
'context.dart'
;
import
'context.dart'
;
import
'file_system.dart'
;
import
'process.dart'
;
const
String
_kRecordingType
=
'process'
;
const
ProcessManager
_kLocalProcessManager
=
LocalProcessManager
();
const
ProcessManager
_kLocalProcessManager
=
LocalProcessManager
();
/// The active process manager.
/// The active process manager.
ProcessManager
get
processManager
=>
context
.
get
<
ProcessManager
>()
??
_kLocalProcessManager
;
ProcessManager
get
processManager
=>
context
.
get
<
ProcessManager
>()
??
_kLocalProcessManager
;
/// Gets a [ProcessManager] that will record process invocation activity to the
/// specified base recording [location].
///
/// Activity will be recorded in a subdirectory of [location] named `"process"`.
/// It is permissible for [location] to represent an existing non-empty
/// directory as long as there is no collision with the `"process"`
/// subdirectory.
RecordingProcessManager
getRecordingProcessManager
(
String
location
)
{
final
Directory
dir
=
getRecordingSink
(
location
,
_kRecordingType
);
const
ProcessManager
delegate
=
LocalProcessManager
();
final
RecordingProcessManager
manager
=
RecordingProcessManager
(
delegate
,
dir
);
addShutdownHook
(()
async
{
await
manager
.
flush
(
finishRunningProcesses:
true
);
},
ShutdownStage
.
SERIALIZE_RECORDING
);
return
manager
;
}
/// Gets a [ProcessManager] that replays process activity from a previously
/// recorded set of invocations.
///
/// [location] must represent a directory to which process activity has been
/// recorded (i.e. the result of having been previously passed to
/// [getRecordingProcessManager]), or a [ToolExit] will be thrown.
Future
<
ReplayProcessManager
>
getReplayProcessManager
(
String
location
)
async
{
final
Directory
dir
=
getReplaySource
(
location
,
_kRecordingType
);
ProcessManager
manager
;
try
{
manager
=
await
ReplayProcessManager
.
create
(
dir
);
}
on
ArgumentError
catch
(
error
)
{
throwToolExit
(
'Invalid replay-from:
$error
'
);
}
return
manager
as
ReplayProcessManager
;
}
packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
View file @
b96d818c
...
@@ -8,8 +8,6 @@ import 'package:args/args.dart';
...
@@ -8,8 +8,6 @@ import 'package:args/args.dart';
import
'package:args/command_runner.dart'
;
import
'package:args/command_runner.dart'
;
import
'package:completion/completion.dart'
;
import
'package:completion/completion.dart'
;
import
'package:file/file.dart'
;
import
'package:file/file.dart'
;
import
'package:platform/platform.dart'
;
import
'package:process/process.dart'
;
import
'../artifacts.dart'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/common.dart'
;
...
@@ -17,10 +15,7 @@ import '../base/context.dart';
...
@@ -17,10 +15,7 @@ import '../base/context.dart';
import
'../base/file_system.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
as
io
;
import
'../base/io.dart'
as
io
;
import
'../base/logger.dart'
;
import
'../base/logger.dart'
;
import
'../base/os.dart'
;
import
'../base/platform.dart'
;
import
'../base/platform.dart'
;
import
'../base/process.dart'
;
import
'../base/process_manager.dart'
;
import
'../base/terminal.dart'
;
import
'../base/terminal.dart'
;
import
'../base/user_messages.dart'
;
import
'../base/user_messages.dart'
;
import
'../base/utils.dart'
;
import
'../base/utils.dart'
;
...
@@ -32,7 +27,6 @@ import '../globals.dart';
...
@@ -32,7 +27,6 @@ import '../globals.dart';
import
'../reporting/reporting.dart'
;
import
'../reporting/reporting.dart'
;
import
'../tester/flutter_tester.dart'
;
import
'../tester/flutter_tester.dart'
;
import
'../version.dart'
;
import
'../version.dart'
;
import
'../vmservice.dart'
;
const
String
kFlutterRootEnvironmentVariableName
=
'FLUTTER_ROOT'
;
// should point to //flutter/ (root of flutter/flutter repo)
const
String
kFlutterRootEnvironmentVariableName
=
'FLUTTER_ROOT'
;
// should point to //flutter/ (root of flutter/flutter repo)
const
String
kFlutterEngineEnvironmentVariableName
=
'FLUTTER_ENGINE'
;
// should point to //engine/src/ (root of flutter/engine repo)
const
String
kFlutterEngineEnvironmentVariableName
=
'FLUTTER_ENGINE'
;
// should point to //engine/src/ (root of flutter/engine repo)
...
@@ -96,10 +90,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
...
@@ -96,10 +90,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
argParser
.
addFlag
(
'suppress-analytics'
,
argParser
.
addFlag
(
'suppress-analytics'
,
negatable:
false
,
negatable:
false
,
help:
'Suppress analytics reporting when this command runs.'
);
help:
'Suppress analytics reporting when this command runs.'
);
argParser
.
addFlag
(
'bug-report'
,
negatable:
false
,
help:
'Captures a bug report file to submit to the Flutter team.
\n
'
'Contains local paths, device identifiers, and log snippets.'
);
String
packagesHelp
;
String
packagesHelp
;
bool
showPackagesCommand
;
bool
showPackagesCommand
;
...
@@ -141,19 +131,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
...
@@ -141,19 +131,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
if
(
verboseHelp
)
{
if
(
verboseHelp
)
{
argParser
.
addSeparator
(
'Options for testing the "flutter" tool itself:'
);
argParser
.
addSeparator
(
'Options for testing the "flutter" tool itself:'
);
}
}
argParser
.
addOption
(
'record-to'
,
hide:
!
verboseHelp
,
help:
'Enables recording of process invocations (including stdout and stderr of all such invocations), '
'and file system access (reads and writes).
\n
'
'Serializes that recording to a directory with the path specified in this flag. If the '
'directory does not already exist, it will be created.'
);
argParser
.
addOption
(
'replay-from'
,
hide:
!
verboseHelp
,
help:
'Enables mocking of process invocations by replaying their stdout, stderr, and exit code from '
'the specified recording (obtained via --record-to). The path specified in this flag must refer '
'to a directory that holds serialized process invocations structured according to the output of '
'--record-to.'
);
argParser
.
addFlag
(
'show-test-device'
,
argParser
.
addFlag
(
'show-test-device'
,
negatable:
false
,
negatable:
false
,
hide:
!
verboseHelp
,
hide:
!
verboseHelp
,
...
@@ -291,63 +268,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
...
@@ -291,63 +268,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
FlutterTesterDevices
.
showFlutterTesterDevice
=
true
;
FlutterTesterDevices
.
showFlutterTesterDevice
=
true
;
}
}
String
recordTo
=
topLevelResults
[
'record-to'
]
as
String
;
String
replayFrom
=
topLevelResults
[
'replay-from'
]
as
String
;
if
(
topLevelResults
[
'bug-report'
]
as
bool
)
{
// --bug-report implies --record-to=<tmp_path>
final
Directory
tempDir
=
const
LocalFileSystem
()
.
systemTempDirectory
.
createTempSync
(
'flutter_tools_bug_report.'
);
recordTo
=
tempDir
.
path
;
// Record the arguments that were used to invoke this runner.
final
File
manifest
=
tempDir
.
childFile
(
'MANIFEST.txt'
);
final
StringBuffer
buffer
=
StringBuffer
()
..
writeln
(
'# arguments'
)
..
writeln
(
topLevelResults
.
arguments
)
..
writeln
()
..
writeln
(
'# rest'
)
..
writeln
(
topLevelResults
.
rest
);
manifest
.
writeAsStringSync
(
buffer
.
toString
(),
flush:
true
);
// ZIP the recording up once the recording has been serialized.
addShutdownHook
(()
{
final
File
zipFile
=
getUniqueFile
(
fs
.
currentDirectory
,
'bugreport'
,
'zip'
);
os
.
zip
(
tempDir
,
zipFile
);
printStatus
(
userMessages
.
runnerBugReportFinished
(
zipFile
.
basename
));
},
ShutdownStage
.
POST_PROCESS_RECORDING
);
addShutdownHook
(()
=>
tempDir
.
deleteSync
(
recursive:
true
),
ShutdownStage
.
CLEANUP
);
}
assert
(
recordTo
==
null
||
replayFrom
==
null
);
if
(
recordTo
!=
null
)
{
recordTo
=
recordTo
.
trim
();
if
(
recordTo
.
isEmpty
)
{
throwToolExit
(
userMessages
.
runnerNoRecordTo
);
}
contextOverrides
.
addAll
(<
Type
,
dynamic
>{
ProcessManager:
getRecordingProcessManager
(
recordTo
),
FileSystem:
getRecordingFileSystem
(
recordTo
),
Platform:
getRecordingPlatform
(
recordTo
),
});
VMService
.
enableRecordingConnection
(
recordTo
);
}
if
(
replayFrom
!=
null
)
{
replayFrom
=
replayFrom
.
trim
();
if
(
replayFrom
.
isEmpty
)
{
throwToolExit
(
userMessages
.
runnerNoReplayFrom
);
}
contextOverrides
.
addAll
(<
Type
,
dynamic
>{
ProcessManager:
await
getReplayProcessManager
(
replayFrom
),
FileSystem:
getReplayFileSystem
(
replayFrom
),
Platform:
getReplayPlatform
(
replayFrom
),
});
VMService
.
enableReplayConnection
(
replayFrom
);
}
// We must set Cache.flutterRoot early because other features use it (e.g.
// We must set Cache.flutterRoot early because other features use it (e.g.
// enginePath's initializer uses it).
// enginePath's initializer uses it).
final
String
flutterRoot
=
topLevelResults
[
'flutter-root'
]
as
String
??
defaultFlutterRoot
;
final
String
flutterRoot
=
topLevelResults
[
'flutter-root'
]
as
String
??
defaultFlutterRoot
;
...
...
packages/flutter_tools/lib/src/vmservice.dart
View file @
b96d818c
...
@@ -5,7 +5,6 @@
...
@@ -5,7 +5,6 @@
import
'dart:async'
;
import
'dart:async'
;
import
'dart:math'
as
math
;
import
'dart:math'
as
math
;
import
'package:file/file.dart'
;
import
'package:json_rpc_2/error_code.dart'
as
rpc_error_code
;
import
'package:json_rpc_2/error_code.dart'
as
rpc_error_code
;
import
'package:json_rpc_2/json_rpc_2.dart'
as
rpc
;
import
'package:json_rpc_2/json_rpc_2.dart'
as
rpc
;
import
'package:meta/meta.dart'
show
required
;
import
'package:meta/meta.dart'
show
required
;
...
@@ -22,7 +21,6 @@ import 'convert.dart' show base64, utf8;
...
@@ -22,7 +21,6 @@ import 'convert.dart' show base64, utf8;
import
'device.dart'
;
import
'device.dart'
;
import
'globals.dart'
;
import
'globals.dart'
;
import
'version.dart'
;
import
'version.dart'
;
import
'vmservice_record_replay.dart'
;
/// Override `WebSocketConnector` in [context] to use a different constructor
/// Override `WebSocketConnector` in [context] to use a different constructor
/// for [WebSocket]s (used by tests).
/// for [WebSocket]s (used by tests).
...
@@ -62,8 +60,6 @@ typedef CompileExpression = Future<String> Function(
...
@@ -62,8 +60,6 @@ typedef CompileExpression = Future<String> Function(
bool
isStatic
,
bool
isStatic
,
);
);
const
String
_kRecordingType
=
'vmservice'
;
Future
<
StreamChannel
<
String
>>
_defaultOpenChannel
(
Uri
uri
,
{
io
.
CompressionOptions
compression
=
io
.
CompressionOptions
.
compressionDefault
})
async
{
Future
<
StreamChannel
<
String
>>
_defaultOpenChannel
(
Uri
uri
,
{
io
.
CompressionOptions
compression
=
io
.
CompressionOptions
.
compressionDefault
})
async
{
Duration
delay
=
const
Duration
(
milliseconds:
100
);
Duration
delay
=
const
Duration
(
milliseconds:
100
);
int
attempts
=
0
;
int
attempts
=
0
;
...
@@ -284,31 +280,6 @@ class VMService {
...
@@ -284,31 +280,6 @@ class VMService {
}
}
}
}
/// Enables recording of VMService JSON-rpc activity to the specified base
/// recording [location].
///
/// Activity will be recorded in a subdirectory of [location] named
/// `"vmservice"`. It is permissible for [location] to represent an existing
/// non-empty directory as long as there is no collision with the
/// `"vmservice"` subdirectory.
static
void
enableRecordingConnection
(
String
location
)
{
final
Directory
dir
=
getRecordingSink
(
location
,
_kRecordingType
);
_openChannel
=
(
Uri
uri
,
{
io
.
CompressionOptions
compression
})
async
{
final
StreamChannel
<
String
>
delegate
=
await
_defaultOpenChannel
(
uri
);
return
RecordingVMServiceChannel
(
delegate
,
dir
);
};
}
/// Enables VMService JSON-rpc replay mode.
///
/// [location] must represent a directory to which VMService JSON-rpc
/// activity has been recorded (i.e. the result of having been previously
/// passed to [enableRecordingConnection]), or a [ToolExit] will be thrown.
static
void
enableReplayConnection
(
String
location
)
{
final
Directory
dir
=
getReplaySource
(
location
,
_kRecordingType
);
_openChannel
=
(
Uri
uri
,
{
io
.
CompressionOptions
compression
})
async
=>
ReplayVMServiceChannel
(
dir
);
}
static
void
_unhandledError
(
dynamic
error
,
dynamic
stack
)
{
static
void
_unhandledError
(
dynamic
error
,
dynamic
stack
)
{
logger
.
printTrace
(
'Error in internal implementation of JSON RPC.
\n
$error
\n
$stack
'
);
logger
.
printTrace
(
'Error in internal implementation of JSON RPC.
\n
$error
\n
$stack
'
);
assert
(
false
);
assert
(
false
);
...
...
packages/flutter_tools/lib/src/vmservice_record_replay.dart
deleted
100644 → 0
View file @
a484db66
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'package:file/file.dart'
;
import
'package:stream_channel/stream_channel.dart'
;
import
'base/io.dart'
;
import
'base/process.dart'
;
import
'base/utils.dart'
;
import
'convert.dart'
;
import
'globals.dart'
;
const
String
_kManifest
=
'MANIFEST.txt'
;
const
String
_kRequest
=
'request'
;
const
String
_kResponse
=
'response'
;
const
String
_kId
=
'id'
;
const
String
_kType
=
'type'
;
const
String
_kData
=
'data'
;
/// A [StreamChannel] that expects VM service (JSON-rpc) protocol messages and
/// serializes all such messages to the file system for later playback.
class
RecordingVMServiceChannel
extends
DelegatingStreamChannel
<
String
>
{
RecordingVMServiceChannel
(
StreamChannel
<
String
>
delegate
,
Directory
location
)
:
super
(
delegate
)
{
addShutdownHook
(()
{
// Sort the messages such that they are ordered
// `[request1, response1, request2, response2, ...]`. This serves no
// purpose other than to make the serialized format more human-readable.
_messages
.
sort
();
final
File
file
=
_getManifest
(
location
);
final
String
json
=
const
JsonEncoder
.
withIndent
(
' '
).
convert
(
_messages
);
file
.
writeAsStringSync
(
json
,
flush:
true
);
},
ShutdownStage
.
SERIALIZE_RECORDING
);
}
final
List
<
_Message
>
_messages
=
<
_Message
>[];
_RecordingStream
_streamRecorder
;
_RecordingSink
_sinkRecorder
;
@override
Stream
<
String
>
get
stream
{
_streamRecorder
??=
_RecordingStream
(
super
.
stream
,
_messages
);
return
_streamRecorder
.
stream
;
}
@override
StreamSink
<
String
>
get
sink
=>
_sinkRecorder
??=
_RecordingSink
(
super
.
sink
,
_messages
);
}
/// Base class for request and response JSON-rpc messages.
abstract
class
_Message
implements
Comparable
<
_Message
>
{
_Message
(
this
.
type
,
this
.
data
);
factory
_Message
.
fromRecording
(
Map
<
String
,
dynamic
>
recordingData
)
{
return
recordingData
[
_kType
]
==
_kRequest
?
_Request
(
castStringKeyedMap
(
recordingData
[
_kData
]))
:
_Response
(
castStringKeyedMap
(
recordingData
[
_kData
]));
}
final
String
type
;
final
Map
<
String
,
dynamic
>
data
;
int
get
id
=>
data
[
_kId
]
as
int
;
/// Allows [JsonEncoder] to properly encode objects of this type.
Map
<
String
,
dynamic
>
toJson
()
{
return
<
String
,
dynamic
>{
_kType:
type
,
_kData:
data
,
};
}
@override
int
compareTo
(
_Message
other
)
{
if
(
id
==
null
)
{
printError
(
'Invalid VMService message data detected:
$data
'
);
return
-
1
;
}
final
int
result
=
id
.
compareTo
(
other
.
id
);
if
(
result
!=
0
)
{
return
result
;
}
else
if
(
type
==
_kRequest
)
{
return
-
1
;
}
else
{
return
1
;
}
}
}
/// A VM service JSON-rpc request (sent to the VM).
class
_Request
extends
_Message
{
_Request
(
Map
<
String
,
dynamic
>
data
)
:
super
(
_kRequest
,
data
);
_Request
.
fromString
(
String
data
)
:
this
(
castStringKeyedMap
(
json
.
decode
(
data
)));
}
/// A VM service JSON-rpc response (from the VM).
class
_Response
extends
_Message
{
_Response
(
Map
<
String
,
dynamic
>
data
)
:
super
(
_kResponse
,
data
);
_Response
.
fromString
(
String
data
)
:
this
(
castStringKeyedMap
(
json
.
decode
(
data
)));
}
/// A matching request/response pair.
///
/// A request and response match by virtue of having matching
/// [IDs](_Message.id).
class
_Transaction
{
_Request
request
;
_Response
response
;
}
/// A helper class that monitors a [Stream] of VM service JSON-rpc responses
/// and saves the responses to a recording.
class
_RecordingStream
{
_RecordingStream
(
Stream
<
String
>
stream
,
this
.
_recording
)
:
_delegate
=
stream
,
_controller
=
stream
.
isBroadcast
?
StreamController
<
String
>.
broadcast
()
:
StreamController
<
String
>()
{
_controller
.
onListen
=
()
{
assert
(
_subscription
==
null
);
_subscription
=
_listenToStream
();
};
_controller
.
onCancel
=
()
async
{
assert
(
_subscription
!=
null
);
await
_subscription
.
cancel
();
_subscription
=
null
;
};
_controller
.
onPause
=
()
{
assert
(
_subscription
!=
null
&&
!
_subscription
.
isPaused
);
_subscription
.
pause
();
};
_controller
.
onResume
=
()
{
assert
(
_subscription
!=
null
&&
_subscription
.
isPaused
);
_subscription
.
resume
();
};
}
final
Stream
<
String
>
_delegate
;
final
StreamController
<
String
>
_controller
;
final
List
<
_Message
>
_recording
;
StreamSubscription
<
String
>
_subscription
;
StreamSubscription
<
String
>
_listenToStream
()
{
return
_delegate
.
listen
(
(
String
element
)
{
_recording
.
add
(
_Response
.
fromString
(
element
));
_controller
.
add
(
element
);
},
onError:
_controller
.
addError
,
// We currently don't support recording of errors.
onDone:
_controller
.
close
,
);
}
/// The wrapped [Stream] to expose to callers.
Stream
<
String
>
get
stream
=>
_controller
.
stream
;
}
/// A [StreamSink] that monitors VM service JSON-rpc requests and saves the
/// requests to a recording.
class
_RecordingSink
implements
StreamSink
<
String
>
{
_RecordingSink
(
this
.
_delegate
,
this
.
_recording
);
final
StreamSink
<
String
>
_delegate
;
final
List
<
_Message
>
_recording
;
@override
Future
<
dynamic
>
close
()
=>
_delegate
.
close
();
@override
Future
<
dynamic
>
get
done
=>
_delegate
.
done
;
@override
void
add
(
String
data
)
{
_delegate
.
add
(
data
);
_recording
.
add
(
_Request
.
fromString
(
data
));
}
@override
void
addError
(
dynamic
errorEvent
,
[
StackTrace
stackTrace
])
{
throw
UnimplementedError
(
'Add support for this if the need ever arises'
);
}
@override
Future
<
dynamic
>
addStream
(
Stream
<
String
>
stream
)
{
throw
UnimplementedError
(
'Add support for this if the need ever arises'
);
}
}
/// A [StreamChannel] that expects VM service (JSON-rpc) requests to be written
/// to its [StreamChannel.sink], looks up those requests in a recording, and
/// replays the corresponding responses back from the recording.
class
ReplayVMServiceChannel
extends
StreamChannelMixin
<
String
>
{
ReplayVMServiceChannel
(
Directory
location
)
:
_transactions
=
_loadTransactions
(
location
);
final
Map
<
int
,
_Transaction
>
_transactions
;
final
StreamController
<
String
>
_controller
=
StreamController
<
String
>();
_ReplaySink
_replaySink
;
static
Map
<
int
,
_Transaction
>
_loadTransactions
(
Directory
location
)
{
final
File
file
=
_getManifest
(
location
);
final
String
jsonData
=
file
.
readAsStringSync
();
final
Iterable
<
_Message
>
messages
=
(
json
.
decode
(
jsonData
)
as
List
<
dynamic
>)
.
cast
<
Map
<
String
,
dynamic
>>()
.
map
<
_Message
>(
_toMessage
);
final
Map
<
int
,
_Transaction
>
transactions
=
<
int
,
_Transaction
>{};
for
(
_Message
message
in
messages
)
{
final
_Transaction
transaction
=
transactions
.
putIfAbsent
(
message
.
id
,
()
=>
_Transaction
());
if
(
message
.
type
==
_kRequest
)
{
assert
(
transaction
.
request
==
null
);
transaction
.
request
=
message
as
_Request
;
}
else
{
assert
(
transaction
.
response
==
null
);
transaction
.
response
=
message
as
_Response
;
}
}
return
transactions
;
}
static
_Message
_toMessage
(
Map
<
String
,
dynamic
>
jsonData
)
{
return
_Message
.
fromRecording
(
jsonData
);
}
void
send
(
_Request
request
)
{
if
(!
_transactions
.
containsKey
(
request
.
id
))
{
throw
ArgumentError
(
'No matching invocation found'
);
}
final
_Transaction
transaction
=
_transactions
.
remove
(
request
.
id
);
// TODO(tvolkert): validate that `transaction.request` matches `request`
if
(
transaction
.
response
==
null
)
{
// This signals that when we were recording, the VM shut down before
// we received the response. This is typically due to the user quitting
// the app runner. We follow suit here and exit.
printStatus
(
'Exiting due to dangling request'
);
exit
(
0
);
}
else
{
_controller
.
add
(
json
.
encoder
.
convert
(
transaction
.
response
.
data
));
if
(
_transactions
.
isEmpty
)
{
_controller
.
close
();
}
}
}
@override
StreamSink
<
String
>
get
sink
=>
_replaySink
??=
_ReplaySink
(
this
);
@override
Stream
<
String
>
get
stream
=>
_controller
.
stream
;
}
class
_ReplaySink
implements
StreamSink
<
String
>
{
_ReplaySink
(
this
.
channel
);
final
ReplayVMServiceChannel
channel
;
final
Completer
<
void
>
_completer
=
Completer
<
void
>();
@override
Future
<
dynamic
>
close
()
{
_completer
.
complete
();
return
_completer
.
future
;
}
@override
Future
<
dynamic
>
get
done
=>
_completer
.
future
;
@override
void
add
(
String
data
)
{
if
(
_completer
.
isCompleted
)
{
throw
StateError
(
'Sink already closed'
);
}
channel
.
send
(
_Request
.
fromString
(
data
));
}
@override
void
addError
(
dynamic
errorEvent
,
[
StackTrace
stackTrace
])
{
throw
UnimplementedError
(
'Add support for this if the need ever arises'
);
}
@override
Future
<
dynamic
>
addStream
(
Stream
<
String
>
stream
)
{
throw
UnimplementedError
(
'Add support for this if the need ever arises'
);
}
}
File
_getManifest
(
Directory
location
)
{
final
String
path
=
location
.
fileSystem
.
path
.
join
(
location
.
path
,
_kManifest
);
return
location
.
fileSystem
.
file
(
path
);
}
packages/flutter_tools/test/general.shard/bug_report_test.dart
deleted
100644 → 0
View file @
a484db66
// Copyright 2014 The Flutter Authors. 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:file_testing/file_testing.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:flutter_tools/executable.dart'
as
tools
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/os.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
void
main
(
)
{
Cache
.
disableLocking
();
int
exitCode
;
setExitFunctionForTests
((
int
code
)
{
exitCode
=
code
;
});
group
(
'--bug-report'
,
()
{
testUsingContext
(
'generates valid zip file'
,
()
async
{
await
tools
.
main
(<
String
>[
'devices'
,
'--bug-report'
]);
expect
(
exitCode
,
0
);
verify
(
os
.
zip
(
any
,
argThat
(
hasPath
(
matches
(
r'bugreport_01\.zip'
)))));
},
overrides:
<
Type
,
Generator
>{
OperatingSystemUtils:
()
=>
MockOperatingSystemUtils
(),
});
});
}
class
MockOperatingSystemUtils
extends
Mock
implements
OperatingSystemUtils
{
}
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