/* * Checks if the returned string segments are within memory limit for ascii characters. */ void test__find_memory_limited_substring__ascii_chars_within_memory_limit(void **state) { int subStringByteLength = -1; int subStringCharLength = -1; int cumulativeLengthConsidered = 0; char *strStart = 0xabcdefab; int totalByteLength = 25; while (cumulativeLengthConsidered < totalByteLength - MEMORY_LIMIT) { will_return(pg_database_encoding_max_length, 1); find_memory_limited_substring(strStart, totalByteLength - cumulativeLengthConsidered, MEMORY_LIMIT, &subStringByteLength, &subStringCharLength); cumulativeLengthConsidered += subStringByteLength; assert_true(subStringByteLength == MEMORY_LIMIT); assert_true(subStringByteLength == subStringCharLength); } #ifdef USE_ASSERT_CHECKING expect_any(ExceptionalCondition,conditionName); expect_any(ExceptionalCondition,errorType); expect_any(ExceptionalCondition,fileName); expect_any(ExceptionalCondition,lineNumber); will_be_called_with_sideeffect(ExceptionalCondition,&_ExceptionalCondition,NULL); /* Test if the left-over string that fits in memory cause assertion failure */ PG_TRY(); { find_memory_limited_substring(strStart, totalByteLength - cumulativeLengthConsidered, MEMORY_LIMIT, &subStringByteLength, &subStringCharLength); assert_true(false); } PG_CATCH(); { } PG_END_TRY(); expect_any(ExceptionalCondition,conditionName); expect_any(ExceptionalCondition,errorType); expect_any(ExceptionalCondition,fileName); expect_any(ExceptionalCondition,lineNumber); will_be_called_with_sideeffect(ExceptionalCondition,&_ExceptionalCondition,NULL); /* Test if null strings cause assertion failure */ PG_TRY(); { find_memory_limited_substring(NULL, totalByteLength, MEMORY_LIMIT, &subStringByteLength, &subStringCharLength); } PG_CATCH(); { return; } PG_END_TRY(); assert_true(false); #endif }
/* * Checks if null input string causes assertion failure. */ void test__find_memory_limited_substring__null_string(void **state) { int subStringByteLength = -1; int subStringCharLength = -1; int totalByteLength = MEMORY_LIMIT + 1; char *strStart = NULL; #ifdef USE_ASSERT_CHECKING expect_any(ExceptionalCondition,conditionName); expect_any(ExceptionalCondition,errorType); expect_any(ExceptionalCondition,fileName); expect_any(ExceptionalCondition,lineNumber); will_be_called_with_sideeffect(ExceptionalCondition,&_ExceptionalCondition,NULL); /* Test if null strings cause assertion failure */ PG_TRY(); { find_memory_limited_substring(strStart, totalByteLength, MEMORY_LIMIT, &subStringByteLength, &subStringCharLength); assert_true(false); } PG_CATCH(); { } PG_END_TRY(); #endif }
/* * A shared method to test proper deactivation during IdleTracker_Shutdown() * or a direct call to IdleTracker_DeactivateProcess() during regular * deactivation of an active process when a proper cleanup was done, throwing * and elog(ERROR,...) and therefore the call would never return to the calling * function */ static void CheckForDeactivationWithProperCleanup(void (*testFunc)(void)) { static EventVersion fakeCurrentVersion = 10; CurrentVersion = &fakeCurrentVersion; InitFakeSessionState(1 /* activeProcessCount */, CLEANUP_COUNTDOWN_BEFORE_RUNAWAY /* cleanupCountdown */, RunawayStatus_NotRunaway /* runawayStatus */, 1 /* pinCount */, 0 /* vmem */); EventVersion oldVersion = *CurrentVersion; /* Ensure we have a pending runaway event */ EventVersion fakeLatestRunawayVersion = *CurrentVersion - 1; latestRunawayVersion = &fakeLatestRunawayVersion; activationVersion = 0; deactivationVersion = 0; assert_true(*CurrentVersion != activationVersion); assert_true(*CurrentVersion != deactivationVersion); /* * Set to true as we want to verify that it gets set to false * once the testFunc() call returns */ isProcessActive = true; assert_true(MySessionState->activeProcessCount == 1); /* * Deactivation must call RunawayCleaner_StartCleanup before finishing deactivation * to check for cleanup requirement for any pending runaway event. The mocked method * is throwing an exception here, which would block execution of code following the call * site */ will_be_called_with_sideeffect(RunawayCleaner_StartCleanup, &_ExceptionalCondition, NULL); PG_TRY(); { testFunc(); assert_false("Expected an exception"); } PG_CATCH(); { } PG_END_TRY(); assert_true(activationVersion == 0); assert_true(deactivationVersion == *CurrentVersion); assert_true(isProcessActive == false); assert_true(MySessionState->activeProcessCount == 0); }
/* * SUT: rest_request * call_rest throws an error while not in HA mode */ void test__rest_request__callRestThrowsNoHA(void **state) { GPHDUri *hadoop_uri = (GPHDUri*) palloc0(sizeof(GPHDUri)); hadoop_uri->host = pstrdup("host1"); hadoop_uri->port = pstrdup("port1"); ClientContext* client_context = (ClientContext*) palloc0(sizeof(ClientContext)); char *restMsg = "empty message"; expect_any(call_rest, hadoop_uri); expect_any(call_rest, client_context); expect_any(call_rest, rest_msg); will_be_called_with_sideeffect(call_rest, &FirstException, NULL); /* test */ PG_TRY(); { rest_request(hadoop_uri, client_context, restMsg); } PG_CATCH(); { pfree(hadoop_uri->host); pfree(hadoop_uri->port); pfree(hadoop_uri); pfree(client_context); CurrentMemoryContext = 1; ErrorData *edata = CopyErrorData(); /*Validate the type of expected error */ assert_string_equal(edata->message, "first exception"); return; } PG_END_TRY(); assert_true(false); }
/* * SUT: rest_request * call_rest throws an error while in HA mode * and the failover method finds an active IP so the second * call to call_rest does no throw an exception */ void test__rest_request__callRestThrowsHAFirstTime(void **state) { GPHDUri *hadoop_uri = (GPHDUri*) palloc0(sizeof(GPHDUri)); hadoop_uri->host = pstrdup("host1"); hadoop_uri->port = pstrdup("port1"); NNHAConf *ha_nodes = (NNHAConf*) palloc0(sizeof(NNHAConf)); hadoop_uri->ha_nodes = ha_nodes; ha_nodes->nodes = (char *[]){"host1", "host2"}; ha_nodes->restports = (char *[]){"port1", "port2"}; ha_nodes->numn = 2; ClientContext* client_context = (ClientContext*) palloc0(sizeof(ClientContext)); char *restMsg = "empty message"; expect_any(call_rest, hadoop_uri); expect_any(call_rest, client_context); expect_any(call_rest, rest_msg); will_be_called_with_sideeffect(call_rest, &FirstException, NULL); /* the second call from ha_failover */ expect_any(call_rest, hadoop_uri); expect_any(call_rest, client_context); expect_any(call_rest, rest_msg); will_be_called(call_rest); /* test */ rest_request(hadoop_uri, client_context, restMsg); pfree(hadoop_uri); pfree(client_context); } /* * SUT: rest_request * call_rest throws an error while in HA mode * and the failover method finds an an active IP so the second * call to call_rest is issued on the second IP. This call also throws * an exception - but this time the exception is not caught. */ void test__rest_request__callRestThrowsHASecondTime(void **state) { GPHDUri *hadoop_uri = (GPHDUri*) palloc0(sizeof(GPHDUri)); hadoop_uri->host = pstrdup("host1"); hadoop_uri->port = pstrdup("port1"); NNHAConf *ha_nodes = (NNHAConf*) palloc0(sizeof(NNHAConf)); hadoop_uri->ha_nodes = ha_nodes; ha_nodes->nodes = (char *[]){"host1", "host2"}; ha_nodes->restports = (char *[]){"port1", "port2"}; ha_nodes->numn = 2; ClientContext* client_context = (ClientContext*) palloc0(sizeof(ClientContext)); char *restMsg = "empty message"; expect_any(call_rest, hadoop_uri); expect_any(call_rest, client_context); expect_any(call_rest, rest_msg); will_be_called_with_sideeffect(call_rest, &FirstException, NULL); /* the second call from ha_failover */ expect_any(call_rest, hadoop_uri); expect_any(call_rest, client_context); expect_any(call_rest, rest_msg); will_be_called_with_sideeffect(call_rest, &SecondException, NULL); /* test */ PG_TRY(); { rest_request(hadoop_uri, client_context, restMsg); } PG_CATCH(); { pfree(hadoop_uri->host); pfree(hadoop_uri->port); pfree(hadoop_uri); pfree(client_context); CurrentMemoryContext = 1; ErrorData *edata = CopyErrorData(); /*Validate the type of expected error */ assert_string_equal(edata->message, "second exception"); /* the first exception was caught by rest_request() */ return; } PG_END_TRY(); assert_true(false); } /* * SUT: rest_request * the first time call_rest is called we succeed, since the first IP is valid * No exceptions are thrown */ void test__rest_request__callRestHASuccessFromTheFirstCall(void **state) { GPHDUri *hadoop_uri = (GPHDUri*) palloc0(sizeof(GPHDUri)); hadoop_uri->host = pstrdup("host1"); hadoop_uri->port = pstrdup("port1"); NNHAConf *ha_nodes = (NNHAConf*) palloc0(sizeof(NNHAConf)); hadoop_uri->ha_nodes = ha_nodes; ha_nodes->nodes = (char *[]){"host1", "host2"}; ha_nodes->restports = (char *[]){"port1", "port2"}; ha_nodes->numn = 2; ClientContext* client_context = (ClientContext*) palloc0(sizeof(ClientContext)); char *restMsg = "empty message"; expect_any(call_rest, hadoop_uri); expect_any(call_rest, client_context); expect_any(call_rest, rest_msg); will_be_called(call_rest); /* test */ rest_request(hadoop_uri, client_context, restMsg); pfree(hadoop_uri->host); pfree(hadoop_uri->port); pfree(hadoop_uri); pfree(client_context); } void test__normalize_size(void **state) { float4 result = normalize_size(10000000, "B"); assert_int_equal(result, 10000000); result = normalize_size(10000000, "KB"); assert_int_equal(result, 10240000000); result = normalize_size(500, "MB"); assert_int_equal(result, 524288000); result = normalize_size(10, "GB"); assert_int_equal(result, 10737418240); result = normalize_size(10000, "TB"); assert_int_equal(result, 10995116277760000); } int main(int argc, char *argv[]) { cmockery_parse_arguments(argc, argv); const UnitTest tests[] = { unit_test(test__rest_request__callRestThrowsNoHA), unit_test(test__rest_request__callRestThrowsHAFirstTime), unit_test(test__rest_request__callRestThrowsHASecondTime), unit_test(test__rest_request__callRestHASuccessFromTheFirstCall), unit_test(test__normalize_size) }; return run_tests(tests); }
/* 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 */ void test__ExecSetParamPlan__Check_Dispatch_Results(void **state) { /*Set plan to explain.*/ SubPlanState *plan = makeNode(SubPlanState); plan->xprstate.expr = makeNode(SubPlanState); plan->planstate = makeNode(SubPlanState); plan->planstate->instrument = (Instrumentation *)palloc(sizeof(Instrumentation)); plan->planstate->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 = (EState *)palloc(sizeof(EState)); queryDesc->estate->es_sliceTable = (SliceTable *) palloc(sizeof(SliceTable)); /*QueryDescriptor generated when shouldDispatch is true.*/ QueryDesc *internalQueryDesc = (QueryDesc *)palloc(sizeof(QueryDesc)); internalQueryDesc->estate = (EState *)palloc(sizeof(EState)); /* Added to force assertion on queryDesc->estate->interconnect_context; to fail */ internalQueryDesc->estate->interconnect_context=NULL; internalQueryDesc->estate->es_sliceTable = (SliceTable *) palloc(sizeof(SliceTable)); expect_any(CreateQueryDesc,plannedstmt); expect_any(CreateQueryDesc,sourceText); expect_any(CreateQueryDesc,snapshot); expect_any(CreateQueryDesc,crosscheck_snapshot); expect_any(CreateQueryDesc,dest); expect_any(CreateQueryDesc,params); expect_any(CreateQueryDesc,doInstrument); will_return(CreateQueryDesc,internalQueryDesc); Gp_role = GP_ROLE_DISPATCH; plan->planstate->plan->dispatch=DISPATCH_PARALLEL; will_be_called(isCurrentDtxTwoPhase); expect_any(cdbdisp_dispatchPlan,queryDesc); expect_any(cdbdisp_dispatchPlan,planRequiresTxn); expect_any(cdbdisp_dispatchPlan,cancelOnError); expect_any(cdbdisp_dispatchPlan,ds); will_be_called(cdbdisp_dispatchPlan); expect_any(SetupInterconnect,estate); /* Force SetupInterconnect to fail */ will_be_called_with_sideeffect(SetupInterconnect,&_RETHROW,NULL); expect_any(cdbexplain_localExecStats,planstate); expect_any(cdbexplain_localExecStats,showstatctx); will_be_called(cdbexplain_localExecStats); expect_any(CdbCheckDispatchResult,ds); expect_any(CdbCheckDispatchResult,waitMode); will_be_called(CdbCheckDispatchResult); 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); will_be_called(TeardownSequenceServer); expect_any(TeardownInterconnect,transportStates); expect_any(TeardownInterconnect,mlStates); expect_any(TeardownInterconnect,forceEOS); will_be_called(TeardownInterconnect); /* Catch PG_RE_THROW(); after cleaning with CdbCheckDispatchResult */ PG_TRY(); ExecSetParamPlan(plan,econtext,queryDesc); PG_CATCH(); assert_true(true); PG_END_TRY(); }
/* * Checks if the returned string segments are within memory limit for multi-bytes chars. */ void test__find_memory_limited_substring__mb_chars_within_memory_limit(void **state) { int subStringByteLength = -1; int subStringCharLength = -1; int cumulativeLengthConsidered = 0; /* Lengths of the multi-byte characters at different positions */ int stringByteLengths[] = {3, 3, 3 /* seg1 */, 2, 2, 1, 2 /* seg2 */, 2, 1, 1, 1, 2, /* seg3 */ 5, 4 /* seg4 */, 4}; /* Total length in terms of number of characters */ int stringCharLength = sizeof(stringByteLengths) / sizeof(int); /* Total byte lengths of all the characters */ int totalByteLength = 0; for (int charIndex = 0; charIndex < stringCharLength; charIndex++) { totalByteLength += stringByteLengths[charIndex]; } int segmentByteLength = 0; /* Number of bytes in current segment */ int segmentCharLength = 0; /* Number of characters in current segment */ /* Length of the char that spilled over from one partition to another */ int carryoverLength = 0; /* Fictitious multi-byte string to segment */ char *strStart = 0xabcdefab; for (int charIndex = 0; charIndex < stringCharLength; charIndex++) { if (carryoverLength > 0) { expect_any(pg_mblen, mbstr); will_return(pg_mblen, carryoverLength); carryoverLength = 0; } expect_any(pg_mblen, mbstr); will_return(pg_mblen, stringByteLengths[charIndex]); segmentByteLength += stringByteLengths[charIndex]; segmentCharLength++; if (segmentByteLength > MEMORY_LIMIT) { will_return(pg_database_encoding_max_length, 6); find_memory_limited_substring(strStart, totalByteLength - cumulativeLengthConsidered, MEMORY_LIMIT, &subStringByteLength, &subStringCharLength); assert_true(subStringByteLength == (segmentByteLength - stringByteLengths[charIndex])); assert_true(subStringCharLength == (segmentCharLength - 1)); assert_true(subStringByteLength <= MEMORY_LIMIT); assert_true(subStringCharLength <= MEMORY_LIMIT); cumulativeLengthConsidered += subStringByteLength; segmentByteLength = stringByteLengths[charIndex]; segmentCharLength = 1; carryoverLength = stringByteLengths[charIndex]; } } /* Now purge any unused pg_mblen call because of the suffix that does not exceed MEMORY_LIMIT */ for (int partitionCharIndex = 0; partitionCharIndex < segmentCharLength; partitionCharIndex++) { pg_mblen("a"); } #ifdef USE_ASSERT_CHECKING expect_any(ExceptionalCondition,conditionName); expect_any(ExceptionalCondition,errorType); expect_any(ExceptionalCondition,fileName); expect_any(ExceptionalCondition,lineNumber); will_be_called_with_sideeffect(ExceptionalCondition,&_ExceptionalCondition,NULL); /* Test if the left-over string that fits in memory cause assertion failure */ PG_TRY(); { find_memory_limited_substring(strStart, totalByteLength - cumulativeLengthConsidered, MEMORY_LIMIT, &subStringByteLength, &subStringCharLength); } PG_CATCH(); { return; } PG_END_TRY(); assert_true(false); #endif }
/* Tests whether SharedChunkHeadersMemoryAccount ignores the overhead of null Account header */ void test__AllocFreeInfo__SharedChunkHeadersMemoryAccountIgnoresNullHeader(void **state) { /* This has two parts: * 1. Check the assertion that nullAccountHeader creation requires * SharedChunkHeadersMemoryAccount to be NULL * * 2. Reset the context that hosts the nullAccountHeader, and make sure * that SharedChunkHeadersMemoryAccount balance does not get changed */ MemoryContext *newContext = AllocSetContextCreate(ErrorContext, "TestContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); AllocSet newSet = (AllocSet)newContext; assert_true(newSet->sharedHeaderList == NULL); assert_true(newSet->nullAccountHeader == NULL); MemoryAccount *oldActive = ActiveMemoryAccount; MemoryAccount *oldShared = SharedChunkHeadersMemoryAccount; /* Turning off memory monitoring */ ActiveMemoryAccount = NULL; #ifdef USE_ASSERT_CHECKING expect_any(ExceptionalCondition,conditionName); expect_any(ExceptionalCondition,errorType); expect_any(ExceptionalCondition,fileName); expect_any(ExceptionalCondition,lineNumber); will_be_called_with_sideeffect(ExceptionalCondition, &_ExceptionalCondition, NULL); /* Test if within memory-limit strings cause assertion failure */ PG_TRY(); { /* * ActiveMemoryAccount is NULL, but SharedChunkHeadersMemoryAccount is * *not* null. This should trigger an assertion */ void *testAlloc = MemoryContextAlloc(newContext, NEW_ALLOC_SIZE); assert_true(false); } PG_CATCH(); { } PG_END_TRY(); #endif /* * Now make SharedChunkHeadersMemoryAccount NULL to avoid assert failure * and allow creation of a nullAccountHeader */ SharedChunkHeadersMemoryAccount = NULL; /* Allocate from the new context which should trigger a nullAccountHeader creation*/ void *testAlloc = MemoryContextAlloc(newContext, NEW_ALLOC_SIZE); StandardChunkHeader *header = (StandardChunkHeader *) ((char *) testAlloc - STANDARDCHUNKHEADERSIZE); /* * Assert if we are using nullAccountHeader, as we have simulated absence * of memory monitoring */ assert_true(header->sharedHeader != NULL && header->sharedHeader == newSet->nullAccountHeader); /* * Restore the SharedChunkHeadersMemoryAccount so that we can turn on * sharedHeader balance releasing if a sharedHeader is deleted (except * nullAccountHeader of course) */ SharedChunkHeadersMemoryAccount = oldShared; /* Activate the memory accounting */ ActiveMemoryAccount = oldActive; uint64 sharedBalance = SharedChunkHeadersMemoryAccount->allocated - SharedChunkHeadersMemoryAccount->freed; pfree(testAlloc); /* * As testAlloc is holding a pointer to nullAccountHeader, releasing that allocation * should not change SharedChunkHeadersMemoryAccount balance */ assert_true(sharedBalance == SharedChunkHeadersMemoryAccount->allocated - SharedChunkHeadersMemoryAccount->freed); MemoryContextDelete(newContext); }