Skip to content

network/test_sg_client.cpp

Unit tests for SGJobSubmitter, SGResultCollector, and SGClient. More...

Functions

Name
TEST(SGJobSubmitter , DefaultConstructs )
TEST(SGJobSubmitter , RejectsOversizedPayload )
TEST(SGJobSubmitter , AcceptsMaxSizeMinusOne )
TEST(SGJobSubmitter , RejectsEmptyPayloadWithoutSDK )
TEST(SGResultCollector , DefaultConfigTimeoutIs120Seconds )
TEST(SGResultCollector , CustomTimeoutAccepted )
TEST(SGResultCollector , ShortTimeoutReturnsError )
TEST(SGResultCollector , AsyncPollCompletesGracefully )
TEST(SGResultCollector , DefaultTimeoutResolves )
TEST(SGResultCollector , MultipleInstancesIndependent )
TEST(SGClient , DefaultConfigMatchesNamedConstants )
TEST(SGClient , IsConnectedBeforeInitReturnsFalse )
TEST(SGClient , ConstructWithConfigDoesNotCrash )
TEST(SGClient , MoveConstructorTransfersOwnership )
TEST(SGClient , DisconnectBeforeInitDoesNotCrash )

Detailed Description

Unit tests for SGJobSubmitter, SGResultCollector, and SGClient.

Date: 2026-07-09

Functions Documentation

function TEST

TEST(
    SGJobSubmitter ,
    DefaultConstructs 
)

function TEST

TEST(
    SGJobSubmitter ,
    RejectsOversizedPayload 
)

function TEST

TEST(
    SGJobSubmitter ,
    AcceptsMaxSizeMinusOne 
)

function TEST

TEST(
    SGJobSubmitter ,
    RejectsEmptyPayloadWithoutSDK 
)

function TEST

TEST(
    SGResultCollector ,
    DefaultConfigTimeoutIs120Seconds 
)

function TEST

TEST(
    SGResultCollector ,
    CustomTimeoutAccepted 
)

function TEST

TEST(
    SGResultCollector ,
    ShortTimeoutReturnsError 
)

function TEST

TEST(
    SGResultCollector ,
    AsyncPollCompletesGracefully 
)

function TEST

TEST(
    SGResultCollector ,
    DefaultTimeoutResolves 
)

function TEST

TEST(
    SGResultCollector ,
    MultipleInstancesIndependent 
)

function TEST

TEST(
    SGClient ,
    DefaultConfigMatchesNamedConstants 
)

function TEST

TEST(
    SGClient ,
    IsConnectedBeforeInitReturnsFalse 
)

function TEST

TEST(
    SGClient ,
    ConstructWithConfigDoesNotCrash 
)

function TEST

TEST(
    SGClient ,
    MoveConstructorTransfersOwnership 
)

function TEST

TEST(
    SGClient ,
    DisconnectBeforeInitDoesNotCrash 
)

Source code

#include "network/sg_client/sg_job_submitter.hpp"
#include "network/sg_client/sg_result_collector.hpp"
#include "network/sg_client/super_genius_client.hpp"
#include "common/error.hpp"
#include "GeniusSDK.h"
#include <gtest/gtest.h>
#include <chrono>
#include <filesystem>
#include <future>

using namespace sgns::neoswarm::network;
using namespace sgns::neoswarm;

namespace
{
    constexpr auto kShortPollTimeout = std::chrono::seconds( 1 );      
    constexpr auto kPollCompletionSlack = std::chrono::seconds( 3 );   
    constexpr auto kDefaultCollectorTimeout = std::chrono::seconds( 120 ); 
    constexpr auto kCustomTimeout = std::chrono::seconds( 30 );        
} // namespace

// =======================================================================
// SGJobSubmitter
// =======================================================================

TEST( SGJobSubmitter, DefaultConstructs )
{
    SGJobSubmitter submitter;
}

TEST( SGJobSubmitter, RejectsOversizedPayload )
{
    SGJobSubmitter submitter;
    std::string largePayload( sizeof( JsonData_t ), 'x' );
    auto result = submitter.PublishJob( largePayload );
    ASSERT_FALSE( result.has_value() );
    EXPECT_NE( result.error(), Error::BroadcastTimeout );
}

TEST( SGJobSubmitter, AcceptsMaxSizeMinusOne )
{
    SGJobSubmitter submitter;
    std::string maxPayload( sizeof( JsonData_t ) - 1, 'x' );
    auto result = submitter.PublishJob( maxPayload );
    // Size check passes. Without SDK, dispatch fails — but NOT from InvalidArgument.
    ASSERT_FALSE( result.has_value() );
    EXPECT_NE( result.error(), Error::InvalidArgument );
}

TEST( SGJobSubmitter, RejectsEmptyPayloadWithoutSDK )
{
    SGJobSubmitter submitter;
    auto result = submitter.PublishJob( "" );
    ASSERT_FALSE( result.has_value() );
    EXPECT_NE( result.error(), Error::InvalidArgument );
}

// =======================================================================
// SGResultCollector
// =======================================================================

TEST( SGResultCollector, DefaultConfigTimeoutIs120Seconds )
{
    SGResultCollectorConfig cfg;
    EXPECT_EQ( cfg.m_resultTimeout, kDefaultCollectorTimeout );
}

TEST( SGResultCollector, CustomTimeoutAccepted )
{
    SGResultCollectorConfig cfg;
    cfg.m_resultTimeout = kCustomTimeout;
    SGResultCollector collector( cfg );
}

TEST( SGResultCollector, ShortTimeoutReturnsError )
{
    SGResultCollector collector;
    auto start = std::chrono::steady_clock::now();
    auto result = collector.PollForResult( kShortPollTimeout );
    auto elapsed = std::chrono::steady_clock::now() - start;

    ASSERT_FALSE( result.has_value() );
    // Should return within timeout window
    EXPECT_LE( elapsed, kPollCompletionSlack );
}

TEST( SGResultCollector, AsyncPollCompletesGracefully )
{
    SGResultCollectorConfig cfg;
    cfg.m_resultTimeout = kShortPollTimeout;
    SGResultCollector collector( cfg );
    auto future = collector.PollForResultAsync();
    auto status = future.wait_for( kPollCompletionSlack );
    EXPECT_EQ( status, std::future_status::ready );
}

TEST( SGResultCollector, DefaultTimeoutResolves )
{
    SGResultCollector collector;
    auto result = collector.PollForResult();
    // Without SDK, polling returns error — verify not a crash
    ASSERT_FALSE( result.has_value() );
}

TEST( SGResultCollector, MultipleInstancesIndependent )
{
    SGResultCollector collector1;
    SGResultCollector collector2;
    auto r1 = collector1.PollForResult( kShortPollTimeout );
    auto r2 = collector2.PollForResult( kShortPollTimeout );
    ASSERT_FALSE( r1.has_value() );
    ASSERT_FALSE( r2.has_value() );
}

// =======================================================================
// SGClient (lifecycle — post-02-05 API: m_geniusNodeConfig + m_resultTimeout,
// Initialize() takes no identity, SDK generates its own keypair)
// =======================================================================

TEST( SGClient, DefaultConfigMatchesNamedConstants )
{
    SGClient::Config cfg;
    // SGClient result deadline is kDefaultResultTimeoutSeconds (WR-02);
    // SGResultCollector's own default (120s) is overridden at construction.
    EXPECT_EQ( cfg.m_resultTimeout, std::chrono::seconds( kDefaultResultTimeoutSeconds ) );
    // BaseWritePath default is "./sdk" via GeniusNodeConfig default.
    EXPECT_EQ( cfg.m_geniusNodeConfig.BaseWritePath, "./sdk" );
}

TEST( SGClient, IsConnectedBeforeInitReturnsFalse )
{
    SGClient::Config cfg;
    SGClient client( std::move( cfg ) );
    EXPECT_FALSE( client.IsConnected() );
}

TEST( SGClient, ConstructWithConfigDoesNotCrash )
{
    SGClient::Config cfg;
    cfg.m_geniusNodeConfig.BaseWritePath =
        ( std::filesystem::temp_directory_path() / "test-sgclient-sdk" ).string();
    SGClient client( std::move( cfg ) );
    EXPECT_FALSE( client.IsConnected() );
}

TEST( SGClient, MoveConstructorTransfersOwnership )
{
    SGClient::Config cfg;
    cfg.m_geniusNodeConfig.BaseWritePath =
        ( std::filesystem::temp_directory_path() / "test-sgclient-sdk-move" ).string();
    SGClient client1( std::move( cfg ) );
    SGClient client2( std::move( client1 ) );
    // client2 owns the state; neither is initialized.
    EXPECT_FALSE( client2.IsConnected() );
    // Moved-from client1 has null m_impl — IsConnected() must be safe (no segfault).
    EXPECT_FALSE( client1.IsConnected() );
}

TEST( SGClient, DisconnectBeforeInitDoesNotCrash )
{
    SGClient::Config cfg;
    SGClient client( std::move( cfg ) );
    // Disconnect() on a never-initialized client must be safe (no SDK node up).
    client.Disconnect();
    EXPECT_FALSE( client.IsConnected() );
}

Updated on 2026-10-09 at 03:59:42 +0000