toxcore/auto_tests/friends_test.c
Chris Hall 4293c4b1e6 Messenger refactor - redid work from pull request 79
Moves static state out of Messenger.c and into a Messenger struct
Purely stylistic, no functional changes were made.

This commit also changed all the callers of Messenger as they now have
to pass an instance of the Messenger struct to messenger functions.

Also removed some uses of the 'static' keyword at the beginning of
function definitions when the function was already declared static, as
these caused gcc to whine.
2013-08-12 21:37:38 +12:00

228 lines
5.9 KiB
C
Executable File

/* Unit testing for friend requests, statuses, and messages.
* Purpose: Check that messaging functions actually do what
* they're supposed to by setting up two local clients.
*
* Design: (Subject to change.)
* 1. Parent sends a friend request, and waits for a response.
* It it doesn't get one, it kills the child.
* 2. Child gets friend request, accepts, then waits for a status change.
* 3. The parent waits on a status change, killing the child if it takes
* too long.
* 4. The child gets the status change, then sends a message. After that,
* it returns. If if doesn't get the status change, it just loops forever.
* 5. After getting the status change, the parent waits for a message, on getting
* one, it waits on the child to return, then returns 0.
*
* Note about "waiting":
* Wait time is decided by WAIT_COUNT and WAIT_TIME. c_sleep(WAIT_TIME) WAIT_COUNT
* times. This is used both to ensure that we don't loop forever on a broken build,
* and that we don't get too slow with messaging. The current time is 15 seconds. */
#include "../core/friend_requests.h"
#include "../core/Messenger.h"
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>
#include <sys/wait.h>
#define WAIT_COUNT 30
#define WAIT_TIME 500
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
/* first step, second step */
#define FIRST_FLAG 0x1
#define SECOND_FLAG 0x2
/* ensure that we sleep in milliseconds */
#ifdef WIN32
#define c_sleep(x) Sleep(x)
#else
#define c_sleep(x) usleep(1000*x)
#endif
static Messenger *m;
uint8_t *parent_id = NULL;
uint8_t *child_id = NULL;
pid_t child_pid = 0;
int request_flags = 0;
void do_tox(void)
{
static int dht_on = 0;
if(!dht_on && DHT_isconnected()) {
dht_on = 1;
} else if(dht_on && !DHT_isconnected()) {
dht_on = 0;
}
doMessenger(m);
}
void parent_confirm_message(Messenger *m, int num, uint8_t *data, uint16_t length)
{
puts("OK");
request_flags |= SECOND_FLAG;
}
void parent_confirm_status(Messenger *m, int num, uint8_t *data, uint16_t length)
{
puts("OK");
request_flags |= FIRST_FLAG;
}
int parent_friend_request(void)
{
char *message = "Watson, come here, I need you.";
int len = strlen(message);
int i = 0;
fputs("Sending child request.", stdout);
fflush(stdout);
m_addfriend(m, child_id, (uint8_t *)message, len);
/* wait on the status change */
for(i = 0; i < WAIT_COUNT; i++) {
do_tox();
if(request_flags & FIRST_FLAG)
break;
fputs(".", stdout);
fflush(stdout);
c_sleep(WAIT_TIME);
}
if(!(request_flags & FIRST_FLAG)) {
fputs("\nfriends_test: The child took to long to respond!\n"
"Friend requests may be broken, failing build!\n", stderr);
kill(child_pid, SIGKILL);
return -1;
}
return 0;
}
void child_got_request(uint8_t *public_key, uint8_t *data, uint16_t length)
{
fputs("OK\nsending status to parent", stdout);
fflush(stdout);
m_addfriend_norequest(m, public_key);
request_flags |= FIRST_FLAG;
}
void child_got_statuschange(Messenger *m, int friend_num, uint8_t *string, uint16_t length)
{
request_flags |= SECOND_FLAG;
}
int parent_wait_for_message(void)
{
int i = 0;
fputs("Parent waiting for message.", stdout);
fflush(stdout);
for(i = 0; i < WAIT_COUNT; i++) {
do_tox();
if(request_flags & SECOND_FLAG)
break;
fputs(".", stdout);
fflush(stdout);
c_sleep(WAIT_TIME);
}
if(!(request_flags & SECOND_FLAG)) {
fputs("\nParent hasn't received the message yet!\n"
"Messaging may be broken, failing the build!\n", stderr);
kill(child_pid, SIGKILL);
return -1;
}
return 0;
}
void cleanup(void)
{
munmap(parent_id, crypto_box_PUBLICKEYBYTES);
munmap(child_id, crypto_box_PUBLICKEYBYTES);
puts("============= END TEST =============");
}
int main(int argc, char *argv[])
{
puts("=========== FRIENDS_TEST ===========");
/* set up the global memory */
parent_id = mmap(NULL, crypto_box_PUBLICKEYBYTES, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
child_id = mmap(NULL, crypto_box_PUBLICKEYBYTES, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
fputs("friends_test: Starting test...\n", stdout);
if((child_pid = fork()) == 0) {
/* child */
int i = 0;
char *message = "Y-yes Mr. Watson?";
m = initMessenger();
Messenger_save(m, child_id);
msync(child_id, crypto_box_PUBLICKEYBYTES, MS_SYNC);
m_callback_friendrequest(m, child_got_request);
m_callback_statusmessage(m, child_got_statuschange);
/* wait on the friend request */
while(!(request_flags & FIRST_FLAG))
do_tox();
/* wait for the status change */
while(!(request_flags & SECOND_FLAG))
do_tox();
for(i = 0; i < 6; i++) {
/* send the message six times, just to be sure */
m_sendmessage(m, 0, (uint8_t *)message, strlen(message));
do_tox();
}
cleanupMessenger(m);
return 0;
}
/* parent */
if(atexit(cleanup) != 0) {
fputs("friends_test: atexit() failed!\nFailing build...\n", stderr);
kill(child_pid, SIGKILL);
return -1;
}
m = initMessenger();
msync(parent_id, crypto_box_PUBLICKEYBYTES, MS_SYNC);
m_callback_statusmessage(m, parent_confirm_status);
m_callback_friendmessage(m, parent_confirm_message);
/* hacky way to give the child time to set up */
c_sleep(50);
Messenger_save(m, parent_id);
if(parent_friend_request() == -1)
return -1;
if(parent_wait_for_message() == -1)
return -1;
wait(NULL);
fputs("friends_test: Build passed!\n", stdout);
return 0;
}