1 #include <check.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include "../../test.h"
6 #include "../../../src/alloc.h"
7 #include "../../../src/fsops.h"
8 #include "../../../src/hexmap.h"
9 #include "../../../src/iobuf.h"
10 #include "../../../src/lock.h"
11 #include "../../../src/prepend.h"
12 #include "../../../src/server/protocol2/dpth.h"
13 #include "../../../src/protocol2/blk.h"
14 #include "../../builders/build_file.h"
15 
16 #define LOCKPATH	"utest_dpth"
17 #define CFILES		LOCKPATH "/cfiles"
18 #define TESTCLIENT	"testclient"
19 
assert_path_components(struct dpth * dpth,int prim,int seco,int tert)20 static void assert_path_components(struct dpth *dpth,
21 	int prim, int seco, int tert)
22 {
23 	fail_unless(dpth->comp[0]==prim);
24 	fail_unless(dpth->comp[1]==seco);
25 	fail_unless(dpth->comp[2]==tert);
26 }
27 
assert_components(struct dpth * dpth,int prim,int seco,int tert,int sig)28 static void assert_components(struct dpth *dpth,
29 	int prim, int seco, int tert, int sig)
30 {
31 	assert_path_components(dpth, prim, seco, tert);
32 	fail_unless(dpth->comp[3]==sig);
33 }
34 
setup(void)35 static struct dpth *setup(void)
36 {
37 	struct dpth *dpth;
38 	hexmap_init();
39 	fail_unless(recursive_delete(LOCKPATH)==0);
40 	fail_unless((dpth=dpth_alloc())!=NULL);
41 	assert_components(dpth, 0, 0, 0, 0);
42 	return dpth;
43 }
44 
tear_down(struct dpth ** dpth)45 static void tear_down(struct dpth **dpth)
46 {
47 	dpth_free(dpth);
48 	fail_unless(recursive_delete(LOCKPATH)==0);
49 	alloc_check();
50 }
51 
write_to_dpth(struct dpth * dpth,const char * savepathstr)52 static int write_to_dpth(struct dpth *dpth, const char *savepathstr)
53 {
54 	int ret;
55 	struct iobuf wbuf;
56 	struct blk *blk=blk_alloc();
57 	blk->savepath=savepathstr_with_sig_to_uint64(savepathstr);
58 	wbuf.buf=strdup_w("abc", __FUNCTION__);
59 	wbuf.len=3;
60 	ret=dpth_protocol2_fwrite(dpth, &wbuf, blk);
61 	free_w(&wbuf.buf);
62 	blk_free(&blk);
63 	return ret;
64 }
65 
do_fork(void)66 static void do_fork(void)
67 {
68 	switch(fork())
69 	{
70 		case -1: fail_unless(0==1);
71 			 break;
72 		case 0: // Child.
73 		{
74 			struct dpth *dpth;
75 			const char *savepath;
76 			dpth=dpth_alloc();
77 			dpth_protocol2_init(dpth,
78 				LOCKPATH,
79 				TESTCLIENT,
80 				CFILES,
81 				MAX_STORAGE_SUBDIRS);
82 			savepath=dpth_protocol2_mk(dpth);
83 			write_to_dpth(dpth, savepath);
84 			sleep(2);
85 			dpth_free(&dpth);
86 			exit(0);
87 		}
88 		default: break;
89 	}
90 	// Parent.
91 }
92 
prepare_simple_lock(void)93 static struct dpth *prepare_simple_lock(void)
94 {
95 	struct dpth *dpth;
96 	const char *savepath;
97 	dpth=setup();
98 	fail_unless(dpth_protocol2_init(dpth,
99 		LOCKPATH,
100 		TESTCLIENT,
101 		CFILES,
102 		MAX_STORAGE_SUBDIRS)==0);
103 	savepath=dpth_protocol2_mk(dpth);
104 	ck_assert_str_eq(savepath, "0000/0000/0000/0000");
105 	fail_unless(dpth->head->lock->status==GET_LOCK_GOT);
106 	// Fill up the data file, so that the next call to dpth_incr_sig will
107 	// need to open a new one.
108 	while(dpth->comp[3]<DATA_FILE_SIG_MAX-1)
109 	{
110 		fail_unless(write_to_dpth(dpth, savepath)==0);
111 		fail_unless(dpth_protocol2_incr_sig(dpth)==0);
112 	}
113 	return dpth;
114 }
115 
check_simple_lock(struct dpth ** dpth,const char * expected_savepath,int expected_tert)116 static void check_simple_lock(struct dpth **dpth,
117 	const char *expected_savepath, int expected_tert)
118 {
119 	const char *savepath;
120 	fail_unless(dpth_protocol2_incr_sig(*dpth)==0);
121 	savepath=dpth_protocol2_mk(*dpth);
122 	ck_assert_str_eq(savepath, expected_savepath);
123 	assert_components(*dpth, 0, 0, expected_tert, 0);
124 	fail_unless((*dpth)->head!=(*dpth)->tail);
125 	fail_unless((*dpth)->head->lock->status==GET_LOCK_GOT);
126 	fail_unless((*dpth)->tail->lock->status==GET_LOCK_GOT);
127 	tear_down(dpth);
128 }
129 
START_TEST(test_simple_lock)130 START_TEST(test_simple_lock)
131 {
132 	int stat;
133 	struct dpth *dpth;
134 
135 	dpth=prepare_simple_lock();
136 
137 	// Child will lock the next data file. So, the next call to dpth_mk
138 	// will get the next one after that.
139 	do_fork();
140 	sleep(1);
141 
142 	check_simple_lock(&dpth, "0000/0000/0002/0000", 2);
143 
144 	wait(&stat);
145 }
146 END_TEST
147 
START_TEST(test_simple_lock_with_existant_data_files)148 START_TEST(test_simple_lock_with_existant_data_files)
149 {
150 	struct dpth *dpth;
151 
152 	dpth=prepare_simple_lock();
153 
154 	// Create some data files that did not exist previously. The next call
155 	// to incr_sig should skip over them.
156 	build_file(LOCKPATH "/0000/0000/0001", "");
157 	build_file(LOCKPATH "/0000/0000/0002", "");
158 	build_file(LOCKPATH "/0000/0000/0003", "");
159 
160 	check_simple_lock(&dpth, "0000/0000/0004/0000", 4);
161 }
162 END_TEST
163 
164 struct incr_data
165 {
166         uint16_t prim;
167         uint16_t seco;
168         uint16_t tert;
169         uint16_t sig;
170         uint16_t prim_expected;
171         uint16_t seco_expected;
172         uint16_t tert_expected;
173         uint16_t sig_expected;
174 	int ret_expected;
175 };
176 
177 static struct incr_data d[] = {
178 	{ 0x0000, 0x0000, 0x0000, 0x0000,
179 	  0x0000, 0x0000, 0x0000, 0x0001, 0 },
180 	{ 0x0000, 0x0000, 0x0000, 0x0001,
181 	  0x0000, 0x0000, 0x0000, 0x0002, 0 },
182 	{ 0x0000, 0x0000, 0x0000, 0x1000,
183 	  0x0000, 0x0000, 0x0001, 0x0000, 0 },
184 	{ 0x0000, 0x0000, 0x0AAA, 0x0000,
185 	  0x0000, 0x0000, 0x0AAA, 0x0001, 0 },
186 	{ 0x0000, 0x0000, 0x0AAA, 0x0AAA,
187 	  0x0000, 0x0000, 0x0AAA, 0x0AAB, 0 },
188 	{ 0x0000, 0x0000, 0xFFFF, 0x1000,
189 	  0x0000, 0x0001, 0x0000, 0x0000, 0 },
190 	{ 0x0000, 0x3333, 0xFFFF, 0x1000,
191 	  0x0000, 0x3334, 0x0000, 0x0000, 0 },
192 	{ 0x0000, 0x7530, 0xFFFF, 0x1000,
193 	  0x0001, 0x0000, 0x0000, 0x0000, 0 },
194 	{ 0x3333, 0x3333, 0x3333, 0x0050,
195 	  0x3333, 0x3333, 0x3333, 0x0051, 0 },
196 	{ 0x3333, 0xFFFF, 0xFFFF, 0x1000,
197 	  0x3334, 0x0000, 0x0000, 0x0000, 0 },
198 	{ 0x7530, 0x7530, 0xFFFF, 0x1000,
199 	  0x0000, 0x0000, 0x0000, 0x0000, -1 }
200 };
201 
START_TEST(test_incr_sig)202 START_TEST(test_incr_sig)
203 {
204         FOREACH(d)
205         {
206 		struct dpth *dpth;
207 		dpth=setup();
208 		fail_unless(dpth_protocol2_init(dpth,
209 			LOCKPATH,
210 			TESTCLIENT,
211 			CFILES,
212 			MAX_STORAGE_SUBDIRS)==0);
213 		dpth->comp[0]=d[i].prim;
214 		dpth->comp[1]=d[i].seco;
215 		dpth->comp[2]=d[i].tert;
216 		dpth->comp[3]=d[i].sig;
217 		fail_unless(dpth_protocol2_incr_sig(dpth)==d[i].ret_expected);
218 		if(!d[i].ret_expected)
219 			assert_components(dpth,
220 				d[i].prim_expected,
221 				d[i].seco_expected,
222 				d[i].tert_expected,
223 				d[i].sig_expected);
224 		tear_down(&dpth);
225         }
226 }
227 END_TEST
228 
229 struct init_data
230 {
231         uint16_t prim;
232         uint16_t seco;
233         uint16_t tert;
234         uint16_t prim_expected;
235         uint16_t seco_expected;
236         uint16_t tert_expected;
237 	int ret_expected;
238 };
239 
240 static struct init_data in[] = {
241 	{ 0x0000, 0x0000, 0x0000,
242 	  0x0000, 0x0000, 0x0001, 0 },
243 	{ 0x0000, 0x0000, 0xAAAA,
244 	  0x0000, 0x0000, 0xAAAB, 0 },
245 	{ 0x0000, 0x0000, 0xFFFF,
246 	  0x0000, 0x0001, 0x0000, 0 },
247 	{ 0x0000, 0x3333, 0xFFFF,
248 	  0x0000, 0x3334, 0x0000, 0 },
249 	{ 0x0000, 0x7530, 0xFFFF,
250 	  0x0001, 0x0000, 0x0000, 0 },
251 	{ 0x3333, 0xFFFF, 0xFFFF,
252 	  0x3334, 0x0000, 0x0000, 0 },
253 	{ 0x7530, 0x7530, 0xFFFF,
254 	  0x0000, 0x0000, 0x0000, -1 }
255 };
256 
START_TEST(test_init)257 START_TEST(test_init)
258 {
259         FOREACH(in)
260 	{
261 		struct fzp *fp=NULL;
262 		char *path=NULL;
263 		struct dpth *dpth;
264 		char *savepath;
265 		dpth=setup();
266 		dpth->comp[0]=in[i].prim;
267 		dpth->comp[1]=in[i].seco;
268 		dpth->comp[2]=in[i].tert;
269 		dpth->comp[3]=0;
270 		savepath=dpth_protocol2_get_save_path(dpth);
271 		// Truncate it to remove the sig part.
272 		savepath[14]='\0';
273 		path=prepend_s(LOCKPATH, savepath);
274 		fail_unless(build_path_w(path)==0);
275 		// Create a file.
276 		fail_unless((fp=fzp_open(path, "wb"))!=NULL);
277 		fzp_close(&fp);
278 
279 		// Now when calling dpth_init(), the components should be
280 		// incremented appropriately.
281 		dpth_free(&dpth);
282 		fail_unless((dpth=dpth_alloc())!=NULL);
283 		fail_unless(dpth_protocol2_init(dpth,
284 			LOCKPATH,
285 			TESTCLIENT,
286 			CFILES,
287 			MAX_STORAGE_SUBDIRS)==in[i].ret_expected);
288 		assert_path_components(dpth,
289 			in[i].prim_expected,
290 			in[i].seco_expected,
291 			in[i].tert_expected);
292 
293 		free_w(&path);
294 		tear_down(&dpth);
295 	}
296 }
297 END_TEST
298 
suite_server_protocol2_dpth(void)299 Suite *suite_server_protocol2_dpth(void)
300 {
301 	Suite *s;
302 	TCase *tc_core;
303 
304 	s=suite_create("server_protocol2_dpth");
305 
306 	tc_core=tcase_create("Core");
307 
308 	tcase_add_test(tc_core, test_simple_lock);
309 	tcase_add_test(tc_core, test_simple_lock_with_existant_data_files);
310 	tcase_add_test(tc_core, test_incr_sig);
311 	tcase_add_test(tc_core, test_init);
312 	suite_add_tcase(s, tc_core);
313 
314 	return s;
315 }
316