Apertur-SDK

 view release on metacpan or  search on metacpan

t/01_client.t  view on Meta::CPAN

use_ok('Apertur::SDK::Resource::Uploads');
use_ok('Apertur::SDK::Resource::Polling');
use_ok('Apertur::SDK::Resource::Destinations');
use_ok('Apertur::SDK::Resource::Keys');
use_ok('Apertur::SDK::Resource::Webhooks');
use_ok('Apertur::SDK::Resource::Encryption');
use_ok('Apertur::SDK::Resource::Stats');

# --- Constructor ---

my $client = Apertur::SDK->new(api_key => 'aptr_live_test123');
isa_ok($client, 'Apertur::SDK');
is($client->env, 'live', 'live key detected as live env');

my $test_client = Apertur::SDK->new(api_key => 'aptr_test_abc');
is($test_client->env, 'test', 'test key detected as test env');

# Require at least one auth method
eval { Apertur::SDK->new() };
like($@, qr/api_key or oauth_token/, 'dies without credentials');

# OAuth token constructor
my $oauth_client = Apertur::SDK->new(oauth_token => 'some_oauth_token');
isa_ok($oauth_client, 'Apertur::SDK');
is($oauth_client->env, 'live', 'non-prefixed oauth token defaults to live');

# --- Resource accessors ---

isa_ok($client->sessions,     'Apertur::SDK::Resource::Sessions');
isa_ok($client->upload,       'Apertur::SDK::Resource::Upload');
isa_ok($client->uploads,      'Apertur::SDK::Resource::Uploads');
isa_ok($client->polling,      'Apertur::SDK::Resource::Polling');
isa_ok($client->destinations, 'Apertur::SDK::Resource::Destinations');
isa_ok($client->keys,         'Apertur::SDK::Resource::Keys');
isa_ok($client->webhooks,     'Apertur::SDK::Resource::Webhooks');
isa_ok($client->encryption,   'Apertur::SDK::Resource::Encryption');
isa_ok($client->stats,        'Apertur::SDK::Resource::Stats');

# --- Error classes ---

subtest 'Error hierarchy' => sub {
    plan tests => 17;

    my $base = Apertur::SDK::Error->new(
        status_code => 500,
        code        => 'INTERNAL',
        message     => 'Server error',
    );
    isa_ok($base, 'Apertur::SDK::Error');
    is($base->status_code, 500,            'base status_code');
    is($base->code,        'INTERNAL',     'base code');
    is($base->message,     'Server error', 'base message');

    my $auth = Apertur::SDK::Error::Authentication->new(message => 'Bad key');
    isa_ok($auth, 'Apertur::SDK::Error::Authentication');
    isa_ok($auth, 'Apertur::SDK::Error');
    is($auth->status_code, 401, 'auth status_code');

    my $nf = Apertur::SDK::Error::NotFound->new();
    isa_ok($nf, 'Apertur::SDK::Error');
    is($nf->status_code, 404,         'not found status_code');
    is($nf->message,     'Not found', 'not found default message');

    my $rl = Apertur::SDK::Error::RateLimit->new(
        message     => 'Slow down',
        retry_after => 30,
    );
    isa_ok($rl, 'Apertur::SDK::Error');
    is($rl->status_code,  429,         'rate limit status_code');
    is($rl->retry_after,  30,          'rate limit retry_after');

    my $val = Apertur::SDK::Error::Validation->new(message => 'Bad input');
    isa_ok($val, 'Apertur::SDK::Error');
    is($val->status_code, 400, 'validation status_code');

    # Test throw mechanism
    eval { Apertur::SDK::Error::NotFound->throw(message => 'Gone') };
    my $caught = $@;
    isa_ok($caught, 'Apertur::SDK::Error::NotFound');
    is($caught->message, 'Gone', 'thrown error message');
};

# --- Signature verification ---

subtest 'Signature verification' => sub {
    plan tests => 6;

    use Apertur::SDK::Signature qw(
        verify_webhook_signature
        verify_event_signature
        verify_svix_signature
    );

    # Webhook signature
    my $secret = 'my_secret';
    my $body   = '{"event":"test"}';

    use Digest::SHA qw(hmac_sha256_hex);
    my $sig_hex = hmac_sha256_hex($body, $secret);
    ok(
        verify_webhook_signature($body, "sha256=$sig_hex", $secret),
        'valid webhook signature accepted',
    );
    ok(
        !verify_webhook_signature($body, 'sha256=bad', $secret),
        'invalid webhook signature rejected',
    );

    # Event signature
    my $timestamp = '1700000000';
    my $event_sig = hmac_sha256_hex("${timestamp}.${body}", $secret);
    ok(
        verify_event_signature($body, $timestamp, "sha256=$event_sig", $secret),
        'valid event signature accepted',
    );
    ok(
        !verify_event_signature($body, $timestamp, 'sha256=bad', $secret),
        'invalid event signature rejected',
    );

    # Svix signature



( run in 1.832 second using v1.01-cache-2.11-cpan-97f6503c9c8 )