mirror of https://github.com/AMT-Cheif/drift.git
Add wasm integration test using the database
This commit is contained in:
parent
3f178a154f
commit
e801dceae6
|
@ -1,11 +1,13 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:build_daemon/client.dart';
|
||||
import 'package:build_daemon/constants.dart';
|
||||
import 'package:build_daemon/data/build_status.dart';
|
||||
import 'package:build_daemon/data/build_target.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:shelf/shelf_io.dart';
|
||||
import 'package:shelf_proxy/shelf_proxy.dart';
|
||||
|
@ -27,8 +29,13 @@ class TestAssetServer {
|
|||
}
|
||||
|
||||
static Future<TestAssetServer> start() async {
|
||||
final script = Platform.script.toFilePath(windows: Platform.isWindows);
|
||||
final packageDir = p.dirname(p.dirname(script));
|
||||
final packageConfig =
|
||||
await loadPackageConfigUri((await Isolate.packageConfig)!);
|
||||
final ownPackage = packageConfig['web_wasm']!.root;
|
||||
var packageDir = ownPackage.toFilePath(windows: Platform.isWindows);
|
||||
if (packageDir.endsWith('/')) {
|
||||
packageDir = packageDir.substring(0, packageDir.length - 1);
|
||||
}
|
||||
|
||||
final buildRunner = await BuildDaemonClient.connect(
|
||||
packageDir,
|
||||
|
@ -92,8 +99,8 @@ class DriftWebDriver {
|
|||
Set<WasmStorageImplementation> storages,
|
||||
Set<MissingBrowserFeature> missingFeatures,
|
||||
})> probeImplementations() async {
|
||||
final rawResult =
|
||||
await driver.executeAsync('detectImplementations(arguments[0])', []);
|
||||
final rawResult = await driver
|
||||
.executeAsync('detectImplementations("", arguments[0])', []);
|
||||
final result = json.decode(rawResult);
|
||||
|
||||
return (
|
||||
|
@ -107,4 +114,9 @@ class DriftWebDriver {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> openDatabase([WasmStorageImplementation? implementation]) async {
|
||||
await driver.executeAsync(
|
||||
'open(arguments[0], arguments[1])', [implementation?.name]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import 'package:drift/drift.dart';
|
||||
|
||||
part 'database.g.dart';
|
||||
|
||||
class TestTable extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get content => text()();
|
||||
}
|
||||
|
||||
@DriftDatabase(tables: [TestTable])
|
||||
class TestDatabase extends _$TestDatabase {
|
||||
TestDatabase(super.e);
|
||||
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'database.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
class $TestTableTable extends TestTable
|
||||
with TableInfo<$TestTableTable, TestTableData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$TestTableTable(this.attachedDatabase, [this._alias]);
|
||||
static const VerificationMeta _idMeta = const VerificationMeta('id');
|
||||
@override
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
static const VerificationMeta _contentMeta =
|
||||
const VerificationMeta('content');
|
||||
@override
|
||||
late final GeneratedColumn<String> content = GeneratedColumn<String>(
|
||||
'content', aliasedName, false,
|
||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, content];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'test_table';
|
||||
@override
|
||||
String get actualTableName => 'test_table';
|
||||
@override
|
||||
VerificationContext validateIntegrity(Insertable<TestTableData> instance,
|
||||
{bool isInserting = false}) {
|
||||
final context = VerificationContext();
|
||||
final data = instance.toColumns(true);
|
||||
if (data.containsKey('id')) {
|
||||
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
||||
}
|
||||
if (data.containsKey('content')) {
|
||||
context.handle(_contentMeta,
|
||||
content.isAcceptableOrUnknown(data['content']!, _contentMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_contentMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
TestTableData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return TestTableData(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.int, data['${effectivePrefix}id'])!,
|
||||
content: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}content'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$TestTableTable createAlias(String alias) {
|
||||
return $TestTableTable(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class TestTableData extends DataClass implements Insertable<TestTableData> {
|
||||
final int id;
|
||||
final String content;
|
||||
const TestTableData({required this.id, required this.content});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['id'] = Variable<int>(id);
|
||||
map['content'] = Variable<String>(content);
|
||||
return map;
|
||||
}
|
||||
|
||||
TestTableCompanion toCompanion(bool nullToAbsent) {
|
||||
return TestTableCompanion(
|
||||
id: Value(id),
|
||||
content: Value(content),
|
||||
);
|
||||
}
|
||||
|
||||
factory TestTableData.fromJson(Map<String, dynamic> json,
|
||||
{ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return TestTableData(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
content: serializer.fromJson<String>(json['content']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'content': serializer.toJson<String>(content),
|
||||
};
|
||||
}
|
||||
|
||||
TestTableData copyWith({int? id, String? content}) => TestTableData(
|
||||
id: id ?? this.id,
|
||||
content: content ?? this.content,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('TestTableData(')
|
||||
..write('id: $id, ')
|
||||
..write('content: $content')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, content);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is TestTableData &&
|
||||
other.id == this.id &&
|
||||
other.content == this.content);
|
||||
}
|
||||
|
||||
class TestTableCompanion extends UpdateCompanion<TestTableData> {
|
||||
final Value<int> id;
|
||||
final Value<String> content;
|
||||
const TestTableCompanion({
|
||||
this.id = const Value.absent(),
|
||||
this.content = const Value.absent(),
|
||||
});
|
||||
TestTableCompanion.insert({
|
||||
this.id = const Value.absent(),
|
||||
required String content,
|
||||
}) : content = Value(content);
|
||||
static Insertable<TestTableData> custom({
|
||||
Expression<int>? id,
|
||||
Expression<String>? content,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (content != null) 'content': content,
|
||||
});
|
||||
}
|
||||
|
||||
TestTableCompanion copyWith({Value<int>? id, Value<String>? content}) {
|
||||
return TestTableCompanion(
|
||||
id: id ?? this.id,
|
||||
content: content ?? this.content,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = Variable<int>(id.value);
|
||||
}
|
||||
if (content.present) {
|
||||
map['content'] = Variable<String>(content.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('TestTableCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('content: $content')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$TestDatabase extends GeneratedDatabase {
|
||||
_$TestDatabase(QueryExecutor e) : super(e);
|
||||
late final $TestTableTable testTable = $TestTableTable(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [testTable];
|
||||
}
|
|
@ -14,6 +14,7 @@ dependencies:
|
|||
shelf_proxy: ^1.0.4
|
||||
path: ^1.8.3
|
||||
js: ^0.6.7
|
||||
package_config: ^2.1.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.5
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
// ignore: implementation_imports
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:drift/src/web/wasm_setup/types.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:web_wasm/driver.dart';
|
||||
import 'package:webdriver/async_io.dart';
|
||||
|
||||
enum Browser {
|
||||
chrome(
|
||||
driverUriString: 'http://localhost:4444/wd/hub/',
|
||||
isChromium: true,
|
||||
unsupportedImplementations: {WasmStorageImplementation.opfsShared},
|
||||
missingFeatures: {MissingBrowserFeature.dedicatedWorkersInSharedWorkers},
|
||||
),
|
||||
firefox(driverUriString: 'http://localhost:4444/');
|
||||
|
||||
final bool isChromium;
|
||||
final String driverUriString;
|
||||
final Set<WasmStorageImplementation> unsupportedImplementations;
|
||||
final Set<MissingBrowserFeature> missingFeatures;
|
||||
|
||||
const Browser({
|
||||
required this.driverUriString,
|
||||
this.isChromium = false,
|
||||
this.unsupportedImplementations = const {},
|
||||
this.missingFeatures = const {},
|
||||
});
|
||||
|
||||
Uri get driverUri => Uri.parse(driverUriString);
|
||||
|
||||
Set<WasmStorageImplementation> get availableImplementations {
|
||||
return WasmStorageImplementation.values.toSet()
|
||||
..removeAll(unsupportedImplementations);
|
||||
}
|
||||
|
||||
Future<Process> spawnDriver() async {
|
||||
return switch (this) {
|
||||
firefox => Process.start('geckodriver', []),
|
||||
chrome =>
|
||||
Process.start('chromedriver', ['--port=4444', '--url-base=/wd/hub']),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
late TestAssetServer server;
|
||||
|
||||
setUpAll(() async {
|
||||
server = await TestAssetServer.start();
|
||||
});
|
||||
tearDownAll(() => server.close());
|
||||
|
||||
for (final browser in Browser.values) {
|
||||
group(browser.name, () {
|
||||
late Process driverProcess;
|
||||
late DriftWebDriver driver;
|
||||
|
||||
setUpAll(() async => driverProcess = await browser.spawnDriver());
|
||||
tearDownAll(() => driverProcess.kill());
|
||||
|
||||
setUp(() async {
|
||||
final rawDriver = await createDriver(
|
||||
spec: browser.isChromium ? WebDriverSpec.JsonWire : WebDriverSpec.W3c,
|
||||
uri: browser.driverUri,
|
||||
);
|
||||
|
||||
driver = DriftWebDriver(server, rawDriver);
|
||||
|
||||
await driver.driver.get('http://localhost:8080/');
|
||||
});
|
||||
|
||||
tearDown(() => driver.driver.quit());
|
||||
|
||||
test('compatibility check', () async {
|
||||
final result = await driver.probeImplementations();
|
||||
|
||||
final expectedImplementations = WasmStorageImplementation.values.toSet()
|
||||
..removeAll(browser.unsupportedImplementations);
|
||||
|
||||
expect(result.missingFeatures, browser.missingFeatures);
|
||||
expect(result.storages, expectedImplementations);
|
||||
});
|
||||
|
||||
group('supports', () {
|
||||
for (final entry in browser.availableImplementations) {
|
||||
test(entry.name, () async {
|
||||
await driver.openDatabase();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
// ignore: implementation_imports
|
||||
import 'package:drift/src/web/wasm_setup/types.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:web_wasm/driver.dart';
|
||||
import 'package:webdriver/async_io.dart';
|
||||
|
||||
enum Browser {
|
||||
chrome(
|
||||
isChromium: true,
|
||||
unsupportedImplementations: {WasmStorageImplementation.opfsShared},
|
||||
missingFeatures: {MissingBrowserFeature.dedicatedWorkersInSharedWorkers},
|
||||
),
|
||||
firefox();
|
||||
|
||||
final bool isChromium;
|
||||
final Set<WasmStorageImplementation> unsupportedImplementations;
|
||||
final Set<MissingBrowserFeature> missingFeatures;
|
||||
|
||||
const Browser({
|
||||
this.isChromium = false,
|
||||
this.unsupportedImplementations = const {},
|
||||
this.missingFeatures = const {},
|
||||
});
|
||||
}
|
||||
|
||||
void main(List<String> args) {
|
||||
final browser = Browser.values.byName(args[0]);
|
||||
final webDriverUri = Uri.parse(args[1]);
|
||||
|
||||
late TestAssetServer server;
|
||||
late DriftWebDriver driver;
|
||||
|
||||
setUpAll(() async {
|
||||
server = await TestAssetServer.start();
|
||||
});
|
||||
tearDownAll(() => server.close());
|
||||
|
||||
setUp(() async {
|
||||
final rawDriver = await createDriver(
|
||||
spec: browser.isChromium ? WebDriverSpec.JsonWire : WebDriverSpec.W3c,
|
||||
uri: webDriverUri,
|
||||
);
|
||||
|
||||
driver = DriftWebDriver(server, rawDriver);
|
||||
|
||||
await driver.driver.get('http://localhost:8080/');
|
||||
});
|
||||
|
||||
tearDown(() => driver.driver.quit());
|
||||
|
||||
group('compatibility check', () {
|
||||
test('can enumerate', () async {
|
||||
final result = await driver.probeImplementations();
|
||||
|
||||
final expectedImplementations = WasmStorageImplementation.values.toSet()
|
||||
..removeAll(browser.unsupportedImplementations);
|
||||
|
||||
expect(result.missingFeatures, browser.missingFeatures);
|
||||
expect(result.storages, expectedImplementations);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -5,27 +5,31 @@ import 'dart:js_util';
|
|||
import 'package:drift/wasm.dart';
|
||||
// ignore: invalid_use_of_internal_member
|
||||
import 'package:drift/src/web/wasm_setup.dart';
|
||||
import 'package:web_wasm/src/database.dart';
|
||||
|
||||
const dbName = 'drift_test';
|
||||
TestDatabase? openedDatabase;
|
||||
|
||||
void main() {
|
||||
_addCallbackForWebDriver('detectImplementations', _detectImplementations);
|
||||
_addCallbackForWebDriver('open', _open);
|
||||
|
||||
document.getElementById('selfcheck')?.onClick.listen((event) async {
|
||||
print('starting');
|
||||
final database = await openDatabase();
|
||||
final database = await _opener.open();
|
||||
|
||||
print('selected storage: ${database.chosenImplementation}');
|
||||
print('missing features: ${database.missingFeatures}');
|
||||
});
|
||||
}
|
||||
|
||||
void _addCallbackForWebDriver(String name, Future Function() impl) {
|
||||
setProperty(globalThis, name, allowInterop((Function callback) async {
|
||||
void _addCallbackForWebDriver(String name, Future Function(String?) impl) {
|
||||
setProperty(globalThis, name,
|
||||
allowInterop((String? arg, Function callback) async {
|
||||
Object? result;
|
||||
|
||||
try {
|
||||
result = await impl();
|
||||
result = await impl(arg);
|
||||
} catch (e, s) {
|
||||
final console = getProperty(globalThis, 'console');
|
||||
callMethod(console, 'error', [e, s]);
|
||||
|
@ -35,16 +39,6 @@ void _addCallbackForWebDriver(String name, Future Function() impl) {
|
|||
}));
|
||||
}
|
||||
|
||||
Future<String> _detectImplementations() async {
|
||||
final opener = _opener;
|
||||
await opener.probe();
|
||||
|
||||
return json.encode({
|
||||
'impls': opener.availableImplementations.map((r) => r.name).toList(),
|
||||
'missing': opener.missingFeatures.map((r) => r.name).toList(),
|
||||
});
|
||||
}
|
||||
|
||||
WasmDatabaseOpener get _opener {
|
||||
return WasmDatabaseOpener(
|
||||
databaseName: dbName,
|
||||
|
@ -53,6 +47,32 @@ WasmDatabaseOpener get _opener {
|
|||
);
|
||||
}
|
||||
|
||||
Future<WasmDatabaseResult> openDatabase() async {
|
||||
return await _opener.open();
|
||||
Future<String> _detectImplementations(String? _) async {
|
||||
final opener = _opener;
|
||||
await opener.probe();
|
||||
|
||||
return json.encode({
|
||||
'impls': opener.availableImplementations.map((r) => r.name).toList(),
|
||||
'missing': opener.missingFeatures.map((r) => r.name).toList(),
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> _open(String? implementationName) async {
|
||||
final opener = _opener;
|
||||
WasmDatabaseResult result;
|
||||
|
||||
if (implementationName != null) {
|
||||
await opener.probe();
|
||||
result = await opener
|
||||
.openWith(WasmStorageImplementation.values.byName(implementationName));
|
||||
} else {
|
||||
result = await opener.open();
|
||||
}
|
||||
|
||||
final db = openedDatabase = TestDatabase(result.resolvedExecutor);
|
||||
|
||||
// Make sure it works!
|
||||
await db.customSelect('SELECT 1').get();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue