Skip to content

Commit 279cd4c

Browse files
committed
Fix web tests
1 parent 70617c0 commit 279cd4c

File tree

9 files changed

+196
-161
lines changed

9 files changed

+196
-161
lines changed

sqlite3/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ In this directory, run:
147147

148148
```
149149
cmake -S assets/wasm -B .dart_tool/sqlite3_build --toolchain toolchain.cmake
150-
make -C .dart_tool/sqlite3_build/ -j output
150+
cmake --build .dart_tool/sqlite3_build/ -t output -j
151151
```
152152

153153
(Of course, you can also run the build in any other directory).

sqlite3/dart_test.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,24 @@ override_platforms:
1212
firefox:
1313
settings:
1414
arguments: "-headless"
15+
chrome:
16+
settings:
17+
arguments: "--enable-features=SharedArrayBuffer"
18+
edge:
19+
settings:
20+
arguments: "--enable-features=SharedArrayBuffer"
1521

1622
presets:
1723
full:
1824
platforms: [vm, chrome, firefox]
25+
on_os:
26+
windows:
27+
platforms: [vm, chrome, firefox, edge]
1928
web:
2029
platforms: [chrome, firefox]
30+
on_os:
31+
windows:
32+
platforms: [chrome, firefox, edge]
2133
ci:
2234
tags:
2335
ci_only:

sqlite3/lib/src/wasm/vfs/async_opfs/client.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ class WasmVfs extends BaseVirtualFileSystem {
8080
_runInWorker(WorkerOperation.xSleep, Flags(duration.inMilliseconds, 0, 0));
8181
}
8282

83+
void close() {
84+
_runInWorker(WorkerOperation.stopServer, const EmptyMessage());
85+
}
86+
8387
static bool get supportsAtomicsAndSharedMemory {
8488
return Atomics.supported && hasProperty(globalThis, 'SharedArrayBuffer');
8589
}

sqlite3/lib/src/wasm/vfs/async_opfs/sync_channel.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ enum WorkerOperation<Req extends Message, Res extends Message> {
181181
MessageSerializer.readFlags,
182182
MessageSerializer.readEmpty,
183183
),
184+
stopServer<EmptyMessage, EmptyMessage>(
185+
MessageSerializer.readEmpty,
186+
MessageSerializer.readEmpty,
187+
),
184188
;
185189

186190
final Req Function(MessageSerializer) readRequest;

sqlite3/lib/src/wasm/vfs/async_opfs/worker.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class VfsWorker {
6565
final FileSystemDirectoryHandle root;
6666

6767
var _fdCounter = 0;
68+
var _stopped = false;
69+
6870
final Map<int, _OpenedFileHandle> _openFiles = {};
6971
final Set<_OpenedFileHandle> _implicitlyHeldLocks = {};
7072

@@ -277,7 +279,7 @@ class VfsWorker {
277279
}
278280

279281
Future<void> start() async {
280-
while (true) {
282+
while (!_stopped) {
281283
final waitResult = synchronizer.waitForRequest();
282284
if (waitResult == Atomics.timedOut) {
283285
// No requests for some time, transition to idle
@@ -335,6 +337,11 @@ class VfsWorker {
335337
case WorkerOperation.xUnlock:
336338
response = await _xUnlock(request as Flags);
337339
break;
340+
case WorkerOperation.stopServer:
341+
response = const EmptyMessage();
342+
_stopped = true;
343+
_releaseImplicitLocks();
344+
break;
338345
}
339346

340347
messages.write(response);

sqlite3/lib/src/wasm/wasm_interop.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ class _InjectedValues {
487487
'dart': {
488488
// See assets/wasm/bridge.h
489489
'error_log': allowInterop((Pointer ptr) {
490-
print('Error reported by native handler: ${memory.readString(ptr)}');
490+
print('[sqlite3] ${memory.readString(ptr)}');
491491
}),
492492
'xOpen': allowInterop((int vfsId, Pointer zName, Pointer dartFdPtr,
493493
int flags, Pointer pOutFlags) {
Lines changed: 48 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@Tags(['wasm'])
22
import 'dart:async';
3+
import 'dart:developer';
34
import 'dart:math';
45
import 'dart:typed_data';
56

@@ -12,55 +13,15 @@ const _fsRoot = '/test';
1213

1314
Future<void> main() async {
1415
group('in memory', () {
15-
_testWith(() => FileSystem.inMemory());
16+
_testWith(() => InMemoryFileSystem());
1617
});
1718

1819
group('indexed db', () {
1920
_testWith(() => IndexedDbFileSystem.open(dbName: _randomName()));
2021

21-
test('with proper persistence', () async {
22-
final data = Uint8List.fromList(List.generate(255, (i) => i));
23-
final dbName = _randomName();
24-
25-
await expectLater(IndexedDbFileSystem.databases(),
26-
completion(anyOf(isNull, isNot(contains(dbName)))),
27-
reason: 'Database $dbName should not exist');
28-
29-
final db1 = await IndexedDbFileSystem.open(dbName: dbName);
30-
expect(db1.files.length, 0, reason: 'db1 is not empty');
31-
32-
db1.createFile('test');
33-
db1.write('test', data, 0);
34-
db1.truncateFile('test', 128);
35-
await db1.flush();
36-
expect(db1.files, ['test'], reason: 'File must exist');
37-
await db1.close();
38-
39-
final db2 = await IndexedDbFileSystem.open(dbName: dbName);
40-
expect(db2.files, ['test'], reason: 'Single file must be in db2 as well');
41-
42-
final read = Uint8List(128);
43-
expect(db2.read('test', read, 0), 128, reason: 'Should read 128 bytes');
44-
expect(read, List.generate(128, (i) => i),
45-
reason: 'The data written and read do not match');
46-
47-
await db2.clear();
48-
expect(db2.files, isEmpty, reason: 'There must be no files in db2');
49-
50-
await db2.close();
51-
await expectLater(
52-
Future.sync(db2.clear), throwsA(isA<FileSystemException>()));
53-
54-
await IndexedDbFileSystem.deleteDatabase(dbName);
55-
await expectLater(IndexedDbFileSystem.databases(),
56-
completion(anyOf(isNull, isNot(contains(dbName)))),
57-
reason: 'Database $dbName should not exist in the end');
58-
});
59-
6022
test('example with frequent writes', () async {
6123
final fileSystem = await IndexedDbFileSystem.open(dbName: 'test');
62-
final sqlite3 =
63-
await loadSqlite3(SqliteEnvironment(fileSystem: fileSystem));
24+
final sqlite3 = await loadSqlite3(fileSystem);
6425
final database = sqlite3.open('test');
6526
expect(database.userVersion, 0);
6627
database.userVersion = 1;
@@ -95,53 +56,26 @@ Future<void> main() async {
9556
await fileSystem.close().timeout(const Duration(seconds: 1));
9657

9758
final fileSystem2 = await IndexedDbFileSystem.open(dbName: 'test');
98-
final sqlite32 =
99-
await loadSqlite3(SqliteEnvironment(fileSystem: fileSystem2));
59+
final sqlite32 = await loadSqlite3(fileSystem2);
10060
final database2 = sqlite32.open('test');
10161
expect(database2.userVersion, 1);
10262
expect(database2.select('SELECT * FROM users'), hasLength(200));
10363
});
104-
105-
test('can delete and re-create files', () async {
106-
final dbName = _randomName();
107-
final fs = await IndexedDbFileSystem.open(dbName: dbName);
108-
addTearDown(() async {
109-
await fs.close();
110-
return IndexedDbFileSystem.deleteDatabase(dbName);
111-
});
112-
113-
fs.createFile('foo');
114-
fs.write('foo', Uint8List.fromList([1, 2, 3]), 0);
115-
await fs.flush();
116-
117-
fs.deleteFile('foo');
118-
await fs.flush();
119-
120-
fs.createFile('foo');
121-
fs.write('foo', Uint8List.fromList([4, 5, 6]), 0);
122-
await fs.flush();
123-
124-
final target = Uint8List(3);
125-
fs.read('foo', target, 0);
126-
expect(target, [4, 5, 6]);
127-
});
12864
});
12965
}
13066

13167
final _random = Random(DateTime.now().millisecond);
13268
String _randomName() => _random.nextInt(0x7fffffff).toString();
13369

134-
Future<void> _disposeFileSystem(FileSystem fs, [String? name]) async {
70+
Future<void> _disposeFileSystem(VirtualFileSystem fs, [String? name]) async {
13571
if (fs is IndexedDbFileSystem) {
13672
await fs.close();
13773
if (name != null) await IndexedDbFileSystem.deleteDatabase(name);
138-
} else {
139-
await Future.sync(fs.clear);
14074
}
14175
}
14276

143-
Future<void> _testWith(FutureOr<FileSystem> Function() open) async {
144-
late FileSystem fs;
77+
Future<void> _testWith(FutureOr<VirtualFileSystem> Function() open) async {
78+
late VirtualFileSystem fs;
14579

14680
setUp(() async {
14781
fs = await open();
@@ -151,55 +85,68 @@ Future<void> _testWith(FutureOr<FileSystem> Function() open) async {
15185

15286
test('can create files', () {
15387
expect(fs.exists('$_fsRoot/foo.txt'), isFalse);
154-
expect(fs.files, isEmpty);
15588
fs.createFile('$_fsRoot/foo.txt');
15689
expect(fs.exists('$_fsRoot/foo.txt'), isTrue);
157-
expect(fs.files, ['$_fsRoot/foo.txt']);
158-
fs.deleteFile('$_fsRoot/foo.txt');
159-
expect(fs.files, isEmpty);
90+
fs.xDelete('$_fsRoot/foo.txt', 0);
91+
expect(fs.exists('$_fsRoot/foo.txt'), isFalse);
16092
});
16193

16294
test('can create and delete multiple files', () {
95+
final paths = <String>[];
96+
16397
for (var i = 1; i <= 10; i++) {
164-
fs.createFile('$_fsRoot/foo$i.txt');
98+
final path = '$_fsRoot/foo$i.txt';
99+
paths.add(path);
100+
101+
debugger();
102+
fs.createFile(path);
103+
expect(fs.exists(path), isTrue);
165104
}
166-
expect(fs.files, hasLength(10));
167-
for (final f in fs.files) {
168-
fs.deleteFile(f);
105+
106+
for (final path in paths) {
107+
fs.xDelete(path, 0);
108+
expect(fs.exists(path), isFalse);
169109
}
170-
expect(fs.files, isEmpty);
171110
});
172111

173112
test('reads and writes', () {
174113
expect(fs.exists('$_fsRoot/foo.txt'), isFalse);
114+
115+
final file = fs
116+
.xOpen(Sqlite3Filename('$_fsRoot/foo.txt'), SqlFlag.SQLITE_OPEN_CREATE)
117+
.file;
118+
175119
fs.createFile('$_fsRoot/foo.txt');
176-
addTearDown(() => fs.deleteFile('$_fsRoot/foo.txt'));
120+
addTearDown(() {
121+
file.xClose();
122+
fs.xDelete('$_fsRoot/foo.txt', 0);
123+
});
177124

178-
expect(fs.sizeOfFile('$_fsRoot/foo.txt'), isZero);
125+
expect(file.xFileSize(), isZero);
179126

180-
fs.truncateFile('$_fsRoot/foo.txt', 1024);
181-
expect(fs.sizeOfFile('$_fsRoot/foo.txt'), 1024);
127+
file.xTruncate(1024);
128+
expect(file.xFileSize(), 1024);
182129

183-
fs.truncateFile('$_fsRoot/foo.txt', 600);
184-
expect(fs.sizeOfFile('$_fsRoot/foo.txt'), 600);
130+
file.xTruncate(600);
131+
expect(file.xFileSize(), 600);
185132

186-
fs.truncateFile('$_fsRoot/foo.txt', 0);
187-
expect(fs.sizeOfFile('$_fsRoot/foo.txt'), 0);
133+
file.xTruncate(0);
134+
expect(file.xFileSize(), 0);
188135

189-
fs.write('$_fsRoot/foo.txt', Uint8List.fromList([1, 2, 3]), 0);
190-
expect(fs.sizeOfFile('$_fsRoot/foo.txt'), 3);
136+
file.xWrite(Uint8List.fromList([1, 2, 3]), 0);
137+
expect(file.xFileSize(), 3);
191138

192139
final target = Uint8List(3);
193-
expect(fs.read('$_fsRoot/foo.txt', target, 0), 3);
140+
file.xRead(target, 0);
194141
expect(target, [1, 2, 3]);
195142
});
143+
}
196144

197-
test('can create files and clear fs', () async {
198-
for (var i = 1; i <= 10; i++) {
199-
fs.createFile('$_fsRoot/foo$i.txt');
200-
}
201-
expect(fs.files, hasLength(10));
202-
await Future.sync(fs.clear);
203-
expect(fs.files, isEmpty);
204-
});
145+
extension on VirtualFileSystem {
146+
bool exists(String file) => xAccess(file, 0) != 0;
147+
148+
void createFile(String path) {
149+
final open = xOpen(Sqlite3Filename(path), SqlFlag.SQLITE_OPEN_CREATE);
150+
open.file.xClose();
151+
}
205152
}

sqlite3/test/wasm/sqlite3_test.dart

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -77,27 +77,39 @@ void main() {
7777
});
7878

7979
// See worker.dart for the supported backends
80-
for (final backend in ['memory', 'opfs-simple', 'indexeddb']) {
81-
test(backend, () async {
82-
final worker = Worker(workerUri);
83-
84-
worker.onError.listen((event) {
85-
if (event is ErrorEvent) {
86-
fail('Error ${event.message} - ${event.error}');
87-
} else {
88-
fail(event.toString());
80+
for (final backend in ['memory', 'opfs-simple', 'opfs', 'indexeddb']) {
81+
final requiresSab = backend == 'opfs';
82+
83+
test(
84+
backend,
85+
() async {
86+
final worker = Worker(workerUri);
87+
88+
worker.onError.listen((event) {
89+
if (event is ErrorEvent) {
90+
fail('Error ${event.message} - ${event.error}');
91+
} else {
92+
fail(event.toString());
93+
}
94+
});
95+
// Inform the worker about the test we want to run
96+
worker.postMessage([backend, wasmUri]);
97+
98+
final response = (await worker.onMessage.first).data as List;
99+
final status = response[0] as bool;
100+
101+
if (!status) {
102+
throw 'Exception in worker: $response';
89103
}
90-
});
91-
// Inform the worker about the test we want to run
92-
worker.postMessage([backend, wasmUri]);
93-
94-
final response = (await worker.onMessage.first).data as List;
95-
final status = response[0] as bool;
96-
97-
if (!status) {
98-
throw 'Exception in worker: $response';
99-
}
100-
});
104+
},
105+
onPlatform: <String, Object?>{
106+
if (requiresSab)
107+
'!chrome && !edge': Skip(
108+
'This test requires SharedArrayBuffers that cannot be enabled '
109+
'on this platform with a simple `dart test` setup.',
110+
),
111+
},
112+
);
101113
}
102114
},
103115
);

0 commit comments

Comments
 (0)