diff options
author | Kevin Smith <git@kismith.co.uk> | 2012-03-03 11:56:45 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2012-03-04 16:01:01 (GMT) |
commit | 4b6694377e3a0308009bdf90be0a4e0de463b215 (patch) | |
tree | 86b860395d040c38774dfa4400979f9687dff8ae | |
parent | fde71bd59b1412ae475c06f2d4100ce088e86af6 (diff) | |
download | swift-4b6694377e3a0308009bdf90be0a4e0de463b215.zip swift-4b6694377e3a0308009bdf90be0a4e0de463b215.tar.bz2 |
Pass along errors about DNS resolution.
-rw-r--r-- | Swiften/Client/CoreClient.cpp | 15 | ||||
-rw-r--r-- | Swiften/Client/CoreClient.h | 2 | ||||
-rw-r--r-- | Swiften/Elements/DeliveryReceipt.h | 2 | ||||
-rw-r--r-- | Swiften/Network/ChainedConnector.cpp | 19 | ||||
-rw-r--r-- | Swiften/Network/ChainedConnector.h | 8 | ||||
-rw-r--r-- | Swiften/Network/Connector.cpp | 8 | ||||
-rw-r--r-- | Swiften/Network/Connector.h | 3 | ||||
-rw-r--r-- | Swiften/Network/UnitTest/ChainedConnectorTest.cpp | 29 | ||||
-rw-r--r-- | Swiften/Network/UnitTest/ConnectorTest.cpp | 34 |
9 files changed, 88 insertions, 32 deletions
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index e2a8e5a..f7e3b21 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -18,6 +18,7 @@ #include <Swiften/Network/ChainedConnector.h> #include <Swiften/Network/NetworkFactories.h> #include <Swiften/Network/ProxyProvider.h> +#include <Swiften/Network/DomainNameResolveError.h> #include <Swiften/TLS/PKCS12Certificate.h> #include <Swiften/Session/BasicSessionStream.h> #include <Swiften/Session/BOSHSessionStream.h> @@ -63,7 +64,7 @@ void CoreClient::connect(const std::string& host) { disconnectRequested_ = false; assert(!connector_); assert(proxyConnectionFactories.empty()); - if(networkFactories->getProxyProvider()->getSOCKS5Proxy().isValid()) { + if (networkFactories->getProxyProvider()->getSOCKS5Proxy().isValid()) { proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getConnectionFactory(), networkFactories->getProxyProvider()->getSOCKS5Proxy())); } if(networkFactories->getProxyProvider()->getHTTPConnectProxy().isValid()) { @@ -73,7 +74,7 @@ void CoreClient::connect(const std::string& host) { if (options.boshURL.empty()) { connectionFactories.push_back(networkFactories->getConnectionFactory()); connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); - connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); + connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1, _2)); connector_->setTimeoutMilliseconds(60*1000); connector_->start(); } @@ -129,13 +130,17 @@ void CoreClient::bindSessionToStream() { /** * Only called for TCP sessions. BOSH is handled inside the BOSHSessionStream. */ -void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection) { +void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> error) { resetConnector(); if (!connection) { if (options.forgetPassword) { purgePassword(); } - onDisconnected(disconnectRequested_ ? boost::optional<ClientError>() : boost::optional<ClientError>(ClientError::ConnectionError)); + boost::optional<ClientError> clientError; + if (!disconnectRequested_) { + clientError = boost::dynamic_pointer_cast<DomainNameResolveError>(error) ? boost::optional<ClientError>(ClientError::DomainNameResolveError) : boost::optional<ClientError>(ClientError::ConnectionError); + } + onDisconnected(clientError); } else { assert(!connection_); @@ -356,7 +361,7 @@ void CoreClient::purgePassword() { } void CoreClient::resetConnector() { - connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); + connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1, _2)); connector_.reset(); foreach(ConnectionFactory* f, proxyConnectionFactories) { delete f; diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index c9a6f30..cafc634 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -203,7 +203,7 @@ namespace Swift { virtual void handleConnected() {}; private: - void handleConnectorFinished(boost::shared_ptr<Connection>); + void handleConnectorFinished(boost::shared_ptr<Connection>, boost::shared_ptr<Error> error); void handleStanzaChannelAvailableChanged(bool available); void handleSessionFinished(boost::shared_ptr<Error>); void handleNeedCredentials(); diff --git a/Swiften/Elements/DeliveryReceipt.h b/Swiften/Elements/DeliveryReceipt.h index f42176f..bd634db 100644 --- a/Swiften/Elements/DeliveryReceipt.h +++ b/Swiften/Elements/DeliveryReceipt.h @@ -8,6 +8,8 @@ #include <string> +#include <string> + #include <Swiften/Elements/Payload.h> namespace Swift { diff --git a/Swiften/Network/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp index 1a38e53..0a1283f 100644 --- a/Swiften/Network/ChainedConnector.cpp +++ b/Swiften/Network/ChainedConnector.cpp @@ -41,18 +41,18 @@ void ChainedConnector::start() { void ChainedConnector::stop() { if (currentConnector) { - currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); currentConnector->stop(); currentConnector.reset(); } - finish(boost::shared_ptr<Connection>()); + finish(boost::shared_ptr<Connection>(), boost::shared_ptr<Error>()); } void ChainedConnector::tryNextConnectionFactory() { assert(!currentConnector); if (connectionFactoryQueue.empty()) { SWIFT_LOG(debug) << "No more connection factories" << std::endl; - finish(boost::shared_ptr<Connection>()); + finish(boost::shared_ptr<Connection>(), lastError); } else { ConnectionFactory* connectionFactory = connectionFactoryQueue.front(); @@ -60,23 +60,24 @@ void ChainedConnector::tryNextConnectionFactory() { connectionFactoryQueue.pop_front(); currentConnector = Connector::create(hostname, resolver, connectionFactory, timerFactory); currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); - currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); currentConnector->start(); } } -void ChainedConnector::handleConnectorFinished(boost::shared_ptr<Connection> connection) { +void ChainedConnector::handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> error) { SWIFT_LOG(debug) << "Connector finished" << std::endl; - currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1, _2)); + lastError = error; currentConnector.reset(); if (connection) { - finish(connection); + finish(connection, error); } else { tryNextConnectionFactory(); } } -void ChainedConnector::finish(boost::shared_ptr<Connection> connection) { - onConnectFinished(connection); +void ChainedConnector::finish(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> error) { + onConnectFinished(connection, error); } diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h index 15b17f3..12ef023 100644 --- a/Swiften/Network/ChainedConnector.h +++ b/Swiften/Network/ChainedConnector.h @@ -12,6 +12,7 @@ #include <boost/shared_ptr.hpp> #include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/Error.h> namespace Swift { class Connection; @@ -28,12 +29,12 @@ namespace Swift { void start(); void stop(); - boost::signal<void (boost::shared_ptr<Connection>)> onConnectFinished; + boost::signal<void (boost::shared_ptr<Connection>, boost::shared_ptr<Error>)> onConnectFinished; private: - void finish(boost::shared_ptr<Connection> connection); + void finish(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error>); void tryNextConnectionFactory(); - void handleConnectorFinished(boost::shared_ptr<Connection>); + void handleConnectorFinished(boost::shared_ptr<Connection>, boost::shared_ptr<Error>); private: std::string hostname; @@ -43,5 +44,6 @@ namespace Swift { int timeoutMilliseconds; std::deque<ConnectionFactory*> connectionFactoryQueue; boost::shared_ptr<Connector> currentConnector; + boost::shared_ptr<Error> lastError; }; }; diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 378875b..5e7f8d9 100644 --- a/Swiften/Network/Connector.cpp +++ b/Swiften/Network/Connector.cpp @@ -17,7 +17,7 @@ namespace Swift { -Connector::Connector(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, int defaultPort) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), defaultPort(defaultPort), timeoutMilliseconds(0), queriedAllServices(true) { +Connector::Connector(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory, int defaultPort) : hostname(hostname), resolver(resolver), connectionFactory(connectionFactory), timerFactory(timerFactory), defaultPort(defaultPort), timeoutMilliseconds(0), queriedAllServices(true), foundSomeDNS(false) { } void Connector::setTimeoutMilliseconds(int milliseconds) { @@ -56,6 +56,9 @@ void Connector::handleServiceQueryResult(const std::vector<DomainNameServiceQuer SWIFT_LOG(debug) << result.size() << " SRV result(s)" << std::endl; serviceQueryResults = std::deque<DomainNameServiceQuery::Result>(result.begin(), result.end()); serviceQuery.reset(); + if (!serviceQueryResults.empty()) { + foundSomeDNS = true; + } tryNextServiceOrFallback(); } @@ -86,6 +89,7 @@ void Connector::handleAddressQueryResult(const std::vector<HostAddress>& address tryNextServiceOrFallback(); } else { + foundSomeDNS = true; addressQueryResults = std::deque<HostAddress>(addresses.begin(), addresses.end()); tryNextAddress(); } @@ -160,7 +164,7 @@ void Connector::finish(boost::shared_ptr<Connection> connection) { currentConnection->onConnectFinished.disconnect(boost::bind(&Connector::handleConnectionConnectFinished, shared_from_this(), _1)); currentConnection.reset(); } - onConnectFinished(connection); + onConnectFinished(connection, (connection || foundSomeDNS) ? boost::shared_ptr<Error>() : boost::make_shared<DomainNameResolveError>()); } void Connector::handleTimeout() { diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index 8f2c359..bf0efaf 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -35,7 +35,7 @@ namespace Swift { void start(); void stop(); - boost::signal<void (boost::shared_ptr<Connection>)> onConnectFinished; + boost::signal<void (boost::shared_ptr<Connection>, boost::shared_ptr<Error>)> onConnectFinished; private: Connector(const std::string& hostname, DomainNameResolver*, ConnectionFactory*, TimerFactory*, int defaultPort); @@ -67,5 +67,6 @@ namespace Swift { std::deque<HostAddress> addressQueryResults; bool queriedAllServices; boost::shared_ptr<Connection> currentConnection; + bool foundSomeDNS; }; }; diff --git a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp index c7d23da..a2fceb9 100644 --- a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp @@ -17,6 +17,7 @@ #include <Swiften/Network/StaticDomainNameResolver.h> #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/DomainNameResolveError.h> using namespace Swift; @@ -25,11 +26,13 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST(testConnect_FirstConnectorSucceeds); CPPUNIT_TEST(testConnect_SecondConnectorSucceeds); CPPUNIT_TEST(testConnect_NoConnectorSucceeds); + CPPUNIT_TEST(testConnect_NoDNS); CPPUNIT_TEST(testStop); CPPUNIT_TEST_SUITE_END(); public: void setUp() { + error.reset(); host = HostAddressPort(HostAddress("1.1.1.1"), 1234); eventLoop = new DummyEventLoop(); resolver = new StaticDomainNameResolver(eventLoop); @@ -58,6 +61,7 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT_EQUAL(1, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_SecondConnectorSucceeds() { @@ -71,6 +75,7 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT_EQUAL(2, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoConnectorSucceeds() { @@ -83,6 +88,24 @@ class ChainedConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); + } + + void testConnect_NoDNS() { + /* Reset resolver so there's no record */ + delete resolver; + resolver = new StaticDomainNameResolver(eventLoop); + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = false; + connectionFactory2->connects = false; + + testling->start(); + //testling->stop(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testStop() { @@ -104,11 +127,12 @@ class ChainedConnectorTest : public CppUnit::TestFixture { factories.push_back(connectionFactory1); factories.push_back(connectionFactory2); boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", resolver, factories, timerFactory); - connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1)); + connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; } - void handleConnectorFinished(boost::shared_ptr<Connection> connection) { + void handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> resultError) { + error = resultError; boost::shared_ptr<MockConnection> c(boost::dynamic_pointer_cast<MockConnection>(connection)); if (connection) { assert(c); @@ -156,6 +180,7 @@ class ChainedConnectorTest : public CppUnit::TestFixture { MockConnectionFactory* connectionFactory2; DummyTimerFactory* timerFactory; std::vector< boost::shared_ptr<MockConnection> > connections; + boost::shared_ptr<Error> error; }; CPPUNIT_TEST_SUITE_REGISTRATION(ChainedConnectorTest); diff --git a/Swiften/Network/UnitTest/ConnectorTest.cpp b/Swiften/Network/UnitTest/ConnectorTest.cpp index 6488e67..67270be 100644 --- a/Swiften/Network/UnitTest/ConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ConnectorTest.cpp @@ -17,6 +17,7 @@ #include <Swiften/Network/StaticDomainNameResolver.h> #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/DomainNameAddressQuery.h> using namespace Swift; @@ -67,6 +68,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host1 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoSRVHost() { @@ -79,6 +81,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_FirstAddressHostFails() { @@ -97,6 +100,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(HostAddressPort(address2, 1234) == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoHosts() { @@ -107,6 +111,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_FirstSRVHostFails() { @@ -120,6 +125,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(host2 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_AllSRVHostsFailWithoutFallbackHost() { @@ -134,6 +140,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_AllSRVHostsFailWithFallbackHost() { @@ -150,6 +157,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_SRVAndFallbackHostsFail() { @@ -164,6 +172,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_TimeoutDuringResolve() { @@ -177,6 +186,7 @@ class ConnectorTest : public CppUnit::TestFixture { eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); CPPUNIT_ASSERT(!connections[0]); } @@ -193,6 +203,7 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testConnect_NoTimeout() { @@ -207,19 +218,21 @@ class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT(!boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testStop_DuringSRVQuery() { - Connector::ref testling(createConnector()); - resolver->addXMPPClientService("foo.com", host1); + Connector::ref testling(createConnector()); + resolver->addXMPPClientService("foo.com", host1); - testling->start(); - testling->stop(); + testling->start(); + testling->stop(); - eventLoop->processEvents(); + eventLoop->processEvents(); - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); - CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<DomainNameResolveError>(error)); } void testStop_Timeout() { @@ -242,16 +255,17 @@ class ConnectorTest : public CppUnit::TestFixture { private: Connector::ref createConnector() { Connector::ref connector = Connector::create("foo.com", resolver, connectionFactory, timerFactory); - connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1)); + connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; } - void handleConnectorFinished(boost::shared_ptr<Connection> connection) { + void handleConnectorFinished(boost::shared_ptr<Connection> connection, boost::shared_ptr<Error> resultError) { boost::shared_ptr<MockConnection> c(boost::dynamic_pointer_cast<MockConnection>(connection)); if (connection) { assert(c); } connections.push_back(c); + error = resultError; } struct MockConnection : public Connection { @@ -299,6 +313,8 @@ class ConnectorTest : public CppUnit::TestFixture { MockConnectionFactory* connectionFactory; DummyTimerFactory* timerFactory; std::vector< boost::shared_ptr<MockConnection> > connections; + boost::shared_ptr<Error> error; + }; CPPUNIT_TEST_SUITE_REGISTRATION(ConnectorTest); |