/*! * \brief Unit tests for \ref RemoteDispatcher * * \copyright Copyright (c) 2017-2018 Governikus GmbH & Co. KG, Germany */ #include "RemoteDispatcherImpl.h" #include "messages/IfdConnect.h" #include "messages/IfdDisconnect.h" #include "messages/IfdEstablishContext.h" #include "messages/IfdEstablishContextResponse.h" #include "messages/IfdTransmit.h" #include "MockDataChannel.h" #include "RemoteMessageChecker.h" #include #include using namespace governikus; class RemoteDispatcherSpy : public QObject { Q_OBJECT private: const QSharedPointer mRemoteDispatcher; bool mClosed; GlobalStatus::Code mCloseCode; QVector > mReceivedMessages; QVector > mReceivedSignalSenders; public: RemoteDispatcherSpy(const QSharedPointer pRemoteDispatcher); virtual ~RemoteDispatcherSpy(); bool isClosed() const; GlobalStatus::Code getCloseCode() const; const QVector >& getReceivedMessages() const; const QVector >& getReceivedSignalSenders() const; private Q_SLOTS: void onClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pDispatcher); void onReceived(const QSharedPointer& pMessage, const QSharedPointer& pDispatcher); }; RemoteDispatcherSpy::RemoteDispatcherSpy(const QSharedPointer pRemoteDispatcher) : mRemoteDispatcher(pRemoteDispatcher) , mClosed(false) , mCloseCode(GlobalStatus::Code::RemoteReader_CloseCode_Undefined) { connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteDispatcherSpy::onClosed); connect(mRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &RemoteDispatcherSpy::onReceived); } RemoteDispatcherSpy::~RemoteDispatcherSpy() { disconnect(mRemoteDispatcher.data(), &RemoteDispatcher::fireClosed, this, &RemoteDispatcherSpy::onClosed); disconnect(mRemoteDispatcher.data(), &RemoteDispatcher::fireReceived, this, &RemoteDispatcherSpy::onReceived); } bool RemoteDispatcherSpy::isClosed() const { return mClosed; } GlobalStatus::Code RemoteDispatcherSpy::getCloseCode() const { return mCloseCode; } const QVector >& RemoteDispatcherSpy::getReceivedMessages() const { return mReceivedMessages; } const QVector >& RemoteDispatcherSpy::getReceivedSignalSenders() const { return mReceivedSignalSenders; } void RemoteDispatcherSpy::onClosed(GlobalStatus::Code pCloseCode, const QSharedPointer& pDispatcher) { mClosed = true; mCloseCode = pCloseCode; mReceivedSignalSenders += pDispatcher; } void RemoteDispatcherSpy::onReceived(const QSharedPointer& pMessage, const QSharedPointer& pDispatcher) { qDebug() << "RemoteDispatcherSpy::onReceived() -" << pMessage->getType(); mReceivedMessages += pMessage; mReceivedSignalSenders += pDispatcher; } class test_RemoteDisp : public QObject { Q_OBJECT private: RemoteMessageChecker mChecker; private Q_SLOTS: void channelClosedNormally() { const QSharedPointer channel(new MockDataChannel()); const QSharedPointer dispatcher(new RemoteDispatcherImpl(channel)); RemoteDispatcherSpy spy(dispatcher); channel->close(); QVERIFY(spy.isClosed()); QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_NormalClose); const QVector >& senders = spy.getReceivedSignalSenders(); QCOMPARE(senders.size(), 1); QCOMPARE(senders.first().data(), dispatcher.data()); } void channelClosedAbnormally() { const QSharedPointer channel(new MockDataChannel()); const QSharedPointer dispatcher(new RemoteDispatcherImpl(channel)); RemoteDispatcherSpy spy(dispatcher); channel->closeAbnormal(); QVERIFY(spy.isClosed()); QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_AbnormalClose); const QVector >& senders = spy.getReceivedSignalSenders(); QCOMPARE(senders.size(), 1); QCOMPARE(senders.first().data(), dispatcher.data()); } void messagesAreDelivered() { const QSharedPointer clientChannel(new MockDataChannel()); const QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); const QSharedPointer serverChannel(new MockDataChannel()); const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); connect(serverChannel.data(), &MockDataChannel::fireSend, clientChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); RemoteDispatcherSpy spy(serverDispatcher); clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()))); clientDispatcher->send(QSharedPointer(new IfdConnect(QStringLiteral("NFC Reader")))); clientDispatcher->send(QSharedPointer(new IfdTransmit(QStringLiteral("NFC Reader"), QByteArray::fromHex("00A402022F00")))); clientDispatcher->send(QSharedPointer(new IfdDisconnect(QStringLiteral("NFC Reader")))); const QVector > receivedMessages = spy.getReceivedMessages(); QCOMPARE(receivedMessages.size(), 3); QCOMPARE(receivedMessages.at(0)->getType(), RemoteCardMessageType::IFDConnect); mChecker.receive(receivedMessages.at(0)); QCOMPARE(receivedMessages.at(1)->getType(), RemoteCardMessageType::IFDTransmit); mChecker.receive(receivedMessages.at(1)); QCOMPARE(receivedMessages.at(2)->getType(), RemoteCardMessageType::IFDDisconnect); mChecker.receive(receivedMessages.at(2)); const QVector >& senders = spy.getReceivedSignalSenders(); QCOMPARE(senders.size(), 3); QCOMPARE(senders.at(0).data(), serverDispatcher.data()); QCOMPARE(senders.at(1).data(), serverDispatcher.data()); QCOMPARE(senders.at(2).data(), serverDispatcher.data()); } void channelIsClosedWhenRemoteDispatcherIsDestroyed() { const QSharedPointer clientChannel(new MockDataChannel()); QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); const QSharedPointer serverChannel(new MockDataChannel()); const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); connect(clientChannel.data(), &DataChannel::fireClosed, serverChannel.data(), &DataChannel::close, Qt::DirectConnection); RemoteDispatcherSpy spy(serverDispatcher); QVERIFY(!spy.isClosed()); // Destroying a remote dispatcher should close the underlying channel. clientDispatcher.reset(); QVERIFY(spy.isClosed()); QCOMPARE(spy.getCloseCode(), GlobalStatus::Code::RemoteReader_CloseCode_NormalClose); const QVector >& senders = spy.getReceivedSignalSenders(); QCOMPARE(senders.size(), 1); QCOMPARE(senders.at(0).data(), serverDispatcher.data()); } void repeatedIfdEstablishContextGenerateCorrectErrorMessage() { const QSharedPointer clientChannel(new MockDataChannel()); const QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); const QSharedPointer serverChannel(new MockDataChannel()); const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); connect(serverChannel.data(), &MockDataChannel::fireSend, clientChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()))); clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v0"), DeviceInfo::getName()))); const QVector& clientReceivedDataBlocks = clientChannel->getReceivedDataBlocks(); QCOMPARE(clientReceivedDataBlocks.size(), 2); const QSharedPointer message1 = RemoteMessageParser().parse(clientReceivedDataBlocks.at(0)).dynamicCast(); QVERIFY(!message1.isNull()); QCOMPARE(message1->getType(), RemoteCardMessageType::IFDEstablishContextResponse); QCOMPARE(message1->resultHasError(), false); QCOMPARE(message1->getResultMinor(), QString()); const QSharedPointer message2 = RemoteMessageParser().parse(clientReceivedDataBlocks.at(1)).dynamicCast(); QVERIFY(!message2.isNull()); QCOMPARE(message2->getType(), RemoteCardMessageType::IFDEstablishContextResponse); QCOMPARE(message2->resultHasError(), true); QCOMPARE(message2->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownError")); } void ifdEstablishContextWithWrongProtocolGeneratesCorrectErrorMessage() { const QSharedPointer clientChannel(new MockDataChannel()); const QSharedPointer clientDispatcher(new RemoteDispatcherImpl(clientChannel)); const QSharedPointer serverChannel(new MockDataChannel()); const QSharedPointer serverDispatcher(new RemoteDispatcherImpl(serverChannel)); connect(clientChannel.data(), &MockDataChannel::fireSend, serverChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); connect(serverChannel.data(), &MockDataChannel::fireSend, clientChannel.data(), &MockDataChannel::onReceived, Qt::DirectConnection); clientDispatcher->send(QSharedPointer(new IfdEstablishContext(QStringLiteral("IFDInterface_WebSocket_v2"), DeviceInfo::getName()))); const QVector& clientReceivedDataBlocks = clientChannel->getReceivedDataBlocks(); QCOMPARE(clientReceivedDataBlocks.size(), 1); const QSharedPointer message = RemoteMessageParser().parse(clientReceivedDataBlocks.at(0)); QVERIFY(!message.isNull()); QCOMPARE(message->getType(), RemoteCardMessageType::IFDEstablishContextResponse); const QSharedPointer ifdEstablishContextResponse = message.dynamicCast(); QVERIFY(!ifdEstablishContextResponse.isNull()); QCOMPARE(ifdEstablishContextResponse->resultHasError(), true); QCOMPARE(ifdEstablishContextResponse->getResultMinor(), QStringLiteral("http://www.bsi.bund.de/ecard/api/1.1/resultminor/al/common#unknownError")); } public: test_RemoteDisp() : mChecker() { } }; QTEST_GUILESS_MAIN(test_RemoteDisp) #include "test_RemoteDispImpl.moc"