提交 dc345256 编写于 作者: H Heikki Linnakangas

Replace nodeSubplan cmockery test with a fault injection case.

The mock setup in the old test was very limited, the Node structs it set
up were left to zeros, and even allocated with incorrect lengths (SubPlan
vs SubPlanState). It worked just enough for the codepath that it was
testing, but IMHO it's better to test the error "in vivo", and it requires
less setup, too. So remove the mock test, and replace with a fault
injector test that exercises the same codepath.
上级 e00da975
......@@ -2,18 +2,10 @@ subdir=src/backend/executor
top_builddir=../../../..
include $(top_builddir)/src/Makefile.global
TARGETS=nodeSubplan nodeShareInputScan
TARGETS=nodeShareInputScan
include $(top_builddir)/src/backend/mock.mk
nodeSubplan.t: \
$(MOCK_DIR)/backend/cdb/dispatcher/cdbdisp_mock.o \
$(MOCK_DIR)/backend/cdb/dispatcher/cdbdisp_query_mock.o \
$(MOCK_DIR)/backend/commands/explain_mock.o \
$(MOCK_DIR)/backend/cdb/cdbtm_mock.o \
$(MOCK_DIR)/backend/cdb/motion/ic_common_mock.o \
$(MOCK_DIR)/backend/tcop/pquery_mock.o
nodeShareInputScan.t: \
$(MOCK_DIR)/backend/executor/execUtils_mock.o \
$(MOCK_DIR)/backend/utils/sort/tuplestorenew_mock.o
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include "cmockery.h"
#include "../nodeSubplan.c"
/*
* These functions are defined in explain_gp.c, which in turn is included
* from explain.c. Since the mocker.py utility has trouble mocking this
* structure, we include the relevant functions we need here instead.
*/
void cdbexplain_localExecStats(struct PlanState *planstate,
struct CdbExplain_ShowStatCtx *showstatctx)
{
check_expected(planstate);
check_expected(showstatctx);
mock();
}
void
cdbexplain_recvExecStats(struct PlanState *planstate,
struct CdbDispatchResults *dispatchResults,
int sliceIndex,
struct CdbExplain_ShowStatCtx *showstatctx)
{
check_expected(planstate);
check_expected(dispatchResults);
check_expected(sliceIndex);
check_expected(showstatctx);
mock();
}
void
cdbexplain_sendExecStats(QueryDesc *queryDesc)
{
mock();
}
static void
cdbdispatch_succeed(void *ptr)
{
EState *estate = (EState*) ptr;
estate->dispatcherState = (CdbDispatcherState *) palloc(sizeof(CdbDispatcherState));
}
/* Function passed to testing framework
* in order to force SetupInterconnect to fail */
static void
setupinterconnect_fail(void *ptr)
{
PG_RE_THROW();
}
/* Checks CdbCheckDispatchResult is called when queryDesc
* is not null (when shouldDispatch is true).
* This test falls in PG_CATCH when SetupInterconnect
* does not allocate queryDesc->estate->interconnect_context.
* The test is successful if the */
static void
test__ExecSetParamPlan__Check_Dispatch_Results(void **state)
{
/* Set plan to explain. */
SubPlanState *plan = makeNode(SubPlanState);
plan->xprstate.expr = (Expr *) makeNode(SubPlanState);
plan->planstate = (PlanState *) makeNode(SubPlanState);
plan->planstate->instrument = (Instrumentation *)palloc(sizeof(Instrumentation));
plan->planstate->instrument->need_timer = true;
plan->planstate->instrument->need_cdb = true;
plan->planstate->plan = (Plan *) makeNode(SubPlanState);
EState *estate = CreateExecutorState();
/*Assign mocked estate to plan.*/
((PlanState *)(plan->planstate))->state= estate;
/*Re-use estate mocked object. Needed as input parameter for
tested function */
ExprContext *econtext = GetPerTupleExprContext(estate);
/*Set QueryDescriptor input parameter for tested function */
PlannedStmt *plannedstmt = (PlannedStmt *)palloc(sizeof(PlannedStmt));
QueryDesc *queryDesc = (QueryDesc *)palloc(sizeof(QueryDesc));
queryDesc->plannedstmt = plannedstmt;
queryDesc->estate = CreateExecutorState();
queryDesc->estate->es_sliceTable = (SliceTable *) palloc(sizeof(SliceTable));
Gp_role = GP_ROLE_DISPATCH;
((SubPlan*)(plan->xprstate.expr))->initPlanParallel = true;
will_be_called(isCurrentDtxTwoPhaseActivated);
expect_any(CdbDispatchPlan,queryDesc);
expect_any(CdbDispatchPlan,planRequiresTxn);
expect_any(CdbDispatchPlan,cancelOnError);
will_be_called_with_sideeffect(CdbDispatchPlan, &cdbdispatch_succeed, queryDesc->estate);
expect_any(SetupInterconnect,estate);
/* Force SetupInterconnect to fail */
will_be_called_with_sideeffect(SetupInterconnect, &setupinterconnect_fail, NULL);
expect_any(cdbexplain_localExecStats,planstate);
expect_any(cdbexplain_localExecStats,showstatctx);
will_be_called(cdbexplain_localExecStats);
expect_any(cdbdisp_cancelDispatch,ds);
will_be_called(cdbdisp_cancelDispatch);
expect_any(CdbDispatchHandleError, ds);
will_be_called(CdbDispatchHandleError);
expect_any(cdbexplain_recvExecStats,planstate);
expect_any(cdbexplain_recvExecStats,dispatchResults);
expect_any(cdbexplain_recvExecStats,sliceIndex);
expect_any(cdbexplain_recvExecStats,showstatctx);
will_be_called(cdbexplain_recvExecStats);
/* Catch PG_RE_THROW(); after cleaning with CdbCheckDispatchResult */
PG_TRY();
ExecSetParamPlan(plan,econtext,queryDesc);
PG_CATCH();
assert_true(true);
PG_END_TRY();
}
int
main(int argc, char* argv[])
{
cmockery_parse_arguments(argc, argv);
const UnitTest tests[] = {
unit_test(test__ExecSetParamPlan__Check_Dispatch_Results)
};
MemoryContextInit();
return run_tests(tests);
}
......@@ -490,13 +490,28 @@ SELECT gp_inject_fault('interconnect_setup_palloc', 'error', 1);
SELECT * FROM a;
ERROR: fault triggered, fault name:'interconnect_setup_palloc' fault type:'error'
DROP TABLE a;
SELECT gp_inject_fault('interconnect_setup_palloc', 'reset', 1);
gp_inject_fault
-----------------
Success:
(1 row)
-- The same, but the fault happens while dispatching an Init Plan.
SELECT gp_inject_fault('interconnect_setup_palloc', 'error', 1);
gp_inject_fault
-----------------
Success:
(1 row)
SELECT * FROM generate_series(1, 5) g WHERE g < (SELECT max(a.j) FROM a);
ERROR: fault triggered, fault name:'interconnect_setup_palloc' fault type:'error'
SELECT gp_inject_fault('interconnect_setup_palloc', 'reset', 1);
gp_inject_fault
-----------------
Success:
(1 row)
DROP TABLE a;
-- Test sender QE errors out when setup outgoing connection, the receiver QE is waiting,
-- at this time, QD should be able to process the error and cancel the receiver QE.
CREATE TABLE test_ic_error(a INT, b int);
......
......@@ -208,9 +208,15 @@ CREATE TABLE a (i INT, j INT) DISTRIBUTED BY (i);
INSERT INTO a (SELECT i, i * i FROM generate_series(1, 10) as i);
SELECT gp_inject_fault('interconnect_setup_palloc', 'error', 1);
SELECT * FROM a;
DROP TABLE a;
SELECT gp_inject_fault('interconnect_setup_palloc', 'reset', 1);
-- The same, but the fault happens while dispatching an Init Plan.
SELECT gp_inject_fault('interconnect_setup_palloc', 'error', 1);
SELECT * FROM generate_series(1, 5) g WHERE g < (SELECT max(a.j) FROM a);
SELECT gp_inject_fault('interconnect_setup_palloc', 'reset', 1);
DROP TABLE a;
-- Test sender QE errors out when setup outgoing connection, the receiver QE is waiting,
-- at this time, QD should be able to process the error and cancel the receiver QE.
CREATE TABLE test_ic_error(a INT, b int);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册