notify_regenerate.c [plain text]
#include <stdlib.h>
#include <notify.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <darwintest.h>
#include <signal.h>
#include "../libnotify.h"
#define T_ASSERT_GROUP_WAIT(g, timeout, ...) ({ \
dispatch_time_t _timeout = dispatch_time(DISPATCH_TIME_NOW, \
(uint64_t)(timeout * NSEC_PER_SEC)); \
T_ASSERT_FALSE(dispatch_group_wait(g, _timeout), __VA_ARGS__); \
})
T_DECL(notify_regenerate, "Make sure regenerate registrations works",
T_META("owner", "Core Darwin Daemons & Tools"),
T_META_ASROOT(YES))
{
const char *KEY = "com.apple.notify.test.regenerate";
int v_token, n_token, rc;
pid_t old_pid, new_pid;
uint64_t state;
dispatch_queue_t dq = dispatch_queue_create_with_target("q", NULL, NULL);
dispatch_group_t dg = dispatch_group_create();
T_LOG("Grab the current instance pid & version");
{
rc = notify_register_check(NOTIFY_IPC_VERSION_NAME, &v_token);
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "register_check(NOTIFY_IPC_VERSION_NAME)");
state = ~0ull;
rc = notify_get_state(v_token, &state);
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "notify_get_state(NOTIFY_IPC_VERSION_NAME)");
old_pid = (pid_t)(state >> 32);
T_EXPECT_EQ((uint32_t)state, NOTIFY_IPC_VERSION, "IPC version should be set");
}
T_LOG("Register for our test topic, and check it works");
{
rc = notify_register_dispatch(KEY, &n_token, dq, ^(int token){
dispatch_group_leave(dg);
});
T_EXPECT_EQ(rc, NOTIFY_STATUS_OK, "register dispatch should work");
dispatch_group_enter(dg);
notify_post(KEY);
T_ASSERT_GROUP_WAIT(dg, 5., "we received our own notification");
}
T_LOG("Make sure notifyd changes pid due to a kill");
{
state = ~0ull;
rc = notify_get_state(v_token, &state);
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "notify_get_state(NOTIFY_IPC_VERSION_NAME)");
new_pid = (pid_t)(state >> 32);
T_ASSERT_EQ(old_pid, new_pid, "Pid should not have changed yet");
rc = kill(old_pid, SIGKILL);
T_ASSERT_POSIX_SUCCESS(rc, "Killing notifyd");
new_pid = old_pid;
for (int i = 0; i < 10 && new_pid == old_pid; i++) {
usleep(100000);
state = ~0ull;
rc = notify_get_state(v_token, &state);
T_ASSERT_EQ(rc, NOTIFY_STATUS_OK, "notify_get_state(NOTIFY_IPC_VERSION_NAME)");
new_pid = (pid_t)(state >> 32);
}
T_ASSERT_NE(old_pid, new_pid, "Pid should have changed within 1s");
}
T_LOG("Make sure our old registration works");
{
dispatch_group_enter(dg);
notify_post(KEY);
T_ASSERT_GROUP_WAIT(dg, 5., "we received our own notification");
}
}