diff options
-rw-r--r-- | include/nostr.hpp | 6 | ||||
-rw-r--r-- | src/nostr_service.cpp | 3 | ||||
-rw-r--r-- | test/nostr_service_test.cpp | 105 |
3 files changed, 108 insertions, 6 deletions
diff --git a/include/nostr.hpp b/include/nostr.hpp index a59bd33..5e7dbfe 100644 --- a/include/nostr.hpp +++ b/include/nostr.hpp @@ -191,8 +191,12 @@ public: /** * @brief Queries all open relay connections for events matching the given set of filters. * @param filters The filters to use for the query. - * @param responseHandler A callable object that will be invoked each time the client receives + * @param eventHandler A callable object that will be invoked each time the client receives * an event matching the filters. + * @param eoseHandler A callable object that will be invoked when the relay sends an EOSE + * message. + * @param closeHandler A callable object that will be invoked when the relay sends a CLOSE + * message. * @returns The ID of the subscription created for the query. * @remark By providing a response handler, the caller assumes responsibility for handling all * events returned from the relay for the given filters. The service will not store the diff --git a/src/nostr_service.cpp b/src/nostr_service.cpp index a1adbbb..a1f475c 100644 --- a/src/nostr_service.cpp +++ b/src/nostr_service.cpp @@ -273,9 +273,6 @@ string NostrService::queryRelays( for (const string relay : this->_activeRelays) { this->_subscriptions[relay].push_back(subscriptionId); - - promise<tuple<string, bool>> requestPromise; - requestFutures.push_back(move(requestPromise.get_future())); future<tuple<string, bool>> requestFuture = async( [this, &relay, &request, &eventHandler, &eoseHandler, &closeHandler]() { diff --git a/test/nostr_service_test.cpp b/test/nostr_service_test.cpp index e80406e..b2f6876 100644 --- a/test/nostr_service_test.cpp +++ b/test/nostr_service_test.cpp @@ -16,8 +16,10 @@ using std::lock_guard; using std::make_shared; using std::make_unique; using std::mutex; +using std::promise; using std::shared_ptr; using std::string; +using std::thread; using std::tuple; using std::unordered_map; using std::vector; @@ -741,7 +743,6 @@ TEST_F(NostrServiceTest, QueryRelays_ReturnsEvents_UpToEOSE) vector<shared_ptr<nostr::Event>> signedTestEvents; for (nostr::Event testEvent : testEvents) { - std::cout << "TEST: Signing event" << std::endl; auto signedEvent = make_shared<nostr::Event>(testEvent); signer->sign(signedEvent); @@ -759,7 +760,6 @@ TEST_F(NostrServiceTest, QueryRelays_ReturnsEvents_UpToEOSE) string uri, function<void(const string&)> messageHandler) { - std::cout << "TEST: Sending message: " << message << std::endl; json messageArr = json::parse(message); string subscriptionId = messageArr.at(1); @@ -798,5 +798,106 @@ TEST_F(NostrServiceTest, QueryRelays_ReturnsEvents_UpToEOSE) } }; +TEST_F(NostrServiceTest, QueryRelays_CallsHandler_WithReturnedEvents) +{ + mutex connectionStatusMutex; + auto connectionStatus = make_shared<unordered_map<string, bool>>(); + connectionStatus->insert({ defaultTestRelays[0], false }); + connectionStatus->insert({ defaultTestRelays[1], false }); + + EXPECT_CALL(*mockClient, isConnected(_)) + .WillRepeatedly(Invoke([connectionStatus, &connectionStatusMutex](string uri) + { + lock_guard<mutex> lock(connectionStatusMutex); + bool status = connectionStatus->at(uri); + if (status == false) + { + connectionStatus->at(uri) = true; + } + return status; + })); + + auto signer = make_unique<FakeSigner>(); + auto nostrService = make_unique<nostr::NostrService>( + testAppender, + mockClient, + fakeSigner, + defaultTestRelays); + nostrService->openRelayConnections(); + + auto testEvents = getMultipleTextNoteTestEvents(); + vector<shared_ptr<nostr::Event>> signedTestEvents; + for (nostr::Event testEvent : testEvents) + { + auto signedEvent = make_shared<nostr::Event>(testEvent); + signer->sign(signedEvent); + + auto serializedEvent = signedEvent->serialize(); + auto deserializedEvent = nostr::Event::fromString(serializedEvent); + + signedEvent = make_shared<nostr::Event>(deserializedEvent); + signedTestEvents.push_back(signedEvent); + } + + EXPECT_CALL(*mockClient, send(_, _, _)) + .Times(2) + .WillRepeatedly(Invoke([&testEvents, &signer]( + string message, + string uri, + function<void(const string&)> messageHandler) + { + json messageArr = json::parse(message); + string subscriptionId = messageArr.at(1); + + for (auto event : testEvents) + { + auto sendableEvent = make_shared<nostr::Event>(event); + signer->sign(sendableEvent); + json jarr = json::array({ "EVENT", subscriptionId, sendableEvent->serialize() }); + messageHandler(jarr.dump()); + } + + json jarr = json::array({ "EOSE", subscriptionId }); + messageHandler(jarr.dump()); + + return make_tuple(uri, true); + })); + + auto filters = make_shared<nostr::Filters>(getKind0And1TestFilters()); + promise<void> eoseReceivedPromise; + auto eoseReceivedFuture = eoseReceivedPromise.get_future(); + int eoseCount = 0; + + string generatedSubscriptionId = nostrService->queryRelays( + filters, + [&generatedSubscriptionId, &signedTestEvents](const string& subscriptionId, shared_ptr<nostr::Event> event) + { + ASSERT_STREQ(subscriptionId.c_str(), generatedSubscriptionId.c_str()); + ASSERT_NE( + find_if( + signedTestEvents.begin(), + signedTestEvents.end(), + [&event](shared_ptr<nostr::Event> testEvent) + { + return *testEvent == *event; + }), + signedTestEvents.end()); + }, + [&generatedSubscriptionId, &eoseReceivedPromise, &eoseCount] + (const string& subscriptionId) + { + std::cout << "EOSE received for subscription ID: " << subscriptionId << std::endl; + ASSERT_STREQ(subscriptionId.c_str(), generatedSubscriptionId.c_str()); + + if (++eoseCount == 2) + { + eoseReceivedPromise.set_value(); + } + }, + [](const string&, const string&) {}); + + eoseReceivedFuture.wait(); +}; + // TODO: Add unit tests for closing subscriptions. } // namespace nostr_test |