blob: 74266c1e13306280a7037d7d365a12e71ce97992 [file] [log] [blame] [edit]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. 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:developer';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
// AUTOGENERATED START
//
// Update these constants by running:
//
// dart pkg/vm_service/test/update_line_numbers.dart pkg/vm_service/test/id_zones_test.dart
//
const LINE_A = 34;
// AUTOGENERATED END
class D {}
@pragma('vm:entry-point')
D getDLiteral() => D();
class C {
final field = D();
}
void testeeMain() {
// ignore: unused_local_variable
final c = C();
debugger(); // LINE_A
}
final tests = <IsolateTest>[
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
// Test the behaviour of an ID Zone with a `backingBufferKind` of `Ring`, an
// `idAssignmentPolicy` of `AlwaysAllocate`, and the default capacity.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone1 = await service.createIdZone(
isolateId,
IdZoneBackingBufferKind.kRing,
IdAssignmentPolicy.kAlwaysAllocate,
);
expect(idZone1.id, 'zones/1');
expect(idZone1.backingBufferKind, IdZoneBackingBufferKind.kRing);
expect(idZone1.idAssignmentPolicy, IdAssignmentPolicy.kAlwaysAllocate);
final cInstanceRef1 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone1.id,
) as InstanceRef;
final cObjectId1 = cInstanceRef1.id!;
expect(cObjectId1, 'objects/0/1');
final cInstance1 = await service.getObject(isolateId, cObjectId1);
expect(cInstance1.type, 'Instance');
final cInstanceRef2 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone1.id,
) as InstanceRef;
final cObjectId2 = cInstanceRef2.id!;
expect(cObjectId2, 'objects/1/1');
final cInstance2 = await service.getObject(isolateId, cObjectId2);
expect(cInstance2.type, 'Instance');
await service.invalidateIdZone(
isolateId,
idZone1.id!,
);
try {
await service.getObject(isolateId, cObjectId1);
fail('successfully retrieved object using expired ID');
} on SentinelException catch (e) {
expect(e.sentinel.kind, startsWith('Expired'));
expect(e.sentinel.valueAsString, equals('<expired>'));
}
// Ensure that the zone can be reused after it was invalidated.
final cInstanceRef3 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone1.id,
) as InstanceRef;
expect(cInstanceRef3.id, 'objects/0/1');
},
// Test the behaviour of an ID Zone with a `backingBufferKind` of `Ring`, an
// `idAssignmentPolicy` of `AlwaysAllocate`, and a capacity of 1.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone2 = await service.createIdZone(
isolateId,
IdZoneBackingBufferKind.kRing,
IdAssignmentPolicy.kAlwaysAllocate,
capacity: 1,
);
expect(idZone2.id, 'zones/2');
expect(idZone2.backingBufferKind, IdZoneBackingBufferKind.kRing);
expect(idZone2.idAssignmentPolicy, IdAssignmentPolicy.kAlwaysAllocate);
final cInstanceRef1 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone2.id,
) as InstanceRef;
final cObjectId1 = cInstanceRef1.id!;
expect(cObjectId1, 'objects/0/2');
final cInstance1 = await service.getObject(isolateId, cObjectId1);
expect(cInstance1.type, 'Instance');
final cInstanceRef2 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone2.id,
) as InstanceRef;
final cObjectId2 = cInstanceRef2.id!;
expect(cObjectId2, 'objects/1/2');
final cInstance2 = await service.getObject(isolateId, cObjectId2);
expect(cInstance2.type, 'Instance');
// [idZone2] only has a capacity of 1, so [cObjectId1] should have been
// evicted when [cObjectId2] was allocated.
try {
await service.getObject(isolateId, cObjectId1);
fail('successfully retrieved object using expired ID');
} on SentinelException catch (e) {
expect(e.sentinel.kind, startsWith('Expired'));
expect(e.sentinel.valueAsString, equals('<expired>'));
}
},
// Test the behaviour of an ID Zone with a `backingBufferKind` of `Ring`, an
// `idAssignmentPolicy` of `ReuseExisting`, and the default capacity.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone3 = await service.createIdZone(
isolateId,
IdZoneBackingBufferKind.kRing,
IdAssignmentPolicy.kReuseExisting,
);
expect(idZone3.id, 'zones/3');
expect(idZone3.backingBufferKind, IdZoneBackingBufferKind.kRing);
expect(idZone3.idAssignmentPolicy, IdAssignmentPolicy.kReuseExisting);
final cInstanceRef1 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone3.id,
) as InstanceRef;
final cObjectId1 = cInstanceRef1.id!;
expect(cObjectId1, 'objects/0/3');
final cInstance1 = await service.getObject(isolateId, cObjectId1);
expect(cInstance1.type, 'Instance');
final cInstanceRef2 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone3.id,
) as InstanceRef;
final cObjectId2 = cInstanceRef2.id!;
expect(cObjectId2, 'objects/0/3');
final cInstance2 = await service.getObject(isolateId, cObjectId2);
expect(cInstance2.type, 'Instance');
await service.invalidateIdZone(
isolateId,
idZone3.id!,
);
try {
await service.getObject(isolateId, cObjectId1);
fail('successfully retrieved object using expired ID');
} on SentinelException catch (e) {
expect(e.sentinel.kind, startsWith('Expired'));
expect(e.sentinel.valueAsString, equals('<expired>'));
}
// Ensure that the zone can be reused after it was invalidated.
final cInstanceRef3 = await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone3.id,
) as InstanceRef;
expect(cInstanceRef3.id, 'objects/0/3');
},
// Test deleting an ID Zone.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone4 = await service.createIdZone(
isolateId,
IdZoneBackingBufferKind.kRing,
IdAssignmentPolicy.kAlwaysAllocate,
);
expect(idZone4.id, 'zones/4');
expect(idZone4.backingBufferKind, IdZoneBackingBufferKind.kRing);
expect(idZone4.idAssignmentPolicy, IdAssignmentPolicy.kAlwaysAllocate);
await service.deleteIdZone(
isolateId,
idZone4.id!,
);
try {
await service.evaluateInFrame(
isolateId,
0,
'c',
idZoneId: idZone4.id,
);
fail('successfully used an ID zone that should have been deleted');
} on RPCError catch (e) {
expect(e.code, RPCErrorKind.kInvalidParams.code);
}
},
// Test the `idZoneId` parameters of all RPCs that have them.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone5 = await service.createIdZone(
isolateId,
IdZoneBackingBufferKind.kRing,
IdAssignmentPolicy.kAlwaysAllocate,
capacity: 30,
);
expect(idZone5.id, 'zones/5');
expect(idZone5.backingBufferKind, IdZoneBackingBufferKind.kRing);
expect(idZone5.idAssignmentPolicy, IdAssignmentPolicy.kAlwaysAllocate);
// The `idZoneId` parameter of [VmService.evaluateInFrame] is already tested
// by the tests above.
// Test the `idZoneId` parameter of [VmService.evaluate].
final isolate = await service.getIsolate(isolateId);
final dLiteralInstanceRef = await service.evaluate(
isolateId,
isolate.rootLib!.id!,
'getDLiteral()',
idZoneId: idZone5.id,
) as InstanceRef;
final dLiteralObjectId = dLiteralInstanceRef.id!;
expect(dLiteralObjectId, 'objects/0/5');
final dLiteralInstance =
await service.getObject(isolateId, dLiteralObjectId);
expect(dLiteralInstance.type, 'Instance');
final dClassRef = dLiteralInstance.classRef!;
// Test the `idZoneId` parameter of [VmService.getInstances].
final dInstanceSet = await service.getInstances(
isolateId,
dClassRef.id!,
1,
idZoneId: idZone5.id,
);
expect(dInstanceSet.totalCount, 1);
expect(dInstanceSet.instances!.first.id, 'objects/1/5');
// Test the `idZoneId` parameters of [VmService.getInstancesAsList] and
// [VmService.getObject].
final listInstanceRef = await service.getInstancesAsList(
isolateId,
dClassRef.id!,
idZoneId: idZone5.id,
);
expect(listInstanceRef.length, 1);
final listId = listInstanceRef.id!;
expect(listId, 'objects/3/5');
final listInstance = await service.getObject(
isolateId,
listId,
idZoneId: idZone5.id,
) as Instance;
expect(listInstance.elements!.first.id, 'objects/6/5');
// Test the `idZoneId` parameter of [VmService.getInboundReferences].
final dWithinCInstanceRef = await service.evaluateInFrame(
isolateId,
0,
'c.field',
idZoneId: idZone5.id,
) as InstanceRef;
final dWithinCObjectId = dWithinCInstanceRef.id!;
final inboundReferences = await service.getInboundReferences(
isolateId,
dWithinCObjectId,
1,
idZoneId: idZone5.id,
);
expect(inboundReferences.references!.length, 1);
expect(inboundReferences.references![0].source!.id, 'objects/8/5');
// Test the `idZoneId` parameter of [VmService.getRetainingPath].
final retainingPath = await service.getRetainingPath(
isolateId,
dWithinCObjectId,
2,
idZoneId: idZone5.id,
);
expect(retainingPath.length, 2);
expect(retainingPath.elements!.first.value!.id, 'objects/9/5');
// Test the `idZoneId` parameter of [VmService.getStack].
final stack = await service.getStack(
isolateId,
limit: 1,
idZoneId: idZone5.id,
);
expect(stack.frames!.length, 1);
final boundVariables = stack.frames!.first.vars!;
expect(boundVariables.length, 1);
expect((boundVariables.first.value as InstanceRef).id, 'objects/11/5');
// Test the `idZoneId` parameter of [VmService.invoke].
final dLiteral2InstanceRef = await service.invoke(
isolateId,
isolate.rootLib!.id!,
'getDLiteral',
[],
idZoneId: idZone5.id,
) as InstanceRef;
expect(dLiteral2InstanceRef.id!, 'objects/12/5');
},
resumeIsolate,
];
Future<void> main([args = const <String>[]]) => runIsolateTests(
args,
tests,
'id_zones_test.dart',
testeeConcurrent: testeeMain,
);