Files
namaste/tests/unit/writeBrokerMongoTest.php
gramps 373ebc8c93 Archive: Namaste PHP AMQP framework v1.0 (2017-2020)
952 days continuous production uptime, 40k+ tp/s single node.
Original corpo Bitbucket history not included — clean archive commit.
2026-04-05 09:49:30 -07:00

1678 lines
88 KiB
PHP

<?php
$_REDIRECT = false;
require(dirname(__DIR__) . '/../config/sneakerstrap.inc'); // and load the namaste environment
use /** @noinspection PhpUndefinedClassInspection */ PHPUnit\Framework\TestCase;
/** @noinspection PhpUndefinedClassInspection */
class writeBrokerMongoTest extends TestCase
{
protected gacBrokerClient $readBrokerClient;
protected gacBrokerClient $writeBrokerClient;
protected gacBrokerClient $adminOutClient;
protected static ?array $meta = null;
protected static ?array $adminMeta = null;
protected static ?object $widget;
protected static string $cKey = '';
protected static ?array $testRecord;
protected static ?array $journalRecord;
protected static string $checksum = '';
protected static string $testRecordToken;
protected static string $auditRecordToken;
protected static string $eventRecordToken;
protected static ?array $originalTestRecord;
protected static ?array $auditRecord;
protected static string $jayne = "Ten percent of nothin' is ... let me do the math here ... nothin' into nothin' ... carry the nothin' ... ";
/**
* setUpBeforeClass() -- public static unit test method
*
* this method is called first, and once, on execution. It sets up a list of brokers we're going to test.
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 07-31-17 mks original coding
*
*/
public static function setUpBeforeClass()
{
/** @noinspection PhpUndefinedClassInspection */
parent::setUpBeforeClass();
// meta data (for namaste)
static::$meta = [
META_CLIENT => 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:
* ========
* 07-31-17 mks original coding
* 12-10-18 mks DB-71: support for audit/journal testing
*
*/
protected function 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:
* ========
* 07-27-17 mks original coding
*
*/
protected function tearDown()
{
/** @noinspection PhpUndefinedMethodInspection */
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)) {
/** @noinspection PhpUndefinedMethodInspection */
static::$widget->__destruct();
}
static::$widget = null;
}
/**
* testInsert() -- unit test method
*
* this unit test method is a simple test consisting of the following:
*
* 1. validate that we have a valid widget object
* 2. validate that we were able to create a test record of 1 record
* -- submit the create-event to the broker
* 3. validate that the create-event was successful and returned 1 cache-key
* -- fetch the cached record
* 4. validate that the integer, float, bool and string values are the same
* 5. validate that the guid, status and cData values were inserted
* 6. validate the guid
* 7. validate the status (active)
* 8. validate the date as an integer
*
* Assumptions:
* ------------
* That we know the test class being used supports caching.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 07-31-17 mks CORE-486: original coding
* 12-11-18 mks DB-71: additional queries for testing audit/journaling
* 03-14-19 mks DB-116: updated for the new cacheMapping
*
*/
public function testOneInsert()
{
$testRecord = null;
$this->assertTrue(is_object(static::$widget), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_WIDGET_404);
// create one record
$testRecord = static::$widget->template->buildTestData(1);
$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)));
// create the query/broker-event payload
$request = [
BROKER_REQUEST => BROKER_REQUEST_CREATE,
BROKER_DATA => $testRecord,
BROKER_META_DATA => static::$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);
// 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])));
// get the cache-key from the response payload
$cKey = $response[PAYLOAD_RESULTS][0];
$cacheRecord = gasCache::get($cKey);
$cacheRecord = json_decode(gzuncompress($cacheRecord), true);
// test the four primary values (int, float, bool, string) of the pre-saved record and
// the post-saved cached record
$this->assertEquals($testRecord[0][CM_TST_FIELD_TEST_INT], $cacheRecord[0][CM_TST_FIELD_TEST_INT], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_INT));
$this->assertEquals($testRecord[0][CM_TST_FIELD_TEST_STRING], $cacheRecord[0][CM_TST_FIELD_TEST_STRING], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_STRING));
$this->assertEquals($testRecord[0][CM_TST_FIELD_TEST_DOUBLE], $cacheRecord[0][CM_TST_FIELD_TEST_DOUBLE], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_DOUBLE));
$this->assertEquals($testRecord[0][CM_TST_FIELD_TEST_BOOL], $cacheRecord[0][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, $cacheRecord[0]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, CM_TST_FIELD_TEST_CDATE, RESOURCE_CACHE));
$this->assertTrue(array_key_exists(CM_TST_TOKEN, $cacheRecord[0]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, CM_TST_TOKEN, RESOURCE_CACHE));
$this->assertTrue(array_key_exists(CM_TST_FIELD_TEST_STATUS, $cacheRecord[0]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, CM_TST_FIELD_TEST_STATUS, RESOURCE_CACHE));
// validate that these fields have content of the correct type or that the literals match
// validate the token guid
$this->assertTrue(validateGUID($cacheRecord[0][CM_TST_TOKEN]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_VALUE, CM_TST_TOKEN));
// validate the status value
$this->assertEquals(STATUS_ACTIVE, $cacheRecord[0][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($cacheRecord[0][CM_TST_FIELD_TEST_CDATE]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_VALUE, CM_TST_FIELD_TEST_CDATE));
// to prepare for the next unit test, let's store some data about the newly-created record for compare/contrast
// start by fetching an unfiltered version of the new record
$query = [ DB_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [$cacheRecord[0][CM_TST_TOKEN]]]]];
$tmpMeta = static::$meta;
$tmpMeta[META_DONUT_FILTER] = 1;
$payload = [
BROKER_REQUEST => BROKER_REQUEST_FETCH,
BROKER_DATA => [
STRING_QUERY_DATA => $query
],
BROKER_META_DATA => $tmpMeta
];
$payload = gzcompress(json_encode($payload));
$response = $this->readBrokerClient->call($payload);
$results = json_decode(gzuncompress($response), true);
static::$testRecord = $results[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0]; // store a copy of the new record
static::$checksum = md5(base64_encode(json_encode(static::$testRecord))); // calculate & store the checksum
// save the cKey value as we're going to use this record in subsequent tests
static::$cKey = $cKey;
}
/**
* testInsertAudit() -- unit test method
*
* This unit test will validate that the previous test, for creating/inserting a new record, will proc an audit
* event. We've saved a copy, in the stored format, of the record just created as static member and we've
* calculated the checksum of the encoded record snapshot, also in a member variable, prior to calling this method.
*
* The first assertions in this test confirm that the requisite saved data exists and is in the correct format.
*
* Next, we fetch the cached record so that we can extract both the GUID of newly-created record, and the record's
* event GUID. Validate both as GUIDs.
*
* Then we build a query to fetch the audit record from admin. We test that we were able to fetch the record and
* then we calculate the checksum of the record snapshot and compare it to the stored checksum.
*
* If all assertion complete successfully, then we store the token GUID for the audit record as a member static
* to use in the next test.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 12-11-18 mks DB-77: original coding
*
*/
public function testInsertAudit()
{
// pause to allow disk writes to catch up
sleep(1);
$this->assertNotEmpty(static::$cKey, __FILE__ . COLON . __LINE__ . COLON . 'lost the cache key');
$this->assertNotEmpty(static::$testRecord, __FILE__ . COLON . __LINE__ . COLON . 'lost the record');
$this->assertTrue(is_array(static::$testRecord), __FILE__ . COLON . __LINE__ . COLON . 'munged the record');
$this->assertNotEmpty(static::$checksum, __FILE__ . COLON . __LINE__ . COLON . 'lost the cksum');
// fetch the cached record
$cacheRecord = gasCache::get(static::$cKey);
$this->assertNotNull($cacheRecord, (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_CACHE_FETCH_FAIL);
$cacheRecord = json_decode(gzuncompress($cacheRecord), true);
$cacheRecord = $cacheRecord[0];
// extract the token for the cached record, and the eventGUID to fetch the audit record that should
// have been created in the last test...
$recordToken = $cacheRecord[CM_TST_TOKEN];
$eventToken = $cacheRecord[CM_TST_EVENT_GUID];
$this->assertTrue(validateGUID($recordToken), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . $recordToken);
$this->assertTrue(validateGUID($eventToken), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . $eventToken);
// save these two tokens for the next test
static::$eventRecordToken = $eventToken;
static::$testRecordToken = $recordToken;
// build the query to fetch the audit record from the admin service
$query = [
AUDIT_RECORD_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ $recordToken ]]],
DB_EVENT_GUID => [ OPERAND_NULL => [ OPERATOR_EQ => [ $eventToken ]]],
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]));
$auditData = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0];
// we've validated that we created an audit record -- test that it's the correct record
// because the order of the fields may have changed, we validate by looking at the record GUID values
$ext = COLLECTION_MONGO_TEST_EXT;
$t1 = static::$testRecord[(DB_TOKEN . $ext)];
$t2 = $auditData[(AUDIT_RECORD_TOKEN . COLLECTION_MONGO_AUDIT_EXT)];
$this->assertEquals($t1, $t2, __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_VALS_NOT_EQUAL, 'new record checksum', 'audit record checksum'));
$this->assertTrue(validateGUID($auditData[DB_TOKEN . COLLECTION_MONGO_AUDIT_EXT]), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . $auditData[DB_TOKEN . COLLECTION_MONGO_AUDIT_EXT]);
// save the audit record token
static::$auditRecordToken = $auditData[DB_TOKEN . COLLECTION_MONGO_AUDIT_EXT];
}
/**
* testInsertJournal() -- unit test method
*
* This test takes information saved in the previous method (hence the assertions at the start of the method),
* and uses this data to fetch the journal record from the database.
*
* We're going to query the db on three elements:
*
* 1. The namaste-record token
* 2. The event GUID generated during the unit-test insert (one record) test
* 3. The audit-record guid generated from the insert operation
*
* Even if there is more than one journal record associated with the namaste record, using the audit record key
* (as well as the event guid) and the record GUID, forces the query to return, at most, a single record.
* And it validates that we've successfully saved the correct journal record to the database using that query
* instead of multiple assertions.
*
* We assert that the fetch request was successful and that we returned only one record in the query. The method
* then extracts the data from the return payload and assigns it to a member variable for the next unit test.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 12-11-18 mks DB-77: original coding
*
*/
public function testInsertJournal()
{
// pause to let disk-writes catch-up
sleep(1);
$this->assertTrue(validateGUID(static::$auditRecordToken), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . static::$auditRecordToken);
$this->assertTrue(validateGUID(static::$eventRecordToken), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . static::$eventRecordToken);
$this->assertTrue(validateGUID(static::$testRecordToken), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . static::$testRecordToken);
$this->assertNotEmpty(static::$cKey, __FILE__ . COLON . __LINE__ . COLON . 'lost the cache key');
$testRecord = gasCache::get(static::$cKey);
$this->assertNotNull($testRecord, (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_CACHE_FETCH_FAIL);
// 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];
}
/**
* testInsertJournalRecovery() -- unit test method
*
* This method tests that we're able to "recover" the previous operation using the audit record that was created
* when we created the new namaste record. Because the previous operation was a "CREATE", the rollback event
* stored in journaling should remove the record from existence. Because the test class supports soft-deletes,
* that means that the record will not actually be deleted but, instead, have it's status set to DELETED.
*
* This means that we're also, albeit indirectly, testing the fetch-broker's ability to process a query that
* executes successfully but returns no records.
*
* ASSERTIONS:
* -----------
* Validate that we have stored the the necessary data in member statics -- ensure that they're valid and available
* Restore the audit record (by invoking the recovery event) and test that the event completed successfully
* Fetch the original record and validate that the record was "restored" (deleted) successfully
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 12-11-18 mks DB-77: original coding
*
*/
public function testInsertJournalRecovery()
{
$this->assertTrue(!empty(static::$journalRecord), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, 'journalRecord', 'class member'));
$this->assertTrue(validateGUID(static::$auditRecordToken), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . static::$auditRecordToken);
$this->assertTrue(validateGUID(static::$testRecordToken), __FILE__ . COLON . __LINE__ . COLON . ERROR_INVALID_GUID . static::$testRecordToken);
$this->assertNotEmpty(static::$cKey, __FILE__ . COLON . __LINE__ . COLON . 'lost the cache key');
$testRecord = gasCache::get(static::$cKey);
$this->assertNotNull($testRecord, (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_CACHE_FETCH_FAIL);
// build the recovery query which should flag the targeted record into a 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
$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 method functions almost identically to the previous test method except, in this method, we're testing
* batch-inserts of between 50 and 100 records.
*
* 1. validate that the widget object is still viable
* -- generate a random value between 50 and 100
* -- generate that number of random test records
* 2. validate that we were able to generate the correct number of random records
* -- build, submit and evaluate the broker-event request return data
* 3. validate that the event returned the same number of records processed (count)
* -- generate a random number between 0 and the number of records generated
* -- fetch that record from cache and unpack the cache record
* 4. validate that the base values are the same (request -> insert -> cache -> test)
* 5. validate that we added createdData, guid, and status to the record
* 6. validate the type of the added data elements
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 08-01-17 mks original coding
* 11-28-17 mks CORE-635: updated the unit test for the new cache-handling method
* 03-15-19 mks DB-116: refactored for broker-level cacheMapping
*
*/
public function testMultipleInserts()
{
$testRecord = null;
$this->assertTrue(is_object(static::$widget), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_WIDGET_404);
// create a random number of records between 50 and 100
$recCount = mt_rand(50,100);
$testRecord = static::$widget->template->buildTestData($recCount);
$this->assertTrue(is_array($testRecord), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_TRUE . 'is_array($testRecord)');
$this->assertEquals($recCount, count($testRecord), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 1, count($testRecord)));
// create the query/broker-event payload
$request = [
BROKER_REQUEST => BROKER_REQUEST_CREATE,
BROKER_DATA => $testRecord,
BROKER_META_DATA => static::$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);
$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 = json_decode(gzuncompress(gasCache::get($response[PAYLOAD_RESULTS][0])), true);
$this->assertTrue(is_array($guidPayload), basename(__METHOD__) . AT . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_VALUE, 'guidPayload'));
$this->assertEquals(count($guidPayload), $recCount + 1, basename(__METHOD__) . AT . __LINE__ . COLON . sprintf(ERROR_UT_VALS_NOT_EQUAL, count($guidPayload), ($recCount + 1)));
// validate the checksum for the cached-key list
$checksum = $guidPayload[STRING_CHECKSUM];
unset($guidPayload[STRING_CHECKSUM]);
$newCSum = md5(gzcompress(json_encode($guidPayload)));
$this->assertEquals($checksum, $newCSum, (__FILE__ . COLON . __LINE__ . COLON) . ERROR_UT_CHECKSUM);
// 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($testRecord[$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($testRecord[$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($testRecord[$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($testRecord[$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, RESOURCE_CACHE));
$this->assertTrue(array_key_exists(CM_TST_TOKEN, $rec), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_404, CM_TST_TOKEN, RESOURCE_CACHE));
$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, RESOURCE_CACHE));
// validate that these fields have content of the correct type or that the literals match
// validate the token guid
$this->assertTrue(validateGUID($rec[CM_TST_TOKEN]), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_FIELD_VALUE, CM_TST_TOKEN));
// 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(ERROR_UT_FIELD_VALUE, CM_TST_FIELD_TEST_CDATE));
}
/**
* testNegativeInsertCountExceedsLimit()
*
* this is a negative unit test in that we're intentionally provoking a failure in the form of a request that the
* number of new records to create exceeds the declared maximum number of allowable records to be processed in a
* single event request.
*
* Pull the current record limit from the configuration and then generate a payload of records that is equal to
* the record limit, plus one.
*
* Create the payload for the event, submit the request, and then test out the return payload results against
* the expectations.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 09-11-17 mks CORE-501: original coding
*
*/
public function testNegativeInsertCountExceedsLimit()
{
$testRecords = null;
$this->assertTrue(is_object(static::$widget), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_WIDGET_404);
// create more records than the current configuration allows
$qrl = intval(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_RECORD_LIMIT]);
$recCount = 1 + $qrl;
$testRecords = static::$widget->template->buildTestData($recCount);
$this->assertTrue(is_array($testRecords), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_TRUE . 'is_array($testRecord)');
$this->assertEquals($recCount, count($testRecords), __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 1, count($testRecords)));
// create the query/broker-event payload
$request = [
BROKER_REQUEST => BROKER_REQUEST_CREATE,
BROKER_DATA => $testRecords,
BROKER_META_DATA => static::$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);
// test that the event was rejected with the expected state value
$this->assertFalse($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_FALSE . BROKER_REQUEST_CREATE);
$this->assertEquals(STATE_DATA_ERROR, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_STRING_MISMATCH, STATE_DATA_ERROR, $response[PAYLOAD_STATE]));
}
/**
* testUpdateOne() -- unit test method
*
* this unit test will pull the record we saved in testOneInsert() -- because this was a recently saved record,
* we know the primary key value and can launch a query to cache to fetch the record.
*
* We'll pull the token value from the cache record and compare it to the static::$cKey to ensure it's the same and
* use the value to build the query for the update event.
*
* Create a new string value to replace the string value in the target record and use this value in the update
* query.
*
* Build the event-request payload and submit it, and evaluate the return.
*
* 1. Validate that the widget class is still active
* 2. Validate that the cache key is available via a local property
* 3. Validate that we were able to fetch the cached record by the key
* -- Build the event-query payload
* -- Submit and unpack the broker response
* 4. Validate that the response reported a successful completion
* -- Fetch the cached record which should have been updated on a successful update db event
* 5. Validate that the cached record now has the updated string stored
*
* Note that we're implicitly validating the cache-update process by going to cache for our records instead
* of submitting queries to the read-broker.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 08-01-17 mks CORE-486: original coding
* 01-03-19 mks DB-79: audit-testing support -- refactored to grab a random record b/c we "deleted" the
* record in a previous method testing journal recovery on a create operation
*
*/
public function testUpdateOne()
{
$testRecord = null;
// build a simple update query by pulling an active record that doesn't have the jayne string
$query = [TEST_FIELD_TEST_STRING => [ OPERAND_NULL => [ OPERATOR_DNE => [static::$jayne]]]];
// we need to fetch the "before" version of the record before it's updated for testing the audit later
$adminMeta = static::$adminMeta;
$adminMeta[META_DONUT_FILTER] = 1;
$adminMeta[META_SKIP_AUDIT] = 1;
$adminMeta[META_TEMPLATE] = TEMPLATE_CLASS_TEST_MONGO;
$adminMeta[META_LIMIT] = 1;
$adminMeta[META_EVENT_GUID] = guid();
$ext = '_tst';
$request = [
BROKER_REQUEST => BROKER_REQUEST_FETCH,
BROKER_DATA => [ STRING_QUERY_DATA => $query ],
BROKER_META_DATA => $adminMeta
];
$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]));
$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);
$testRecord = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0];
$this->assertEquals(STATUS_ACTIVE, $testRecord[(DB_STATUS . $ext)], (basename(__FILE__) . COLON . __FILE__) . COLON . sprintf(ERROR_UT_VALS_NOT_EQUAL, STATUS_ACTIVE, $testRecord[(DB_STATUS . $ext)]));
$this->assertArrayHasKey((STRING_TOKEN . $ext), $testRecord, (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_FIELD_404, STRING_TOKEN, 'testRecord'));
$guid = $testRecord[(STRING_TOKEN . $ext)];
$this->assertTrue(validateGUID($guid), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . $guid);
// we have a copy of the record we're going to update - build the update query
$query = [ DB_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [$guid]]]];
// quick validate that we're working with a new string
$testString = '';
if (array_key_exists((TEST_FIELD_TEST_STRING . $ext), $testRecord)) $testString = $testRecord[(TEST_FIELD_TEST_STRING . $ext)];
elseif (array_key_exists(TEST_FIELD_TEST_STRING, $testRecord)) $testString = $testRecord[TEST_FIELD_TEST_STRING];
$this->assertNotEquals(static::$jayne, $testString, (__FILE__ . COLON . __LINE__) . COLON . sprintf(ERROR_UT_STRING_MATCH, 'jayne', (TEST_FIELD_TEST_STRING . $ext)));
// build the update query
$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);
// we're no longer testing the cache-record since we disabled caching for this event
// $newRecord = json_decode(gzuncompress(gasCache::get($guid)), true);
// $newString = $newRecord[0][CM_TST_FIELD_TEST_STRING];
// $this->assertEquals(static::$jayne, $newString, (__FILE__ . COLON . __LINE__) . COLON . sprintf(ERROR_UT_STRING_MISMATCH, static::$jayne, $newString));
// save the guids and a copy of the original record in the class statics
static::$eventRecordToken = $eventGUID;
static::$testRecordToken = $guid;
static::$originalTestRecord = $testRecord;
}
/**
* testUpdateAudit() -- unit test method
*
* This unit test is predicated on the previous method where we fetched a random, valid record that hasn't had the
* string value changed and, was updated to change the string value stored.
*
* We've previously stored the original record prior to update. In this method, we'll fetch the audit record
* based on the record and event GUIDs and validate that we created an audit record off the update event.
*
* Next, we extract the audit record token and store it as a class static as well as the entire audit record.
*
* This sets us up for the next method which tests that a journal record was created, also off the update event,
* that's linked-back to the audit record.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 01-04-19 mks DB-79: 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:
* ========
* 01-04-19 mks DB-78: original coding
*
*/
public function testUpdateJournal()
{
// 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:
* ========
* 01-07-19 mks DB-79: 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;
$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::$originalTestRecord[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));
}
/**
* testUpdateMany() -- unit test method
*
* this unit test is similar to the previous test except for:
*
* -- we're executing a more-complex query which may not return records to update
* -- we had to provide query-options so that namaste would update past the first matching record
*
* 1. assert that the widget object persisted
* -- generate a target value for matching the test-integer field
* -- generate the query
* -- submit query to the broker and process the return payload
* 2. payload return a success status
* 3. payload return records (if null, it could mean that the query did not pick up qualifying records)
* -- grab random updated record from cache
* 4. verify that the string was updated in the refreshed cache record
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 08-01-17 mks CORE-486: original coding
* 03-28-19 mks DB-116: refactored selection query to limit the update to affecting a max of 10 records
* 06-18-19 mks DB-122: support for META_LIMIT and mongoDB update scope
*
*/
public function testUpdateMany()
{
$recordCount = 5;
$testRecord = null;
$this->assertTrue(is_object(static::$widget), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_WIDGET_404);
// plan is to update the records that have an active status
$query = [ CM_TST_FIELD_TEST_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]]];
// we're going to update the string field to this:
$jayne = "Ten percent of nothin' is ... let me do the math here ... nothin' into nothin' ... carry the nothin' ... ";
// build the update query
$update = [ CM_TST_FIELD_TEST_STRING => $jayne ];
// build the broker-event payload
$payload = [
STRING_QUERY_DATA => $query,
STRING_UPDATE_DATA => $update
];
$meta = static::$meta;
$meta[META_LIMIT] = $recordCount; // namaste will limit the delete to $recordCount records
// create the query/broker-event payload
$request = [
BROKER_REQUEST => BROKER_REQUEST_UPDATE,
BROKER_DATA => $payload,
BROKER_META_DATA => $meta
];
// submit the request and unpack the results
$eventPayload = gzcompress(json_encode($request));
$response = $this->writeBrokerClient->call($eventPayload);
$response = json_decode(gzuncompress($response), true);
// verify that the update was successful
// json_decode(gzuncompress(gasCache::get('')), true);
$this->assertTrue($response[PAYLOAD_STATUS], (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_EXPECTING_TRUE . PAYLOAD_STATUS);
$this->assertNotNull($response[PAYLOAD_RESULTS], (__FILE__ . COLON . __LINE__) . ERROR_UT_EMPTY_RESULTS);
// grab the cache-key and fetch the data
$cData = json_decode(gzuncompress(gasCache::get($response[PAYLOAD_RESULTS][0])), true);
unset($cData[STRING_CHECKSUM]);
$this->assertEquals(count($cData), $recordCount, basename(__METHOD__) . AT . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, count($cData), $recordCount));
$rr = mt_rand(0, $recordCount); // rr = random record
$this->assertEquals($jayne, $cData[$rr][CM_TST_FIELD_TEST_STRING], basename(__METHOD__) . AT . __LINE__ . COLON . sprintf(ERROR_UT_STRING_MISMATCH, 'jayne', $cData[$rr][CM_TST_FIELD_TEST_STRING]));
}
/**
* testNegativeUpdateOne() -- unit test method
*
* This unit test tests the ability to update a record by resetting a field marked as protected. If the framework
* processes the request correctly, the event should fail with a validation state error.
*
* Create a request to update a record -- the field to be updated is protected -- and test the return payload
* for a false status and a validation error in the state return.
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 09-11-17 mks CORE-558: original coding
*
*/
public function testNegativeUpdateOne()
{
$testRecord = null;
$this->assertTrue(is_object(static::$widget), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_UT_WIDGET_404);
// we lost the cached record in insertJournalRecovery() - so fetch a new record
$meta = static::$meta;
$meta[META_LIMIT] = 1;
$request = [
BROKER_REQUEST => BROKER_REQUEST_FETCH,
BROKER_DATA => [ STRING_QUERY_DATA => [] ],
BROKER_META_DATA => $meta
];
// submit the request and unpack the results
$eventPayload = gzcompress(json_encode($request));
$response = $this->readBrokerClient->call($eventPayload);
$response = json_decode(gzuncompress($response), true);
static::$cKey = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0];
// get the cached record and extract the guid and the text string (query/replace values)
$testRecord = gasCache::get(static::$cKey);
$this->assertNotNull($testRecord, (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_CACHE_FETCH_FAIL);
$testRecord = json_decode(gzuncompress($testRecord), true);
$testRecord = $testRecord[0];
$guid = $testRecord[CM_TST_TOKEN]; // this is the raw guid
$this->assertTrue(validateGUID($guid), (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_INVALID_GUID . $guid);
$this->assertNotEmpty($guid, (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_UT_FIELD_404 . CM_TST_TOKEN);
// build a simple update query
$query = [
CM_TST_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [$guid] ] ]
];
// build the update query using a protected field -- doesn't matter since it should be rejected/dropped
$update = [ CM_TST_FIELD_TEST_CDATE => STRING_DATA ];
// meta data should reflect a client request as unit-test, as a client, will bypass the protected field check
$meta = static::$meta;
$meta[META_CLIENT] = CLIENT_CLIENT;
// build the broker-update-event payload
$payload = [
STRING_QUERY_DATA => $query,
STRING_UPDATE_DATA => $update
];
// create the query/broker-event payload
$request = [
BROKER_REQUEST => BROKER_REQUEST_UPDATE,
BROKER_DATA => $payload,
BROKER_META_DATA => static::$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);
$this->assertFalse($response[PAYLOAD_STATUS], (basename(__METHOD__) . AT . __LINE__ . COLON) . ERROR_UT_EXPECTING_FALSE . BROKER_REQUEST_UPDATE);
$this->assertEquals(STATE_VALIDATION_ERROR, $response[PAYLOAD_STATE], (basename(__METHOD__) . AT . __LINE__ . COLON) . sprintf(ERROR_UT_STRING_MISMATCH, STATE_VALIDATION_ERROR, $response[PAYLOAD_STATE]));
}
/**
* testDeleteOneRecord() -- unit test method
*
* this method tests the deletion of a single record, denoted by the cache-key we created earlier and stored
* as a member property.
*
* 1. validate that the widget is still instantiated
* 2. validate that the cacheKey still exists
* -- Fetch the record from cache and extract the guid.
* 3. validate the cache-extracted guid
* 4. validate the cached record has status = active
* -- build the query, submit, and unpack the return payload
* 5. validate the response returned a status of true
* -- fetch the record from cache
* 6. validate that the record status is not long available in cache
*
* Since the test class has soft-deletes configured, we can pull the update from cache.
*
* Notes:
* ------
* Created JIRA case: CORE-497 to delete cached records
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 08-01-17 mks CORE-486: original coding
* 08-07-17 mks CORE-497: update for the removal of deleted records from cache
* 01-08-19 mks DB-80: saving original record data, and the delete event guid, to static members
* for audit/journal testing later
*
*/
public function testDeleteOneRecord()
{
$testRecord = null;
// we've deleted the test record so, fetch any record with an active status
static::$meta[META_LIMIT] = 1;
$query = [
BROKER_REQUEST => BROKER_REQUEST_FETCH,
BROKER_DATA => [
STRING_QUERY_DATA => []
],
BROKER_META_DATA => static::$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]));
static::$cKey = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0];
// fetch the cached record so we can get the guid
$record = gasCache::get(static::$cKey);
$this->assertNotNull($record, (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_CACHE_FETCH_FAIL);
$record = json_decode(gzuncompress($record), true);
$record = $record[0];
$guid = $record[CM_TST_TOKEN];
// validate the guid
$this->assertTrue(validateGUID($guid), (__FILE__ . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . $guid);
// save the original record for testing audit/journaling in following test methods
static::$testRecordToken = $guid;
static::$originalTestRecord = $record;
// validate that the current record has an ACTIVE (e.g.: not-deleted) status
$this->assertEquals(STATUS_ACTIVE, $record[CM_TST_FIELD_TEST_STATUS], (__FILE__ . COLON . __LINE__) . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_STATUS));
// delete the record we created a couple methods ago referenced by the static $cKey value
$query = [ CM_TST_TOKEN => [ OPERAND_NULL => [OPERATOR_EQ => [$guid]]]];
$request = [ STRING_QUERY_DATA => $query];
// save the event guid for audit/journal record look-ups later
$eventGUID = guid();
$this->assertTrue(validateGUID($eventGUID), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_INVALID_GUID . $eventGUID);
$meta = static::$meta;
$meta[META_EVENT_GUID] = $eventGUID;
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);
// fetch record from cache
$record = gasCache::get(static::$cKey);
$this->assertNull($record, (__FILE__ . COLON . __LINE__) . COLON . ERROR_UT_CACHE_FETCH_FAIL . COLON . $guid);
}
/**
* testDeleteAudit() -- unit test method
*
* This unit test confirms that the record, deleted in the previous test-method, was successfully deleted and that
* an audit record was created for that event.
*
* Assertions:
* -----------
* 1-3: saved variables from the previous method are accessible and valid
* 4: We successfully fetched the audit record from admin service (implying that the audit token was created)
* 5: We pull a valid audit-record token from the data payload
* 6: We pull the audit record and store it (confirming array format)
* 7: We successfully fetch the original record
* 8: That the fetch event resulted in a status of SUCCESS (soft delete) or NOT_FOUND (hard delete)
* 9: If the delete was soft, that the status of the record was changed to DELETED
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 01-09-19 mks DB-80: original coding
*
*/
public function testDeleteAudit()
{
sleep(1); // ensure we've completed writing the audit(delete) event record
$ext = '_aud';
// 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::$originalTestRecord), (basename(__FILE__) . COLON . __LINE__) . COLON . ERROR_UT_LOST_VARIABLE . 'originalTestRecord');
// 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::$auditRecordToken = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][(DB_TOKEN . $ext)];
static::$auditRecord = $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0];
$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]));
$state = $results[PAYLOAD_STATE];
$vString = STATE_SUCCESS . ' or ' . STATE_NOT_FOUND;
$this->assertTrue(($state == STATE_SUCCESS or $state == STATE_NOT_FOUND), (basename(__FILE__) . COLON . __LINE__) . sprintf(ERROR_UT_VALS_NOT_EQUAL, $state, $vString));
if ($state == STATE_SUCCESS) {
$newStatus = $results[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][(DB_STATUS . COLLECTION_MONGO_TEST_EXT)];
$this->assertEquals(STATUS_DELETED, $newStatus, (basename(__FILE__) . COLON . __LINE__) . COLON . sprintf(ERROR_UT_VALS_NOT_EQUAL, STATUS_DELETED, $newStatus));
}
}
/**
* testDeleteJournalRecovery() -- unit test method
*
* This method tests that a journal record was created off the audit event from the delete-record event posted
* a couple of methods ago. We make the following assertions in this test:
*
* 1-5: That all stored variables are in the correct format and available through class statics
* 6: That we're able to fetch a journal record (implicitly stating that the journal record was created)
* 7: That we're able to successfully post a audit-recovery event and that the event successfully completes
* 8: That deleted record has been recovered back to an active state
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 01-09-19 mks DB-80: original coding
*
*/
public function testDeleteJournalRecovery()
{
$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::$originalTestRecord), (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'));
// 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);
$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]));
}
/**
* grabRandomTestRecord() -- private method for code reduction
*
* this is a private function that fetches a random record from the test collection. The function is invoked in
* the two sub-collection methods immediately following this one.
*
* There is an optional input parameter to this method:
*
* $_limit -- integer value, that defaults to 1, allowing you to specify the number of records to be returned,
* up to the maximum allowable.
*
* the function build a read-broker query, submits it, unpacks the result, and then validates/tests the return
* status. If the request was successful, we'll return the response payload otherwise execution of the testing
* will halt.
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param int $_limit -- optional parameter allowing user to specify number of records to be returned
* @return array
*
* HISTORY:
* ========
* 09-07-17 mks CORE-494: original coding
* 03-28-19 mks DB-116: added $_limit optional parameter
*
*/
private function grabRandomTestRecord(int $_limit = 1): array
{
$this->assertTrue($this->readBrokerClient->status, __METHOD__ . __LINE__ . ERROR_BROKER_QUEUE_DECLARE . BROKER_QUEUE_R);
$this->assertTrue($this->writeBrokerClient->status, __METHOD__ . __LINE__ . ERROR_BROKER_QUEUE_DECLARE . BROKER_QUEUE_W);
// validate the amount passed, if any, via the $_limit parameter
$_limit = (!is_numeric($_limit)) ? 1 : intval($_limit);
if ($_limit > gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_RECORD_LIMIT])
$_limit = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_RECORD_LIMIT];
// first thing we want to do is pull a random record in active status...
$query = [
CM_TST_FIELD_TEST_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
CM_TST_FIELD_TEST_INT => [ OPERAND_NULL => [ OPERATOR_EQ => [ intval(mt_rand(0,20))]]],
OPERAND_AND => null
];
// limit the return data count to 1 record (we'll test for this...)
static::$meta[META_LIMIT] = $_limit;
// set up the broker request
$request = [
BROKER_REQUEST => BROKER_REQUEST_FETCH,
BROKER_DATA => [STRING_QUERY_DATA => $query ],
BROKER_META_DATA => static::$meta
];
// build the request payload and submit the request to the read broker
$payload = gzcompress(json_encode($request));
$response = $this->readBrokerClient->call($payload);
$response = json_decode(gzuncompress($response), true);
unset(static::$meta[META_LIMIT]);
$this->assertTrue($response[PAYLOAD_STATUS], (__FILE__ . COLON) . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_FETCH, $response[PAYLOAD_STATE]));
return($response);
}
/**
* testSubCollectionInserts() -- unit test method
*
* This method evaluates the wBroker sub-Collection insert event by adding a new subC record to a randomly
* selected test record.
*
* NOTE THAT THIS TEST WILL ONLY WORK ON A CACHE-SUPPORTED CLASS!
*
* Criteria for a successful test:
* -------------------------------
* 1. The readBroker class object is still available
* 2. The writeBroker class object is still available
* 3. We can fetch a random, active, record
* 4. That we can fetch the same record from cache
* 5. That we can successfully publish a subC insert event
* 6. That we can fetch the updated (reflecting the db status) record from cache
* 7. That the subC count incremented by 1 record
* 8. That the inserted record exists
* 9. That all of the inserted record fields were set correctly
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 08-29-17 mks CORE-494: initial coding
* 09-06-17 mks CORE-556: injecting guids into sub-collection records on create
* 09-07-17 mks CORE-494: broke fetch-random record out to private method and invoked
*
*/
public function testSubCollectionInserts()
{
$response = $this->grabRandomTestRecord();
sleep(1);
$ck = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0];
$this->assertNotNull($ck,basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_UT_LOST_VARIABLE . STRING_CACHE_CKEY);
$this->assertTrue(gasCache::validateCacheKey($ck), (__FILE__ . COLON) . __LINE__ . ERROR_INVALID_GUID . $ck);
// we have the cache key for the record - fetch the record data
$data = gasCache::get($ck);
$data = json_decode(gzuncompress($data), true);
$data = $data[0];
$this->assertTrue(is_array($data), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_CACHE_FETCH_FAIL);
if (isset($data[CM_TST_FIELD_TEST_SUBC]) and count($data[CM_TST_FIELD_TEST_SUBC])) {
$numRecsOld = count($data[CM_TST_FIELD_TEST_SUBC]);
$this->assertGreaterThan(0, $numRecsOld, __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 0, $numRecsOld, 'number of subC recs'));
} else {
$numRecsOld = 0;
}
$key = $data[CM_TST_TOKEN];
$this->assertTrue(validateGUID($key), __FILE__ . COLON . __LINE__ . ERROR_INVALID_GUID . $key);
// create and add a new subC record
$newGUID = guid();
$intVal = 33;
$doubleVal = 33.33;
$boolVal = false;
$newSubCRecord = [
[
CM_TST_FIELD_TEST_INT => $intVal,
CM_TST_FIELD_TEST_DOUBLE => $doubleVal,
CM_TST_FIELD_TEST_STRING => $newGUID,
CM_TST_FIELD_TEST_NIF => STRING_UT_RECORD_INSERT,
CM_TST_FIELD_TEST_BOOL => $boolVal
]
];
$field = CM_TST_FIELD_TEST_SUBC;
$brokerData = [
STRING_GUID_KEY => $key,
STRING_SUBC_FIELD => $field,
STRING_DATA => $newSubCRecord
];
// create the query/broker-event payload
$request = [
BROKER_REQUEST => BROKER_REQUEST_SUBC_CREATE,
BROKER_DATA => $brokerData,
BROKER_META_DATA => static::$meta
];
$payload = gzcompress(json_encode($request));
$response = $this->writeBrokerClient->call($payload);
$response = json_decode(gzuncompress($response), true);
sleep(1); // give up some time for the cache record to be updated
$this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . AT . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_SUBC_CREATE, $response[PAYLOAD_STATE]));
$newCk = $response[PAYLOAD_RESULTS][0];
$this->assertTrue(gasCache::validateCacheKey($newCk), __FILE__ . AT . __LINE__ . COLON . ERROR_INVALID_GUID . $newCk);
// using the "new key", fetch the record from cache and check the count of the sub-collection
$newData = gasCache::get($newCk);
$newData = json_decode(gzuncompress($newData), true);
$this->assertTrue(is_array($newData), __FILE__ . AT . __LINE__ . COLON . ERROR_UT_CACHE_FETCH_FAIL);
$newData = $newData[0];
$numRecsNew = count($newData[CM_TST_FIELD_TEST_SUBC]);
$this->assertEquals(($numRecsOld + 1), $numRecsNew, __FILE__ . AT . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, $numRecsNew, ($numRecsOld + 1), CM_TST_FIELD_TEST_SUBC));
// get new subC record and validate the added fields and the injected guid
$subCRecord = $newData[CM_TST_FIELD_TEST_SUBC][$numRecsOld];
$this->assertEquals($subCRecord[CM_TST_FIELD_TEST_INT], $intVal, __FILE__ . AT . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_INT));
$this->assertEquals($subCRecord[CM_TST_FIELD_TEST_DOUBLE], $doubleVal, __FILE__ . AT . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_DOUBLE));
$this->assertEquals($subCRecord[CM_TST_FIELD_TEST_STRING], $newGUID, __FILE__ . AT . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_STRING));
$this->assertEquals($subCRecord[CM_TST_FIELD_TEST_BOOL], $boolVal, __FILE__ . AT . __LINE__ . COLON . sprintf(ERROR_UT_SAME_FIELD_COMPARE_FAIL, CM_TST_FIELD_TEST_BOOL));
$this->assertNotEmpty($subCRecord[CM_TST_TOKEN], __FILE__ . COLON . __LINE__ . AT . ERROR_DATA_KEY_404 . CM_TST_TOKEN);
$this->assertTrue(validateGUID($subCRecord[CM_TST_TOKEN]), __FILE__ . AT . __LINE__ . COLON . ERROR_INVALID_GUID . $subCRecord[CM_TST_TOKEN]);
}
/**
* testNegativeSubCollectionInsert() -- unit test method
*
* This is a negative unit test in that we're intentionally submitting an event request we expect to fail. For this
* test, we're looking at exceeding the maximum number of records allowed for a transaction.
*
* We'll pull a random record to get the guid values for the request - and then we'll also pull the max number
* of allowing records-per-transaction value from the XML configuration file.
*
* Next, we'll build a data payload which exceeds the count of allowable records and then submit the event request.
*
* Our tests will validate that the request was rejected with the appropriate error state and status.
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 09-11-17 mks CORE-501: original coding
*
*/
public function testNegativeSubCollectionInsert()
{
$records = null;
$response = $this->grabRandomTestRecord();
$ck = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0];
$this->assertTrue(gasCache::validateCacheKey($ck), (__FILE__ . COLON) . __LINE__ . ERROR_INVALID_GUID . $ck);
// we have the cache key for the record - fetch the record data
$data = gasCache::get($ck);
$data = json_decode(gzuncompress($data), true);
$data = $data[0];
$this->assertTrue(is_array($data), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_CACHE_FETCH_FAIL);
$key = $data[CM_TST_TOKEN];
$this->assertTrue(validateGUID($key), __FILE__ . COLON . __LINE__ . ERROR_INVALID_GUID . $key);
$qrl = intval(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_RECORD_LIMIT]);
$recCount = 1 + $qrl;
// create and add a new subC record
$newGUID = guid();
$intVal = 33;
$doubleVal = 33.33;
$boolVal = false;
$newSubCRecord = [
[
CM_TST_FIELD_TEST_INT => $intVal,
CM_TST_FIELD_TEST_DOUBLE => $doubleVal,
CM_TST_FIELD_TEST_STRING => $newGUID,
CM_TST_FIELD_TEST_NIF => STRING_UT_RECORD_INSERT,
CM_TST_FIELD_TEST_BOOL => $boolVal
]
];
for ($index = 0; $index < $recCount; $index++) $records[] = $newSubCRecord;
$field = CM_TST_FIELD_TEST_SUBC;
$brokerData = [
STRING_GUID_KEY => $key,
STRING_SUBC_FIELD => $field,
STRING_DATA => $records
];
// create the query/broker-event payload
$request = [
BROKER_REQUEST => BROKER_REQUEST_SUBC_CREATE,
BROKER_DATA => $brokerData,
BROKER_META_DATA => static::$meta
];
$payload = gzcompress(json_encode($request));
$response = $this->writeBrokerClient->call($payload);
$response = json_decode(gzuncompress($response), true);
// test that the event was rejected with the expected state value
$this->assertFalse($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_EXPECTING_FALSE . BROKER_REQUEST_CREATE);
$this->assertEquals(STATE_DATA_ERROR, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_STRING_MISMATCH, STATE_DATA_ERROR, $response[PAYLOAD_STATE]));
}
/**
* testSubCollectionDeletes() -- unit test method
*
* this unit test evaluates the BROKER_REQUEST_SUBC_DELETE event in the write-broker by fetching a random record
* from the test collection and selecting a sub-collection record (with a key) for deletion.
*
* The payload request is build and submitted to namaste for processing after which we evaluate the success or
* fail for the event.
*
* next, because this is a cached-class, we're going to pull the updated record from cache using the reference to
* the cache key returned in the broker-payload and we're going to test that the count of sub-collection records
* was de-incremented by one and then we're going to spin through every sub-collection record with a key and compare
* the key value.
*
* Finally, we're going to re-submit the request again to test that we got a successful event, but we returned a
* 404 (STATE_NOT_FOUND) message.
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 09-07-17 mks CORE-494: original coding
*
*/
public function testSubCollectionDeletes()
{
$subCKey = '';
$found = false;
$data = null;
while (!$found) {
$response = $this->grabRandomTestRecord();
$ck = $response[PAYLOAD_RESULTS][PAYLOAD_QUERY][0];
$this->assertTrue(gasCache::validateCacheKey($ck), (__FILE__ . COLON) . __LINE__ . ERROR_INVALID_GUID . $ck);
// we have the cache key for the record - fetch the record data
$data = gasCache::get($ck);
$data = json_decode(gzuncompress($data), true);
$data = $data[0];
$this->assertTrue(is_array($data), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_CACHE_FETCH_FAIL);
$found = (isset($data[CM_TST_FIELD_TEST_SUBC]) and !empty($data[CM_TST_FIELD_TEST_SUBC])) ? true : false;
}
$numRecsOld = count($data[CM_TST_FIELD_TEST_SUBC]);
$this->assertGreaterThan(0, $numRecsOld, __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_INTEGER_MISMATCH, 0, $numRecsOld, 'number of subC recs'));
$key = $data[CM_TST_TOKEN];
$this->assertTrue(validateGUID($key), __FILE__ . COLON . __LINE__ . ERROR_INVALID_GUID . $key);
$subCArray = $data[CM_TST_FIELD_TEST_SUBC];
$found = false;
$index = 0;
while (!$found and $index < $numRecsOld) {
if (array_key_exists(CM_TST_TOKEN, $subCArray[$index])) {
$found = true;
$subCKey = $subCArray[$index][CM_TST_TOKEN];
} else {
$index++;
}
}
$this->assertTrue($found, __FILE__ . COLON . __LINE__ . COLON . ERROR_SUBC_RECORD_NO_KEY);
// build and submit the request to delete the selected sub-collection record
$payload = [
BROKER_REQUEST => BROKER_REQUEST_SUBC_DELETE,
BROKER_DATA => [
STRING_GUID_KEY => $key,
STRING_SUBC_FIELD => CM_TST_FIELD_TEST_SUBC,
STRING_SUBC_GUID => $subCKey
],
BROKER_META_DATA => static::$meta
];
$request = gzcompress(json_encode($payload));
$response = $this->writeBrokerClient->call($request);
$response = json_decode(gzuncompress($response), true);
// check that we successfully removed the sub-collection record
// first, check that the request was successfully processed
$this->assertTrue($response[PAYLOAD_STATUS], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_SUBC_DELETE, $response[PAYLOAD_STATE]));
$this->assertEquals(STATE_SUCCESS, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_SUBC_DELETE, $response[PAYLOAD_STATE]));
// fetch the updated record from cache
$newData = gasCache::get($response[PAYLOAD_RESULTS][0]);
$newData = json_decode(gzuncompress($newData), true);
$newData = $newData[0];
$this->assertTrue(is_array($newData), __FILE__ . COLON . __LINE__ . COLON . ERROR_UT_CACHE_FETCH_FAIL);
$numRecsNew = !isset($newData[CM_TST_FIELD_TEST_SUBC]) ? 0 : count($newData[CM_TST_FIELD_TEST_SUBC]);
if ($numRecsNew != 0) {
$this->assertEquals(($numRecsOld - 1), $numRecsNew, __FILE__ . COLON . __LINE__ . sprintf(ERROR_UT_INTEGER_MISMATCH, $numRecsNew, ($numRecsOld + 1), CM_TST_FIELD_TEST_SUBC));
// search every sub-collection record with a key and compare it to the key in the delete request
foreach ($newData[CM_TST_FIELD_TEST_SUBC] as $subRecord) {
if (array_key_exists(CM_TST_TOKEN, $subRecord)) {
$this->assertNotEquals($subRecord[CM_TST_TOKEN], $subCKey, __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_SUBC_RECORD_KEY_FOUND, $subCKey));
}
}
}
// test the 404 return payload by re-submitting the request
$request = gzcompress(json_encode($payload));
$response = $this->writeBrokerClient->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_SUBC_DELETE, $response[PAYLOAD_STATE]));
$this->assertEquals(STATE_NOT_FOUND, $response[PAYLOAD_STATE], __FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UT_BROKER_EVENT_FAIL, BROKER_REQUEST_SUBC_DELETE, $response[PAYLOAD_STATE]));
}
}