Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ readline-5.0-1-lib.zip
test/integration/.network

test/tontester/tests/tl/generated
test/tontester/src/tontester/tl
test/tontester/src/tonapi
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -678,5 +678,7 @@ ton_test(test-emulator)
ton_test(test-fec)
ton_test(test-tddb ${TEST_OPTIONS})
ton_test(test-db ${TEST_OPTIONS})

add_subdirectory(test)
endif()
#END internal
6 changes: 5 additions & 1 deletion tdutils/td/utils/port/detail/EventFdWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ void EventFdWindows::acquire() {
}

void EventFdWindows::wait(int timeout_ms) {
WaitForSingleObject(event_.fd(), timeout_ms);
if (timeout_ms == -1) {
WaitForSingleObject(event_.fd(), INFINITE);
} else {
WaitForSingleObject(event_.fd(), timeout_ms);
}
if (ResetEvent(event_.fd()) == 0) {
auto error = OS_ERROR("ResetEvent failed");
LOG(FATAL) << error;
Expand Down
4 changes: 4 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
add_library(td-test-main test-td-main.cpp)
target_link_libraries(td-test-main PRIVATE tdutils)

add_subdirectory(tonlib)
7 changes: 5 additions & 2 deletions test/integration/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pathlib import Path

from tontester.install import Install
from tontester.network import Network
from tontester.network import FullNode, Network


async def main():
Expand All @@ -24,7 +24,7 @@ async def main():
async with Network(install, working_dir) as network:
dht = network.create_dht_node()

nodes: list[Network.Node] = []
nodes: list[FullNode] = []
for _ in range(2):
node = network.create_full_node()
node.make_initial_validator()
Expand All @@ -37,6 +37,9 @@ async def main():

await network.wait_mc_block(seqno=1)

actor_stats = await nodes[0].engine_console.get_actor_stats()
assert "= ACTORS STATS =" in actor_stats and "= PERF COUNTERS =" in actor_stats


if __name__ == "__main__":
asyncio.run(asyncio.wait_for(main(), 5 * 60))
16 changes: 16 additions & 0 deletions test/tonlib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
set(TONLIB_TESTS
test-ffi-awaitable
)

# FIXME: Enable this on MacOS once we figure out why it fails in CI because of too slow wake ups.
if(NOT APPLE)
list(APPEND TONLIB_TESTS test-ffi-event-loop)
endif()

foreach(TEST_NAME IN LISTS TONLIB_TESTS)
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)

target_link_libraries(${TEST_NAME} PRIVATE td-test-main tonlibjson_objects tonlibjson_private_interface)

ton_test(${TEST_NAME})
endforeach()
4 changes: 4 additions & 0 deletions test/tonlib/integration/tonlibjson_consumer.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#include "tonlib/tonlib_client_json.h"
#include "tonlib/tonlib_engine_console.h"

int main() {
void* client = tonlib_client_json_create();
tonlib_client_json_destroy(client);

TonlibEventLoop* loop = tonlib_event_loop_create(1);
tonlib_event_loop_destroy(loop);

return 0;
}
216 changes: 216 additions & 0 deletions test/tonlib/test-ffi-awaitable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
#include <chrono>
#include <thread>

#include "td/utils/Status.h"
#include "td/utils/tests.h"
#include "tonlib/FFIAwaitable.h"

namespace tonlib {
namespace {

struct Tag {};

static constexpr Tag tags[2];
static constexpr const void* continuation_0 = &tags[0];
static constexpr const void* continuation_1 = &tags[1];

Continuation wait_for_continuation(FFIEventLoop& loop) {
std::optional<Continuation> result;
while (!result.has_value()) {
result = loop.wait(-1);
}
return *result;
}

TEST(FFIAwaitable, CreateResolvedWithValue) {
FFIEventLoop loop(1);
auto awaitable = FFIAwaitable<int>::create_resolved(loop, 42);

EXPECT(awaitable->await_ready());
EXPECT(awaitable->result().is_ok());
EXPECT_EQ(awaitable->result().ok(), 42);
}

TEST(FFIAwaitable, CreateResolvedWithError) {
FFIEventLoop loop(1);
auto awaitable = FFIAwaitable<int>::create_resolved(loop, td::Status::Error(123, "test error"));

EXPECT(awaitable->await_ready());
EXPECT(awaitable->result().is_error());
EXPECT_EQ(awaitable->result().error().code(), 123);
}

TEST(FFIAwaitable, AwaitSuspendOnResolved) {
FFIEventLoop loop(1);
auto awaitable = FFIAwaitable<int>::create_resolved(loop, 42);

awaitable->await_suspend({continuation_0});

auto result = loop.wait(0);
EXPECT(result.has_value());
EXPECT_EQ(result->ptr(), continuation_0);
}

TEST(FFIAwaitable, CreateBridgeResolveWithoutSuspend) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<int>::create_bridge<int>(loop, [](int x) { return x * 2; });

EXPECT(!bridge.awaitable->await_ready());

bridge.promise.set_value(21);

EXPECT(bridge.awaitable->await_ready());
EXPECT(bridge.awaitable->result().is_ok());
EXPECT_EQ(bridge.awaitable->result().ok(), 42);
}

TEST(FFIAwaitable, CreateBridgeResolveAfterSuspend) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<int>::create_bridge<int>(loop, [](int x) { return x * 2; });

EXPECT(!bridge.awaitable->await_ready());

bridge.awaitable->await_suspend({continuation_0});

bridge.promise.set_value(21);

auto result = loop.wait(0);
EXPECT(result.has_value());
EXPECT_EQ(result->ptr(), continuation_0);

EXPECT(bridge.awaitable->await_ready());
EXPECT(bridge.awaitable->result().is_ok());
EXPECT_EQ(bridge.awaitable->result().ok(), 42);
}

TEST(FFIAwaitable, TransformString) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<std::string>::create_bridge<int>(loop, [](int x) { return std::to_string(x); });

bridge.promise.set_value(123);

EXPECT(bridge.awaitable->await_ready());
EXPECT(bridge.awaitable->result().is_ok());
EXPECT_EQ(bridge.awaitable->result().ok(), "123");
}

TEST(FFIAwaitable, ResolveFromDifferentThread) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<int>::create_bridge<int>(loop, [](int x) { return x + 10; });

bridge.awaitable->await_suspend({continuation_1});

loop.run_in_context([&] {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
bridge.promise.set_value(90);
});

auto result = wait_for_continuation(loop);
EXPECT_EQ(result.ptr(), continuation_1);

EXPECT(bridge.awaitable->result().is_ok());
EXPECT_EQ(bridge.awaitable->result().ok(), 100);
}

TEST(FFIAwaitable, ConcurrentResolveAndSuspend) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<int>::create_bridge<int>(loop, [](int x) { return x; });

std::thread suspender([&]() {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
bridge.awaitable->await_suspend({continuation_0});
});

std::thread resolver([promise = std::move(bridge.promise)]() mutable {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
promise.set_value(777);
});

auto result = wait_for_continuation(loop);
EXPECT_EQ(result.ptr(), continuation_0);

suspender.join();
resolver.join();

EXPECT(bridge.awaitable->await_ready());
EXPECT_EQ(bridge.awaitable->result().ok(), 777);
}

TEST(FFIAwaitable, DestroyUnresolvedWithoutSuspend) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<int>::create_bridge<int>(loop, [](int x) { return x; });

bridge.awaitable->destroy();

auto result = loop.wait(0);
EXPECT(!result.has_value());
}

TEST(FFIAwaitable, DestroyUnresolvedAfterSuspend) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<int>::create_bridge<int>(loop, [](int x) { return x; });

bridge.awaitable->await_suspend({continuation_0});
bridge.awaitable->destroy();

auto result = loop.wait(0);
EXPECT(result.has_value());
EXPECT_EQ(result->ptr(), continuation_0);
}

TEST(FFIAwaitable, DestroyResolvedWithoutSuspend) {
FFIEventLoop loop(1);

auto awaitable = FFIAwaitable<int>::create_resolved(loop, 42);

EXPECT(awaitable->await_ready());
awaitable->destroy();
}

TEST(FFIAwaitable, DestroyResolvedAfterSuspend) {
FFIEventLoop loop(1);

auto awaitable = FFIAwaitable<int>::create_resolved(loop, 42);

awaitable->await_suspend({continuation_1});
awaitable->destroy();

auto result = loop.wait(0);
EXPECT(result.has_value());
EXPECT_EQ(result->ptr(), continuation_1);
}

TEST(FFIAwaitable, DestroyConcurrentWithResolve) {
FFIEventLoop loop(1);

auto bridge = FFIAwaitable<int>::create_bridge<int>(loop, [](int x) { return x; });

bridge.awaitable->await_suspend({continuation_0});

std::thread resolver([promise = std::move(bridge.promise)]() mutable {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
promise.set_value(999);
});

std::thread destroyer([&]() {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
bridge.awaitable->destroy();
});

auto result = wait_for_continuation(loop);

resolver.join();
destroyer.join();

EXPECT_EQ(result.ptr(), continuation_0);
}

} // namespace
} // namespace tonlib
Loading
Loading