1/*
2   Unix SMB/CIFS implementation.
3   SMB torture UI functions
4
5   Copyright (C) Jelmer Vernooij 2006
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#ifndef __TORTURE_UI_H__
22#define __TORTURE_UI_H__
23
24struct torture_test;
25struct torture_context;
26struct torture_suite;
27struct torture_tcase;
28struct torture_results;
29
30enum torture_result {
31	TORTURE_OK=0,
32	TORTURE_FAIL=1,
33	TORTURE_ERROR=2,
34	TORTURE_SKIP=3
35};
36
37/*
38 * These callbacks should be implemented by any backend that wishes
39 * to listen to reports from the torture tests.
40 */
41struct torture_ui_ops
42{
43	void (*init) (struct torture_results *);
44	void (*comment) (struct torture_context *, const char *);
45	void (*warning) (struct torture_context *, const char *);
46	void (*suite_start) (struct torture_context *, struct torture_suite *);
47	void (*suite_finish) (struct torture_context *, struct torture_suite *);
48	void (*tcase_start) (struct torture_context *, struct torture_tcase *);
49	void (*tcase_finish) (struct torture_context *, struct torture_tcase *);
50	void (*test_start) (struct torture_context *,
51						struct torture_tcase *,
52						struct torture_test *);
53	void (*test_result) (struct torture_context *,
54						 enum torture_result, const char *reason);
55};
56
57void torture_ui_test_start(struct torture_context *context,
58							   struct torture_tcase *tcase,
59							   struct torture_test *test);
60
61void torture_ui_test_result(struct torture_context *context,
62								enum torture_result result,
63								const char *comment);
64
65/*
66 * Holds information about a specific run of the testsuite.
67 * The data in this structure should be considered private to
68 * the torture tests and should only be used directly by the torture
69 * code and the ui backends.
70 *
71 * Torture tests should instead call the torture_*() macros and functions
72 * specified below.
73 */
74
75struct torture_context
76{
77	struct torture_results *results;
78
79	char *active_testname;
80	struct torture_test *active_test;
81	struct torture_tcase *active_tcase;
82
83	enum torture_result last_result;
84	char *last_reason;
85
86	/** Directory used for temporary test data */
87	const char *outputdir;
88
89	/** Event context */
90	struct tevent_context *ev;
91
92	/** Loadparm context (will go away in favor of torture_setting_ at some point) */
93	struct loadparm_context *lp_ctx;
94};
95
96struct torture_results
97{
98	const struct torture_ui_ops *ui_ops;
99	void *ui_data;
100
101	/** Whether tests should avoid writing output to stdout */
102	bool quiet;
103
104	bool returncode;
105};
106
107/*
108 * Describes a particular torture test
109 */
110struct torture_test {
111	/** Short unique name for the test. */
112	const char *name;
113
114	/** Long description for the test. */
115	const char *description;
116
117	/** Whether this is a dangerous test
118	 * (can corrupt the remote servers data or bring it down). */
119	bool dangerous;
120
121	/** Function to call to run this test */
122	bool (*run) (struct torture_context *torture_ctx,
123				 struct torture_tcase *tcase,
124				 struct torture_test *test);
125
126	struct torture_test *prev, *next;
127
128	/** Pointer to the actual test function. This is run by the
129	  * run() function above. */
130	void *fn;
131
132	/** Use data for this test */
133	const void *data;
134};
135
136/*
137 * Describes a particular test case.
138 */
139struct torture_tcase {
140    const char *name;
141	const char *description;
142	bool (*setup) (struct torture_context *tcase, void **data);
143	bool (*teardown) (struct torture_context *tcase, void *data);
144	bool fixture_persistent;
145	void *data;
146	struct torture_test *tests;
147	struct torture_tcase *prev, *next;
148};
149
150struct torture_suite
151{
152	const char *name;
153	const char *description;
154	struct torture_tcase *testcases;
155	struct torture_suite *children;
156
157	/* Pointers to siblings of this torture suite */
158	struct torture_suite *prev, *next;
159};
160
161/** Create a new torture suite */
162struct torture_suite *torture_suite_create(TALLOC_CTX *mem_ctx,
163		const char *name);
164
165/** Change the setup and teardown functions for a testcase */
166void torture_tcase_set_fixture(struct torture_tcase *tcase,
167		bool (*setup) (struct torture_context *, void **),
168		bool (*teardown) (struct torture_context *, void *));
169
170/* Add another test to run for a particular testcase */
171struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase,
172		const char *name,
173		bool (*run) (struct torture_context *test,
174			const void *tcase_data, const void *test_data),
175		const void *test_data);
176
177/* Add a testcase to a testsuite */
178struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite,
179							 const char *name);
180
181/* Convenience wrapper that adds a testcase against only one
182 * test will be run */
183struct torture_tcase *torture_suite_add_simple_tcase_const(
184		struct torture_suite *suite,
185		const char *name,
186		bool (*run) (struct torture_context *test,
187			const void *test_data),
188		const void *data);
189
190/* Convenience function that adds a test which only
191 * gets the test case data */
192struct torture_test *torture_tcase_add_simple_test_const(
193		struct torture_tcase *tcase,
194		const char *name,
195		bool (*run) (struct torture_context *test,
196			const void *tcase_data));
197
198/* Convenience wrapper that adds a test that doesn't need any
199 * testcase data */
200struct torture_tcase *torture_suite_add_simple_test(
201		struct torture_suite *suite,
202		const char *name,
203		bool (*run) (struct torture_context *test));
204
205/* Add a child testsuite to an existing testsuite */
206bool torture_suite_add_suite(struct torture_suite *suite,
207		struct torture_suite *child);
208
209/* Run the specified testsuite recursively */
210bool torture_run_suite(struct torture_context *context,
211					   struct torture_suite *suite);
212
213/* Run the specified testcase */
214bool torture_run_tcase(struct torture_context *context,
215					   struct torture_tcase *tcase);
216
217/* Run the specified test */
218bool torture_run_test(struct torture_context *context,
219					  struct torture_tcase *tcase,
220					  struct torture_test *test);
221
222void torture_comment(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3);
223void torture_warning(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3);
224void torture_result(struct torture_context *test,
225			enum torture_result, const char *reason, ...) PRINTF_ATTRIBUTE(3,4);
226
227#define torture_assert(torture_ctx,expr,cmt) \
228	if (!(expr)) { \
229		torture_result(torture_ctx, TORTURE_FAIL, __location__": Expression `%s' failed: %s", __STRING(expr), cmt); \
230		return false; \
231	}
232
233#define torture_assert_werr_equal(torture_ctx, got, expected, cmt) \
234	do { WERROR __got = got, __expected = expected; \
235	if (!W_ERROR_EQUAL(__got, __expected)) { \
236		torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", win_errstr(__got), win_errstr(__expected), cmt); \
237		return false; \
238	} \
239	} while (0)
240
241#define torture_assert_ntstatus_equal(torture_ctx,got,expected,cmt) \
242	do { NTSTATUS __got = got, __expected = expected; \
243	if (!NT_STATUS_EQUAL(__got, __expected)) { \
244		torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", nt_errstr(__got), nt_errstr(__expected), cmt); \
245		return false; \
246	}\
247	} while(0)
248
249#define torture_assert_ntstatus_equal_goto(torture_ctx,got,expected,ret,label,cmt) \
250	do { NTSTATUS __got = got, __expected = expected; \
251	if (!NT_STATUS_EQUAL(__got, __expected)) { \
252		torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", nt_errstr(__got), nt_errstr(__expected), cmt); \
253		ret = false; \
254		goto label; \
255	}\
256	} while(0)
257
258#define torture_assert_ndr_err_equal(torture_ctx,got,expected,cmt) \
259	do { enum ndr_err_code __got = got, __expected = expected; \
260	if (__got != __expected) { \
261		torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %d, expected %d (%s): %s", __got, __expected, __STRING(expected), cmt); \
262		return false; \
263	}\
264	} while(0)
265
266#define torture_assert_casestr_equal(torture_ctx,got,expected,cmt) \
267	do { const char *__got = (got), *__expected = (expected); \
268	if (!strequal(__got, __expected)) { \
269		torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", __got, __expected, cmt); \
270		return false; \
271	} \
272	} while(0)
273
274#define torture_assert_str_equal(torture_ctx,got,expected,cmt)\
275	do { const char *__got = (got), *__expected = (expected); \
276	if (strcmp_safe(__got, __expected) != 0) { \
277		torture_result(torture_ctx, TORTURE_FAIL, \
278					   __location__": "#got" was %s, expected %s: %s", \
279					   __got, __expected, cmt); \
280		return false; \
281	} \
282	} while(0)
283
284#define torture_assert_str_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
285	do { const char *__got = (got), *__expected = (expected); \
286	if (strcmp_safe(__got, __expected) != 0) { \
287		torture_result(torture_ctx, TORTURE_FAIL, \
288					   __location__": "#got" was %s, expected %s: %s", \
289					   __got, __expected, cmt); \
290		ret = false; \
291		goto label; \
292	} \
293	} while(0)
294
295#define torture_assert_mem_equal(torture_ctx,got,expected,len,cmt)\
296	do { const void *__got = (got), *__expected = (expected); \
297	if (memcmp(__got, __expected, len) != 0) { \
298		torture_result(torture_ctx, TORTURE_FAIL, \
299			       __location__": "#got" of len %d did not match "#expected": %s", (int)len, cmt); \
300		return false; \
301	} \
302	} while(0)
303
304#define torture_assert_data_blob_equal(torture_ctx,got,expected,cmt)\
305	do { const DATA_BLOB __got = (got), __expected = (expected); \
306	if (__got.length != __expected.length) { \
307		torture_result(torture_ctx, TORTURE_FAIL, \
308			       __location__": "#got".len %d did not match "#expected" len %d: %s", \
309			       (int)__got.length, (int)__expected.length, cmt); \
310		return false; \
311	} \
312	if (memcmp(__got.data, __expected.data, __got.length) != 0) { \
313		torture_result(torture_ctx, TORTURE_FAIL, \
314			       __location__": "#got" of len %d did not match "#expected": %s", (int)__got.length, cmt); \
315		return false; \
316	} \
317	} while(0)
318
319#define torture_assert_file_contains_text(torture_ctx,filename,expected,cmt)\
320	do { \
321	char *__got; \
322	const char *__expected = (expected); \
323	size_t __size; \
324	__got = file_load(filename, &__size, 0, torture_ctx); \
325	if (__got == NULL) { \
326		torture_result(torture_ctx, TORTURE_FAIL, \
327			       __location__": unable to open %s: %s\n", \
328			       filename, cmt); \
329		return false; \
330	} \
331	\
332	if (strcmp_safe(__got, __expected) != 0) { \
333		torture_result(torture_ctx, TORTURE_FAIL, \
334			__location__": %s contained:\n%sExpected: %s%s\n", \
335			filename, __got, __expected, cmt); \
336		talloc_free(__got); \
337		return false; \
338	} \
339	talloc_free(__got); \
340	} while(0)
341
342#define torture_assert_file_contains(torture_ctx,filename,expected,cmt)\
343	do { const char *__got, *__expected = (expected); \
344	size_t __size; \
345	__got = file_load(filename, *size, 0, torture_ctx); \
346	if (strcmp_safe(__got, __expected) != 0) { \
347		torture_result(torture_ctx, TORTURE_FAIL, \
348					   __location__": %s contained:\n%sExpected: %s%s\n", \
349					   __got, __expected, cmt); \
350		talloc_free(__got); \
351		return false; \
352	} \
353	talloc_free(__got); \
354	} while(0)
355
356#define torture_assert_int_equal(torture_ctx,got,expected,cmt)\
357	do { int __got = (got), __expected = (expected); \
358	if (__got != __expected) { \
359		torture_result(torture_ctx, TORTURE_FAIL, \
360			__location__": "#got" was %d, expected %d: %s", \
361			__got, __expected, cmt); \
362		return false; \
363	} \
364	} while(0)
365
366#define torture_assert_int_equal_goto(torture_ctx,got,expected,ret,label,cmt)\
367	do { int __got = (got), __expected = (expected); \
368	if (__got != __expected) { \
369		torture_result(torture_ctx, TORTURE_FAIL, \
370			__location__": "#got" was %d, expected %d: %s", \
371			__got, __expected, cmt); \
372		ret = false; \
373		goto label; \
374	} \
375	} while(0)
376
377#define torture_assert_u64_equal(torture_ctx,got,expected,cmt)\
378	do { uint64_t __got = (got), __expected = (expected); \
379	if (__got != __expected) { \
380		torture_result(torture_ctx, TORTURE_FAIL, \
381			__location__": "#got" was %llu, expected %llu: %s", \
382			(unsigned long long)__got, (unsigned long long)__expected, cmt); \
383		return false; \
384	} \
385	} while(0)
386
387#define torture_assert_errno_equal(torture_ctx,expected,cmt)\
388	do { int __expected = (expected); \
389	if (errno != __expected) { \
390		torture_result(torture_ctx, TORTURE_FAIL, \
391			__location__": errno was %d (%s), expected %d: %s: %s", \
392					   errno, strerror(errno), __expected, \
393					   strerror(__expected), cmt); \
394		return false; \
395	} \
396	} while(0)
397
398
399
400#define torture_skip(torture_ctx,cmt) do {\
401		torture_result(torture_ctx, TORTURE_SKIP, __location__": %s", cmt);\
402		return true; \
403	} while(0)
404#define torture_skip_goto(torture_ctx,label,cmt) do {\
405		torture_result(torture_ctx, TORTURE_SKIP, __location__": %s", cmt);\
406		goto label; \
407	} while(0)
408#define torture_fail(torture_ctx,cmt) do {\
409		torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\
410		return false; \
411	} while (0)
412#define torture_fail_goto(torture_ctx,label,cmt) do {\
413		torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\
414		goto label; \
415	} while (0)
416
417#define torture_out stderr
418
419/* Convenience macros */
420#define torture_assert_ntstatus_ok(torture_ctx,expr,cmt) \
421		torture_assert_ntstatus_equal(torture_ctx,expr,NT_STATUS_OK,cmt)
422
423#define torture_assert_ntstatus_ok_goto(torture_ctx,expr,ret,label,cmt) \
424		torture_assert_ntstatus_equal_goto(torture_ctx,expr,NT_STATUS_OK,ret,label,cmt)
425
426#define torture_assert_werr_ok(torture_ctx,expr,cmt) \
427		torture_assert_werr_equal(torture_ctx,expr,WERR_OK,cmt)
428
429#define torture_assert_ndr_success(torture_ctx,expr,cmt) \
430		torture_assert_ndr_err_equal(torture_ctx,expr,NDR_ERR_SUCCESS,cmt)
431
432/* Getting settings */
433const char *torture_setting_string(struct torture_context *test, \
434								   const char *name,
435								   const char *default_value);
436
437int torture_setting_int(struct torture_context *test,
438						const char *name,
439						int default_value);
440
441double torture_setting_double(struct torture_context *test,
442						const char *name,
443						double default_value);
444
445bool torture_setting_bool(struct torture_context *test,
446						  const char *name,
447						  bool default_value);
448
449struct torture_suite *torture_find_suite(struct torture_suite *parent,
450										 const char *name);
451
452NTSTATUS torture_temp_dir(struct torture_context *tctx,
453				   const char *prefix,
454				   char **tempdir);
455
456struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase,
457		const char *name,
458		bool (*run) (struct torture_context *test, void *tcase_data));
459
460
461bool torture_suite_init_tcase(struct torture_suite *suite,
462			      struct torture_tcase *tcase,
463			      const char *name);
464
465struct torture_context *torture_context_init(struct tevent_context *event_ctx, struct torture_results *results);
466
467struct torture_results *torture_results_init(TALLOC_CTX *mem_ctx, const struct torture_ui_ops *ui_ops);
468
469struct torture_context *torture_context_child(struct torture_context *tctx);
470
471extern const struct torture_ui_ops torture_subunit_ui_ops;
472
473#endif /* __TORTURE_UI_H__ */
474