mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[client] transport: test fallback lifecycle
This commit is contained in:
@@ -144,6 +144,39 @@ foreach(name IN LISTS MOUSE_CASES)
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_executable(transport-fallback-tests
|
||||
transport_fallback_test.c
|
||||
../src/transport_fallback.c
|
||||
)
|
||||
target_include_directories(transport-fallback-tests PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
|
||||
)
|
||||
target_link_libraries(transport-fallback-tests
|
||||
${EXE_FLAGS}
|
||||
lg_common
|
||||
)
|
||||
if(ENABLE_AUDIO)
|
||||
target_compile_definitions(transport-fallback-tests PRIVATE
|
||||
ENABLE_AUDIO
|
||||
)
|
||||
endif()
|
||||
set(TRANSPORT_FALLBACK_CASES
|
||||
graceful
|
||||
dead
|
||||
mismatch
|
||||
revoke
|
||||
retry
|
||||
cancel
|
||||
)
|
||||
foreach(name IN LISTS TRANSPORT_FALLBACK_CASES)
|
||||
add_test(NAME transport-fallback-${name}
|
||||
COMMAND transport-fallback-tests ${name}
|
||||
)
|
||||
set_tests_properties(transport-fallback-${name} PROPERTIES
|
||||
TIMEOUT 10
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_executable(render-queue-tests
|
||||
render_queue_test.c
|
||||
../src/render_queue.c
|
||||
|
||||
613
client/tests/transport_fallback_test.c
Normal file
613
client/tests/transport_fallback_test.c
Normal file
@@ -0,0 +1,613 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "transport_fallback.h"
|
||||
#include "test.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TEST_WAIT_MS 3000U
|
||||
#define TEST_ALARM_S 5U
|
||||
|
||||
struct LG_Transport
|
||||
{
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
struct ProviderTrace
|
||||
{
|
||||
atomic_uint set;
|
||||
atomic_uint clear;
|
||||
atomic_uint drop;
|
||||
};
|
||||
|
||||
struct TransportTrace
|
||||
{
|
||||
atomic_uint make;
|
||||
atomic_uint free;
|
||||
atomic_uint conn;
|
||||
atomic_uint disc;
|
||||
atomic_uint attach;
|
||||
atomic_uint detach;
|
||||
atomic_uint on;
|
||||
atomic_uint off;
|
||||
atomic_uint getInput;
|
||||
atomic_uint getAudio;
|
||||
atomic_uint getClipboard;
|
||||
atomic_bool alive;
|
||||
atomic_bool hold;
|
||||
atomic_bool release;
|
||||
atomic_bool cancel;
|
||||
atomic_bool badProvider;
|
||||
atomic_uint_fast64_t connTime[4];
|
||||
unsigned int failConn;
|
||||
bool uuidValid;
|
||||
uint8_t uuid[16];
|
||||
};
|
||||
|
||||
struct EventTrace
|
||||
{
|
||||
atomic_uint conn;
|
||||
atomic_uint disc;
|
||||
atomic_uint mismatch;
|
||||
LG_TransportSession session;
|
||||
uint8_t primary[16];
|
||||
uint8_t fallback[16];
|
||||
};
|
||||
|
||||
static struct TransportTrace t;
|
||||
static struct EventTrace e;
|
||||
static struct ProviderTrace pInput;
|
||||
#ifdef ENABLE_AUDIO
|
||||
static struct ProviderTrace pAudio;
|
||||
#endif
|
||||
static struct ProviderTrace pClipboard;
|
||||
|
||||
static const uint8_t UUID_A[16] =
|
||||
{ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
|
||||
static const uint8_t UUID_B[16] =
|
||||
{ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f };
|
||||
|
||||
static uint64_t nowNS(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
CHECK(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
|
||||
return (uint64_t)ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
|
||||
}
|
||||
|
||||
static bool waitCount(const atomic_uint * count, unsigned int value)
|
||||
{
|
||||
for (unsigned int i = 0; i < TEST_WAIT_MS; ++i)
|
||||
{
|
||||
if (atomic_load(count) >= value)
|
||||
return true;
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool waitReady(const LG_TransportFallback * fallback)
|
||||
{
|
||||
for (unsigned int i = 0; i < TEST_WAIT_MS; ++i)
|
||||
{
|
||||
if (lgTransportFallback_ready(fallback))
|
||||
return true;
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void setRemote(const uint8_t uuid[16])
|
||||
{
|
||||
t.uuidValid = true;
|
||||
memcpy(t.uuid, uuid, sizeof(t.uuid));
|
||||
}
|
||||
|
||||
static bool fakeCreate(LG_Transport ** transport)
|
||||
{
|
||||
LG_Transport * result = calloc(1, sizeof(*result));
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
result->id = atomic_fetch_add(&t.make, 1) + 1;
|
||||
*transport = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void fakeDestroy(LG_Transport ** transport)
|
||||
{
|
||||
CHECK(transport);
|
||||
CHECK(*transport);
|
||||
atomic_fetch_add(&t.free, 1);
|
||||
free(*transport);
|
||||
*transport = NULL;
|
||||
}
|
||||
|
||||
static LG_TransportStatus fakeConnect(LG_Transport * transport,
|
||||
LG_TransportSession * session, LG_TransportCancelledFn cancelled,
|
||||
void * opaque)
|
||||
{
|
||||
CHECK(transport);
|
||||
CHECK(session);
|
||||
|
||||
const unsigned int no = atomic_load(&t.conn);
|
||||
if (no < 4)
|
||||
atomic_store(&t.connTime[no], nowNS());
|
||||
atomic_fetch_add(&t.conn, 1);
|
||||
|
||||
while (atomic_load(&t.hold) && !atomic_load(&t.release))
|
||||
{
|
||||
if (cancelled && cancelled(opaque))
|
||||
{
|
||||
atomic_store(&t.cancel, true);
|
||||
return LG_TRANSPORT_UNAVAILABLE;
|
||||
}
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
if (no < t.failConn)
|
||||
return LG_TRANSPORT_UNAVAILABLE;
|
||||
|
||||
*session = (LG_TransportSession) { 0 };
|
||||
memcpy(session->version, "fallback-test", sizeof("fallback-test"));
|
||||
memcpy(session->name, "fallback", sizeof("fallback"));
|
||||
session->uuidValid = t.uuidValid;
|
||||
memcpy(session->uuid, t.uuid, sizeof(session->uuid));
|
||||
atomic_store(&t.alive, true);
|
||||
return LG_TRANSPORT_OK;
|
||||
}
|
||||
|
||||
static void fakeDisconnect(LG_Transport * transport)
|
||||
{
|
||||
CHECK(transport);
|
||||
atomic_store(&t.alive, false);
|
||||
atomic_fetch_add(&t.disc, 1);
|
||||
}
|
||||
|
||||
static bool fakeValid(LG_Transport * transport)
|
||||
{
|
||||
CHECK(transport);
|
||||
return atomic_load(&t.alive);
|
||||
}
|
||||
|
||||
static bool fakeAttach(LG_Transport * transport,
|
||||
const LG_SwSurfaceEventOps * events, void * opaque)
|
||||
{
|
||||
CHECK(transport);
|
||||
CHECK(events);
|
||||
atomic_fetch_add(&t.attach, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void fakeDetach(LG_Transport * transport)
|
||||
{
|
||||
CHECK(transport);
|
||||
atomic_fetch_add(&t.detach, 1);
|
||||
}
|
||||
|
||||
static bool fakeActive(LG_Transport * transport, bool active)
|
||||
{
|
||||
CHECK(transport);
|
||||
atomic_fetch_add(active ? &t.on : &t.off, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const LG_InputOps inputOps =
|
||||
{
|
||||
.name = "fake",
|
||||
};
|
||||
|
||||
static const LG_AudioOps audioOps =
|
||||
{
|
||||
.name = "fake",
|
||||
};
|
||||
|
||||
static const LG_ClipboardOps clipboardOps =
|
||||
{
|
||||
.name = "fake",
|
||||
};
|
||||
|
||||
static const LG_InputOps * fakeGetInput(
|
||||
LG_Transport * transport, void ** opaque)
|
||||
{
|
||||
atomic_fetch_add(&t.getInput, 1);
|
||||
*opaque = transport;
|
||||
return &inputOps;
|
||||
}
|
||||
|
||||
static const LG_AudioOps * fakeGetAudio(
|
||||
LG_Transport * transport, void ** opaque)
|
||||
{
|
||||
atomic_fetch_add(&t.getAudio, 1);
|
||||
*opaque = transport;
|
||||
return &audioOps;
|
||||
}
|
||||
|
||||
static const LG_ClipboardOps * fakeGetClipboard(
|
||||
LG_Transport * transport, void ** opaque)
|
||||
{
|
||||
atomic_fetch_add(&t.getClipboard, 1);
|
||||
*opaque = transport;
|
||||
return &clipboardOps;
|
||||
}
|
||||
|
||||
static const LG_SwSurfaceOps surfaceOps =
|
||||
{
|
||||
.attach = fakeAttach,
|
||||
.detach = fakeDetach,
|
||||
.setActive = fakeActive,
|
||||
};
|
||||
|
||||
static const LG_VideoOps videoOps =
|
||||
{
|
||||
.name = "fake",
|
||||
.type = LG_VIDEO_TYPE_SW_SURFACE,
|
||||
.swSurface = &surfaceOps,
|
||||
};
|
||||
|
||||
static const LG_VideoOps * fakeGetVideo(LG_Transport * transport)
|
||||
{
|
||||
CHECK(transport);
|
||||
return &videoOps;
|
||||
}
|
||||
|
||||
static const LG_TransportOps transportOps =
|
||||
{
|
||||
.name = "fake",
|
||||
.create = fakeCreate,
|
||||
.destroy = fakeDestroy,
|
||||
.connectCancellable = fakeConnect,
|
||||
.disconnect = fakeDisconnect,
|
||||
.sessionValid = fakeValid,
|
||||
.getVideoOps = fakeGetVideo,
|
||||
.getInputOps = fakeGetInput,
|
||||
.getAudioOps = fakeGetAudio,
|
||||
.getClipboardOps = fakeGetClipboard,
|
||||
};
|
||||
|
||||
bool lgTransport_isValid(const char * name)
|
||||
{
|
||||
return name && strcmp(name, transportOps.name) == 0;
|
||||
}
|
||||
|
||||
bool lgTransport_create(const char * name, LG_TransportInstance * instance)
|
||||
{
|
||||
if (!instance || !lgTransport_isValid(name))
|
||||
return false;
|
||||
|
||||
*instance = (LG_TransportInstance) { 0 };
|
||||
if (!transportOps.create(&instance->handle))
|
||||
return false;
|
||||
instance->ops = &transportOps;
|
||||
return true;
|
||||
}
|
||||
|
||||
void lgTransport_destroy(LG_TransportInstance * instance)
|
||||
{
|
||||
CHECK(instance);
|
||||
if (instance->ops)
|
||||
instance->ops->destroy(&instance->handle);
|
||||
*instance = (LG_TransportInstance) { 0 };
|
||||
}
|
||||
|
||||
static void setProvider(struct ProviderTrace * trace, const void * ops,
|
||||
const void * expected, void * opaque)
|
||||
{
|
||||
if (ops)
|
||||
{
|
||||
atomic_fetch_add(&trace->set, 1);
|
||||
if (ops != expected || !opaque)
|
||||
atomic_store(&t.badProvider, true);
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_fetch_add(&trace->clear, 1);
|
||||
if (opaque)
|
||||
atomic_store(&t.badProvider, true);
|
||||
}
|
||||
|
||||
void lgInput_setFallback(const LG_InputOps * ops, void * opaque)
|
||||
{
|
||||
setProvider(&pInput, ops, &inputOps, opaque);
|
||||
}
|
||||
|
||||
void lgInput_dropFallback(void)
|
||||
{
|
||||
atomic_fetch_add(&pInput.drop, 1);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_AUDIO
|
||||
void lgAudio_setFallback(const LG_AudioOps * ops, void * opaque)
|
||||
{
|
||||
setProvider(&pAudio, ops, &audioOps, opaque);
|
||||
}
|
||||
|
||||
void lgAudio_dropFallback(void)
|
||||
{
|
||||
atomic_fetch_add(&pAudio.drop, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void lgClipboard_setFallback(const LG_ClipboardOps * ops, void * opaque)
|
||||
{
|
||||
setProvider(&pClipboard, ops, &clipboardOps, opaque);
|
||||
}
|
||||
|
||||
void lgClipboard_dropFallback(void)
|
||||
{
|
||||
atomic_fetch_add(&pClipboard.drop, 1);
|
||||
}
|
||||
|
||||
static void onConnected(void * opaque,
|
||||
const LG_TransportSession * session)
|
||||
{
|
||||
CHECK(opaque == &e);
|
||||
e.session = *session;
|
||||
atomic_fetch_add(&e.conn, 1);
|
||||
}
|
||||
|
||||
static void onDisconnected(void * opaque)
|
||||
{
|
||||
CHECK(opaque == &e);
|
||||
atomic_fetch_add(&e.disc, 1);
|
||||
}
|
||||
|
||||
static void onMismatch(void * opaque, const uint8_t primary[16],
|
||||
const uint8_t fallback[16])
|
||||
{
|
||||
CHECK(opaque == &e);
|
||||
memcpy(e.primary, primary, sizeof(e.primary));
|
||||
memcpy(e.fallback, fallback, sizeof(e.fallback));
|
||||
atomic_fetch_add(&e.mismatch, 1);
|
||||
}
|
||||
|
||||
static LG_TransportFallback * start(const uint8_t primary[16])
|
||||
{
|
||||
static const LG_SwSurfaceEventOps surfaceEvents = { 0 };
|
||||
static const LG_TransportFallbackEventOps eventOps =
|
||||
{
|
||||
.connected = onConnected,
|
||||
.disconnected = onDisconnected,
|
||||
.uuidMismatch = onMismatch,
|
||||
};
|
||||
|
||||
LG_TransportFallback * fallback = NULL;
|
||||
CHECK(lgTransportFallback_start("fake", &surfaceEvents, NULL,
|
||||
&eventOps, &e, primary, &fallback));
|
||||
CHECK(fallback);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
static void checkPublished(unsigned int set, unsigned int clear,
|
||||
unsigned int drop)
|
||||
{
|
||||
CHECK(atomic_load(&t.getInput) == set);
|
||||
CHECK(atomic_load(&t.getAudio) == set);
|
||||
CHECK(atomic_load(&t.getClipboard) == set);
|
||||
CHECK(atomic_load(&pInput.set) == set);
|
||||
CHECK(atomic_load(&pInput.clear) == clear);
|
||||
CHECK(atomic_load(&pInput.drop) == drop);
|
||||
#ifdef ENABLE_AUDIO
|
||||
CHECK(atomic_load(&pAudio.set) == set);
|
||||
CHECK(atomic_load(&pAudio.clear) == clear);
|
||||
CHECK(atomic_load(&pAudio.drop) == drop);
|
||||
#endif
|
||||
CHECK(atomic_load(&pClipboard.set) == set);
|
||||
CHECK(atomic_load(&pClipboard.clear) == clear);
|
||||
CHECK(atomic_load(&pClipboard.drop) == drop);
|
||||
CHECK(!atomic_load(&t.badProvider));
|
||||
}
|
||||
|
||||
static void testGraceful(void)
|
||||
{
|
||||
setRemote(UUID_A);
|
||||
atomic_store(&t.hold, true);
|
||||
|
||||
LG_TransportFallback * fallback = start(UUID_A);
|
||||
CHECK(waitCount(&t.conn, 1));
|
||||
lgTransportFallback_requestVideoActive(fallback, true);
|
||||
CHECK(lgTransportFallback_videoRequested(fallback));
|
||||
atomic_store(&t.release, true);
|
||||
CHECK(waitReady(fallback));
|
||||
CHECK(waitCount(&e.conn, 1));
|
||||
|
||||
CHECK(lgTransportFallback_admitted(fallback));
|
||||
CHECK(atomic_load(&t.on) == 1);
|
||||
CHECK(memcmp(e.session.uuid, UUID_A, sizeof(UUID_A)) == 0);
|
||||
checkPublished(1, 0, 0);
|
||||
|
||||
lgTransportFallback_stop(&fallback);
|
||||
CHECK(!fallback);
|
||||
CHECK(atomic_load(&e.conn) == 1);
|
||||
CHECK(atomic_load(&e.disc) == 1);
|
||||
CHECK(atomic_load(&t.off) == 1);
|
||||
CHECK(atomic_load(&t.detach) == 1);
|
||||
CHECK(atomic_load(&t.disc) == 1);
|
||||
CHECK(atomic_load(&t.free) == 1);
|
||||
checkPublished(1, 1, 0);
|
||||
}
|
||||
|
||||
static void testDead(void)
|
||||
{
|
||||
setRemote(UUID_A);
|
||||
LG_TransportFallback * fallback = start(UUID_A);
|
||||
CHECK(waitReady(fallback));
|
||||
CHECK(waitCount(&e.conn, 1));
|
||||
|
||||
lgTransportFallback_requestVideoActive(fallback, true);
|
||||
CHECK(waitCount(&t.on, 1));
|
||||
atomic_store(&t.alive, false);
|
||||
lgTransportFallback_requestVideoActive(fallback, true);
|
||||
CHECK(waitCount(&e.disc, 1));
|
||||
|
||||
CHECK(!lgTransportFallback_ready(fallback));
|
||||
CHECK(!lgTransportFallback_admitted(fallback));
|
||||
CHECK(atomic_load(&t.off) == 0);
|
||||
checkPublished(1, 0, 1);
|
||||
|
||||
lgTransportFallback_stop(&fallback);
|
||||
CHECK(atomic_load(&e.disc) == 1);
|
||||
CHECK(atomic_load(&t.detach) == 1);
|
||||
CHECK(atomic_load(&t.disc) == 1);
|
||||
CHECK(atomic_load(&t.free) == 1);
|
||||
}
|
||||
|
||||
static void testMismatch(void)
|
||||
{
|
||||
setRemote(UUID_B);
|
||||
LG_TransportFallback * fallback = start(UUID_A);
|
||||
CHECK(waitCount(&t.free, 2));
|
||||
|
||||
CHECK(!lgTransportFallback_ready(fallback));
|
||||
CHECK(!lgTransportFallback_admitted(fallback));
|
||||
CHECK(atomic_load(&e.conn) == 0);
|
||||
CHECK(atomic_load(&e.disc) == 0);
|
||||
CHECK(atomic_load(&e.mismatch) == 1);
|
||||
CHECK(memcmp(e.primary, UUID_A, sizeof(UUID_A)) == 0);
|
||||
CHECK(memcmp(e.fallback, UUID_B, sizeof(UUID_B)) == 0);
|
||||
checkPublished(0, 0, 0);
|
||||
|
||||
lgTransportFallback_stop(&fallback);
|
||||
CHECK(atomic_load(&t.conn) == 2);
|
||||
CHECK(atomic_load(&t.attach) == 2);
|
||||
CHECK(atomic_load(&t.detach) == 2);
|
||||
CHECK(atomic_load(&t.disc) == 2);
|
||||
CHECK(atomic_load(&t.free) == 2);
|
||||
}
|
||||
|
||||
static void testRevoke(void)
|
||||
{
|
||||
setRemote(UUID_A);
|
||||
LG_TransportFallback * fallback = start(UUID_A);
|
||||
CHECK(waitReady(fallback));
|
||||
CHECK(waitCount(&e.conn, 1));
|
||||
|
||||
lgTransportFallback_setPrimaryUUID(fallback, UUID_B);
|
||||
lgTransportFallback_setPrimaryUUID(fallback, UUID_B);
|
||||
CHECK(waitCount(&t.free, 2));
|
||||
|
||||
CHECK(!lgTransportFallback_ready(fallback));
|
||||
CHECK(!lgTransportFallback_admitted(fallback));
|
||||
CHECK(atomic_load(&e.conn) == 1);
|
||||
CHECK(atomic_load(&e.disc) == 1);
|
||||
CHECK(atomic_load(&e.mismatch) == 1);
|
||||
CHECK(memcmp(e.primary, UUID_B, sizeof(UUID_B)) == 0);
|
||||
CHECK(memcmp(e.fallback, UUID_A, sizeof(UUID_A)) == 0);
|
||||
checkPublished(1, 0, 1);
|
||||
|
||||
lgTransportFallback_stop(&fallback);
|
||||
CHECK(atomic_load(&t.conn) == 2);
|
||||
CHECK(atomic_load(&t.detach) == 2);
|
||||
CHECK(atomic_load(&t.disc) == 2);
|
||||
CHECK(atomic_load(&t.free) == 2);
|
||||
}
|
||||
|
||||
static void testRetry(void)
|
||||
{
|
||||
setRemote(UUID_A);
|
||||
t.failConn = 2;
|
||||
LG_TransportFallback * fallback = start(UUID_A);
|
||||
CHECK(waitReady(fallback));
|
||||
CHECK(waitCount(&e.conn, 1));
|
||||
|
||||
const uint64_t first = atomic_load(&t.connTime[0]);
|
||||
const uint64_t second = atomic_load(&t.connTime[1]);
|
||||
const uint64_t third = atomic_load(&t.connTime[2]);
|
||||
CHECK(second - first >= UINT64_C(200000000));
|
||||
CHECK(third - second >= UINT64_C(400000000));
|
||||
CHECK(atomic_load(&t.conn) == 3);
|
||||
CHECK(atomic_load(&t.free) == 2);
|
||||
|
||||
lgTransportFallback_stop(&fallback);
|
||||
CHECK(atomic_load(&e.conn) == 1);
|
||||
CHECK(atomic_load(&e.disc) == 1);
|
||||
CHECK(atomic_load(&t.attach) == 3);
|
||||
CHECK(atomic_load(&t.detach) == 3);
|
||||
CHECK(atomic_load(&t.disc) == 3);
|
||||
CHECK(atomic_load(&t.free) == 3);
|
||||
checkPublished(1, 1, 0);
|
||||
}
|
||||
|
||||
static void testCancel(void)
|
||||
{
|
||||
setRemote(UUID_A);
|
||||
atomic_store(&t.hold, true);
|
||||
LG_TransportFallback * fallback = start(UUID_A);
|
||||
CHECK(waitCount(&t.conn, 1));
|
||||
|
||||
lgTransportFallback_stop(&fallback);
|
||||
CHECK(!fallback);
|
||||
CHECK(atomic_load(&t.cancel));
|
||||
CHECK(atomic_load(&e.conn) == 0);
|
||||
CHECK(atomic_load(&e.disc) == 0);
|
||||
CHECK(atomic_load(&t.attach) == 1);
|
||||
CHECK(atomic_load(&t.detach) == 1);
|
||||
CHECK(atomic_load(&t.disc) == 1);
|
||||
CHECK(atomic_load(&t.free) == 1);
|
||||
checkPublished(0, 0, 0);
|
||||
}
|
||||
|
||||
struct Test
|
||||
{
|
||||
const char * name;
|
||||
void (*run)(void);
|
||||
};
|
||||
|
||||
static const struct Test tests[] =
|
||||
{
|
||||
{ "graceful", testGraceful },
|
||||
{ "dead" , testDead },
|
||||
{ "mismatch", testMismatch },
|
||||
{ "revoke" , testRevoke },
|
||||
{ "retry" , testRetry },
|
||||
{ "cancel" , testCancel },
|
||||
};
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "usage: %s <case>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
alarm(TEST_ALARM_S);
|
||||
debug_init();
|
||||
for (unsigned int i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
|
||||
if (strcmp(argv[1], tests[i].name) == 0)
|
||||
{
|
||||
tests[i].run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "unknown test: %s\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
Reference in New Issue
Block a user