fix(core): Fix components' stanza matching

This commit is contained in:
PapaTutuWawa committed 2023-04-05 13:17:18 +02:00
1 parent 5c47c35a46
commit 916be1c927
51 files changed
+324 -82

No files matched your search

+9
View File
@@ -24,6 +24,15 @@ To run the example, make sure that Flutter is correctly set up and working. If y
the development shell provided by the NixOS Flake, ensure that `ANDROID_HOME` and the development shell provided by the NixOS Flake, ensure that `ANDROID_HOME` and
`ANDROID_AVD_HOME` are pointing to the correct directories. `ANDROID_AVD_HOME` are pointing to the correct directories.
## Examples
This repository contains 2 types of examples:
- `example_flutter`: An example of using moxxmpp using Flutter
- `examples_dart`: A collection of pure Dart examples for showing different aspects of moxxmpp
For more information, see the respective README files.
## License ## License
See `./LICENSE`. See `./LICENSE`.
-6
View File
@@ -1,6 +0,0 @@
# melos_managed_dependency_overrides: moxxmpp,moxxmpp_socket_tcp
dependency_overrides:
moxxmpp:
path: ../packages/moxxmpp
moxxmpp_socket_tcp:
path: ../packages/moxxmpp_socket_tcp
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+6
View File
@@ -0,0 +1,6 @@
# Files and directories created by pub.
.dart_tool/
.packages
# Conventional directory for build output.
build/
+7
View File
@@ -0,0 +1,7 @@
# Dart Examples
Run using `dart run bin/<example>.dart`.
## Examples
- `component.dart`: Use moxxmpp to implement a component using XEP-0114.
+30
View File
@@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
+90
View File
@@ -0,0 +1,90 @@
import 'package:logging/logging.dart';
import 'package:moxxmpp/moxxmpp.dart';
import 'package:moxxmpp_socket_tcp/moxxmpp_socket_tcp.dart';
class TestingTCPSocketWrapper extends TCPSocketWrapper {
@override
bool onBadCertificate(dynamic certificate, String domain) {
return true;
}
}
class EchoMessageManager extends XmppManagerBase {
EchoMessageManager() : super('org.moxxy.example.message');
@override
Future<bool> isSupported() async => true;
@override
List<StanzaHandler> getIncomingStanzaHandlers() => [
StanzaHandler(
stanzaTag: 'message',
callback: _onMessage,
priority: -100,
xmlns: null,
)
];
Future<StanzaHandlerData> _onMessage(
Stanza stanza,
StanzaHandlerData state,
) async {
final body = stanza.firstTag('body');
if (body == null) return state.copyWith(done: true);
final bodyText = body.innerText();
await getAttributes().sendStanza(
Stanza.message(
to: stanza.from,
children: [
XMLNode(
tag: 'body',
text: 'Hello, ${stanza.from}! You said "$bodyText"',
),
],
),
awaitable: false,
);
return state.copyWith(done: true);
}
}
void main(List<String> arguments) async {
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((record) {
// ignore: avoid_print
print(
'[${record.level.name}] (${record.loggerName}) ${record.time}: ${record.message}',
);
});
final conn = XmppConnection(
TestingReconnectionPolicy(),
AlwaysConnectedConnectivityManager(),
ComponentToServerNegotiator(),
TestingTCPSocketWrapper(),
)..connectionSettings = ConnectionSettings(
jid: JID.fromString('component.localhost'),
password: 'abc123',
host: '127.0.0.1',
port: 8888,
);
await conn.registerManagers([
EchoMessageManager(),
]);
final result = await conn.connect(
waitUntilLogin: true,
shouldReconnect: false,
enableReconnectOnSuccess: false,
);
if (result.isType<XmppError>()) {
print('Failed to connect as component');
return;
}
// Just block for some time to test the connection
await Future<void>.delayed(const Duration(seconds: 9999));
}
+24
View File
@@ -0,0 +1,24 @@
name: example_dart
description: A sample command-line application.
version: 1.0.0
# homepage: https://www.example.com
environment:
sdk: '>=2.18.0 <3.0.0'
dependencies:
logging: ^1.0.2
moxxmpp:
hosted: https://git.polynom.me/api/packages/Moxxy/pub
version: 0.3.0
moxxmpp_socket_tcp:
hosted: https://git.polynom.me/api/packages/Moxxy/pub
version: 0.3.0
dependency_overrides:
moxxmpp:
path: ../packages/moxxmpp
dev_dependencies:
lints: ^2.0.0
test: ^1.16.0
+4
View File
@@ -446,6 +446,9 @@ class XmppConnection {
break; break;
} }
} }
stanza_ = stanza_.copyWith(
xmlns: _negotiationsHandler.getStanzaNamespace(),
);
_log.fine('Running pre stanza handlers..'); _log.fine('Running pre stanza handlers..');
final data = await _runOutgoingPreStanzaHandlers( final data = await _runOutgoingPreStanzaHandlers(
@@ -731,6 +734,7 @@ class XmppConnection {
), ),
); );
if (!incomingHandlers.done) { if (!incomingHandlers.done) {
_log.warning('Returning error for unhandled stanza');
await handleUnhandledStanza(this, incomingPreHandlers); await handleUnhandledStanza(this, incomingPreHandlers);
} }
} }
@@ -81,6 +81,9 @@ abstract class NegotiationsHandler {
log = Logger(toString()); log = Logger(toString());
} }
/// Returns the xmlns attribute that stanzas should have.
String getStanzaNamespace();
/// Registers the negotiator [negotiator] against this negotiations handler. /// Registers the negotiator [negotiator] against this negotiations handler.
void registerNegotiator(XmppFeatureNegotiatorBase negotiator); void registerNegotiator(XmppFeatureNegotiatorBase negotiator);
@@ -35,6 +35,9 @@ class ClientToServerNegotiator extends NegotiationsHandler {
/// The currently active negotiator. /// The currently active negotiator.
XmppFeatureNegotiatorBase? _currentNegotiator; XmppFeatureNegotiatorBase? _currentNegotiator;
@override
String getStanzaNamespace() => stanzaXmlns;
@override @override
void registerNegotiator(XmppFeatureNegotiatorBase negotiator) { void registerNegotiator(XmppFeatureNegotiatorBase negotiator) {
negotiators[negotiator.id] = negotiator; negotiators[negotiator.id] = negotiator;
@@ -41,6 +41,9 @@ class ComponentToServerNegotiator extends NegotiationsHandler {
/// The state the negotiation handler is currently in /// The state the negotiation handler is currently in
ComponentToServerState _state = ComponentToServerState.idle; ComponentToServerState _state = ComponentToServerState.idle;
@override
String getStanzaNamespace() => componentAcceptXmlns;
@override @override
void registerNegotiator(XmppFeatureNegotiatorBase negotiator) {} void registerNegotiator(XmppFeatureNegotiatorBase negotiator) {}
+69 -49
View File
@@ -4,88 +4,108 @@ import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart'; import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/stringxml.dart'; import 'package:moxxmpp/src/stringxml.dart';
/// A Handler is responsible for matching any kind of toplevel item in the XML stream
/// (stanzas and Nonzas). For that, its [matches] method is called. What happens
/// next depends on the subclass.
// ignore: one_member_abstracts
abstract class Handler { abstract class Handler {
const Handler(this.matchStanzas, {this.nonzaTag, this.nonzaXmlns});
final String? nonzaTag;
final String? nonzaXmlns;
final bool matchStanzas;
/// Returns true if the node matches the description provided by this [Handler]. /// Returns true if the node matches the description provided by this [Handler].
bool matches(XMLNode node);
}
/// A Handler that specialises in matching Nonzas (and stanzas).
class NonzaHandler extends Handler {
NonzaHandler({
required this.callback,
this.nonzaTag,
this.nonzaXmlns,
});
/// The function to call when a nonza matches the description.
final Future<bool> Function(XMLNode) callback;
/// The expected tag of a matching nonza.
final String? nonzaTag;
// The expected xmlns attribute of a matching nonza.
final String? nonzaXmlns;
@override
bool matches(XMLNode node) { bool matches(XMLNode node) {
var matches = false; var matches = true;
if (nonzaTag == null && nonzaXmlns == null) { if (nonzaTag == null && nonzaXmlns == null) {
matches = true; return true;
} } else {
if (nonzaXmlns != null) {
if (nonzaXmlns != null && nonzaTag != null) { matches &= node.attributes['xmlns'] == nonzaXmlns;
matches = (node.attributes['xmlns'] ?? '') == nonzaXmlns! && }
node.tag == nonzaTag!; if (nonzaTag != null) {
} matches &= node.tag == nonzaTag;
}
if (matchStanzas && nonzaTag == null) {
matches = ['iq', 'presence', 'message'].contains(node.tag);
} }
return matches; return matches;
} }
} }
class NonzaHandler extends Handler { /// A Handler that only matches stanzas.
NonzaHandler({
required this.callback,
String? nonzaTag,
String? nonzaXmlns,
}) : super(
false,
nonzaTag: nonzaTag,
nonzaXmlns: nonzaXmlns,
);
final Future<bool> Function(XMLNode) callback;
}
class StanzaHandler extends Handler { class StanzaHandler extends Handler {
StanzaHandler({ StanzaHandler({
required this.callback, required this.callback,
this.tagXmlns, this.tagXmlns,
this.tagName, this.tagName,
this.priority = 0, this.priority = 0,
String? stanzaTag, this.stanzaTag,
}) : super( this.xmlns = stanzaXmlns,
true, });
nonzaTag: stanzaTag,
nonzaXmlns: stanzaXmlns, /// If specified, then the stanza must contain a direct child with a tag equal to
); /// [tagName].
final String? tagName; final String? tagName;
/// If specified, then the stanza must contain a direct child with a xmlns attribute
/// equal to [tagXmlns]. If [tagName] is also non-null, then the element must also
/// have a tag equal to [tagName].
final String? tagXmlns; final String? tagXmlns;
/// If specified, the matching stanza must have a tag equal to [stanzaTag].
final String? stanzaTag;
/// If specified, then the stanza must have a xmlns attribute equal to [xmlns].
/// This defaults to [stanzaXmlns], but can be set to any other value or null. This
/// is useful, for example, for components.
final String? xmlns;
/// The priority after which [StanzaHandler]s are sorted.
final int priority; final int priority;
/// The function to call when a stanza matches the description.
final Future<StanzaHandlerData> Function(Stanza, StanzaHandlerData) callback; final Future<StanzaHandlerData> Function(Stanza, StanzaHandlerData) callback;
@override @override
bool matches(XMLNode node) { bool matches(XMLNode node) {
var matches = super.matches(node); var matches = ['iq', 'message', 'presence'].contains(node.tag);
if (stanzaTag != null) {
if (matches == false) { matches &= node.tag == stanzaTag;
return false; }
if (xmlns != null) {
matches &= node.xmlns == xmlns;
} }
if (tagName != null) { if (tagName != null) {
final firstTag = node.firstTag(tagName!, xmlns: tagXmlns); final firstTag = node.firstTag(tagName!, xmlns: tagXmlns);
matches &= firstTag != null;
matches = firstTag != null; if (tagXmlns != null) {
matches &= firstTag?.xmlns == tagXmlns;
}
} else if (tagXmlns != null) { } else if (tagXmlns != null) {
return listContains( matches &= listContains(
node.children, node.children,
(XMLNode node_) => (XMLNode node_) => node_.attributes['xmlns'] == tagXmlns,
node_.attributes.containsKey('xmlns') &&
node_.attributes['xmlns'] == tagXmlns,
); );
} }
if (tagName == null && tagXmlns == null) {
matches = true;
}
return matches; return matches;
} }
} }
+3 -1
View File
@@ -107,11 +107,13 @@ class PresenceManager extends XmppManagerBase {
} }
final attrs = getAttributes(); final attrs = getAttributes();
attrs.sendNonza( await attrs.sendStanza(
Stanza.presence( Stanza.presence(
from: attrs.getFullJID().toString(), from: attrs.getFullJID().toString(),
children: children, children: children,
), ),
awaitable: false,
addId: false,
); );
} }
+16 -4
View File
@@ -33,6 +33,7 @@ class Stanza extends XMLNode {
List<XMLNode> children = const [], List<XMLNode> children = const [],
required String tag, required String tag,
Map<String, String> attributes = const {}, Map<String, String> attributes = const {},
String? xmlns,
}) : super( }) : super(
tag: tag, tag: tag,
attributes: <String, dynamic>{ attributes: <String, dynamic>{
@@ -45,7 +46,7 @@ class Stanza extends XMLNode {
...from != null ...from != null
? <String, dynamic>{'from': from} ? <String, dynamic>{'from': from}
: <String, dynamic>{}, : <String, dynamic>{},
'xmlns': stanzaXmlns if (xmlns != null) 'xmlns': xmlns,
}, },
children: children, children: children,
); );
@@ -57,6 +58,7 @@ class Stanza extends XMLNode {
String? id, String? id,
List<XMLNode> children = const [], List<XMLNode> children = const [],
Map<String, String>? attributes = const {}, Map<String, String>? attributes = const {},
String? xmlns,
}) { }) {
return Stanza( return Stanza(
tag: 'iq', tag: 'iq',
@@ -64,8 +66,9 @@ class Stanza extends XMLNode {
to: to, to: to,
id: id, id: id,
type: type, type: type,
attributes: <String, String>{...attributes!, 'xmlns': stanzaXmlns}, attributes: <String, String>{...attributes!},
children: children, children: children,
xmlns: xmlns,
); );
} }
@@ -76,6 +79,7 @@ class Stanza extends XMLNode {
String? id, String? id,
List<XMLNode> children = const [], List<XMLNode> children = const [],
Map<String, String>? attributes = const {}, Map<String, String>? attributes = const {},
String? xmlns,
}) { }) {
return Stanza( return Stanza(
tag: 'presence', tag: 'presence',
@@ -83,8 +87,9 @@ class Stanza extends XMLNode {
to: to, to: to,
id: id, id: id,
type: type, type: type,
attributes: <String, String>{...attributes!, 'xmlns': stanzaXmlns}, attributes: <String, String>{...attributes!},
children: children, children: children,
xmlns: xmlns,
); );
} }
factory Stanza.message({ factory Stanza.message({
@@ -94,6 +99,7 @@ class Stanza extends XMLNode {
String? id, String? id,
List<XMLNode> children = const [], List<XMLNode> children = const [],
Map<String, String>? attributes = const {}, Map<String, String>? attributes = const {},
String? xmlns,
}) { }) {
return Stanza( return Stanza(
tag: 'message', tag: 'message',
@@ -101,8 +107,9 @@ class Stanza extends XMLNode {
to: to, to: to,
id: id, id: id,
type: type, type: type,
attributes: <String, String>{...attributes!, 'xmlns': stanzaXmlns}, attributes: <String, String>{...attributes!},
children: children, children: children,
xmlns: xmlns,
); );
} }
@@ -134,6 +141,7 @@ class Stanza extends XMLNode {
String? to, String? to,
String? type, String? type,
List<XMLNode>? children, List<XMLNode>? children,
String? xmlns,
}) { }) {
return Stanza( return Stanza(
tag: tag, tag: tag,
@@ -142,6 +150,10 @@ class Stanza extends XMLNode {
id: id ?? this.id, id: id ?? this.id,
type: type ?? this.type, type: type ?? this.type,
children: children ?? this.children, children: children ?? this.children,
attributes: {
...attributes.cast<String, String>(),
},
xmlns: xmlns ?? this.xmlns,
); );
} }
} }
+45 -15
View File
@@ -3,9 +3,11 @@ import 'package:test/test.dart';
final stanza1 = Stanza.iq( final stanza1 = Stanza.iq(
children: [XMLNode.xmlns(tag: 'tag', xmlns: 'owo')], children: [XMLNode.xmlns(tag: 'tag', xmlns: 'owo')],
xmlns: stanzaXmlns,
); );
final stanza2 = Stanza.message( final stanza2 = Stanza.message(
children: [XMLNode.xmlns(tag: 'some-other-tag', xmlns: 'owo')], children: [XMLNode.xmlns(tag: 'some-other-tag', xmlns: 'owo')],
xmlns: stanzaXmlns,
); );
void main() { void main() {
@@ -19,11 +21,17 @@ void main() {
), ),
); );
expect(handler.matches(Stanza.iq()), true); expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), true);
expect(handler.matches(Stanza.message()), true); expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), true);
expect(handler.matches(Stanza.presence()), true); expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), true);
expect(handler.matches(stanza1), true); expect(handler.matches(stanza1), true);
expect(handler.matches(stanza2), true); expect(handler.matches(stanza2), true);
expect(
handler.matches(
XMLNode.xmlns(tag: 'active', xmlns: csiXmlns),
),
false,
);
}); });
test('xmlns matching', () { test('xmlns matching', () {
final handler = StanzaHandler( final handler = StanzaHandler(
@@ -36,12 +44,13 @@ void main() {
tagXmlns: 'owo', tagXmlns: 'owo',
); );
expect(handler.matches(Stanza.iq()), false); expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.message()), false); expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.presence()), false); expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), false);
expect(handler.matches(stanza1), true); expect(handler.matches(stanza1), true);
expect(handler.matches(stanza2), true); expect(handler.matches(stanza2), true);
}); });
test('stanzaTag matching', () { test('stanzaTag matching', () {
var run = false; var run = false;
final handler = StanzaHandler( final handler = StanzaHandler(
@@ -57,9 +66,9 @@ void main() {
stanzaTag: 'iq', stanzaTag: 'iq',
); );
expect(handler.matches(Stanza.iq()), true); expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), true);
expect(handler.matches(Stanza.message()), false); expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.presence()), false); expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), false);
expect(handler.matches(stanza1), true); expect(handler.matches(stanza1), true);
expect(handler.matches(stanza2), false); expect(handler.matches(stanza2), false);
@@ -74,6 +83,7 @@ void main() {
); );
expect(run, true); expect(run, true);
}); });
test('tagName matching', () { test('tagName matching', () {
final handler = StanzaHandler( final handler = StanzaHandler(
callback: (stanza, _) async => StanzaHandlerData( callback: (stanza, _) async => StanzaHandlerData(
@@ -85,12 +95,13 @@ void main() {
tagName: 'tag', tagName: 'tag',
); );
expect(handler.matches(Stanza.iq()), false); expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.message()), false); expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.presence()), false); expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), false);
expect(handler.matches(stanza1), true); expect(handler.matches(stanza1), true);
expect(handler.matches(stanza2), false); expect(handler.matches(stanza2), false);
}); });
test('combined matching', () { test('combined matching', () {
final handler = StanzaHandler( final handler = StanzaHandler(
callback: (stanza, _) async => StanzaHandlerData( callback: (stanza, _) async => StanzaHandlerData(
@@ -104,13 +115,32 @@ void main() {
tagXmlns: 'owo', tagXmlns: 'owo',
); );
expect(handler.matches(Stanza.iq()), false); expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.message()), false); expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.presence()), false); expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), false);
expect(handler.matches(stanza1), true); expect(handler.matches(stanza1), true);
expect(handler.matches(stanza2), false); expect(handler.matches(stanza2), false);
}); });
test('Test matching stanzas with a different xmlns', () {
final handler = StanzaHandler(
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
null,
stanza,
),
xmlns: componentAcceptXmlns,
);
expect(handler.matches(Stanza.iq(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.message(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.presence(xmlns: stanzaXmlns)), false);
expect(handler.matches(Stanza.iq(xmlns: componentAcceptXmlns)), true);
expect(handler.matches(stanza1), false);
expect(handler.matches(stanza2), false);
});
test('sorting', () { test('sorting', () {
final handlerList = [ final handlerList = [
StanzaHandler( StanzaHandler(
@@ -56,7 +56,7 @@ void main() {
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>', '<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
ignoreId: true, ignoreId: true,
), ),
StringExpectation( StanzaExpectation(
"<presence xmlns='jabber:client' from='polynomdivision@test.server/MU29eEZn'><show>chat</show><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://moxxmpp.example' ver='3QvQ2RAy45XBDhArjxy/vEWMl+E=' /></presence>", "<presence xmlns='jabber:client' from='polynomdivision@test.server/MU29eEZn'><show>chat</show><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://moxxmpp.example' ver='3QvQ2RAy45XBDhArjxy/vEWMl+E=' /></presence>",
'', '',
), ),
+11 -6
View File
@@ -1,3 +1,4 @@
import 'dart:async';
import 'package:moxxmpp/moxxmpp.dart'; import 'package:moxxmpp/moxxmpp.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import '../helpers/logging.dart'; import '../helpers/logging.dart';
@@ -88,6 +89,7 @@ void main() {
final stanza = Stanza( final stanza = Stanza(
to: 'some.user@server.example', to: 'some.user@server.example',
tag: 'message', tag: 'message',
xmlns: stanzaXmlns,
); );
test('Test stream with SM enablement', () async { test('Test stream with SM enablement', () async {
@@ -388,10 +390,14 @@ void main() {
"<enable xmlns='urn:xmpp:sm:3' resume='true' />", "<enable xmlns='urn:xmpp:sm:3' resume='true' />",
'<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />', '<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />',
), ),
StringExpectation( StanzaExpectation(
"<presence xmlns='jabber:client' from='polynomdivision@test.server/MU29eEZn'><show>chat</show></presence>", "<presence xmlns='jabber:client' from='polynomdivision@test.server/MU29eEZn'><show>chat</show></presence>",
'<iq type="result" />', '<iq type="result" />',
), ),
StringExpectation(
"<r xmlns='urn:xmpp:sm:3' />",
"<a xmlns='urn:xmpp:sm:3' h='1' />",
),
StanzaExpectation( StanzaExpectation(
"<iq to='user@example.com' type='get' id='a' xmlns='jabber:client' />", "<iq to='user@example.com' type='get' id='a' xmlns='jabber:client' />",
"<iq from='user@example.com' type='result' id='a' />", "<iq from='user@example.com' type='result' id='a' />",
@@ -425,7 +431,8 @@ void main() {
waitUntilLogin: true, waitUntilLogin: true,
); );
expect(fakeSocket.getState(), 6); await Future<void>.delayed(const Duration(seconds: 3));
expect(fakeSocket.getState(), 7);
expect(await conn.getConnectionState(), XmppConnectionState.connected); expect(await conn.getConnectionState(), XmppConnectionState.connected);
expect( expect(
conn conn
@@ -502,9 +509,6 @@ void main() {
password: 'aaaa', password: 'aaaa',
); );
await conn.registerManagers([ await conn.registerManagers([
PresenceManager(),
RosterManager(TestingRosterStateManager('', [])),
DiscoManager([]),
StreamManagementManager(), StreamManagementManager(),
]); ]);
await conn.registerFeatureNegotiators([ await conn.registerFeatureNegotiators([
@@ -523,7 +527,8 @@ void main() {
await conn.connect( await conn.connect(
waitUntilLogin: true, waitUntilLogin: true,
); );
expect(fakeSocket.getState(), 7);
expect(fakeSocket.getState(), 6);
expect(await conn.getConnectionState(), XmppConnectionState.connected); expect(await conn.getConnectionState(), XmppConnectionState.connected);
expect( expect(
conn conn