Files
dat-thang/tests/test_gui_p2p.c
T
divorce b735900f2e 0.0.002
ddat interop with dat js
cable interop with cabal js
ddat's frontend = dat-thang
cable fe = cable-thang
dillo support based on cel's dillo-dat
bootstrap node
xplatform support

Signed-off-by: divo <418@cryspace.space>
2026-10-19 00:17:02 -04:00

392 lines
16 KiB
C

#define _POSIX_C_SOURCE 200809L
#define main dat_thang_program_main
#include "../src/ddat_gui.c"
#undef main
#include <assert.h>
#include <fcntl.h>
#include <time.h>
#ifdef _WIN32
#include <direct.h>
#include <process.h>
#define test_mkdir(path) _mkdir(path)
#define test_setenv(name, value) _putenv_s((name), (value))
#define test_pid _getpid
#define test_close_socket(fd) closesocket(fd)
typedef int test_socklen_t;
typedef SOCKET test_socket_t;
#define test_socket_valid(fd) ((fd) != INVALID_SOCKET)
#else
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#define test_mkdir(path) mkdir((path), 0700)
#define test_setenv(name, value) setenv((name), (value), 1)
#define test_pid getpid
#define test_close_socket(fd) close(fd)
typedef socklen_t test_socklen_t;
typedef int test_socket_t;
#define test_socket_valid(fd) ((fd) >= 0)
#endif
static uint16_t unused_udp_port(void)
{
test_socket_t fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in address;
test_socklen_t length = sizeof(address);
uint16_t port;
assert(test_socket_valid(fd));
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
assert(bind(fd, (struct sockaddr *)&address, sizeof(address)) == 0);
assert(getsockname(fd, (struct sockaddr *)&address, &length) == 0);
port = ntohs(address.sin_port);
test_close_socket(fd);
return port;
}
static void pause_one_millisecond(void)
{
SDL_Delay(1);
}
static void set_network_environment(uint16_t local_port, uint16_t bootstrap_port)
{
char value[32];
snprintf(value, sizeof(value), "%u", (unsigned)local_port);
assert(test_setenv("DDAT_PORT", value) == 0);
snprintf(value, sizeof(value), "127.0.0.1:%u", (unsigned)bootstrap_port);
assert(test_setenv("DDAT_BOOTSTRAP", value) == 0);
}
static int peer_ready(const gui_state_t *state)
{
size_t i;
if (!state->session_initialized) return 0;
for (i = 0; i < state->session.peer_count; i++)
if (state->session.peers[i].state == DAT_SESSION_PEER_READY) return 1;
return 0;
}
#ifdef DAT_GUI_TEST_MEDIA
static int test_fm_audio_is_playing(gui_state_t *state)
{
gui_fm_voice_t *voice = (gui_fm_voice_t *)state->fm_voice_ptr;
int active;
if (!voice || !state->audio_device) return 0;
SDL_LockAudioDevice(state->audio_device);
active = voice->active;
SDL_UnlockAudioDevice(state->audio_device);
return active;
}
#endif
int main(void)
{
static gui_state_t left, right;
char root[1024];
char left_home[1024], right_home[1024], file_path[1200], destination[1200];
char feed_directory[1024];
uint8_t content_key[32];
uint16_t left_port, right_port;
Uint32 now;
int elapsed;
#ifdef _WIN32
WSADATA winsock;
int fixture_attempt;
assert(WSAStartup(MAKEWORD(2, 2), &winsock) == 0);
for (fixture_attempt = 0; fixture_attempt < 1000; fixture_attempt++) {
assert(snprintf(root, sizeof(root), "build/windows/test-gui-p2p-%ld-%d",
(long)test_pid(), fixture_attempt) < (int)sizeof(root));
if (test_mkdir(root) == 0) break;
}
assert(fixture_attempt < 1000);
#else
strcpy(root, "/tmp/ddat-gui-p2p-XXXXXX");
#endif
memset(&left, 0, sizeof(left));
memset(&right, 0, sizeof(right));
left_port = unused_udp_port();
right_port = unused_udp_port();
if (right_port == left_port) right_port = (uint16_t)(left_port + 1);
#ifndef _WIN32
assert(mkdtemp(root) != NULL);
#endif
assert(snprintf(file_path, sizeof(file_path), "%s/payload.txt", root) <
(int)sizeof(file_path));
{
FILE *file = fopen(file_path, "wb");
assert(file != NULL);
assert(fputs("a real GUI Cesspool to uTP to SLEEP block", file) >= 0);
assert(fclose(file) == 0);
}
assert(snprintf(left_home, sizeof(left_home), "%s/left-home", root) < (int)sizeof(left_home));
assert(snprintf(right_home, sizeof(right_home), "%s/right-home", root) < (int)sizeof(right_home));
assert(test_mkdir(left_home) == 0);
assert(test_mkdir(right_home) == 0);
assert(snprintf(destination, sizeof(destination), "%s/download", root) < (int)sizeof(destination));
assert(test_mkdir(destination) == 0);
assert(test_setenv("HOME", left_home) == 0);
assert(test_setenv("USERPROFILE", left_home) == 0);
#ifdef DAT_GUI_TEST_MEDIA
assert(SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO) == 0);
#else
assert(SDL_Init(SDL_INIT_TIMER) == 0);
#endif
assert(dat_scheme_runtime_init(&left.metadata_scheme) == 0);
strcpy(left.archive_path, root);
strcpy(right.archive_path, destination);
assert(prepare_archive(&left) == 0);
assert(left.archive_open && left.version >= 1);
left.selected_version = 0;
assert(click_archive_version_bar(&left, 210, 80, 84));
assert(left.selected_version == 0);
assert(!click_archive_version_bar(&left, 209, 80, 84));
assert(!click_archive_version_bar(&left, 210, 73, 84));
assert(!click_archive_version_bar(&left, 242, 80, 84));
assert(click_archive_version_bar(&left, 226, 80, 84));
assert(left.selected_version == 1);
left.selected_version = left.version;
assert(click_archive_version_bar(&left, 226, 80, 84));
assert(left.selected_version == left.version);
assert(click_archive_version_bar(&left, 210, 80, 84));
assert(left.selected_version == left.version - 1);
{
dat_link_t link, parsed;
char address[DAT_LINK_BYTES];
memset(&link, 0, sizeof(link));
memcpy(link.key, left.archive_key_bytes, sizeof(link.key));
link.has_version = 1;
link.version = left.selected_version;
assert(dat_link_format(&link, address, sizeof(address)) == 0);
assert(dat_link_parse(address, &parsed) == 0);
assert(parsed.has_version && parsed.version == left.selected_version);
}
{
dat_archive_t source;
char uri[DAT_URL_BYTES];
assert(dat_archive_open(&source, root) == 0);
memcpy(right.remote_metadata_key, source.metadata_key, sizeof(right.remote_metadata_key));
right.remote_key_valid = 1;
assert(dat_key_to_url(source.metadata_key, uri) == 0);
strcpy(right.remote_address, uri);
strcpy(right.remote_archive, uri + 6);
strcpy(right.remote_site, "P2P TEST SOURCE");
strcpy(right.remote_version, "LATEST");
assert(strlen(destination) + sizeof("/.dat") <= sizeof(feed_directory));
strcpy(feed_directory, destination);
strcat(feed_directory, "/.dat");
memcpy(content_key, source.content_key, sizeof(content_key));
dat_archive_close(&source);
}
assert(sleep_crypto_init() == 0);
set_network_environment(left_port, right_port);
network_start(&left);
assert(left.network_requested && left.session_initialized);
assert(!left.online); /* Reachability starts false until a response arrives. */
assert(test_setenv("HOME", right_home) == 0);
assert(test_setenv("USERPROFILE", right_home) == 0);
set_network_environment(right_port, left_port);
network_start_remote_import(&right);
assert(right.network_requested && right.session_initialized);
assert(!right.online);
assert(!memcmp(right.identity.pubkey, right.pool.net.peerid, 32));
for (elapsed = 0; elapsed < 12000; elapsed++) {
now = SDL_GetTicks();
network_pump(&left, now);
if (memcmp(right.identity.pubkey, right.pool.net.peerid, 32)) {
fprintf(stderr, "left client pump overwrote right Cesspool identity at %d ms\\n", elapsed);
abort();
}
network_pump(&right, now);
if (memcmp(right.identity.pubkey, right.pool.net.peerid, 32)) {
size_t changed;
for (changed = 0; changed < 32 &&
right.identity.pubkey[changed] == right.pool.net.peerid[changed]; changed++) {}
fprintf(stderr, "right identity changed during P2P pump at %d ms: byte %lu %02x -> %02x pool=%d online=%d status=%s\n",
elapsed, (unsigned long)changed, right.identity.pubkey[changed],
right.pool.net.peerid[changed], right.pool_initialized, right.online,
right.network_status);
abort();
}
if (peer_ready(&left) && peer_ready(&right) && right.session.content_key_known &&
sleep_feed_has(&right.content_feed, 1)) break;
pause_one_millisecond();
}
if (!peer_ready(&left) || !peer_ready(&right)) {
fprintf(stderr, "peer setup timeout: L=%02x%02x R=%02x%02x left discovered=%lu peers=%lu ps=%d mask=%u rx=%lu tx=%llu/%llu status=%s; right discovered=%lu peers=%lu ps=%d mask=%u rx=%lu tx=%llu/%llu status=%s\n",
left.identity.pubkey[0],left.identity.pubkey[1],right.identity.pubkey[0],right.identity.pubkey[1],
(unsigned long)discovered_peer_count(&left),
(unsigned long)left.session.peer_count,
left.session.peers[0].state, left.session.peers[0].remote_feed_mask,
(unsigned long)left.session.peers[0].rx_buffer_len,
(unsigned long long)left.bytes_received,
(unsigned long long)left.bytes_sent, left.network_status,
(unsigned long)discovered_peer_count(&right),
(unsigned long)right.session.peer_count,
right.session.peers[0].state, right.session.peers[0].remote_feed_mask,
(unsigned long)right.session.peers[0].rx_buffer_len,
(unsigned long long)right.bytes_received,
(unsigned long long)right.bytes_sent, right.network_status);
for (size_t i = 0; i < GUI_TRANSPORT_MAX; i++) {
if (left.transports[i].used)
fprintf(stderr, "left transport %lu state=%d wait=%d auth=%d hello=%d/%d ack=%d/%d seq=%u recv=%u inflight=%lu\n",
(unsigned long)i, left.transports[i].utp.state,
left.transports[i].waiting_incoming, left.transports[i].authenticated,
left.transports[i].hello_sent, left.transports[i].hello_received,
left.transports[i].ack_sent, left.transports[i].ack_received,
left.transports[i].utp.sequence, left.transports[i].utp.acknowledgement,
(unsigned long)left.transports[i].utp.bytes_in_flight);
if (right.transports[i].used)
fprintf(stderr, "right transport %lu state=%d wait=%d auth=%d hello=%d/%d ack=%d/%d seq=%u recv=%u inflight=%lu\n",
(unsigned long)i, right.transports[i].utp.state,
right.transports[i].waiting_incoming, right.transports[i].authenticated,
right.transports[i].hello_sent, right.transports[i].hello_received,
right.transports[i].ack_sent, right.transports[i].ack_received,
right.transports[i].utp.sequence, right.transports[i].utp.acknowledgement,
(unsigned long)right.transports[i].utp.bytes_in_flight);
}
for (size_t i = 0; i < left.pool.peer_count; i++)
fprintf(stderr, "left known peer %lu port=%u topic=%d\n", (unsigned long)i,
ntohs(((struct sockaddr_in *)&left.pool.peers[i].address.addr)->sin_port),
!memcmp(left.pool.peers[i].discovery_topic, left.discovery_topic, 32));
for (size_t i = 0; i < right.pool.peer_count; i++)
fprintf(stderr, "right known peer %lu port=%u topic=%d\n", (unsigned long)i,
ntohs(((struct sockaddr_in *)&right.pool.peers[i].address.addr)->sin_port),
!memcmp(right.pool.peers[i].discovery_topic, right.discovery_topic, 32));
abort();
}
assert(right.content_feed.length > 1);
assert(left.session.peers[0].payload_bytes_sent > 0);
assert(right.session.peers[0].payload_bytes_received > 0);
assert(sleep_feed_has(&right.content_feed, 1));
if (!transport_by_id(&left, right.identity.pubkey)) {
fprintf(stderr, "identity mismatch: L identity=%02x pool=%02x session=%02x; R identity=%02x pool=%02x session=%02x\n",
left.identity.pubkey[0], left.pool.net.peerid[0], left.session.peer_id[0],
right.identity.pubkey[0], right.pool.net.peerid[0], right.session.peer_id[0]);
for (size_t i = 0; i < GUI_TRANSPORT_MAX; i++)
fprintf(stderr, "left transport slot %lu used=%d state=%d auth=%d peer=%02x expected=%02x sessionpeer=%02x session=%d\n",
(unsigned long)i, left.transports[i].used, left.transports[i].utp.state,
left.transports[i].authenticated, left.transports[i].peer_id[0],
right.identity.pubkey[0], left.session.peers[0].peer_id[0],
left.session.peers[0].state);
abort();
}
assert(transport_by_id(&left, right.identity.pubkey)->authenticated);
assert(transport_by_id(&right, left.identity.pubkey) != NULL);
assert(transport_by_id(&right, left.identity.pubkey)->authenticated);
transfer_disconnect(&left, 0, 0);
assert(left.transfer_paused[0] && left.session.peers[0].paused);
assert(peer_ready(&left) && peer_ready(&right));
transfer_resume(&left, 0);
assert(!left.transfer_paused[0] && !left.session.peers[0].paused);
for (elapsed = 0; elapsed < 5000; elapsed++) {
now = SDL_GetTicks();
network_pump(&left, now);
network_pump(&right, now);
if (peer_ready(&left) && peer_ready(&right)) break;
pause_one_millisecond();
}
if (!peer_ready(&left) || !peer_ready(&right))
fprintf(stderr, "resume timeout IDs=%02x/%02x: left session=%d transport=%d/%d wait=%d auth=%d hello=%d/%d ack=%d/%d right session=%d transport=%d/%d wait=%d auth=%d hello=%d/%d ack=%d/%d statuses=%s | %s\n",
left.identity.pubkey[0], right.identity.pubkey[0],
left.session.peers[0].state, left.transports[0].used,
left.transports[0].utp.state, left.transports[0].waiting_incoming,
left.transports[0].authenticated, left.transports[0].hello_sent,
left.transports[0].hello_received, left.transports[0].ack_sent,
left.transports[0].ack_received, right.session.peers[0].state,
right.transports[0].used, right.transports[0].utp.state,
right.transports[0].waiting_incoming, right.transports[0].authenticated,
right.transports[0].hello_sent, right.transports[0].hello_received,
right.transports[0].ack_sent, right.transports[0].ack_received,
left.network_status, right.network_status);
assert(peer_ready(&left) && peer_ready(&right));
assert(left.online && right.online);
memcpy(left.chat_peer_id,right.identity.pubkey,32);
left.chat_open=1;strcpy(left.chat_input,"hello from cable over the authenticated peer link");
if (cable_chat_send(&left) != 0) {
gui_transport_peer_t *chat_transport = transport_by_id(&left, left.chat_peer_id);
fprintf(stderr, "chat after resume: transport=%p used=%d auth=%d utp=%d session=%d errno=%d\n",
(void *)chat_transport, chat_transport ? chat_transport->used : 0,
chat_transport ? chat_transport->authenticated : 0,
chat_transport ? chat_transport->utp.state : 0,
left.session.peers[0].state, errno);
abort();
}
for(elapsed=0;elapsed<3000;elapsed++){
now=SDL_GetTicks();network_pump(&left,now);network_pump(&right,now);
if(right.chat_line_count)break;
pause_one_millisecond();
}
assert(right.chat_line_count==1);
assert(!strcmp(right.chat_lines[0].text,"hello from cable over the authenticated peer link"));
assert(!right.chat_lines[0].outgoing);
{
uint8_t *received = NULL;
size_t received_length = 0;
dat_archive_t downloaded;
sleep_metadata_entry_t entry;
const char expected[] = "a real GUI Cesspool to uTP to SLEEP block";
assert(dat_archive_open(&downloaded, destination) == 0);
assert(dat_archive_find(&downloaded, "payload.txt", &entry) == 0);
assert(dat_archive_read_file(&downloaded, &entry, &received, &received_length) == 0);
assert(received_length == sizeof(expected) - 1);
assert(!memcmp(received, expected, received_length));
free(received);
received = NULL;
dat_archive_close(&downloaded);
assert(sleep_feed_read(&right.content_feed, 1, &received, &received_length) == 0);
/* A content feed block is not the same thing as one source file: the
* archive reader reconstructs files from metadata offsets and blocks. */
assert(received_length > 0);
free(received);
}
sleep_feed_close(&right.content_feed);
assert(sleep_feed_open_remote(&right.content_feed, feed_directory,
"content", content_key) == 0);
assert(sleep_feed_has(&right.content_feed, 1));
{
sleep_feed_t restored;
memset(&restored, 0, sizeof(restored));
strcpy(restored.directory, feed_directory);
strcpy(restored.name, "content");
assert(sleep_feed_load_remote(&restored, content_key) == 0);
assert(sleep_feed_has(&restored, 1));
sleep_feed_close(&restored);
}
#ifdef DAT_GUI_TEST_MEDIA
left.audio_enabled = 1;
fm_audio_start(&left);
assert(left.audio_device != 0);
audio_cue_broadcast(&right, 1);
for (elapsed = 0; elapsed < 2000; elapsed++) {
now = SDL_GetTicks();
network_pump(&left, now);
network_pump(&right, now);
if (((gui_fm_voice_t *)left.fm_voice_ptr)->dolphin && test_fm_audio_is_playing(&left)) break;
pause_one_millisecond();
}
assert(((gui_fm_voice_t *)left.fm_voice_ptr)->dolphin);
assert(test_fm_audio_is_playing(&left));
fm_audio_play(&left);
assert(test_fm_audio_is_playing(&left));
SDL_Delay(2100);
assert(!test_fm_audio_is_playing(&left));
fm_audio_stop(&left);
#endif
network_stop(&right);
network_stop(&left);
dat_scheme_runtime_close(&left.metadata_scheme);
SDL_Quit();
#ifdef _WIN32
WSACleanup();
#endif
#ifdef DAT_GUI_TEST_MEDIA
puts("dat-thang authenticated Cesspool transfer, chat, and dolphin cue: PASS");
#else
puts("dat-thang authenticated Cesspool archive transfer, pause/resume, and chat: PASS");
#endif
return 0;
}