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
017dd3e7
Unverified
Commit
017dd3e7
authored
Aug 09, 2022
by
Christopher Fujino
Committed by
GitHub
Aug 09, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] Fix race condition with completer in devfs_web (#109059)
parent
d823c883
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
120 additions
and
5 deletions
+120
-5
devfs_web.dart
packages/flutter_tools/lib/src/isolated/devfs_web.dart
+21
-4
resident_web_runner_test.dart
...er_tools/test/general.shard/resident_web_runner_test.dart
+1
-1
devfs_web_test.dart
.../flutter_tools/test/general.shard/web/devfs_web_test.dart
+98
-0
No files found.
packages/flutter_tools/lib/src/isolated/devfs_web.dart
View file @
017dd3e7
...
...
@@ -625,6 +625,12 @@ class ConnectionResult {
final
vm_service
.
VmService
vmService
;
}
typedef
VmServiceFactory
=
Future
<
vm_service
.
VmService
>
Function
(
Uri
,
{
CompressionOptions
compression
,
required
Logger
logger
,
});
/// The web specific DevFS implementation.
class
WebDevFS
implements
DevFS
{
/// Create a new [WebDevFS] instance.
...
...
@@ -686,9 +692,17 @@ class WebDevFS implements DevFS {
/// Connect and retrieve the [DebugConnection] for the current application.
///
/// Only calls [AppConnection.runMain] on the subsequent connections.
Future
<
ConnectionResult
?>
connect
(
bool
useDebugExtension
)
{
Future
<
ConnectionResult
?>
connect
(
bool
useDebugExtension
,
{
@visibleForTesting
VmServiceFactory
vmServiceFactory
=
createVmServiceDelegate
,
})
{
final
Completer
<
ConnectionResult
>
firstConnection
=
Completer
<
ConnectionResult
>();
// Note there is an asynchronous gap between this being set to true and
// [firstConnection] completing; thus test the boolean to determine if
// the current connection is the first.
bool
foundFirstConnection
=
false
;
_connectedApps
=
dwds
.
connectedApps
.
listen
((
AppConnection
appConnection
)
async
{
try
{
...
...
@@ -696,10 +710,11 @@ class WebDevFS implements DevFS {
?
await
(
_cachedExtensionFuture
??=
dwds
.
extensionDebugConnections
.
stream
.
first
)
:
await
dwds
.
debugConnection
(
appConnection
);
if
(
f
irstConnection
.
isCompleted
)
{
if
(
f
oundFirstConnection
)
{
appConnection
.
runMain
();
}
else
{
final
vm_service
.
VmService
vmService
=
await
createVmServiceDelegate
(
foundFirstConnection
=
true
;
final
vm_service
.
VmService
vmService
=
await
vmServiceFactory
(
Uri
.
parse
(
debugConnection
.
uri
),
logger:
globals
.
logger
,
);
...
...
@@ -713,7 +728,8 @@ class WebDevFS implements DevFS {
}
},
onError:
(
Object
error
,
StackTrace
stackTrace
)
{
globals
.
printError
(
'Unknown error while waiting for debug connection:
$error
\n
$stackTrace
'
);
'Unknown error while waiting for debug connection:
$error
\n
$stackTrace
'
,
);
if
(!
firstConnection
.
isCompleted
)
{
firstConnection
.
completeError
(
error
,
stackTrace
);
}
...
...
@@ -756,6 +772,7 @@ class WebDevFS implements DevFS {
nullSafetyMode
,
testMode:
testMode
,
);
final
int
selectedPort
=
webAssetServer
.
selectedPort
;
if
(
buildInfo
.
dartDefines
.
contains
(
'FLUTTER_WEB_AUTO_DETECT=true'
))
{
webAssetServer
.
webRenderer
=
WebRendererMode
.
autoDetect
;
...
...
packages/flutter_tools/test/general.shard/resident_web_runner_test.dart
View file @
017dd3e7
...
...
@@ -1352,7 +1352,7 @@ class FakeWebDevFS extends Fake implements WebDevFS {
}
@override
Future
<
ConnectionResult
>
connect
(
bool
useDebugExtension
)
async
{
Future
<
ConnectionResult
>
connect
(
bool
useDebugExtension
,
{
VmServiceFactory
vmServiceFactory
=
createVmServiceDelegate
}
)
async
{
if
(
exception
!=
null
)
{
assert
(
exception
is
Exception
||
exception
is
Error
);
// ignore: only_throw_errors, exception is either Error or Exception here.
...
...
packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
View file @
017dd3e7
...
...
@@ -4,8 +4,11 @@
// @dart = 2.8
import
'dart:async'
;
import
'dart:io'
hide
Directory
,
File
;
import
'package:dwds/dwds.dart'
;
import
'package:fake_async/fake_async.dart'
;
import
'package:flutter_tools/src/artifacts.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
...
...
@@ -24,6 +27,7 @@ import 'package:meta/meta.dart';
import
'package:package_config/package_config.dart'
;
import
'package:shelf/shelf.dart'
;
import
'package:test/fake.dart'
;
import
'package:vm_service/vm_service.dart'
as
vm_service
;
import
'../../src/common.dart'
;
import
'../../src/testbed.dart'
;
...
...
@@ -870,6 +874,71 @@ void main() {
Artifacts:
()
=>
Artifacts
.
test
(),
}));
test
(
'.connect() will never call vmServiceFactory twice'
,
()
=>
testbed
.
run
(()
async
{
await
FakeAsync
().
run
<
Future
<
void
>>((
FakeAsync
time
)
{
final
File
outputFile
=
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
'lib'
,
'main.dart'
))
..
createSync
(
recursive:
true
);
outputFile
.
parent
.
childFile
(
'a.sources'
).
writeAsStringSync
(
''
);
outputFile
.
parent
.
childFile
(
'a.json'
).
writeAsStringSync
(
'{}'
);
outputFile
.
parent
.
childFile
(
'a.map'
).
writeAsStringSync
(
'{}'
);
outputFile
.
parent
.
childFile
(
'a.metadata'
).
writeAsStringSync
(
'{}'
);
final
WebDevFS
webDevFS
=
WebDevFS
(
// if this is any other value, we will do a real ip lookup
hostname:
'any'
,
port:
0
,
packagesFilePath:
'.packages'
,
urlTunneller:
null
,
useSseForDebugProxy:
true
,
useSseForDebugBackend:
true
,
useSseForInjectedClient:
true
,
nullAssertions:
true
,
nativeNullAssertions:
true
,
buildInfo:
const
BuildInfo
(
BuildMode
.
debug
,
''
,
treeShakeIcons:
false
,
),
enableDwds:
true
,
enableDds:
false
,
entrypoint:
Uri
.
base
,
testMode:
true
,
expressionCompiler:
null
,
chromiumLauncher:
null
,
nullSafetyMode:
NullSafetyMode
.
sound
,
);
webDevFS
.
requireJS
.
createSync
(
recursive:
true
);
webDevFS
.
stackTraceMapper
.
createSync
(
recursive:
true
);
final
FakeAppConnection
firstConnection
=
FakeAppConnection
();
final
FakeAppConnection
secondConnection
=
FakeAppConnection
();
final
Future
<
void
>
done
=
webDevFS
.
create
().
then
<
void
>((
Uri
_
)
{
// In non-test mode, webDevFS.create() would have initialized DWDS
webDevFS
.
webAssetServer
.
dwds
=
FakeDwds
(<
AppConnection
>[
firstConnection
,
secondConnection
]);
int
vmServiceFactoryInvocationCount
=
0
;
Future
<
vm_service
.
VmService
>
vmServiceFactory
(
Uri
uri
,
{
CompressionOptions
compression
,
@required
Logger
logger
})
{
if
(
vmServiceFactoryInvocationCount
>
0
)
{
fail
(
'Called vmServiceFactory twice!'
);
}
vmServiceFactoryInvocationCount
+=
1
;
return
Future
<
vm_service
.
VmService
>.
delayed
(
const
Duration
(
seconds:
2
),
()
=>
FakeVmService
(),
);
}
return
webDevFS
.
connect
(
false
,
vmServiceFactory:
vmServiceFactory
).
then
<
void
>((
ConnectionResult
firstConnectionResult
)
{
return
webDevFS
.
destroy
();
});
});
time
.
elapse
(
const
Duration
(
seconds:
1
));
time
.
elapse
(
const
Duration
(
seconds:
2
));
return
done
;
});
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
Artifacts
.
test
(),
}));
test
(
'Can start web server with hostname any'
,
()
=>
testbed
.
run
(()
async
{
final
File
outputFile
=
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
'lib'
,
'main.dart'
))
..
createSync
(
recursive:
true
);
...
...
@@ -1140,3 +1209,32 @@ class FakeShaderCompiler implements DevelopmentShaderCompiler {
throw
UnimplementedError
();
}
}
class
FakeDwds
extends
Fake
implements
Dwds
{
FakeDwds
(
this
.
connectedAppsIterable
)
:
connectedApps
=
Stream
<
AppConnection
>.
fromIterable
(
connectedAppsIterable
);
final
Iterable
<
AppConnection
>
connectedAppsIterable
;
@override
final
Stream
<
AppConnection
>
connectedApps
;
@override
Future
<
DebugConnection
>
debugConnection
(
AppConnection
appConnection
)
=>
Future
<
DebugConnection
>.
value
(
FakeDebugConnection
());
}
class
FakeAppConnection
extends
Fake
implements
AppConnection
{
@override
void
runMain
()
{}
}
class
FakeDebugConnection
extends
Fake
implements
DebugConnection
{
FakeDebugConnection
({
this
.
uri
=
'http://foo'
,
});
@override
final
String
uri
;
}
class
FakeVmService
extends
Fake
implements
vm_service
.
VmService
{}
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