postgres_test.c 4.6 KB
Newer Older
1 2 3 4 5
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include "cmockery.h"

6 7 8 9 10 11
#include "postgres.h"

/*
 * Mock PG_RE_THROW, because we are not using real elog.o.
 * The closest mockery is to call siglongjmp().
 */
A
Ashwin Agrawal 已提交
12
#undef PG_RE_THROW
13 14 15
#define PG_RE_THROW() siglongjmp(*PG_exception_stack, 1)

#define errfinish errfinish_impl
A
Ashwin Agrawal 已提交
16 17
static int
errfinish_impl(int dummy __attribute__((unused)),...)
18 19 20 21
{
	PG_RE_THROW();
}

22 23
#include "../postgres.c"

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#define EXPECT_EREPORT(LOG_LEVEL)     \
	expect_any(errmsg, fmt); \
	will_be_called(errmsg); \
	expect_any(errcode, sqlerrcode); \
	will_be_called(errcode); \
	expect_value(errstart, elevel, (LOG_LEVEL)); \
	expect_any(errstart, filename); \
	expect_any(errstart, lineno); \
	expect_any(errstart, funcname); \
	expect_any(errstart, domain); \
	if (LOG_LEVEL < ERROR) \
	{ \
		will_return(errstart, false); \
	} \
    else \
    { \
		will_return(errstart, true);\
    } \

43 44

/* List with multiple elements, return FALSE. */
A
Ashwin Agrawal 已提交
45
static void
46 47 48 49 50 51 52 53 54 55
test__IsTransactionExitStmtList__MultipleElementList(void **state)
{
	List *list = list_make2_int(1,2);

	assert_false(IsTransactionExitStmtList(list));

	list_free(list);
}

/*  Transaction with Exit Statement, return TRUE. */
A
Ashwin Agrawal 已提交
56
static void
57 58 59 60 61 62 63 64 65 66 67 68 69 70
test__IsTransactionExitStmt__IsTransactionStmt(void **state)
{
	TransactionStmt *stmt = makeNode(TransactionStmt);
	stmt->kind = TRANS_STMT_COMMIT;

	List *list = list_make1(stmt);

	assert_true(IsTransactionExitStmtList(list));

	list_free(list);
	pfree(stmt);
}

/* Query with Transaction with Exit Statement, return TRUE. */
A
Ashwin Agrawal 已提交
71
static void
72 73 74 75 76 77 78
test__IsTransactionExitStmt__IsQuery(void **state)
{
	TransactionStmt *stmt = makeNode(TransactionStmt);
	stmt->kind = TRANS_STMT_COMMIT;
	Query *query = (Query *)palloc(sizeof(Query));
	query->type = T_Query;
	query->commandType = CMD_UTILITY;
A
Ashwin Agrawal 已提交
79
	query->utilityStmt = (Node*) stmt;
80 81 82 83 84 85 86 87 88 89 90 91 92

	List *list = list_make1(query);

	assert_true(IsTransactionExitStmtList(list));

	list_free(list);
	pfree(query);
	pfree(stmt);
}

/*
 * Test ProcessInterrupts when ClientConnectionLost flag is set
 */
A
Ashwin Agrawal 已提交
93
static void
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
test__ProcessInterrupts__ClientConnectionLost(void **state)
{
	will_be_called(DisableNotifyInterrupt);
	will_be_called(DisableCatchupInterrupt);

	/*
	 * Setting all the flags so that ProcessInterrupts only goes in the if-block
	 * we're interested to test
	 */
	InterruptHoldoffCount = 0;
	CritSectionCount = 0;
	ProcDiePending = 0;
	ClientConnectionLost = 1;
	whereToSendOutput = DestDebug;

109 110 111 112 113
	EXPECT_EREPORT(FATAL);

	PG_TRY();
	{
		/* Run function under test */
114
		ProcessInterrupts(__FILE__, __LINE__);
115 116 117 118 119 120
		assert_true(false);
	}
	PG_CATCH();
	{
	}
	PG_END_TRY();
121 122 123 124 125 126 127 128 129

	assert_true(whereToSendOutput == DestNone);
	assert_false(QueryCancelPending);
	assert_false(ImmediateInterruptOK);
}

/*
 * Test ProcessInterrupts when DoingCommandRead is set
 */
A
Ashwin Agrawal 已提交
130
static void
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
test__ProcessInterrupts__DoingCommandRead(void **state)
{
	InterruptHoldoffCount = 0;
	CritSectionCount = 0;
	ProcDiePending = false;
	ClientConnectionLost = false;

	/*
	 * QueryCancelPending = true, DoingCommandRead = true; we should NOT
	 * error out.
	 */
	QueryCancelPending = true;
	DoingCommandRead = true;

	/* Mock up elog_start and elog_finish */
	expect_any(elog_start, filename);
	expect_any(elog_start, lineno);
	expect_any(elog_start, funcname);
	will_be_called(elog_start);
	expect_value(elog_finish, elevel, LOG);
	expect_any(elog_finish, fmt);
	will_be_called(elog_finish);

154
	ProcessInterrupts(__FILE__, __LINE__);
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176

	assert_false(QueryCancelPending);

	/*
	 * QueryCancelPending = true, DoingCommandRead = false; we should
	 * error out.
	 */
	QueryCancelPending = true;
	DoingCommandRead = false;

	/* Mock up elog_start and elog_finish */
	expect_any(elog_start, filename);
	expect_any(elog_start, lineno);
	expect_any(elog_start, funcname);
	will_be_called(elog_start);
	expect_value(elog_finish, elevel, LOG);
	expect_any(elog_finish, fmt);
	will_be_called(elog_finish);

	will_be_called(DisableNotifyInterrupt);
	will_be_called(DisableCatchupInterrupt);

177 178 179 180 181
	EXPECT_EREPORT(ERROR);

	PG_TRY();
	{
		/* Run function under test */
182
		ProcessInterrupts(__FILE__, __LINE__);
183 184 185 186 187 188
		assert_true(false);
	}
	PG_CATCH();
	{
	}
	PG_END_TRY();
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

	assert_false(QueryCancelPending);
	assert_false(ImmediateInterruptOK);
}

int
main(int argc, char* argv[])
{
	cmockery_parse_arguments(argc, argv);

	const UnitTest tests[] = {
		unit_test(test__IsTransactionExitStmtList__MultipleElementList),
		unit_test(test__IsTransactionExitStmt__IsTransactionStmt),
		unit_test(test__IsTransactionExitStmt__IsQuery),
		unit_test(test__ProcessInterrupts__ClientConnectionLost),
		unit_test(test__ProcessInterrupts__DoingCommandRead)
	};

207 208
	MemoryContextInit();

209 210
	return run_tests(tests);
}