#include "testsecevent.h"
#include <assert.h>
#include <CoreFoundation/CFRunLoop.h>
#include <sys/time.h>
#include "testmore.h"
#include "testeventqueue.h"
static OSStatus test_sec_event_callback(SecKeychainEvent keychainEvent,
SecKeychainCallbackInfo *info, void *inContext)
{
if (keychainEvent == kSecLockEvent || keychainEvent == kSecUnlockEvent)
{
return 0;
}
CallbackData cd;
cd.event = keychainEvent;
cd.version = info->version;
cd.itemRef = info->item;
cd.keychain = info->keychain;
cd.pid = info->pid;
if (cd.itemRef)
{
CFRetain (cd.itemRef);
}
if (cd.keychain)
{
CFRetain (cd.keychain);
}
TEQ_Enqueue (&cd);
return 0;
}
OSStatus test_sec_event_register(SecKeychainEventMask mask)
{
return SecKeychainAddCallback(test_sec_event_callback, mask, NULL);
}
OSStatus test_sec_event_deregister()
{
return SecKeychainRemoveCallback(test_sec_event_callback);
}
double GetCurrentTime()
{
struct timeval tv;
gettimeofday(&tv, NULL);
double d = tv.tv_sec + tv.tv_usec / 1000000.0;
return d;
}
int test_is_sec_event(SecKeychainEvent event, SecKeychainRef *keychain,
SecKeychainItemRef *item, pid_t *pid, const char *description,
const char *directive, const char *reason, const char *file, unsigned line)
{
int expected = event == 0 ? 0 : 1;
if (event == 0) {
if (TEQ_ItemsInQueue() == 0)
{
return test_ok(TRUE,
description, directive, reason, file, line,
"", 0, 0);
}
}
double startTime = GetCurrentTime();
double nextTime = startTime + 2.0;
double currentTime;
while ((currentTime = GetCurrentTime()) < nextTime)
{
SInt32 result = kCFRunLoopRunHandledSource;
if (TEQ_ItemsInQueue () == 0) result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, TRUE);
switch (result)
{
case kCFRunLoopRunFinished:
return test_ok(0, description, directive, reason, file, line,
"# no sources registered in runloop\n");
case kCFRunLoopRunStopped:
return test_ok(0, description, directive, reason, file, line,
"# runloop was stopped\n");
case kCFRunLoopRunTimedOut:
continue;
case kCFRunLoopRunHandledSource:
{
CallbackData cd;
bool dataInQueue;
if (expected)
{
dataInQueue = TEQ_Dequeue (&cd);
if (dataInQueue)
{
if (keychain != NULL)
*keychain = cd.keychain;
else if (cd.keychain)
CFRelease(cd.keychain);
if (item != NULL)
*item = cd.itemRef;
else if (cd.itemRef)
CFRelease(cd.itemRef);
return test_ok(cd.event == event,
description, directive, reason, file, line,
"# got: '%d'\n"
"# expected: '%d'\n",
cd.event, event);
}
else
{
return test_ok(0, description, directive, reason, file, line,
"# event expected but not received\n");
}
}
dataInQueue = TEQ_Dequeue (&cd);
int unexpected_events = 0;
while (dataInQueue)
{
test_diag(directive, reason, file, line,
" got unexpected event: '%d'", cd.event);
unexpected_events++;
TEQ_Release (&cd);
dataInQueue = TEQ_Dequeue (&cd);
}
return test_ok(unexpected_events == 0, description, directive, reason, file, line,
"# got %d unexpected events\n", unexpected_events);
}
default:
return test_ok(0, description, directive, reason, file, line,
"# runloop returned: '%d'\n"
"# expected: 'kCFRunLoopRunHandledSource'\n",
result);
}
}
if (expected)
return test_ok(0, description, directive, reason,
file, line, "# runloop timed out waiting for event : %d\n",
event);
else
return test_ok(TRUE, description, directive, reason, file, line,
"# got %d unexpected events\n", 0);
}