File: test_lock.c

package info (click to toggle)
burp 3.1.4-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,684 kB
  • sloc: ansic: 50,989; sh: 3,612; cpp: 2,859; makefile: 868
file content (144 lines) | stat: -rw-r--r-- 3,198 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "test.h"
#include "../src/alloc.h"
#include "../src/lock.h"

static const char *lockfile="utest_lockfile";

static struct lock *setup(void)
{
	struct lock *lock;
	fail_unless((lock=lock_alloc())!=NULL);
	fail_unless(!lock_init(lock, lockfile));
	ck_assert_str_eq(lock->path, lockfile);
	fail_unless(lock->status==GET_LOCK_NOT_GOT);
	return lock;
}

static void tear_down(struct lock **lock, struct lock **locklist)
{
	lock_free(lock);
	locks_release_and_free(locklist);
	alloc_check();
}

static void assert_can_get_lock(struct lock *lock)
{
	fail_unless(!lock_test(lockfile));
	lock_get_quick(lock);
	fail_unless(lock->status==GET_LOCK_GOT);
	fail_unless(!lock_release(lock));
	fail_unless(lock->status==GET_LOCK_NOT_GOT);
}

static void do_fork(int child_exit_early)
{
	switch(fork())
	{
		case -1: fail_unless(0==1);
			break;
		case 0: // Child.
		{
			struct lock *lock;
			lock=lock_alloc_and_init(lockfile);
			lock_get_quick(lock);
			if(!child_exit_early)
			{
				sleep(2);
				lock_release(lock);
				lock_free(&lock);
			}
			exit(0);
		}
		default: break;
	}
	// Parent.
}

static void run_with_fork(int child_exit_early)
{
	int stat;
	struct lock *lock=setup();

	do_fork(child_exit_early);

	if(!child_exit_early)
	{
		sleep(1);
		fail_unless(lock_test(lockfile)==-1);
		lock_get_quick(lock);
		fail_unless(lock->status==GET_LOCK_NOT_GOT);
	}
	wait(&stat);

	// The child has exited, should now be able to get it.
	assert_can_get_lock(lock);
	tear_down(&lock, NULL);
}

START_TEST(test_lock_simple_success)
{
	struct lock *lock;
	lock=setup();
	assert_can_get_lock(lock);
	tear_down(&lock, NULL);
}
END_TEST

START_TEST(test_lock_simple_failure)
{
	// Child will get the lock, and wait.
	// The parent will wait a shorter time, to give the child time to
	// get the lock. The parent will then attempt to get the lock, and
	// it should not succeed.
	run_with_fork(0 /* child will not exit early */);
}
END_TEST

START_TEST(test_lock_left_behind)
{
        // Child will get the lock, then exit, leaving an old lockfile behind.
        // The parent will wait and then attempt to get the lock, and it
	// should succeed.
	run_with_fork(1 /* child will exit early */);
}
END_TEST

static void init_and_add_to_list(struct lock **locklist, const char *path)
{
	struct lock *lock;
	fail_unless((lock=lock_alloc_and_init(path))!=NULL);
	lock_add_to_list(locklist, lock);
}

START_TEST(test_lock_list)
{
	struct lock *lock=NULL;
	struct lock *locklist=NULL;
	init_and_add_to_list(&locklist, "path1");
	init_and_add_to_list(&locklist, "path2");
	init_and_add_to_list(&locklist, "path3");
	lock=locklist;
	ck_assert_str_eq(lock->path, "path3"); lock=lock->next;
	ck_assert_str_eq(lock->path, "path2"); lock=lock->next;
	ck_assert_str_eq(lock->path, "path1"); fail_unless(lock->next==NULL);
	tear_down(NULL, &locklist);
}
END_TEST

Suite *suite_lock(void)
{
	Suite *s;
	TCase *tc_core;

	s=suite_create("lock");

	tc_core=tcase_create("Core");

	tcase_add_test(tc_core, test_lock_simple_success);
	tcase_add_test(tc_core, test_lock_simple_failure);
	tcase_add_test(tc_core, test_lock_left_behind);
	tcase_add_test(tc_core, test_lock_list);
	suite_add_tcase(s, tc_core);

	return s;
}