TF-3337 Write unit test to verify number of times call request when performing mark as read/star and move emails

This commit is contained in:
dab246
2024-12-23 19:17:30 +07:00
committed by Dat H. Pham
parent 9026cfc9fa
commit 47963d162b
2 changed files with 790 additions and 0 deletions
@@ -0,0 +1,689 @@
import 'dart:math';
import 'package:core/data/network/dio_client.dart';
import 'package:core/data/network/download/download_manager.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:jmap_dart_client/http/http_client.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/mark_star_action.dart';
import 'package:model/email/read_actions.dart';
import 'package:model/extensions/account_id_extensions.dart';
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
import 'package:tmail_ui_user/features/email/domain/model/move_action.dart';
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
import 'package:uuid/uuid.dart';
import '../../../../fixtures/account_fixtures.dart';
import '../../../../fixtures/session_fixtures.dart';
import 'email_api_test.mocks.dart';
@GenerateNiceMocks([
MockSpec<HttpClient>(),
MockSpec<DownloadManager>(),
MockSpec<DioClient>(),
MockSpec<Uuid>(),
])
void main() {
group('EmailAPI::test', () {
late HttpClient httpClient;
late DownloadManager downloadManager;
late DioClient dioClient;
late Uuid uuid;
late EmailAPI emailApi;
setUp(() {
httpClient = MockHttpClient();
downloadManager = MockDownloadManager();
dioClient = MockDioClient();
uuid = MockUuid();
emailApi = EmailAPI(
httpClient,
downloadManager,
dioClient,
uuid,
);
});
group('markAsRead::test', () {
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet equal defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 50;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
],
[
"Email/get",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"state": "b965db40-c11c-11ef-9cfb-ef2eae0e64b1",
"list": List.generate(maxBatches, (index) => {
"id": "email_$index",
"keywords": {
"\$seen": true
}
}),
"notFound": []
},
"c1"
]
]
});
final emails = List.generate(
totalEmails,
(index) => Email(id: EmailId(Id('email_$index'))),
);
// Act
final result = await emailApi.markAsRead(
aliceSession,
AccountFixtures.aliceAccountId,
emails,
ReadActions.markAsRead,
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet is greater than defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 200;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
],
[
"Email/get",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"state": "b965db40-c11c-11ef-9cfb-ef2eae0e64b1",
"list": List.generate(maxBatches, (index) => {
"id": "email_$index",
"keywords": {
"\$seen": true
}
}),
"notFound": []
},
"c1"
]
]
});
final emails = List.generate(
totalEmails,
(index) => Email(id: EmailId(Id('email_$index'))),
);
// Act
final result = await emailApi.markAsRead(
aliceSession,
AccountFixtures.aliceAccountId,
emails,
ReadActions.markAsRead,
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet is less than defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 20;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
],
[
"Email/get",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"state": "b965db40-c11c-11ef-9cfb-ef2eae0e64b1",
"list": List.generate(maxBatches, (index) => {
"id": "email_$index",
"keywords": {
"\$seen": true
}
}),
"notFound": []
},
"c1"
]
]
});
final emails = List.generate(
totalEmails,
(index) => Email(id: EmailId(Id('email_$index'))),
);
// Act
final result = await emailApi.markAsRead(
aliceSession,
AccountFixtures.aliceAccountId,
emails,
ReadActions.markAsRead,
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
});
group('markAsStar::test', () {
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet equal defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 50;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
],
[
"Email/get",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"state": "b965db40-c11c-11ef-9cfb-ef2eae0e64b1",
"list": List.generate(maxBatches, (index) => {
"id": "email_$index",
"keywords": {
"\$flagged": true
}
}),
"notFound": []
},
"c1"
]
]
});
final emails = List.generate(
totalEmails,
(index) => Email(id: EmailId(Id('email_$index'))),
);
// Act
final result = await emailApi.markAsStar(
aliceSession,
AccountFixtures.aliceAccountId,
emails,
MarkStarAction.markStar,
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet is greater than defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 200;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
],
[
"Email/get",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"state": "b965db40-c11c-11ef-9cfb-ef2eae0e64b1",
"list": List.generate(maxBatches, (index) => {
"id": "email_$index",
"keywords": {
"\$flagged": true
}
}),
"notFound": []
},
"c1"
]
]
});
final emails = List.generate(
totalEmails,
(index) => Email(id: EmailId(Id('email_$index'))),
);
// Act
final result = await emailApi.markAsStar(
aliceSession,
AccountFixtures.aliceAccountId,
emails,
MarkStarAction.markStar,
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet is less than defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 20;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
],
[
"Email/get",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"state": "b965db40-c11c-11ef-9cfb-ef2eae0e64b1",
"list": List.generate(maxBatches, (index) => {
"id": "email_$index",
"keywords": {
"\$flagged": true
}
}),
"notFound": []
},
"c1"
]
]
});
final emails = List.generate(
totalEmails,
(index) => Email(id: EmailId(Id('email_$index'))),
);
// Act
final result = await emailApi.markAsStar(
aliceSession,
AccountFixtures.aliceAccountId,
emails,
MarkStarAction.markStar,
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
});
group('moveToMailbox::test', () {
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet equal defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 50;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
]
]
});
final emailIds = List.generate(
totalEmails,
(index) => EmailId(Id('email_$index')),
);
// Act
final result = await emailApi.moveToMailbox(
aliceSession,
AccountFixtures.aliceAccountId,
MoveToMailboxRequest(
{
MailboxId(Id('mailboxA')): emailIds,
},
MailboxId(Id('mailboxB')),
MoveAction.moving,
EmailActionType.moveToMailbox,
),
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet is greater than defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 200;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
]
]
});
final emailIds = List.generate(
totalEmails,
(index) => EmailId(Id('email_$index')),
);
// Act
final result = await emailApi.moveToMailbox(
aliceSession,
AccountFixtures.aliceAccountId,
MoveToMailboxRequest(
{
MailboxId(Id('mailboxA')): emailIds,
},
MailboxId(Id('mailboxB')),
MoveAction.moving,
EmailActionType.moveToMailbox,
),
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
test(
'SHOULD calls execute the correct number of times\n'
'WHEN maxObjectsInSet is less than defaultMaxObjectsInSet\n'
'AND defaultMaxObjectsInSet is 50',
() async {
// Arrange
const defaultMaxObjectsInSet = 50;
const maxObjectsInSet = 20;
const totalEmails = 100;
final maxBatches = min(maxObjectsInSet, defaultMaxObjectsInSet);
final countIterations = (totalEmails / maxBatches).ceil();
final aliceSession = SessionFixtures.getAliceSessionWithMaxObjectsInSet(maxObjectsInSet);
when(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).thenAnswer((_) async => {
"sessionState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
"methodResponses": [
[
"Email/set",
{
"accountId": AccountFixtures.aliceAccountId.asString,
"oldState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"newState": "4cb1e760-c11b-11ef-9cfb-ef2eae0e64b1",
"updated": {
for (var item in List.generate(maxBatches, (index) => {"email_$index": null}))
item.keys.first: item.values.first
}
},
"c0"
]
]
});
final emailIds = List.generate(
totalEmails,
(index) => EmailId(Id('email_$index')),
);
// Act
final result = await emailApi.moveToMailbox(
aliceSession,
AccountFixtures.aliceAccountId,
MoveToMailboxRequest(
{
MailboxId(Id('mailboxA')): emailIds,
},
MailboxId(Id('mailboxB')),
MoveAction.moving,
EmailActionType.moveToMailbox,
),
);
// Assert
verify(httpClient.post(
'',
data: anyNamed('data'),
cancelToken: anyNamed('cancelToken'),
)).called(countIterations);
expect(result.length, totalEmails);
});
});
});
}
+101
View File
@@ -101,4 +101,105 @@ class SessionFixtures {
Uri.parse('http://domain.com/eventSource?types={types}&closeAfter={closeafter}&ping={ping}'),
State('2c9f1b12-b35a-43e6-9af2-0106fb53a943')
);
static getAliceSessionWithMaxObjectsInSet(int maxObjectsInSet) => Session(
{
CapabilityIdentifier.jmapSubmission: SubmissionCapability(
maxDelayedSend: UnsignedInt(0), submissionExtensions: {}),
CapabilityIdentifier.jmapCore: CoreCapability(
maxSizeUpload: UnsignedInt(20971520),
maxConcurrentUpload: UnsignedInt(4),
maxSizeRequest: UnsignedInt(10000000),
maxConcurrentRequests: UnsignedInt(4),
maxCallsInRequest: UnsignedInt(16),
maxObjectsInGet: UnsignedInt(500),
maxObjectsInSet: UnsignedInt(maxObjectsInSet),
collationAlgorithms: {CollationIdentifier("i;unicode-casemap")}),
CapabilityIdentifier.jmapMail: MailCapability(
maxMailboxesPerEmail: UnsignedInt(10000000),
maxSizeAttachmentsPerEmail: UnsignedInt(20000000),
emailQuerySortOptions: {
"receivedAt",
"sentAt",
"size",
"from",
"to",
"subject"
},
mayCreateTopLevelMailbox: true),
CapabilityIdentifier.jmapWebSocket: WebSocketCapability(
supportsPush: true, url: Uri.parse('ws://domain.com/jmap/ws')),
CapabilityIdentifier(
Uri.parse('urn:apache:james:params:jmap:mail:quota')):
DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier(
Uri.parse('urn:apache:james:params:jmap:mail:shares')):
DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier.jmapVacationResponse: VacationCapability(),
CapabilityIdentifier.jmapMdn: MdnCapability(),
},
{
AccountFixtures.aliceAccountId:
Account(AccountName('alice@domain.tld'), true, false, {
CapabilityIdentifier.jmapSubmission: SubmissionCapability(
maxDelayedSend: UnsignedInt(0), submissionExtensions: {}),
CapabilityIdentifier.jmapWebSocket: WebSocketCapability(
supportsPush: true, url: Uri.parse('ws://domain.com/jmap/ws')),
CapabilityIdentifier.jmapCore: CoreCapability(
maxSizeUpload: UnsignedInt(20971520),
maxConcurrentUpload: UnsignedInt(4),
maxSizeRequest: UnsignedInt(10000000),
maxConcurrentRequests: UnsignedInt(4),
maxCallsInRequest: UnsignedInt(16),
maxObjectsInGet: UnsignedInt(500),
maxObjectsInSet: UnsignedInt(maxObjectsInSet),
collationAlgorithms: {
CollationIdentifier("i;unicode-casemap")
}),
CapabilityIdentifier.jmapMail: MailCapability(
maxMailboxesPerEmail: UnsignedInt(10000000),
maxSizeAttachmentsPerEmail: UnsignedInt(20000000),
emailQuerySortOptions: {
"receivedAt",
"sentAt",
"size",
"from",
"to",
"subject"
},
mayCreateTopLevelMailbox: true),
CapabilityIdentifier(
Uri.parse('urn:apache:james:params:jmap:mail:quota')):
DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier(
Uri.parse('urn:apache:james:params:jmap:mail:shares')):
DefaultCapability(<String, dynamic>{}),
CapabilityIdentifier.jmapVacationResponse: VacationCapability(),
CapabilityIdentifier.jmapMdn: MdnCapability()
})
},
{
CapabilityIdentifier.jmapSubmission: AccountFixtures.aliceAccountId,
CapabilityIdentifier.jmapWebSocket: AccountFixtures.aliceAccountId,
CapabilityIdentifier.jmapCore: AccountFixtures.aliceAccountId,
CapabilityIdentifier.jmapMail: AccountFixtures.aliceAccountId,
CapabilityIdentifier(
Uri.parse('urn:apache:james:params:jmap:mail:quota')):
AccountFixtures.aliceAccountId,
CapabilityIdentifier(
Uri.parse('urn:apache:james:params:jmap:mail:shares')):
AccountFixtures.aliceAccountId,
CapabilityIdentifier.jmapVacationResponse:
AccountFixtures.aliceAccountId,
CapabilityIdentifier.jmapMdn: AccountFixtures.aliceAccountId,
},
UserName('alice@domain.tld'),
Uri.parse('http://domain.com/jmap'),
Uri.parse(
'http://domain.com/download/{accountId}/{blobId}/?type={type}&name={name}'),
Uri.parse('http://domain.com/upload/{accountId}'),
Uri.parse(
'http://domain.com/eventSource?types={types}&closeAfter={closeafter}&ping={ping}'),
State('2c9f1b12-b35a-43e6-9af2-0106fb53a943'),
);
}