CLIENT_UNIT, META_CLIENT_IP => STRING_SESSION_HOME, META_SYSTEM_NOTES => STRING_ORIGIN_UT, META_TEMPLATE => TEMPLATE_CLASS_TEST_MONGO ]; // meta data for admin requests static::$adminMeta = [ META_CLIENT => CLIENT_UNIT, META_CLIENT_IP => STRING_SESSION_HOME, META_SYSTEM_NOTES => STRING_ORIGIN_UT ]; } /** * setUp() -- unit test reserved method * * the setUp method is executed prior to each test, executing the following tasks: * * 1. validate that the meta data persisted across tests * 2. validate that we successfully created a write-broker client * 3. validate that we successfully created a read-broker client * 4. validate the successful instantiation of a factory-class and assign to the widget static * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 05-28-19 mks original coding * */ protected function setUp() { parent::setUp(); $errors = array(); // validate the meta data for the pending query $this->assertTrue(!empty(static::$meta), __FILE__ . COLON . __LINE__ . COLON . ERROR_DATA_META_404); $this->assertTrue(is_array(static::$meta), __FILE__ . COLON . __LINE__ . COLON . ERROR_META_INVALID_FORMAT_ARRAY); $this->assertTrue(array_key_exists(META_TEMPLATE, static::$meta), __FILE__ . COLON . __LINE__ . COLON . ERROR_DATA_META_KEY_404 . META_TEMPLATE); // create the write broker client $this->writeBrokerClient = new gacBrokerClient(BROKER_QUEUE_W, basename(__FILE__) . COLON . __METHOD__ . COLON . __LINE__); $this->assertTrue($this->writeBrokerClient->status, __METHOD__ . __LINE__ . ERROR_BROKER_QUEUE_DECLARE . BROKER_QUEUE_W); // create the read broker client $this->readBrokerClient = new gacBrokerClient(BROKER_QUEUE_R, basename(__FILE__) . COLON . __METHOD__ . COLON . __LINE__); $this->assertTrue($this->readBrokerClient->status, __METHOD__ . __LINE__ . ERROR_BROKER_QUEUE_DECLARE . BROKER_QUEUE_R); // create the admin broker client $this->adminOutClient = new gacBrokerClient(BROKER_QUEUE_AO, basename(__FILE__) . COLON . __METHOD__ . COLON . __LINE__); $this->assertTrue($this->adminOutClient->status, __FILE__ . COLON . __LINE__ . COLON . ERROR_BROKER_QUEUE_DECLARE . BROKER_QUEUE_AO); // instantiate a new widget $objFactory = new gacFactory(static::$meta, FACTORY_EVENT_NEW_CLASS, '', $errors); $this->assertTrue($objFactory->status, __FILE__ . COLON . __LINE__ . COLON . ERROR_FAILED_TO_INSTANTIATE . static::$meta[META_TEMPLATE]); // extract and assign the factory widget and deallocate the factory static::$widget = $objFactory->widget; if (is_object($objFactory)) $objFactory->__destruct(); unset($objFactory); // ensure that caching, auditing, and journaling are enabled for the class and that deletes are set to false $this->assertTrue(static::$widget->useCache, __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_TRUE . STRING_CACHE); $this->assertGreaterThan(0, static::$widget->useAuditing, __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_NON_ZERO_INT . static::$widget->useAuditing); $this->assertTrue(static::$widget->useJournaling, __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_TRUE . STRING_JOURNAL); $this->assertFalse(static::$widget->useDeletes, __FILE__ . COLON . __LINE__ . ERROR_UT_EXPECTING_FALSE . STRING_DELETE); } /** * tearDown() -- unit test method * * This is the (reserved) tearDown method which is executed at the end of every test. The method deletes the * current broker client. * * * @author mike@givingassistant.org * @version 1.0 * * HISTORY: * ======== * 05-28-19 mks original coding * */ protected function tearDown() { if (is_object($this->readBrokerClient)) $this->readBrokerClient->__destruct(); unset($this->readBrokerClient); if (is_object($this->writeBrokerClient)) $this->writeBrokerClient->__destruct(); unset($this->writeBrokerClient); if (is_object(static::$widget)) { static::$widget->__destruct(); } static::$widget = null; } /** * testOneInsert() -- unit test method * * This unit test method starts the mongo testing by creating a new record in the gaTest collection. The point * of the method is to create a record, then extract the newly-created record from the event return payload - * this data is validated and then stored in the the unit-test statics for future access and queries. * * The following assertions are made: * * -- assert that we successfully created and fetched the new record * -- assert that only one test record was created (prior to the insert) * -- assert that the create request was successful (PAYLOAD_STATUS) * -- assert the the create request returned a state-success (PAYLOAD_STATE) * -- assert that the create event created one and only one new record (PAYLOAD_RESULTS) * * If the randomly generated record has the following, then do: * * -- if there's an integer field, confirm that the integer value matches the test record value * -- if there's a double field, confirm that the floating-point value matches the test record value * -- if there's a string field, confirm that the string value matches the test record value * * We'll finally test that injected fields exist in the record: * * -- assert that a token was created in the new record * -- assert that the token passes GUID validation * -- assert that the status column was created in the new record * -- assert that the status value is active * -- assert that an event guid was inserted into the record * -- assert that the event guid passes token validation * -- assert that the created field was inserted into the record * * If all assertions are created, then store the original test record, the test record token, and the event token. * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-06-19 mks DB-122: original coding * */ public function testOneInsert() { $testRecord = null; $this->assertTrue(is_object(static::$widget), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_WIDGET_404); $thisMeta = static::$meta; $thisMeta[META_DO_CACHE] = false; // create one record $testRecord = static::$widget->template->buildTestData(1); $intVal = (isset($testRecord[0][CM_TST_FIELD_TEST_INT])) ? $testRecord[0][CM_TST_FIELD_TEST_INT] : null; $doubleVal = (isset($testRecord[0][CM_TST_FIELD_TEST_DOUBLE])) ? $testRecord[0][CM_TST_FIELD_TEST_DOUBLE] : null; $strVal = (isset($testRecord[0][CM_TST_FIELD_TEST_STRING])) ? $testRecord[0][CM_TST_FIELD_TEST_STRING] : null; $this->assertTrue(is_array($testRecord), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_TRUE . 'is_array($testRecord)'); $this->assertEquals(1, count($testRecord), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 1, count($testRecord))); static::$originalTestRecord = $testRecord; // store the original record before insertion // create the query/broker-event payload $request = [ BROKER_REQUEST => BROKER_REQUEST_CREATE, BROKER_DATA => $testRecord, BROKER_META_DATA => $thisMeta ]; // build the request payload and submit the request to the write broker $payload = gzcompress(json_encode($request)); $response = $this->writeBrokerClient->call($payload); $response = json_decode(gzuncompress($response), true); // validate the response payload $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_CREATE, $response[PAYLOAD_STATE])); $this->assertEquals(STATE_SUCCESS, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_STRING_MISMATCH, STATE_SUCCESS, $response[PAYLOAD_STATE])); $this->assertEquals(1, count($response[PAYLOAD_RESULTS]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 1, count($response[PAYLOAD_RESULTS]))); // validate that the record was obtained in the return payload and that specific values match the pre-create test record values if (!is_null($intVal)) { $iVal = $response[PAYLOAD_RESULTS][0][CM_TST_FIELD_TEST_INT]; // 2 long 2 type twice $this->assertEquals($intVal, $iVal, (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_VALS_NOT_EQUAL, $intVal, $iVal)); } if (!is_null($doubleVal)) { $dVal = $response[PAYLOAD_RESULTS][0][CM_TST_FIELD_TEST_DOUBLE]; $this->assertEquals($doubleVal, $dVal, (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_VALS_NOT_EQUAL, $doubleVal, $dVal)); } if (!is_null($strVal)) { $sVal = $response[PAYLOAD_RESULTS][0][CM_TST_FIELD_TEST_STRING]; $this->assertEquals($strVal, $sVal, (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_VALS_NOT_EQUAL, $strVal, $sVal)); } // ensure we have the system-side injections $this->assertArrayHasKey(STRING_KEY, $response[PAYLOAD_RESULTS][0], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_FIELD_404, STRING_KEY, PAYLOAD_RESULTS)); $this->assertTrue(validateGUID($response[PAYLOAD_RESULTS][0][STRING_KEY]), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . $response[PAYLOAD_RESULTS][0][STRING_KEY]); $this->assertArrayHasKey(CM_TST_FIELD_TEST_STATUS, $response[PAYLOAD_RESULTS][0], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_FIELD_404, CM_TST_FIELD_TEST_STATUS, PAYLOAD_RESULTS)); $status = $response[PAYLOAD_RESULTS][0][CM_TST_FIELD_TEST_STATUS]; $this->assertEquals(STATUS_ACTIVE, $status, (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_VALS_NOT_EQUAL, STATUS_ACTIVE, $status)); $this->assertArrayHasKey(CM_TST_EVENT_GUID, $response[PAYLOAD_RESULTS][0], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_FIELD_404, CM_TST_EVENT_GUID, PAYLOAD_RESULTS)); $this->assertTrue(validateGUID($response[PAYLOAD_RESULTS][0][CM_TST_EVENT_GUID]), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . $response[PAYLOAD_RESULTS][0][CM_TST_EVENT_GUID]); $this->assertArrayHasKey(CM_TST_FIELD_TEST_CDATE, $response[PAYLOAD_RESULTS][0], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_FIELD_404, CM_TST_FIELD_TEST_CDATE, PAYLOAD_RESULTS)); $this->assertTrue(is_int($response[PAYLOAD_RESULTS][0][CM_TST_FIELD_TEST_CDATE]), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_UT_EXPECTING_NON_ZERO_INT . $response[PAYLOAD_RESULTS][0][CM_TST_FIELD_TEST_CDATE]); // store copies of the data that will be used in subsequent methods... static::$testRecord = $response[PAYLOAD_RESULTS][0]; // store the db-version of the record static::$testRecordToken = static::$testRecord[STRING_KEY]; static::$eventRecordToken = static::$testRecord[CM_TST_EVENT_GUID]; } /** * testInsertAudit() -- unit test method * * This method first validates the statics that were stored previous to this method: * * -- assert that the original test record was saved * -- assert that the (saved) test record was saved * -- assert that test record token was saved * -- assert that the event record token was saved * * Next, build a query and submit the query to the admin service that will fetch the audit record -- said query * was based on the record's token and eventGUID -- this query makes the record returned unique. * * Once the data from the query is returned from the admin server, we make the following assertions: * * -- assert that there exists a token (for the audit record) in the return payload * -- assert that the token is valid * * Store the auditRecordToken and the audit record into a class static. * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-06-19 mks DB-122: original coding * */ public function testInsertAudit() { // sleep for a second to allow the audit record to be written to disk sleep(1); $this->assertNotEmpty(static::$originalTestRecord, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the original test record'); $this->assertNotEmpty(static::$testRecord, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the test record'); $this->assertNotEmpty(static::$testRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the test record token'); $this->assertNotEmpty(static::$eventRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the event token'); // build the query to fetch the audit record from the admin service based on the created-record token and the // eventGUID assigned to the record...this implicitly validates the audit record for the create event. $query = [ AUDIT_RECORD_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$testRecordToken ]]], DB_EVENT_GUID => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$eventRecordToken ]]], OPERAND_AND => null ]; static::$adminMeta[META_TEMPLATE] = TEMPLATE_CLASS_AUDIT; $request = [ BROKER_REQUEST => BROKER_REQUEST_REMOTE_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => static::$adminMeta ]; $payload = gzcompress(json_encode($request)); $response = $this->adminOutClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_REMOTE_FETCH, $response[PAYLOAD_STATE])); // once we got the audit record, validate the operation, the status, and pull the audit record token // for a future query against the journal record $this->assertArrayHasKey((DB_TOKEN . COLLECTION_MONGO_AUDIT_EXT), $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_FIELD_404, DB_TOKEN, STRING_QUERY_RESULTS)); static::$auditRecordToken = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][DB_TOKEN . COLLECTION_MONGO_AUDIT_EXT]; $this->assertTrue(validateGUID(static::$auditRecordToken), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . static::$auditRecordToken); static::$auditRecord = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0]; } /** * testInsertJournal() - unit test method * * This method is used in conjunction with the insert method above. The previous two methods inserted a new record * and validated that the audit record was created as a result of the insert, respectively. This method validates * that the journal record was created for the insert event. * * The following assertions are made in this method: * * -- the test record token was successfully saved * -- the event record token was successfully saved * -- the audit record token was successfully saved * * We then submit a query to the admin-out broker to fetch the journal record based on the audit record and data * record tokens and the event GUID we generated for the create event. (The event token locks down the request * to the insert query.) * * -- the fetch-journal record returned with a true status * -- the fetch event request returned one record * * We save the journal record into the static member so that, in the next method, we validate the content of * the journal record by executing the journal rollback. * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-10-19 mks DB-122: original coding * */ public function testInsertJournal() { $this->assertNotEmpty(static::$testRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the test record token'); $this->assertNotEmpty(static::$eventRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the event token'); $this->assertNotEmpty(static::$auditRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the audit record token'); // implicitly test that we created the journal record off the insert event by querying the database by the // data record token, the event guid, and the audit token together. This way, if the record has more than // one journal record associated with the record guid, we're still filtering by the event guid. // build the fetch query for the journaling collection $query = [ JOURNAL_AUD_TOK => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$auditRecordToken ]]], JOURNAL_SYSEV_TOK => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$eventRecordToken]]], JOURNAL_RECORD_GUID => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$testRecordToken]]], OPERAND_AND => null ]; $tmpMeta = static::$adminMeta; $tmpMeta[META_TEMPLATE] = TEMPLATE_CLASS_JOURNAL; $payload = [ BROKER_REQUEST => BROKER_REQUEST_REMOTE_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $tmpMeta ]; $request = gzcompress(json_encode($payload)); $response = $this->adminOutClient->call($request); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_FETCH, $response[PAYLOAD_STATE])); $this->assertEquals(1, count($response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 1, count($response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS]))); // load the journal record into a static member for the next test static::$journalRecord = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0]; static::$journalRecordToken = static::$journalRecord[DB_TOKEN . COLLECTION_MONGO_JOURNAL_EXT]; $this->assertTrue(validateGUID(static::$journalRecordToken), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . static::$journalRecordToken); } /** * testInsertJournalRecovery() -- unit test method * * This unit test method is responsible for exec'ing the journal-recovery plan from the create event. First, * however, we make the following checks: * * -- assert that the test record token is still stored in the static * -- assert that the event record token is still stored in the static * -- assert that the audit record token is still stored in the static * -- assert that the journal record is still stored in the static * -- assert that the journal token is still stored in the static * * Next, we build and publish the request to the adminOut broker - this event executes the restore query stored * in the journal record which, in this case, should delete the record causing the subsequent fetch event to fail. * * -- assert that the request published returned with true status meaning that the event completed successfully * -- assert that the subsequent fetch request failed (record should still exists albeit with a deleted status) * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-10-19 mks DB-122: original coding * */ public function testInsertJournalRecovery() { $this->assertNotEmpty(static::$testRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the test record token'); $this->assertNotEmpty(static::$eventRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the event token'); $this->assertNotEmpty(static::$auditRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the audit record token'); $this->assertNotEmpty(static::$journalRecord, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the journal record'); $this->assertNotEmpty(static::$journalRecordToken, (basename(__METHOD__) . AT . __LINE__ . COLON) . 'lost the journal record token'); // once we've confirmed that the statics are saved, construct the restore-audit query: $query = [ STRING_KEY => static::$auditRecordToken ]; $meta = static::$adminMeta; $meta[META_TEMPLATE] = TEMPLATE_CLASS_AUDIT; $request = [ BROKER_REQUEST => BROKER_REQUEST_AUDIT_RESTORE, BROKER_DATA => $query, BROKER_META_DATA => $meta ]; $payload = gzcompress(json_encode($request)); $response = $this->adminOutClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_AUDIT_RESTORE, $response[PAYLOAD_STATE])); // if we're still executing, that the record was "restored" --- attempt to pull the record $query = [ DB_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [static::$testRecordToken ]]]]; $request = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => static::$meta ]; $payload = gzcompress(json_encode($request)); $response = $this->readBrokerClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertEquals(STATE_NOT_FOUND, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . sprintf(ERROR_UT_VALS_NOT_EQUAL, STATE_NOT_FOUND, $response[PAYLOAD_STATE])); } /** * testMultipleInserts() -- unit test method * * This is another insert test but we're testing insertion of more than one record in a single event. This test * can be run as a stand-alone test as it's not predicated on any class-stored data. * * -- assert that the widget is still active in the static member * * We're going to generate a random number between 50 and 100 -- this will be the number of records we're going * to create and pass into the event request as the data payload. Prior to submitting the request, we adjust * the standard meta-data payload s.t. we'll disable a cached return payload. * * -- test that the create event return status was successful * -- test that the number of inserted records requested matched the number of records returned * * Pull a random record from the return payload and make the following assertions/comparisons against the originally * submitted record. * * -- assert that the test integer values match * -- assert that the string value matches * -- assert that the double value matches * -- assert that the boolean value matched * * Also test that we have the injected fields: * * -- assert that date-created field is present in the random record * -- assert that the token field is present in the random record * -- assert that the status field is present in the random record * -- assert that the token field is a valid token * -- assert that the status field contains the value STATUS_ACTIVE * -- assert that the date-created field is an integer value * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-10-19 mks DB-122: original coding * */ public function testMultipleInserts() { $this->assertTrue(is_object(static::$widget), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_UT_WIDGET_404); // create a random number of records between 50 and 100 and validate the numbers $recCount = mt_rand(50,100); $testRecords = static::$widget->template->buildTestData($recCount); $this->assertTrue(is_array($testRecords), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_UT_EXPECTING_TRUE . 'is_array(testRecords)'); $this->assertEquals($recCount, count($testRecords), (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_INTEGER_MISMATCH, $recCount, count($testRecords))); // change the meta payload to ignore cache $meta = static::$meta; $meta[META_DO_CACHE] = false; // build the create-event request $request = [ BROKER_REQUEST => BROKER_REQUEST_CREATE, BROKER_DATA => $testRecords, BROKER_META_DATA => $meta ]; // build the request payload and submit the request to the write broker $payload = gzcompress(json_encode($request)); $response = $this->writeBrokerClient->call($payload); $response = json_decode(gzuncompress($response), true); // evaluate the request response $this->assertTrue($response[PAYLOAD_STATUS], (__FILE__ . COLON) . __LINE__ . COLON . ERROR_UT_EXPECTING_TRUE . PAYLOAD_STATUS); // validate that the count of inserted records matches the number of records, or cache keys, returned // first, fetch the referenced item from cache $guidPayload = $response[PAYLOAD_RESULTS]; $this->assertTrue(is_array($guidPayload), basename(__METHOD__) . AT . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_VALUE, 'guidPayload')); $this->assertEquals(count($guidPayload), $recCount, basename(__METHOD__) . AT . __LINE__ . COLON . sprintf(ERROR_UT_VALS_NOT_EQUAL, count($guidPayload), ($recCount + 1))); // fetch a random record from cache $rr = mt_rand(0, ($recCount - 1)); $rec = $guidPayload[$rr]; $recCacheGUID = $rec[STRING_KEY]; $this->assertTrue(validateGUID($recCacheGUID), basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_INVALID_GUID . $recCacheGUID); // compare the random record base values to the same record still stored in the array we submitted to the broker $this->assertEquals($testRecords[$rr][CM_TST_FIELD_TEST_INT], $rec[CM_TST_FIELD_TEST_INT], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_INT)); $this->assertEquals($testRecords[$rr][CM_TST_FIELD_TEST_STRING], $rec[CM_TST_FIELD_TEST_STRING], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_STRING)); $this->assertEquals($testRecords[$rr][CM_TST_FIELD_TEST_DOUBLE], $rec[CM_TST_FIELD_TEST_DOUBLE], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_DOUBLE)); $this->assertEquals($testRecords[$rr][CM_TST_FIELD_TEST_BOOL], $rec[CM_TST_FIELD_TEST_BOOL], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_BOOL)); // validate that we have dateCreated, key and status fields which were inserted by the framework $this->assertTrue(array_key_exists(CM_TST_FIELD_TEST_CDATE, $rec), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, CM_TST_FIELD_TEST_CDATE, STRING_DATA)); $this->assertTrue(array_key_exists(STRING_KEY, $rec), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, STRING_KEY, STRING_DATA)); $this->assertTrue(array_key_exists(CM_TST_FIELD_TEST_STATUS, $rec), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, CM_TST_FIELD_TEST_STATUS, STRING_DATA)); // validate that these fields have content of the correct type or that the literals match // validate the token guid $this->assertTrue(validateGUID($rec[STRING_KEY]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_VALUE, STRING_KEY)); // validate the status value $this->assertEquals(STATUS_ACTIVE, $rec[CM_TST_FIELD_TEST_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_VALUE, CM_TST_FIELD_TEST_STATUS)); // validate the createdData type $this->assertTrue(is_int($rec[CM_TST_FIELD_TEST_CDATE]), __FILE__ . COLON . __LINE__ . COLON . sprintf(CM_TST_FIELD_TEST_CDATE, DB_CREATED)); } /** * testUpdateOneRecord() -- unit test method * * This unit test pulls any record where the test string does not equal to the Jayne string (member static) - * store this test record into member statics for future testing. The query itself has meta fields added so that * the event processing doesn't filter the return data, that we skip auditing for the query fetch, and that * we limit the return payload to a single record. * * Once the fetch request has been submitted... * * -- assert that the query executed successfully (payload status is true) * -- assert that the query returned only one record * -- assert that the record has a token * -- assert that the record token is valid * -- assert that the event guid is valid * -- assert that the string field does not equal $jayne * * We store the test record, the record token and the event guid in member statics. * * Next, we build an update query using the just-pulled record and submit the update-event query: * * -- assert that the update request successfully executed * * Store the event guid into a static member for subsequent tests. * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-11-19 mks DB-122: original coding * */ public function testUpdateOneRecord() { // build a simple update query by pulling an active record that doesn't have the jayne string $query = [CM_TST_FIELD_TEST_STRING => [ OPERAND_NULL => [ OPERATOR_DNE => [static::$jayne]]]]; // we need to fetch a "before" version of a record, before it's updated, for testing the audit later $testRecord = null; $adminMeta = static::$adminMeta; $adminMeta[META_DONUT_FILTER] = 1; $adminMeta[META_SKIP_AUDIT] = 1; $adminMeta[META_TEMPLATE] = TEMPLATE_CLASS_TEST_MONGO; $adminMeta[META_LIMIT] = 1; // build and submit the event request $request = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $adminMeta ]; // this query, incidentally, implicitly tests the ability of namaste to return a non-mapped, non-cached record $eventPayload = gzcompress(json_encode($request)); $response = $this->readBrokerClient->call($eventPayload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], (basename(__FILE__) . COLON . __LINE__ ) . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_FETCH, $response[PAYLOAD_STATE])); // ensure that META_LIMIT works by testing that we only returned one non-cached record $recCount = intval($response[PAYLOAD_RESULTS][STRING_QUERY_DATA][STRING_REC_COUNT_RET]); $this->assertEquals(1, $recCount, (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 1, $recCount) . MONGO_STRING_COUNT); // pull the test record from the payload and validate important fields $testRecord = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0]; $this->assertEquals(STATUS_ACTIVE, $testRecord[(DB_STATUS . COLLECTION_MONGO_TEST_EXT)], (basename(__FILE__) . COLON . __FILE__) . COLON . sprintf(ERROR_UT_VALS_NOT_EQUAL, STATUS_ACTIVE, $testRecord[(DB_STATUS . COLLECTION_MONGO_TEST_EXT)])); $this->assertArrayHasKey((STRING_TOKEN . COLLECTION_MONGO_TEST_EXT), $testRecord, (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_FIELD_404, STRING_TOKEN, 'testRecord')); $guid = $testRecord[(STRING_TOKEN . COLLECTION_MONGO_TEST_EXT)]; $this->assertTrue(validateGUID($guid), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . $guid); $this->assertTrue(validateGUID($testRecord[DB_EVENT_GUID . COLLECTION_MONGO_TEST_EXT]), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . $testRecord[DB_EVENT_GUID . COLLECTION_MONGO_TEST_EXT]); $tString = (isset($testRecord[TEST_FIELD_TEST_STRING . COLLECTION_MONGO_TEST_EXT])) ? $testRecord[TEST_FIELD_TEST_STRING . COLLECTION_MONGO_TEST_EXT] : ''; $this->assertNotEquals(static::$jayne, $tString, (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_STRING_MATCH, static::$jayne, $tString)); // store the test record (and some guids) into the static containers static::$testRecord = $testRecord; static::$testRecordToken = $testRecord[(DB_TOKEN . COLLECTION_MONGO_TEST_EXT)]; static::$eventRecordToken = $testRecord[(DB_EVENT_GUID . COLLECTION_MONGO_TEST_EXT)]; // build the update query $query = [ DB_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [$guid]]]]; $update = [ CM_TST_FIELD_TEST_STRING => static::$jayne ]; // build the broker-update-event payload $payload = [ STRING_QUERY_DATA => $query, STRING_UPDATE_DATA => $update ]; $eventGUID = guid(); // generate a known event guid for audit tracking $meta = static::$meta; $meta[META_EVENT_GUID] = $eventGUID; // create the query/broker-event payload $request = [ BROKER_REQUEST => BROKER_REQUEST_UPDATE, BROKER_DATA => $payload, BROKER_META_DATA => $meta ]; // submit the request and process the result payload $eventPayload = gzcompress(json_encode($request)); $response = $this->writeBrokerClient->call($eventPayload); $response = json_decode(gzuncompress($response), true); // verify that the update was successful $this->assertTrue($response[PAYLOAD_STATUS], (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_EXPECTING_TRUE . PAYLOAD_STATUS); static::$eventRecordToken = $eventGUID; } /** * testUpdateAudit() -- unit test method * * This unit test method validates the audit functionality that should have been triggered by the update event * executed in the previous method. * * -- assert that the event record token was saved and is still available * -- assert that the test record token was saved and is still available * -- assert that the original test record was saved and is still available * * We build the query for the remote-fetch-event and submit the request to fetch the audit record and then we * validate that key columns in the audit record are populated. (We'll need these values for the next unit test.) * * -- assert that the event request (status) executed successfully * -- assert that the record token exists in the data payload * -- assert that the record token is a valid GUID * -- assert that the audit record is in array format * * Store the content of the audit record into a member static. * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-12-19 mks DB-122: original coding * */ public function testUpdateAudit() { // verify that we have a eventGUID so we can fetch the audit token, and verify that we have a copy of // the original record before it was updated in the previous method $this->assertTrue(validateGUID(static::$eventRecordToken), (basename(__FILE__) . COLON . __LINE__) . ERROR_INVALID_GUID . static::$eventRecordToken); $this->assertTrue(validateGUID(static::$testRecordToken), (basename(__FILE__) . COLON . __LINE__) . ERROR_INVALID_GUID . static::$testRecordToken); $this->assertTrue(is_array(static::$originalTestRecord), (basename(__FILE__) . COLON . __LINE__) . ERROR_UT_LOST_VARIABLE . 'originalTestRecord'); // fetch the audit record based on the record and event guids, testing that we successfully created an audit // record off the update operation in the previous method $adminMeta = static::$adminMeta; $adminMeta[META_TEMPLATE] = TEMPLATE_CLASS_AUDIT; $query = [ AUDIT_RECORD_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$testRecordToken ]]], DB_EVENT_GUID => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$eventRecordToken ]]], OPERAND_AND => null ]; $request = [ BROKER_REQUEST => BROKER_REQUEST_REMOTE_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $adminMeta ]; sleep(1); $payload = gzcompress(json_encode($request)); $response = $this->adminOutClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_REMOTE_FETCH, $response[PAYLOAD_STATE])); static::$auditRecordToken = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0][STRING_TOKEN . COLLECTION_MONGO_AUDIT_EXT]; $this->assertNotEmpty(static::$auditRecordToken, (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'audit record token'); $this->assertTrue(validateGUID(static::$auditRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . static::$auditRecordToken); static::$auditRecord = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0]; $this->assertTrue(is_array(static::$auditRecord), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_GENERIC_FAIL . 'failed to fetch audit record'); } /** * testUpdateJournal() -- unit test method * * This function continues the previous two methods of testing by asserting that the previous update event created * a journal record. We're only testing that the journal record exists, and through the query itself, validates * the back-linking to the audit record via the eventGUID and the auditGUID. * * Once we've confirmed that the journal record was successfully created, then we'll store the journal token and * the journal record for the final method/test: restoring the record to it's previous state. * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-12-19 mks DB-122: original coding * */ public function testUpdateJournal() { // sleep for a second to give time for the journal record to be transferred to disk sleep(1); // validate that the carry-over data exists $this->assertTrue(validateGUID(static::$eventRecordToken), (basename(__FILE__) . COLON . __LINE__) . ERROR_INVALID_GUID . static::$eventRecordToken); $this->assertTrue(validateGUID(static::$testRecordToken), (basename(__FILE__) . COLON . __LINE__) . ERROR_INVALID_GUID . static::$testRecordToken); $this->assertTrue(is_array(static::$originalTestRecord), (basename(__FILE__) . COLON . __LINE__) . ERROR_UT_LOST_VARIABLE . 'originalTestRecord'); $this->assertTrue(validateGUID(static::$auditRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . static::$auditRecordToken); $this->assertTrue(is_array(static::$auditRecord), (basename(__FILE__) . COLON . __LINE__) . ERROR_UT_LOST_VARIABLE . 'auditRecord'); // fetch the journal record based on the event guid and the audit guid $query = [ JOURNAL_AUD_TOK => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$auditRecordToken ]]], DB_EVENT_GUID => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$eventRecordToken]]], OPERAND_AND => null ]; $adminMeta = static::$adminMeta; $adminMeta[META_TEMPLATE] = TEMPLATE_CLASS_JOURNAL; $request = [ BROKER_REQUEST => BROKER_REQUEST_REMOTE_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $adminMeta ]; $payload = gzcompress(json_encode($request)); $response = $this->adminOutClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_REMOTE_FETCH, $response[PAYLOAD_STATE])); static::$journalRecord = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0]; $this->assertTrue(is_array(static::$journalRecord), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_GENERIC_FAIL . 'failed to fetch journal record'); } /** * testUpdateJournalRecovery() -- unit test method * * This unit test will invoke the audit/journal-recovery event to restore the previously-updated record back to * it's original state. In the previous update, we changed the string to "jayne" - this test will invoke the audit * restore event and then validate that the update was reversed. * * Assertions: * 1-6: static data persists * 7: Audit-restore event completed successfully (via the broker event request) * 8: That we were able to fetch the updated record * 9: That the test-string in the original record matches the updated record * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-12-19 mks DB-122: original coding * */ public function testUpdateJournalRecovery() { // validate that the carry-over data exists $this->assertTrue(validateGUID(static::$eventRecordToken), (basename(__FILE__) . COLON . __LINE__) . ERROR_INVALID_GUID . static::$eventRecordToken); $this->assertTrue(validateGUID(static::$testRecordToken), (basename(__FILE__) . COLON . __LINE__) . ERROR_INVALID_GUID . static::$testRecordToken); $this->assertTrue(is_array(static::$originalTestRecord), (basename(__FILE__) . COLON . __LINE__) . ERROR_UT_LOST_VARIABLE . 'originalTestRecord'); $this->assertTrue(validateGUID(static::$auditRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . static::$auditRecordToken); $this->assertTrue(is_array(static::$auditRecord), (basename(__FILE__) . COLON . __LINE__) . ERROR_UT_LOST_VARIABLE . 'auditRecord'); $this->assertTrue(is_array(static::$journalRecord), (basename(__FILE__) . COLON . __LINE__) . ERROR_UT_LOST_VARIABLE . 'journalRecord'); // build the recovery query to restore the original record $query = [ STRING_KEY => static::$auditRecordToken ]; $meta = static::$adminMeta; $meta[META_TEMPLATE] = TEMPLATE_CLASS_AUDIT; $request = [ BROKER_REQUEST => BROKER_REQUEST_AUDIT_RESTORE, BROKER_DATA => $query, BROKER_META_DATA => $meta ]; $payload = gzcompress(json_encode($request)); $response = $this->adminOutClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_AUDIT_RESTORE, $response[PAYLOAD_STATE])); // if we're still executing, that the record was "restored" --- attempt to pull the record $query = [ DB_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [static::$testRecordToken ]]]]; $meta = static::$meta; $meta[META_DONUT_FILTER] = 1; $meta[META_DO_CACHE] = false; $request = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $meta ]; $payload = gzcompress(json_encode($request)); $response = $this->readBrokerClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertEquals(STATE_SUCCESS, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . sprintf(ERROR_UT_VALS_NOT_EQUAL, STATE_SUCCESS, $response[PAYLOAD_STATE])); // compare the string field to the original record - they should be the same, or at least not jayne $originalString = static::$testRecord[TEST_FIELD_TEST_STRING . COLLECTION_MONGO_TEST_EXT]; $updatedString = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][TEST_FIELD_TEST_STRING . COLLECTION_MONGO_TEST_EXT]; $this->assertEquals($originalString, $updatedString, (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_VALS_NOT_EQUAL, $originalString, $updatedString)); } /** * testDeleteOneRecord() -- unit test method * * This method test the delete record (one record) method - ensuring that a soft-delete status record is effectively * removed from the collection. * * This method can be executed as a stand-alone method. * * First, we fetch the first active-status record from the collection: * * -- assert that the fetch request executed successfully * * Once we have the record fetched from the collection, save the record in a local static member, and also save the * token (in a separate member variable) for later test use. * * -- assert that the record token is a valid guid * -- assert that the record has an active status * * Next we build the query request payload for the delete event, first generating the event guid and copying it * into the meta payload copy, after validating the guid. * * -- assert that the generated event guid is a valid guid * * Store the event guid in the static member and submit the delete event request: * * -- assert that the delete event request executed successfully * * Attempt to fetch the record based on the token by submitting a fetch event to the read broker: * * -- assert that the return status was true (query successfully executed) * -- assert that the return STATE is STATE_NOT_FOUND for the event request * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-13-19 mks DB-122: original coding * */ public function testDeleteOneRecord() { $meta = static::$meta; $meta[META_DO_CACHE] = false; $meta[META_LIMIT] = 1; // fetch any record with an active status $query = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => [] ], BROKER_META_DATA => $meta ]; $payload = gzcompress(json_encode($query)); $response = $this->readBrokerClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_FETCH, $response[PAYLOAD_STATE])); // extract and save portions of the payload we'll need for later testing static::$testRecord = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0]; static::$testRecordToken = static::$testRecord[STRING_KEY]; // validate the record guid and that the record has an active status $this->assertTrue(validateGUID(static::$testRecordToken), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . static::$testRecordToken); $this->assertEquals(STATUS_ACTIVE, static::$testRecord[CM_TST_FIELD_TEST_STATUS], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_STRING_MATCH, STATUS_ACTIVE, static::$testRecord[CM_TST_FIELD_TEST_STATUS])); // build the query and request to delete the just-fetched record $query = [ CM_TST_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$testRecordToken ]]]]; $request = [ STRING_QUERY_DATA => $query ]; // generate and validate the event guid $eventGUID = guid(); $this->assertTrue(validateGUID($eventGUID), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . $eventGUID); // build the meta-data payload; save the event guid in a member static $meta = static::$meta; $meta[META_EVENT_GUID] = $eventGUID; // we'll need this later... static::$eventRecordToken = $eventGUID; // create the query/broker-event payload $payload = [ BROKER_REQUEST => BROKER_REQUEST_DELETE, BROKER_DATA => $request, BROKER_META_DATA => $meta ]; // submit the request and unpack the results $eventPayload = gzcompress(json_encode($payload)); $response = $this->writeBrokerClient->call($eventPayload); $response = json_decode(gzuncompress($response), true); // verify that the update was successful $this->assertTrue($response[PAYLOAD_STATUS], (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_EXPECTING_TRUE . PAYLOAD_STATUS); $query = [ CM_TST_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$testRecordToken ]]]]; $meta = static::$meta; $meta[META_DO_CACHE] = false; $meta[META_LIMIT] = 1; $request = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $meta ]; $response = json_decode(gzuncompress($this->readBrokerClient->call(gzcompress(json_encode($request)))), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_FETCH, $response[PAYLOAD_STATE])); $this->assertEquals(STATE_NOT_FOUND, $response[PAYLOAD_STATE], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_STRING_MATCH, STATE_NOT_FOUND, $response[PAYLOAD_STATE])); } /** * testDeleteAudit() -- unit test method * * This test validates that we created an audit record as a result of the delete event executing. We confirm that * the audit was created by querying the audit collection using a combination of the test-record token and the event * GUID used in the delete event request. * * --assert that the event-record guid is still stored in a member static and is still a valid guid * --assert that the test record guid is still stored in a member static and is still a valid guid * --assert that the test record is still stored in a member static and is in array format * * Next, build the query payload to submit a fetch event to the admin broker to request the delete-event audit rec: * * -- assert that the fetch request executed successfully * * Store the audit record into member statics: * --assert that the audit record is not-null (successfully fetched) * --assert that the audit record token is a valid guid * --assert that the audit record is in array format * * Build the fetch query -- we're searching on the original (deleted) record token and the status being equal * to deleted. If the class has soft-deletes enabled, this will fetch the record. Otherwise, we'll return a * successful result but the state will set to NOT_FOUND. Test for this state as well. If the state of the fetch * event is neither STATE_SUCCESS or STATE_NOT_FOUND, generate a test fail: * * --assert that the fetch request executed successfully * --assert that the STATE of the request is either STATE_SUCCESS or STATE_NOT_FOUND * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-13-19 mks DB-122: original coding * */ public function testDeleteAudit() { // pause to let stuffs get written sleep(1); $ext = COLLECTION_MONGO_AUDIT_EXT; // ensure we've got the necessary saved data $this->assertTrue(validateGUID(static::$eventRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'eventGUID'); $this->assertTrue(validateGUID(static::$testRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'testRecordToken'); $this->assertTrue(is_array(static::$testRecord), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'testRecord'); // validate that we have an audit record for the delete operation that just occurred $adminMeta = static::$adminMeta; $adminMeta[META_TEMPLATE] = TEMPLATE_CLASS_AUDIT; $adminMeta[META_DONUT_FILTER] = 1; $query = [ AUDIT_RECORD_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$testRecordToken ]]], DB_EVENT_GUID => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$eventRecordToken ]]], OPERAND_AND => null ]; $request = [ BROKER_REQUEST => BROKER_REQUEST_REMOTE_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $adminMeta ]; $response = $this->adminOutClient->call(gzcompress(json_encode($request))); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_REMOTE_FETCH, $response[PAYLOAD_STATE])); // grab and save the audit record token, and the audit record, for the next method... static::$auditRecord = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0]; static::$auditRecordToken = static::$auditRecord[DB_TOKEN . $ext]; $this->assertNotNull(static::$auditRecord, basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_UT_NULL_VALUE . STRING_GUID_KEY); $this->assertTrue(validateGUID(static::$auditRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . static::$auditRecordToken); $this->assertTrue(is_array(static::$auditRecord), (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_FIELD_VALUE, 'auditRecord')); // pull the original record and let's confirm that it's deleted or in a deleted state $meta = static::$meta; $meta[META_DONUT_FILTER] = 1; $query = [ DB_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$testRecordToken]]], DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_DELETED ]]], OPERAND_AND => null ]; $request = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $meta ]; $response = $this->readBrokerClient->call(gzcompress(json_encode($request))); $results = json_decode(gzuncompress($response), true); $this->assertTrue($results[PAYLOAD_STATUS], (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_FETCH, $results[PAYLOAD_STATE])); $oldStatus = $results[PAYLOAD_RESULTS][PAYLOAD_QUERY][0][DB_STATUS . COLLECTION_MONGO_TEST_EXT]; if ($results[PAYLOAD_STATE] == STATE_SUCCESS) $this->assertEquals(STATUS_DELETED, $oldStatus, (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_STRING_MATCH, STATUS_DELETED, $oldStatus)); elseif ($results[PAYLOAD_STATE] != STATE_NOT_FOUND) $this->assertTrue(false, (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_STATE . $results[PAYLOAD_STATE]); } /** * testDeleteJournalRecovery() -- unit test method * * This unit test validates that there's a journal record spawned off the delete event two methods ago and that * we're able to restore (un-delete) the record. Initially, on starting, we need to validate and verify stored * data availability: * * --assert that the eventRecordToken is present and valid as a guid * --assert that the testRecordToken is present and valid as a guid * --assert tha the testRecord record is present and valid as an array * --assert that the auditRecordToken is present and valid as a guid * --assert that the auditRecord is present and valid as an array * * Once we've verified, build the event for fetching the journal record from admin server and submit the request: * * --assert that the fetch (from admin) request executed successfully * * The fact that we fetched the journal record based on the audit token value, we've implicitly verified that * the journal record was created as a result of the delete event. Using the same token value, we next build * the event request query to restore (un-delete) the record. * * --assert that the request successfully executed * * Next, we pause, sleep for a second to allow the data to settle, and then we build a new event request to * fetch the data record from appServer. The query submitted implies an ACTIVE status requirement was injected. * * --assert that the request successfully executed * --assert that the state of the request is not STATE_NOT_FOUND * * The combination of the two (SUCCESS + !(STATE_NOT_FOUND)) means that the record was successfully un-deleted * * * @author mike@givingassistant.org * @version 1.0 * * * HISTORY: * ======== * 06-13-19 mks DB-122: original coding * */ public function testDeleteJournalRecovery() { // verify and validate the stored statics $this->assertTrue(validateGUID(static::$eventRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'eventGUID'); $this->assertTrue(validateGUID(static::$testRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'testRecordToken'); $this->assertTrue(is_array(static::$testRecord), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'originalTestRecord'); $this->assertTrue(validateGUID(static::$auditRecordToken), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . static::$auditRecordToken); $this->assertTrue(is_array(static::$auditRecord), (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_FIELD_VALUE, 'auditRecord')); // fetch the journal record based on the audit token // build the request to fetch the journal record for the delete event $meta = static::$adminMeta; $meta[META_DONUT_FILTER] = 1; $meta[META_TEMPLATE] = TEMPLATE_CLASS_JOURNAL; $query = [ JOURNAL_AUD_TOK => [ OPERAND_NULL => [ OPERATOR_EQ => [ static::$auditRecordToken ]]]]; $request = [ BROKER_REQUEST => BROKER_REQUEST_REMOTE_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $meta ]; $response = $this->adminOutClient->call(gzcompress(json_encode($request))); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_REMOTE_FETCH, $response[PAYLOAD_STATE])); // now that we've confirmed that the journal record exists, invoke the recovery event to restore the // original record back to it's non-deleted state $query = [ STRING_KEY => static::$auditRecordToken ]; $meta = static::$adminMeta; $meta[META_TEMPLATE] = TEMPLATE_CLASS_AUDIT; $request = [ BROKER_REQUEST => BROKER_REQUEST_AUDIT_RESTORE, BROKER_DATA => $query, BROKER_META_DATA => $meta ]; $payload = gzcompress(json_encode($request)); $response = $this->adminOutClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_AUDIT_RESTORE, $response[PAYLOAD_STATE])); // if we're still executing, that the record was "restored" --- attempt to pull the record after a // slightly-respectful delay to give time for the update to propagate... sleep(1); // and build the query for the fetch event and submit the request $query = [ DB_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [static::$testRecordToken ]]]]; $meta = static::$meta; $meta[META_DONUT_FILTER] = 1; $request = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query ], BROKER_META_DATA => $meta ]; $payload = gzcompress(json_encode($request)); $response = $this->readBrokerClient->call($payload); $response = json_decode(gzuncompress($response), true); $this->assertEquals(STATE_SUCCESS, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . sprintf(ERROR_UT_VALS_NOT_EQUAL, STATE_SUCCESS, $response[PAYLOAD_STATE])); $this->assertNotEquals(STATE_NOT_FOUND, $response[PAYLOAD_STATUS], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_STRING_MATCH, STATE_NOT_FOUND, $response[PAYLOAD_STATE])); } }