diff --git a/phpunit.xml b/phpunit.xml index dad99dd69..5ec9092ee 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -36,6 +36,10 @@ + + + + diff --git a/tests/bootstrap.php b/tests/bootstrap.php index fdee3691a..148d060d1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -14,26 +14,46 @@ use Illuminate\Support\Facades\Schema; /** * @todo Migrate to configuration parameters */ - define('PATH_TRUNK', dirname(__DIR__)); -define('PATH_CORE', PATH_TRUNK.'/workflow/engine/'); +define('PATH_CORE', PATH_TRUNK . '/workflow/engine/'); define('PATH_CONFIG', PATH_CORE . 'config/'); -define('PATH_RBAC_CORE',dirname(__DIR__).'/rbac/engine/'); -define('PATH_DB', dirname(__DIR__).'/shared/sites/'); -define('PATH_DATA', dirname(__DIR__).'/shared/rbac/'); +$pathData = PATH_CONFIG . 'paths_installed.php'; +if (file_exists($pathData)) { + require_once $pathData; +} else { + define('PATH_DATA', dirname(__DIR__) . '/shared/rbac/'); +} +define('PATH_RBAC_CORE', dirname(__DIR__) . '/rbac/engine/'); +define('PATH_DB', dirname(__DIR__) . '/shared/sites/'); define('PATH_SEP', '/'); -define('PATH_METHODS', dirname(__DIR__).'/workflow/engine/methods/'); +define('PATH_METHODS', dirname(__DIR__) . '/workflow/engine/methods/'); define('SYS_LANG', 'en'); define('DB_ADAPTER', 'mysql'); define('SYS_SKIN', 'neoclassic'); -define('SYS_SYS', 'workflow'); -define('PATH_WORKSPACE',PATH_TRUNK.'/shared/sites/' . SYS_SYS . '/'); -define('PMTABLE_KEY','pmtable'); +define('SYS_SYS', env('MAIN_SYS_SYS', 'workflow')); +define('PATH_WORKSPACE', PATH_TRUNK . '/shared/sites/' . SYS_SYS . '/'); +define('PMTABLE_KEY', 'pmtable'); +define('PATH_WORKFLOW_MYSQL_DATA', PATH_TRUNK . '/workflow/engine/data/mysql/'); +define('PATH_RBAC_MYSQL_DATA', PATH_TRUNK . '/rbac/engine/data/mysql/'); +define('PATH_LANGUAGECONT', PATH_DATA . '/META-INF/'); + +//timezone +$_SESSION['__SYSTEM_UTC_TIME_ZONE__'] = (int) (env('MAIN_SYSTEM_UTC_TIME_ZONE', 'workflow')) == 1; + +//Set Time Zone +ini_set('date.timezone', $_SESSION['__SYSTEM_UTC_TIME_ZONE__'] ? 'UTC' : env('MAIN_TIME_ZONE', 'America/New_York')); +define('TIME_ZONE', ini_get('date.timezone')); // Setup basic app services $app = require __DIR__ . '/../bootstrap/app.php'; $app->make(Kernel::class)->bootstrap(); +//Overwrite with the Processmaker env.ini configuration used in production environments +//@todo: move env.ini configuration to .env +ini_set('date.timezone', TIME_ZONE); //Set Time Zone +date_default_timezone_set(TIME_ZONE); +config(['app.timezone' => TIME_ZONE]); + // Setup our testexternal database config(['database.connections.testexternal' => [ 'driver' => 'mysql', @@ -49,6 +69,11 @@ config(['database.connections.testexternal' => [ 'engine' => null ]]); +//configuration values +config([ + "system.workspace" => SYS_SYS +]); + // Now, drop all test tables and repopulate with schema Schema::connection('testexternal')->dropIfExists('test'); diff --git a/tests/unit/workflow/engine/src/ProcessMaker/Services/Api/LightTest.php b/tests/unit/workflow/engine/src/ProcessMaker/Services/Api/LightTest.php new file mode 100644 index 000000000..c24d476cc --- /dev/null +++ b/tests/unit/workflow/engine/src/ProcessMaker/Services/Api/LightTest.php @@ -0,0 +1,355 @@ +timezone = config('app.timezone'); + $_SESSION['USR_TIME_ZONE'] = $this->timezone; + $this->baseUri = $this->getBaseUri(); + $this->workspace = env("DB_DATABASE", "test"); + $this->clientId = config("oauthClients.pm.clientId"); + $this->clientSecret = config("oauthClients.pm.clientSecret"); + $this->user = "admin"; + $this->password = "admin"; + $this->createTestSite(); + $this->http = new Client([ + "base_uri" => $this->baseUri + ]); + $this->optionsForConvertDatetime = [ + 'newerThan', + 'oldestthan', + 'date', + 'delegateDate', + 'dueDate', + 'delRiskDate' + ]; + } + + /** + * Get base uri for rest applications. + * @return string + */ + private function getBaseUri() + { + $_SERVER = $this->getServerInformation(); + $baseUri = System::getServerProtocolHost(); + + return $baseUri; + } + + /** + * Get server information. + * @return object + */ + private function getServerInformation() + { + $pathData = PATH_DATA . "sites" . PATH_SEP . config("system.workspace") . PATH_SEP . ".server_info"; + $content = file_get_contents($pathData); + $serverInfo = unserialize($content); + + return $serverInfo; + } + + /** + * This method creates a test workspace so that the endpoints can be functional, + * it is necessary to change the permissions of the directory so that other + * users can access and write to the directory, these users can be for + * example: apache2, www-data, httpd, etc... + * This method finds the license file of the active site and uses it to register + * this license in the LICENSE_MANAGER table. If there is no license file in + * the active workspace, an asersion failure will be notified. + */ + private function createTestSite() + { + //We copy the license, otherwise you will not be able to lift the site + $pathTest = PATH_DATA . "sites" . PATH_SEP . $this->workspace; + File::copyDirectory(PATH_DATA . "sites" . PATH_SEP . config("system.workspace"), $pathTest); + + //Write permission for other users for example: apache2, www-data, httpd. + passthru('chmod 777 -R ' . $pathTest . ' >> .log 2>&1'); + + $installer = new Installer(); + $options = [ + 'isset' => true, + 'name' => $this->workspace, + 'admin' => [ + 'username' => $this->user, + 'password' => $this->password + ], + 'advanced' => [ + 'ao_db_drop' => true, + 'ao_db_wf' => $this->workspace, + 'ao_db_rb' => $this->workspace, + 'ao_db_rp' => $this->workspace + ] + ]; + //The false option creates a connection to the database, necessary to create a site. + $installer->create_site($options, false); + //Now create site + $installer->create_site($options, true); + + //Important so that the dates are stored in the same timezone + file_put_contents($pathTest . "/env.ini", "time_zone ='{$this->timezone}'", FILE_APPEND); + + $matchingFiles = File::glob("{$pathTest}/*.dat"); + $this->assertNotEmpty($matchingFiles); + + //set license + $licensePath = array_pop($matchingFiles); + DB::Table("LICENSE_MANAGER")->insert([ + "LICENSE_UID" => G::generateUniqueID(), + "LICENSE_USER" => "ProcessMaker Inc", + "LICENSE_START" => "1490932800", + "LICENSE_END" => 0, + "LICENSE_SPAN" => 0, + "LICENSE_STATUS" => "ACTIVE", + "LICENSE_DATA" => file_get_contents($licensePath), + "LICENSE_PATH" => $licensePath, + "LICENSE_WORKSPACE" => $this->workspace, + "LICENSE_TYPE" => "" + ]); + } + + /** + * Get authorization values. + */ + private function getAuthorization() + { + $request = $this->http->request("POST", "{$this->workspace}/oauth2/token", [ + "form_params" => [ + "grant_type" => "password", + "scope" => "*", + "client_id" => $this->clientId, + "client_secret" => $this->clientSecret, + "username" => $this->user, + "password" => $this->password + ] + ]); + + //Here is to verify if the connection to the endpoint was satisfactory, + //so the connection status should be 200. + $statusCode = $request->getStatusCode(); + $this->assertEquals(200, $statusCode); + + //If the endpoint has responded we can obtain the data and verify if it + //is what we expected. + $contents = $request->getBody()->getContents(); + $credentials = json_decode($contents); + + $this->assertNotNull($credentials); + $this->assertObjectHasAttribute('access_token', $credentials); + $this->assertObjectHasAttribute('expires_in', $credentials); + $this->assertObjectHasAttribute('refresh_token', $credentials); + $this->assertObjectHasAttribute('scope', $credentials); + $this->assertObjectHasAttribute('token_type', $credentials); + + $this->authorization = ucwords($credentials->token_type) . " {$credentials->access_token}"; + } + + /** + * Get current collection list unassigned. + * @return collection + */ + private function getCollectionListUnassigned() + { + //Create process + $process = factory(Process::class)->create(); + + //Get user + $user = User::select() + ->where('USR_USERNAME', '=', $this->user) + ->first(); + + //Create a task self service + $task = factory(Task::class)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process->PRO_UID + ]); + + //Assign a user in the task + factory(TaskUser::class, 1)->create([ + 'TAS_UID' => $task->TAS_UID, + 'USR_UID' => $user->USR_UID, + 'TU_RELATION' => 1, //Related to the user + 'TU_TYPE' => 1 + ]); + + //Create a record in list unassigned + $listUnassigned = factory(ListUnassigned::class, 15)->create([ + 'TAS_ID' => $task->TAS_ID, + 'DEL_PREVIOUS_USR_UID' => $user->USR_UID + ]); + + $result = $listUnassigned->sortByDesc('DEL_DELEGATE_DATE'); + + return $result; + } + + /** + * Changes the data to the format returned by REST API. + * @param array $collection + * @return array + */ + private function normalizeData($collection) + { + $result = []; + $collection->transform(function ($item, $key) use (&$result) { + $value = [ + 'caseId' => $item->APP_UID, + //The current EndPoint returns this value as a string, an Eloquent + //collection takes into account the string and numeric types. + 'delIndex' => (string) $item->DEL_INDEX, + 'task' => [ + 'taskId' => $item->TAS_UID, + 'name' => $item->APP_TAS_TITLE + ], + 'process' => [ + 'processId' => $item->PRO_UID, + 'name' => $item->APP_PRO_TITLE + ], + //The current EndPoint returns this value as a string, an Eloquent + //collection takes into account the string and numeric types. + 'caseNumber' => (string) $item->APP_NUMBER, + 'caseTitle' => $item->APP_TITLE, + 'date' => $item->APP_UPDATE_DATE->format('Y-m-d H:i:s'), + 'delegateDate' => $item->DEL_DELEGATE_DATE->format('Y-m-d H:i:s'), + 'prevUser' => [ + 'userId' => $item->DEL_PREVIOUS_USR_UID, + 'userName' => $item->DEL_PREVIOUS_USR_USERNAME, + 'firstName' => $item->DEL_PREVIOUS_USR_FIRSTNAME, + 'lastName' => $item->DEL_PREVIOUS_USR_LASTNAME + ], + 'dueDate' => $item->DEL_DUE_DATE->format('Y-m-d H:i:s'), + ]; + $result[] = $value; + }); + + $converted = DateTime::convertUtcToIso8601($result, $this->optionsForConvertDatetime); + + //Convert the elements to an object + $object = json_decode(json_encode($converted)); + + return $object; + } + + /** + * This returns an array of arrays to test the $start and $limit parameters. + * The values correspond to the following structure: + * [ + * [$page, $size, $start, $limit], + * [$page, $size, $start, $limit], + * [$page, $size, $start, $limit], + * ] + * $page and $size are necessary to test the pages we expect to have from the + * model collection. + * @return array + */ + public function pagesProvider() + { + return [ + [1, 5, 0, 5], + [2, 5, 5, 5], + [3, 5, 10, 5], + [4, 5, 15, 5], + [5, 5, 20, 5], + [6, 5, 25, 5] + ]; + } + + /** + * This check if the endpoint {workspace}/light/unassigned, is returning all data. + * @test + * @covers ProcessMaker\Services\Api\Light::doGetCasesListUnassigned + */ + public function it_should_get_all_data_without_start_and_limit_values() + { + $listUnassigned = $this->getCollectionListUnassigned(); + + $this->getAuthorization(); + $request = $this->http->request("GET", "api/1.0/{$this->workspace}/light/unassigned", [ + "headers" => [ + "Authorization" => $this->authorization + ] + ]); + + //Here is to verify if the connection to the endpoint was satisfactory, + //so the connection status should be 200. + $statusCode = $request->getStatusCode(); + $this->assertEquals(200, $statusCode); + + //If the endpoint has responded we can obtain the data and verify if it + //is what we expected. + $expected = $this->normalizeData($listUnassigned); + $contents = $request->getBody()->getContents(); + $content = json_decode($contents); + + $this->assertEquals($expected, $content); + } + + /** + * This check if the endpoint {workspace}/light/unassigned, is returning the + * requested data set according to the start and limit parameters. The $start + * and $limit test values are obtained from the data provider pagesProvider(). + * @test + * @covers ProcessMaker\Services\Api\Light::doGetCasesListUnassigned + * @dataProvider pagesProvider + */ + public function it_should_get_data_with_start_and_limit($page, $size, $start, $limit) + { + $listUnassigned = $this->getCollectionListUnassigned(); + $result = $listUnassigned->forPage($page, $size); + + $this->getAuthorization(); + $request = $this->http->request("GET", "api/1.0/{$this->workspace}/light/unassigned?start={$start}&limit={$limit}", [ + "headers" => [ + "Authorization" => $this->authorization + ] + ]); + + //Here is to verify if the connection to the endpoint was satisfactory, + //so the connection status should be 200. + $statusCode = $request->getStatusCode(); + $this->assertEquals(200, $statusCode); + + //If the endpoint has responded we can obtain the data and verify if it + //is what we expected. + $expected = $this->normalizeData($result); + $contents = $request->getBody()->getContents(); + $content = json_decode($contents); + + $this->assertEquals($expected, $content); + } +} diff --git a/workflow/engine/src/ProcessMaker/Model/ListUnassigned.php b/workflow/engine/src/ProcessMaker/Model/ListUnassigned.php index aa69c2f3c..7dab112f8 100644 --- a/workflow/engine/src/ProcessMaker/Model/ListUnassigned.php +++ b/workflow/engine/src/ProcessMaker/Model/ListUnassigned.php @@ -35,6 +35,14 @@ class ListUnassigned extends Model return $this->belongsTo(Process::class, 'PRO_ID', 'PRO_ID'); } + /** + * Return the user this belongs to + */ + public function previousUser() + { + return $this->belongsTo(User::class, 'DEL_PREVIOUS_USR_UID', 'USR_UID'); + } + /** * Scope a query to only include specific tasks * @@ -93,7 +101,7 @@ class ListUnassigned extends Model * @param array $filters * * @return array - */ + */ public static function doCount($userUid, $filters = []) { $list = new PropelListUnassigned(); @@ -155,4 +163,3 @@ class ListUnassigned extends Model return $result; } } - diff --git a/workflow/engine/src/ProcessMaker/Services/Api/Light.php b/workflow/engine/src/ProcessMaker/Services/Api/Light.php index a1f6a80a3..f59ae6bc5 100644 --- a/workflow/engine/src/ProcessMaker/Services/Api/Light.php +++ b/workflow/engine/src/ProcessMaker/Services/Api/Light.php @@ -652,10 +652,11 @@ class Light extends Api if (preg_match($this->regexNull, $newerThan)) { return []; } + $paged = ($start === 0 && $limit === 0) ? false : true; $dataList['userId'] = $this->getUserId(); $dataList['action'] = 'unassigned'; - $dataList['paged'] = false; + $dataList['paged'] = $paged; $dataList['start'] = $start; $dataList['limit'] = $limit; @@ -682,6 +683,9 @@ class Light extends Api /*----------------------------------********---------------------------------*/ } /*----------------------------------********---------------------------------*/ + if ($paged === true) { + $response = $response['data']; + } $result = $this->parserDataUnassigned($response); return DateTime::convertUtcToIso8601($result, $this->arrayFieldIso8601);