void TCPConnectionManagerTest::test_send() { // Use Case: // client requests a connection // expect client to be registered for any data StreamDataRequest req; DataSpec require; require.addStreamData("testData"); req.addDataOption(require); QTcpSocket* client = _createClient(); _sendRequest( client, req ); QCoreApplication::processEvents(); CPPUNIT_ASSERT_EQUAL( 1, _server->clientsForStream("testData") ); TestDataBlob blob; blob.setData("sometestData"); _server->send("testData",&blob); sleep(1); CPPUNIT_ASSERT( client->state() == QAbstractSocket::ConnectedState ); boost::shared_ptr<ServerResponse> r = _clientProtocol->receive(*client); CPPUNIT_ASSERT( r->type() == ServerResponse::Blob ); DataBlobResponse* res = static_cast<DataBlobResponse*>(r.get()); CPPUNIT_ASSERT( res->dataName() == "testData" ); CPPUNIT_ASSERT( res->blobClass() == "TestDataBlob" ); TestDataBlob recvBlob; recvBlob.deserialise(*client, res->byteOrder()); CPPUNIT_ASSERT(recvBlob == blob); }
// Connect to Pelican Lofar and register requested data type void PelicanBlobClient::connectToLofarPelican() { while (_tcpSocket->state() == QAbstractSocket::UnconnectedState) { _tcpSocket->connectToHost(_server, _port); if (!_tcpSocket->waitForConnected(5000) || _tcpSocket->state() == QAbstractSocket::UnconnectedState) { cerr << "PelicanBlobClient: Unable to connect to server (" << _server.toStdString() << ":" << _port << ")" << endl; sleep(2); continue; } // Define the data type which the client will except and send request StreamDataRequest req; DataSpec require; require.setStreamData(_blobType); req.addDataOption(require); QByteArray data = _protocol->serialise(req); _tcpSocket -> write(data); _tcpSocket -> waitForBytesWritten(data.size()); _tcpSocket -> flush(); } }
/** * @details * adds a data requirement. If the appropriate adapter * has not already been added with setAdater() then * this method will attemp to create a suitable one. */ void DataTypes::addData( const DataSpec& data ) { _dataRequirements.append(data); const QHash<QString,QString>& defaultAdapters = data.getAdapterTypes(); _addData( data.serviceData(), defaultAdapters, AbstractAdapter::Service ); _addData( data.streamData(), defaultAdapters, AbstractAdapter::Stream ); }
void DataSpecTest::test_hash() { // Use Case: // Ensure hash returns a non-zero value. { DataSpec d; d.addStreamData(QString("hello")); CPPUNIT_ASSERT(d.hash() != 0); } // Use Case: // Ensure different DataRequirement objects return different hash values. { DataSpec d1; d1.addStreamData(QString("one")); DataSpec d2; d2.addStreamData(QString("two")); CPPUNIT_ASSERT(d1.hash() != d2.hash()); } // Use Case: // Ensure different ordering returns the same hash. { DataSpec d1; QSet<QString> list1; list1 << "one" << "two"; d1.addStreamData(list1); DataSpec d2; QSet<QString> list2; list2 << "two" << "one"; d2.addStreamData(list2); CPPUNIT_ASSERT(d1.hash() == d2.hash()); } }
/** * @details * Tests two chunkers, starting them multiple times (test for random segfaults * and threading problems). */ void DirectStreamDataClientTest::test_twoChunkersMultipleStarts() { for (int i = 0; i < 100; ++i) { //std::cout << "---------------------------------- " << i << std::endl; try { // Start two telescope emulators. EmulatorDriver emulator1(new RealUdpEmulator(*_emulatorConfig1)); EmulatorDriver emulator2(new RealUdpEmulator(*_emulatorConfig2)); // Create the adapter factory. AbstractAdapterFactory adapterFactory(_config, "pipeline", "adapters"); // Create the data client factory. DataClientFactory clientFactory(_config, "pipeline", "clients", &adapterFactory); // Create the data blob factory. FactoryGeneric<DataBlob> blobFactory(true); // Create a list of data requirements. QString dataType = "DoubleData"; DataSpec req; QList<DataSpec> requirements; req.addStreamData(dataType); requirements.append(req); // Create the client. DirectStreamDataClient* client = static_cast<DirectStreamDataClient*>( clientFactory.create("DirectStreamDataClient")); CPPUNIT_ASSERT(DataClientFactory::whatIs(client) == "DirectStreamDataClient"); client->reset( requirements ); client->addStreamChunker("TestUdpChunker", "a"); client->addStreamChunker("TestUdpChunker", "b"); // Set up the data hash. QHash<QString, DataBlob*> dataHash; dataHash.insert(dataType, blobFactory.create(dataType)); for (int j = 0; j < 2; j++) { // Get the data. QHash<QString, DataBlob*> validData = client->getData(dataHash); // Check the content of the data blob. DoubleData* data = (DoubleData*)validData.value("DoubleData"); _printData(data); } } catch (QString e) { CPPUNIT_FAIL("Unexpected exception: " + e.toStdString()); } } }
void PelicanServerClientTest::test_getData() { Config config; config.setFromString( "<testconfig>" " <server host=\"127.0.0.1\"/>" "</testconfig>" ); Config::TreeAddress address; address << Config::NodeId("testconfig", ""); ConfigNode configNode = config.get(address); TestStreamAdapter streamAdapter; QString stream1("stream1"); QString version1("version1"); DataSpec req; req.addStreamData(stream1); { // Use Case: // data requirements are set, empty hash passed // Expect: throw QList<DataSpec> lreq; lreq.append(req); DataTypes dt; dt.setAdapter(stream1,&streamAdapter); dt.addData(lreq); PelicanServerClient client(configNode, dt, 0); QHash<QString, DataBlob*> dataHash; CPPUNIT_ASSERT_THROW(client.getData(dataHash), QString ); } { // Use Case: // Data Requirements do not match DataBlobs // Expect: // throw with a suitable message // setup the test QList<DataSpec> lreq; lreq.append(req); DataTypes dt; dt.setAdapter(stream1,&streamAdapter); dt.addData(lreq); PelicanServerClient client(configNode, dt, 0); QHash<QString, DataBlob*> dataHash; DataBlob db("DataBlob"); dataHash.insert("pelican/data2", &db); CPPUNIT_ASSERT_THROW(client.getData(dataHash), QString); } }
void TCPConnectionManagerTest::test_brokenConnection() { // Use Case: // client requests a connection // expect client to be registered for any data StreamDataRequest req; DataSpec require; require.addStreamData("testData"); req.addDataOption(require); QTcpSocket* client = _createClient(); _sendRequest( client, req ); QCoreApplication::processEvents(); CPPUNIT_ASSERT_EQUAL( 1, _server->clientsForStream("testData") ); // Use Case: // client dies after connection // expect to be removed from the system delete client; QCoreApplication::processEvents(); CPPUNIT_ASSERT_EQUAL( 0, _server->clientsForStream("testData") ); }
int main(int argc, char** argv) { try { QCoreApplication app(argc, argv); // Get command line arguments. if (argc != 5) { std::cerr << "Usage: directClient <port> <host> <chunk size, bytes> <iterations>" << std::endl; return 1; } int port = atoi(argv[1]); QString host(argv[2]); int chunkSize = atoi(argv[3]); int iterations = atoi(argv[4]); QString pipelineXml = "" "<buffers>" " <DoubleData>" " <buffer maxSize=\"2000000\" maxChunkSize=\"2000000\"/>" " </DoubleData>" "</buffers>" "<chunkers>" " <TestUdpChunker name=\"a\">" " <connection host=\"" + host + "\" port=\"" + QString::number(port) + "\"/>" " <data type=\"DoubleData\" chunkSize=\"" + QString::number(chunkSize) + "\"/>" " </TestUdpChunker>" "</chunkers>" "<clients>" " <DirectStreamDataClient>" " <data type=\"DoubleData\" adapter=\"AdapterRealData\"/>" " </DirectStreamDataClient>" "</clients>" "<adapters>" "</adapters>"; Config config; config.setFromString(pipelineXml); // Create the adapter factory. AbstractAdapterFactory adapterFactory(&config, "pipeline", "adapters"); // Create the data client factory. DataClientFactory clientFactory(&config, "pipeline", "clients", &adapterFactory); // Create the data blob factory. //FactoryGeneric<DataBlob> blobFactory; // Create a list of data requirements. QString dataType = "DoubleData"; DataSpec req; QList<DataSpec> requirements; req.addStreamData(dataType); requirements.append(req); // Create the client. DirectStreamDataClient* client = static_cast<DirectStreamDataClient*>( clientFactory.create("DirectStreamDataClient")); client->reset( requirements ); client->addStreamChunker("TestUdpChunker", "a"); // Set up the data hash. //QHash<QString, DataBlob*> dataHash; //dataHash.insert(dataType, blobFactory.create(dataType)); // Initialise loop counter. QTime timer; timer.start(); int counter = 0; double initValue = 0, value = 0; for (counter = 0; counter < iterations; counter++) { // Get the data. // QHash<QString, DataBlob*> validData = client->getData(dataHash); // Check the content of the data blob. // DoubleData* realData = (DoubleData*)validData.value(dataType); // //printData(realData); // value = realData->ptr()[0]; // if (counter == 0) // initValue = value; } // Check for lost packets. double dataRange = value - initValue; double lostPackets = dataRange + 1 - iterations; // Compute bandwidth. double sec = (double)timer.elapsed() / 1e3; long double megaBytesReceived = (long double)chunkSize * iterations / (1024 * 1024); // Print summary. std::cout << "---------------------------------------------------------\n"; std::cout << "Data range " << dataRange << " over " << iterations << " iterations. (Missed " << lostPackets << " packets.)\n"; std::cout << "Received " << megaBytesReceived << " MiB in " << sec << " seconds.\n"; std::cout << "Bandwidth: " << ((megaBytesReceived * 8) / sec) << " Mb/sec" << std::endl; std::cout << "---------------------------------------------------------\n"; } catch (QString error) { std::cerr << error.toStdString() << std::endl; } return 0; }
void StreamDataRequest::addDataOption(const DataSpec& data) { if( data.streamData().size() != 0 ) _dataOptions.append(data); }
void DataSpecTest::test_isCompatible() { // Use Case: // DataSpec matches the data hash // expect true { DataSpec req; req.addServiceData("wibble1"); QHash<QString, DataBlob*> hashData; hashData.insert("wibble1", NULL); CPPUNIT_ASSERT_EQUAL(true, req.isCompatible(hashData)); DataSpec reqdata; reqdata.addServiceData("wibble1"); CPPUNIT_ASSERT_EQUAL(true, req.isCompatible(reqdata)); } // Use Case: // DataSpec contains a subset of the data hash // expect true { DataSpec req; req.addServiceData("wibble1"); QHash<QString, DataBlob*> hashData; hashData.insert("wibble1", NULL); hashData.insert("wibble2", NULL); CPPUNIT_ASSERT_EQUAL(true, req.isCompatible(hashData)); DataSpec reqdata; reqdata.addServiceData("wibble1"); reqdata.addServiceData("wibble2"); CPPUNIT_ASSERT_EQUAL(true, req.isCompatible(reqdata)); } // Use Case: // DataSpec contains some elements of the data, but is not compatible with it. // The data requirements have an additional data type which is not in the hash. // expect false { DataSpec req; QSet<QString> dataTypes; dataTypes << "wibble1" << "other"; req.addServiceData(dataTypes); QHash<QString, DataBlob*> hashData; hashData.insert("wibble1", NULL); hashData.insert("wibble2", NULL); CPPUNIT_ASSERT_EQUAL(false, req.isCompatible(hashData)); DataSpec reqdata; reqdata.addServiceData("wibble1"); reqdata.addServiceData("wibble2"); CPPUNIT_ASSERT_EQUAL(false, req.isCompatible(reqdata)); } }
void PelicanServerClientTest::test_response() { try { TestServiceAdapter serviceAdapter; TestStreamAdapter streamAdapter; ConfigNode configNode; configNode.setFromString( "<testconfig>" " <server host=\"127.0.0.1\"/>" "</testconfig>" ); QString stream1("stream1"); QString version1("v1"); QString service1("service1"); QString serviceVersion1("sv1"); DataSpec reqStream1; reqStream1.addStreamData(stream1); QByteArray data1("data1"); { // Use Case // receive a StreamData response (single stream, no service data) boost::shared_ptr<ServerResponse> res( new StreamDataResponse ); static_cast<StreamDataResponse*>(res.get())->setStreamData( new StreamData(stream1,version1, data1.size()) ); // set up the adapters and client QList<DataSpec> lreq; lreq.append(reqStream1); DataTypes dt; dt.setAdapter(stream1,&streamAdapter); dt.addData(lreq); PelicanServerClient client(configNode, dt, 0); // set up the memory for receiving data TestDataBlob db; QHash<QString, DataBlob*> dataHash; dataHash.insert(stream1, &db); SocketTester st; QTcpSocket& sock = st.send(data1); QHash<QString, DataBlob*> vhash = client._response( sock , res, dataHash ); CPPUNIT_ASSERT( vhash == dataHash ); CPPUNIT_ASSERT_EQUAL( version1.toStdString(), vhash[stream1]->version().toStdString() ); CPPUNIT_ASSERT_EQUAL( std::string( data1.data() ) , std::string( static_cast<TestDataBlob*>(vhash[stream1])->data() ) ); } QByteArray data2("data2"); { // Use Case // ServiceData response - single service data boost::shared_ptr<ServerResponse> res( new ServiceDataResponse ); static_cast<ServiceDataResponse*>(res.get())->addData( new DataChunk(service1,serviceVersion1, data2.size()) ); // set up the memory for receiving data TestDataBlob db; QHash<QString, DataBlob*> dataHash; dataHash.insert(service1, &db); // set up the adapters and client DataSpec req; req.addStreamData(service1); QList<DataSpec> lreq; lreq.append(req); DataTypes dt; dt.setAdapter(service1,&serviceAdapter); dt.addData(lreq); PelicanServerClient client(configNode, dt, 0); SocketTester st; QTcpSocket& sock = st.send(data2); QHash<QString, DataBlob*> vhash = client._response( sock , res, dataHash ); CPPUNIT_ASSERT( vhash == dataHash ); CPPUNIT_ASSERT_EQUAL( serviceVersion1.toStdString(), vhash[service1]->version().toStdString() ); CPPUNIT_ASSERT_EQUAL( std::string( data2.data() ) , std::string( static_cast<TestDataBlob*>(vhash[service1])->data() ) ); } QString service2("service2"); { // Use Case // ServiceData response - multiple service data boost::shared_ptr<ServerResponse> res( new ServiceDataResponse ); static_cast<ServiceDataResponse*>(res.get())->addData( new DataChunk(service1,version1, data1.size()) ); static_cast<ServiceDataResponse*>(res.get())->addData( new DataChunk(service2,serviceVersion1, data2.size()) ); // set up the memory for receiving data TestDataBlob db; TestDataBlob db2; QHash<QString, DataBlob*> dataHash; dataHash.insert(service1, &db); dataHash.insert(service2, &db2); // set up the adapters and client DataSpec req; req.addStreamData(service1); QList<DataSpec> lreq; lreq.append(req); DataTypes dt; dt.setAdapter(service1,&serviceAdapter); dt.setAdapter(service2,&serviceAdapter); dt.addData(lreq); PelicanServerClient client(configNode, dt, 0); SocketTester st; QTcpSocket& sock = st.send( data1 + data2 ); QHash<QString, DataBlob*> vhash = client._response( sock , res, dataHash ); CPPUNIT_ASSERT( vhash == dataHash ); CPPUNIT_ASSERT_EQUAL( version1.toStdString(), vhash[service1]->version().toStdString() ); CPPUNIT_ASSERT_EQUAL( serviceVersion1.toStdString(), vhash[service2]->version().toStdString() ); CPPUNIT_ASSERT_EQUAL( std::string( data1.data() ) , std::string( static_cast<TestDataBlob*>(vhash[service1])->data() ) ); CPPUNIT_ASSERT_EQUAL( std::string( data2.data() ) , std::string( static_cast<TestDataBlob*>(vhash[service2])->data() ) ); } // { // // Use Case // // receive a StreamData response with associated service data (single stream, single service data) // // no existing service data exists // boost::shared_ptr<ServerResponse> res( new StreamDataResponse ); // StreamData* sd = new StreamData(stream1,version1, data1.size()); // sd->addAssociatedData(boost::shared_ptr<Data>(new Data(service1,serviceVersion1, data2.size()) ) ); // static_cast<StreamDataResponse*>(res.get())->setStreamData( sd ); // // // set up the adapters and client // DataSpec req; // req.addStreamData(stream1); // req.addServiceData(service1); // QList<DataSpec> lreq; // lreq.append(req); // DataTypes dt; // dt.setAdapter(stream1,&streamAdapter); // dt.setAdapter(service1,&serviceAdapter); // dt.addData(lreq); // PelicanServerClient client(configNode, dt, 0); // // // set up the memory for receiving data // TestDataBlob db; // TestDataBlob db2; // QHash<QString, DataBlob*> dataHash; // dataHash.insert(stream1, &db); // dataHash.insert(service1, &db2); // // SocketTester st; // QTcpSocket& sock = st.send(data1); // try { // QHash<QString, DataBlob*> vhash = client._response( sock , res, dataHash ); // } catch (const QString& e) { // CPPUNIT_FAIL(e.toStdString()); // } // CPPUNIT_ASSERT( vhash == dataHash ); // CPPUNIT_ASSERT_EQUAL( version1.toStdString(), vhash[stream1]->version().toStdString() ); // CPPUNIT_ASSERT_EQUAL( serviceVersion1.toStdString(), vhash[service1]->version().toStdString() ); // CPPUNIT_ASSERT_EQUAL( std::string( data1.data() ) , std::string( static_cast<TestDataBlob*>( vhash[stream1])->data() ) ); // CPPUNIT_ASSERT_EQUAL( std::string( data2.data() ) , std::string( static_cast<TestDataBlob*>( vhash[service1])->data() ) ); // } } catch ( const QString& e ) { CPPUNIT_FAIL( e.toStdString() ); } }
void FileDataClientTest::test_method() { try { Config config; config.setFromString( "<testconfig>" " <file name=\"testfile.xml\"/>" "</testconfig>" ); Config::TreeAddress address; address << Config::NodeId("testconfig", ""); ConfigNode configNode = config.get(address); /* No longer relevant { // Use Case: // Empty data requirements // Expect: throw with a suitable complaint // setup the test QList<DataSpec> lreq; DataTypes dt; dt.addData(lreq); FileDataClient* client = 0; CPPUNIT_ASSERT_THROW(client = new FileDataClient(configNode, dt, 0), QString); delete client; } */ TestStreamAdapter streamAdapter; QString stream1("stream1"); QString version1("version1"); DataSpec req; req.addStreamData(stream1); { // Use Case: // data requirements are set, empty hash passed // Expect: throw QList<DataSpec> lreq; lreq.append(req); DataTypes dt; dt.setAdapter(stream1,&streamAdapter); dt.addData(lreq); FileDataClient client(configNode, dt, 0); QHash<QString, DataBlob*> dataHash; CPPUNIT_ASSERT_THROW(client.getData(dataHash), QString ); } { // Use Case: // Specifiy a single file and associate it with a Stream // correct hash is passed // Expect: // Data in file to be streamed DataTypes types; types.setAdapter(stream1,&streamAdapter); types.addData(req); FileDataClient client(configNode, types, &config); QHash<QString, DataBlob*> dataHash; DataBlob db("DataBlob"); dataHash.insert(stream1, &db); client.getData(dataHash); } } catch( QString& e ) { CPPUNIT_FAIL(e.toStdString()); } }
/** * @details * Test if the DataSpec object is compatible with a hash of data blobs. */ bool operator==(const DataSpec& r, const QHash<QString, DataBlob*>& hash) { return r.isCompatible(hash); }
/** * @details * Tests if this requirements object is the same as the other one. */ bool DataSpec::operator==(const DataSpec& d) const { return hash() == d.hash(); }