diff --git a/README.md b/README.md index 5d62b3c5832932bceb7ce2631a50cf129b0c6598..1075569286f43d6e835d510fefe6c27b27da9328 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,7 @@ $config2 = new TestcenterInstanceConfig('http://testcenter2/api', new User('supe $connector = new MultiTestcenterConnector([$config1, $config2]); try { - $result = $connector->addWorkspace('New Workspace'); + $result = $connector->addWorkspaceAsync('New Workspace'); } catch (\Exception $e) { // handle exception } @@ -229,3 +229,6 @@ try { Als Rückgabewerte erhält man ein assoziatives Array mit der Base-URL der jeweiligen Testcenter Instanz als Key und deren Antwort als Wert. + +Um mehrere Testcenter Instanzen parallel anzusprechen, müssen die asynchronen Varianten der Methoden verwendet werden. +Bei den synchronen Methoden werden die Testcenter Instanzen sequentiell nacheinander angesprochen. diff --git a/composer.json b/composer.json index bff20102c2af056db33eed4103379765d68a1ff9..a0f4d609dba9b7b17f35e7f3ce3d4c0d59ad4a99 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "ext-json": "*", "ext-xmlwriter": "*", "ext-zip": "*", + "ext-curl": "*", "guzzlehttp/guzzle": "^7.8" }, "scripts": { diff --git a/e2e/AddAUserTest.php b/e2e/AddAUserTest.php index 20e2d34793fdfad157b432d09b66a4d953e8c53d..15a05ed906ef34ea041d070a0eb1443d559e5274 100644 --- a/e2e/AddAUserTest.php +++ b/e2e/AddAUserTest.php @@ -1,11 +1,15 @@ <?php -use \Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$user = new User('super', 'user123', User::ADMIN_ROLE); -$connector = new TestcenterConnector($user, 'http://localhost/api'); -$result = $connector->addUser('userabc', 'passwabc'); +$config = getTestcenterConfig(); + +$username = getenv('TEST_USERNAME') ? getenv('TEST_USERNAME') : 'userabc'; +$password = getenv('TEST_PASSWORD') ? getenv('TEST_PASSWORD') : 'passwabc'; + +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); +$result = $connector->addUser($username, $password); var_dump($result); diff --git a/e2e/AddAWorkspaceTest.php b/e2e/AddAWorkspaceTest.php index d7c5e57fef8eba78b51e891cb9fdcf48aa5bbd71..26a9f9076f739b0bb05a4b9b85a9e5be0ba27937 100644 --- a/e2e/AddAWorkspaceTest.php +++ b/e2e/AddAWorkspaceTest.php @@ -1,12 +1,15 @@ <?php -use \Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$user = new User('super', 'user123', User::ADMIN_ROLE); -$connector = new TestcenterConnector($user, 'http://localhost/api'); -$workspaceId = $connector->addWorkspace('New test workspace 2'); +$config = getTestcenterConfig(); -var_dump($workspaceId); \ No newline at end of file +$workspaceName = getenv('WORKSPACE_NAME') ?? 'New test workspace 2'; + +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); +$workspaceId = $connector->addWorkspace($workspaceName); + +var_dump($workspaceId); diff --git a/e2e/AddSuperAdminTest.php b/e2e/AddSuperAdminTest.php index 60096bd42c6fc2f8d0296cabda605fbf97d31883..78dd5ebab01994b089b513542ebff8ae19a3505e 100644 --- a/e2e/AddSuperAdminTest.php +++ b/e2e/AddSuperAdminTest.php @@ -1,11 +1,12 @@ <?php use Kompetenztestde\TestcenterConnector\TestcenterConnector; -use Kompetenztestde\TestcenterConnector\Models\User; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$user = new User('super', 'user123', User::ADMIN_ROLE); -$connector = new TestcenterConnector($user, 'http://localhost/api'); +$config = getTestcenterConfig(); + +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $result = $connector->addSuperAdmin('super2', 'user123'); var_dump($result); diff --git a/e2e/AddTestTest.php b/e2e/AddTestTest.php index e7d4d05be8dc6a057cbde5079c37202c2b8c8f8f..7ff30f52745b1dc9a99fdbb2c7227ea17387106b 100644 --- a/e2e/AddTestTest.php +++ b/e2e/AddTestTest.php @@ -1,10 +1,10 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\Models\FileTest; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; $booklet = file_get_contents('./testAssets/Booklet.xml'); $bookletAddress = 'data://application/xml;base64,' . base64_encode($booklet); @@ -29,7 +29,7 @@ $test = new FileTest( ] ); -$user = new User('super', 'user123', User::ADMIN_ROLE); -$connector = new TestcenterConnector($user, 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $response = $connector->addTest(5, $test); var_dump($response); diff --git a/e2e/ChangeUserPasswordTest.php b/e2e/ChangeUserPasswordTest.php index dea1ea6577c7863bd03cf9219776c6ed98cf18dd..f986db82772581f6231e767fffdd3e03102471d7 100644 --- a/e2e/ChangeUserPasswordTest.php +++ b/e2e/ChangeUserPasswordTest.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $response = $connector->changeUserPassword(1, 'user1234'); var_dump($response); diff --git a/e2e/ChangeUserRolesTest.php b/e2e/ChangeUserRolesTest.php index 1b909623b8e698245da66e19a1d3d14216764662..49b60300700f21ddd09e76d294a2edcd152e1781 100644 --- a/e2e/ChangeUserRolesTest.php +++ b/e2e/ChangeUserRolesTest.php @@ -1,15 +1,16 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\Api\Schemas\UserRole; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; $roles = [ new UserRole(1, UserRole::RW) ]; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $response = $connector->changeUserRoles(2, $roles); var_dump($response); diff --git a/e2e/CreateTesttakersTest.php b/e2e/CreateTesttakersTest.php index 33ff66e0cb8118c65b60cd18b4be8c37410fb8b0..e1b1e2d7d91e95b29831f686d56c04a710cf7395 100644 --- a/e2e/CreateTesttakersTest.php +++ b/e2e/CreateTesttakersTest.php @@ -1,15 +1,15 @@ <?php require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\Models\Pupil; use Kompetenztestde\TestcenterConnector\Models\Teacher; use Kompetenztestde\TestcenterConnector\TestcenterConnector; use Kompetenztestde\TestcenterConnector\Models\TestGroup; -$user = new User('super', 'user123', User::ADMIN_ROLE); -$connector = new TestcenterConnector($user, 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $logins = [ new Pupil('login1', 'password1'), @@ -17,4 +17,6 @@ $logins = [ ]; $group = new TestGroup('test-group', 'Test Group', $logins); -$connector->addTestGroup(1, $group, 'BOOKLET.SAMPLE-1'); \ No newline at end of file +$workspaceId = getenv('WORKSPACE_ID') !== false ? intval(getenv('WORKSPACE_ID')) : 1; + +$connector->addTestGroupAsync($workspaceId, $group, 'BOOKLET.SAMPLE-1')->wait(); diff --git a/e2e/DeleteData.php b/e2e/DeleteData.php index cffbd26c854cc2c8e7131e5e0418f79230b5a860..76ca2570a928899000839c1be730dc6f28e1dbe4 100644 --- a/e2e/DeleteData.php +++ b/e2e/DeleteData.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $result = $connector->deleteData(3, ['group1']); -var_dump($result); \ No newline at end of file +var_dump($result); diff --git a/e2e/DeleteFilesTest.php b/e2e/DeleteFilesTest.php index 2dae0514cde2fa8583cba2c73f537f782c6f961d..db6a86182f38a085c5a4c993c48f65ef84974e73 100644 --- a/e2e/DeleteFilesTest.php +++ b/e2e/DeleteFilesTest.php @@ -1,15 +1,13 @@ <?php require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; use Kompetenztestde\TestcenterConnector\Models\File; -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; -$connector = new TestcenterConnector( - new User('super', 'user123', User::ADMIN_ROLE), - 'http://localhost/api' -); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $files = [ new File('SAMPLE_TESTTAKERS.XML', File::TESTTAKERS_FILE) diff --git a/e2e/DeleteSomeUsers.php b/e2e/DeleteSomeUsers.php index 577bc46c669488d116f765c32da4d822469b7cb0..9acdf5d2186831d9f635383e85b35dd15d81b969 100644 --- a/e2e/DeleteSomeUsers.php +++ b/e2e/DeleteSomeUsers.php @@ -1,12 +1,13 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $result = $connector->deleteUsers([3]); if ($result) { echo 'successful'; -} \ No newline at end of file +} diff --git a/e2e/DeleteSomeWorkspacesTest.php b/e2e/DeleteSomeWorkspacesTest.php index 0ebf2fc6d16306e13e8ec54c02396d565c975438..a96c43c3d6c69299eee121d7c1bde74d3a06465d 100644 --- a/e2e/DeleteSomeWorkspacesTest.php +++ b/e2e/DeleteSomeWorkspacesTest.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $result = $connector->deleteWorkspace([3, 4]); -var_dump($result); \ No newline at end of file +var_dump($result); diff --git a/e2e/E2eTestHelper.php b/e2e/E2eTestHelper.php new file mode 100644 index 0000000000000000000000000000000000000000..5ab0ecf6cbe7f0b2e1922621edbd4fa95b553f09 --- /dev/null +++ b/e2e/E2eTestHelper.php @@ -0,0 +1,14 @@ +<?php + +use Kompetenztestde\TestcenterConnector\Models\User; +use Kompetenztestde\TestcenterConnector\TestcenterInstanceConfig; + +function getTestcenterConfig($suffix = ''): TestcenterInstanceConfig +{ + $baseUrl = getenv("TESTCENTER_BASE_URL$suffix") ? getenv("TESTCENTER_BASE_URL$suffix") : 'http://localhost/api'; + $username = getenv("TESTCENTER_USER$suffix") ? getenv("TESTCENTER_USER$suffix") : 'super'; + $password = getenv("TESTCENTER_PASSWORD$suffix") ? getenv("TESTCENTER_PASSWORD$suffix") : 'user123'; + + $user = new User($username, $password, User::ADMIN_ROLE); + return new TestcenterInstanceConfig($baseUrl, $user); +} diff --git a/e2e/GetAListOfUsers.php b/e2e/GetAListOfUsers.php index 0d5119ee25865e0b34ce0817def8735a4d5b1413..cb1449c78d96b168a60bc97947484b57545051bf 100644 --- a/e2e/GetAListOfUsers.php +++ b/e2e/GetAListOfUsers.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $users = $connector->getUsers(); -var_dump($users); \ No newline at end of file +var_dump($users); diff --git a/e2e/GetAListOfWorkspacesTest.php b/e2e/GetAListOfWorkspacesTest.php index 1d249745bd17c22f5da4882bd507968713a6b6d7..b71ed04657b6151c42de9278ade2fb57a8d39fa7 100644 --- a/e2e/GetAListOfWorkspacesTest.php +++ b/e2e/GetAListOfWorkspacesTest.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $workspaces = $connector->getWorkspaces(); var_dump($workspaces); diff --git a/e2e/GetLogEntriesTest.php b/e2e/GetLogEntriesTest.php index 1faf99896e49ac87b745b6736afaff8065fb168a..599957f6750b71f8b301baa3a1b8ab38041551a7 100644 --- a/e2e/GetLogEntriesTest.php +++ b/e2e/GetLogEntriesTest.php @@ -1,10 +1,12 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); -$logEntries = $connector->getLogs(1, ['sample_group']); -var_dump($logEntries); \ No newline at end of file +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); +$workspaceId = getenv('WORKSPACE_ID') !== false ? intval(getenv('WORKSPACE_ID')) : 1; +$logEntries = $connector->getLogs($workspaceId, ['sample_group']); +var_dump($logEntries); diff --git a/e2e/GetResponsesTest.php b/e2e/GetResponsesTest.php index b2daf2a76a59be298c64ac474c7dbfc279c7f443..175164e626b3f0d9338c263a33c8b1c6af77914f 100644 --- a/e2e/GetResponsesTest.php +++ b/e2e/GetResponsesTest.php @@ -3,9 +3,12 @@ use Kompetenztestde\TestcenterConnector\Api\TestcenterApiClient; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$apiClient = new TestcenterApiClient('http://localhost/api'); +$config = getTestcenterConfig(); +$apiClient = new TestcenterApiClient($config->getBaseUrl()); -$session = $apiClient->startAdminSession('super', 'user123'); +$user = $config->getUser(); +$session = $apiClient->startAdminSession($user->getUsername(), $user->getPassword()); $responses = $apiClient->getReportOfItemResponses($session->getToken(), 4, ['test-group-2']); -var_dump($responses); \ No newline at end of file +var_dump($responses); diff --git a/e2e/GetResultsTest.php b/e2e/GetResultsTest.php index 25b409df40b3888f2b0bb165a9d9c4730e73d70a..9891128f0c98610d1735e070106d80d7c59634ae 100644 --- a/e2e/GetResultsTest.php +++ b/e2e/GetResultsTest.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $results = $connector->getResults(1); -var_dump($results); \ No newline at end of file +var_dump($results); diff --git a/e2e/GetSystemCheckReports.php b/e2e/GetSystemCheckReports.php index 146f2bc228fe326fd189bb2c461ca9b67949ad2e..0d85ba8d4bb381e84fb09dd57fc85ca3fe43e2b2 100644 --- a/e2e/GetSystemCheckReports.php +++ b/e2e/GetSystemCheckReports.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $report = $connector->getSystemCheckReport(1, ['SYSCHECK.SAMPLE']); -var_dump($report); \ No newline at end of file +var_dump($report); diff --git a/e2e/GetSystemConfig.php b/e2e/GetSystemConfig.php index 8645f6652eed397c4d84ba74f66d9e6a19d81f9b..4c06f1b313b66bc54cddf63d72f6a5f26fd79a75 100644 --- a/e2e/GetSystemConfig.php +++ b/e2e/GetSystemConfig.php @@ -1,10 +1,12 @@ <?php require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; use Kompetenztestde\TestcenterConnector\Api\TestcenterApiClient; -$apiClient = new TestcenterApiClient('http://localhost/api'); +$config = getTestcenterConfig(); +$apiClient = new TestcenterApiClient($config->getBaseUrl()); $config = $apiClient->getSystemConfig(); -var_dump($config); \ No newline at end of file +var_dump($config); diff --git a/e2e/GetUserWorkspacesTest.php b/e2e/GetUserWorkspacesTest.php index 85c53ee38487bd303ecc928e6f52791e09c48f0b..4f0d27c877c41f42fa1efef635b3085b741fc574 100644 --- a/e2e/GetUserWorkspacesTest.php +++ b/e2e/GetUserWorkspacesTest.php @@ -1,10 +1,11 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $workspaces = $connector->getWorkspacesByUser(1); var_dump($workspaces); diff --git a/e2e/MultiAddWorkspaceTest.php b/e2e/MultiAddWorkspaceTest.php index 6dd406c032a2aa967fd63830ab324dc895ca9232..0931620ed6170ae79d8b999fe425f98e81782f8a 100644 --- a/e2e/MultiAddWorkspaceTest.php +++ b/e2e/MultiAddWorkspaceTest.php @@ -1,13 +1,12 @@ <?php use Kompetenztestde\TestcenterConnector\MultiTestcenterConnector; -use Kompetenztestde\TestcenterConnector\TestcenterInstanceConfig; -use Kompetenztestde\TestcenterConnector\Models\User; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$config1 = new TestcenterInstanceConfig('http://testcenter1/api', new User('super', 'user123', User::ADMIN_ROLE)); -$config2 = new TestcenterInstanceConfig('http://testcenter2/api', new User('super', 'user123', User::ADMIN_ROLE)); +$config1 = getTestcenterConfig('_1'); +$config2 = getTestcenterConfig('_2'); $connector = new MultiTestcenterConnector([$config1, $config2]); $result = $connector->addWorkspace('test-workspace-123'); diff --git a/e2e/MultiGetResponsesTest.php b/e2e/MultiGetResponsesTest.php index 90e34528a0f39589fa70ff4401c2d5fb90ae4047..baea1d661c709228eaa81daf97ac22122a1deaf6 100644 --- a/e2e/MultiGetResponsesTest.php +++ b/e2e/MultiGetResponsesTest.php @@ -1,14 +1,23 @@ <?php use Kompetenztestde\TestcenterConnector\MultiTestcenterConnector; -use Kompetenztestde\TestcenterConnector\TestcenterInstanceConfig; -use Kompetenztestde\TestcenterConnector\Models\User; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$config1 = new TestcenterInstanceConfig('http://testcenter1/api', new User('super', 'user123', User::ADMIN_ROLE)); -$config2 = new TestcenterInstanceConfig('http://testcenter2/api', new User('super', 'user123', User::ADMIN_ROLE)); +$config1 = getTestcenterConfig('_1'); +$config2 = getTestcenterConfig('_2'); -$connector = new MultiTestcenterConnector([$config1, $config2]); -$result = $connector->getGroupResults('Sample Workspace', 'test_group'); -var_dump($result); +$connector1 = new MultiTestcenterConnector([$config1, $config2]); +$start1 = microtime(true); +$result = $connector1->getGroupResultsAsync('Sample Workspace', 'test_group'); +$end1 = microtime(true); +$duration = number_format($end1 - $start1, 2); +echo("Duration async: $duration\n"); + +$connector2 = new MultiTestcenterConnector([$config1, $config2]); +$start2 = microtime(true); +$result = $connector2->getGroupResults('Sample Workspace', 'test_group'); +$end2 = microtime(true); +$duration = number_format($end2 - $start2, 2); +echo("Duration sync: $duration\n"); diff --git a/e2e/RenameAWorkspaceTest.php b/e2e/RenameAWorkspaceTest.php index cd3d6345dd4edc52183936a154adca29194c33a8..7582b6e1155e56009cff4e9f739590b72c1cae7e 100644 --- a/e2e/RenameAWorkspaceTest.php +++ b/e2e/RenameAWorkspaceTest.php @@ -1,12 +1,13 @@ <?php -use Kompetenztestde\TestcenterConnector\Models\User; use Kompetenztestde\TestcenterConnector\TestcenterConnector; require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/E2eTestHelper.php'; -$connector = new TestcenterConnector(new User('super', 'user123', User::ADMIN_ROLE), 'http://localhost/api'); +$config = getTestcenterConfig(); +$connector = new TestcenterConnector($config->getUser(), $config->getBaseUrl()); $result = $connector->renameWorkspace(3, 'renamed-workspace'); if ($result) { echo 'successful'; -} \ No newline at end of file +} diff --git a/src/Api/TestcenterApiClient.php b/src/Api/TestcenterApiClient.php index 19f16ea58f459b09adc371d43bd2b22cae042349..1c71b1fa4b1be0b7c088ba30d7707935c9e4181b 100644 --- a/src/Api/TestcenterApiClient.php +++ b/src/Api/TestcenterApiClient.php @@ -3,8 +3,10 @@ namespace Kompetenztestde\TestcenterConnector\Api; use GuzzleHttp; +use GuzzleHttp\Client; use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Promise\PromiseInterface; use Kompetenztestde\TestcenterConnector\Api\Schemas\FileDeletionResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\Result; use Kompetenztestde\TestcenterConnector\Api\Schemas\StartSessionResponse; @@ -21,6 +23,7 @@ use Kompetenztestde\TestcenterConnector\Api\Schemas\Workspace; use Kompetenztestde\TestcenterConnector\Api\Schemas\SessionResponse; use Kompetenztestde\TestcenterConnector\Exceptions\ApiException; use Kompetenztestde\TestcenterConnector\Exceptions\TestcenterConnectorException; +use Psr\Http\Message\ResponseInterface; class TestcenterApiClient { @@ -36,7 +39,7 @@ class TestcenterApiClient /** * @param string $baseUrl - * @param GuzzleHttp\Client $httpClient + * @param Client|null $httpClient */ public function __construct(string $baseUrl, GuzzleHttp\Client $httpClient = null) { @@ -59,30 +62,42 @@ class TestcenterApiClient * @throws ApiException */ public function startAdminSession(string $username, string $password): StartSessionResponse + { + return $this->startAdminSessionAsync($username, $password)->wait(); + } + + /** + * Asynchronously start a session as admin by username and password + * + * @param string $username + * @param string $password + * @return PromiseInterface resolves to {@see StartSessionResponse} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function startAdminSessionAsync(string $username, string $password): PromiseInterface { $body = [ 'name' => $username, 'password' => $password ]; - try { - $response = $this->httpClient->put($this->baseUrl . '/session/admin', [ - 'json' => $body - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } + $promise = $this->httpClient->putAsync($this->baseUrl . '/session/admin', [ + 'json' => $body + ]); - // TODO: Testcenter API documentation says status code 202 but in source it says 204 - if ($response->getStatusCode() === 204) { - throw new TestcenterConnectorException('User exists but has no admin privileges.'); - } + return $promise->then(function (ResponseInterface $response) { + // TODO: Testcenter API documentation says status code 202 but in source it says 204 + if ($response->getStatusCode() === 204) { + throw new TestcenterConnectorException('User exists but has no admin privileges.'); + } - $body = $response->getBody()->getContents(); - $data = json_decode($body); + $body = $response->getBody()->getContents(); + $data = json_decode($body); - $sessionResponse = new StartSessionResponse($data); - return $sessionResponse; + return new StartSessionResponse($data); + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -102,6 +117,25 @@ class TestcenterApiClient string $filename, string $content ): FileUploadResponse { + return $this->uploadFileAsync($authToken, $workspaceId, $filename, $content)->wait(); + } + + /** + * Asynchronously uploads a Resource, Unit, Booklet, SysCheck or Testtakers file + * + * @param string $authToken + * @param int $workspaceId + * @param string $filename + * @param string $content + * @return PromiseInterface resolves to {@see FileUploadResponse} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function uploadFileAsync( + string $authToken, + int $workspaceId, + string $filename, + string $content + ): PromiseInterface { $requestOptions = [ 'headers' => [ 'AuthToken' => $authToken @@ -115,28 +149,27 @@ class TestcenterApiClient ] ]; - try { - $response = $this->httpClient->post( - $this->baseUrl . '/workspace/' . $workspaceId . '/file', - $requestOptions - ); - } catch (GuzzleException $e) { - $this->handleException($e); - } - - $body = $response->getBody()->getContents(); - $data = json_decode($body); - - $fileValidationResults = []; - foreach ($data as $filename => $fileResponse) { - $errors = isset($fileResponse->error) ? $fileResponse->error : []; - $warnings = isset($fileResponse->warning) ? $fileResponse->warning : []; - $result = new FileValidationResult($filename, $warnings, $errors); - $fileValidationResults[] = $result; - } + $promise = $this->httpClient->postAsync( + $this->baseUrl . '/workspace/' . $workspaceId . '/file', + $requestOptions + ); + + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); + + $fileValidationResults = []; + foreach ($data as $filename => $fileResponse) { + $errors = $fileResponse->error ?? []; + $warnings = $fileResponse->warning ?? []; + $result = new FileValidationResult($filename, $warnings, $errors); + $fileValidationResults[] = $result; + } - $fileResponse = new FileUploadResponse($fileValidationResults); - return $fileResponse; + return new FileUploadResponse($fileValidationResults); + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -151,23 +184,40 @@ class TestcenterApiClient */ public function deleteFiles(string $authToken, int $workspaceId, array $filenames): FileDeletionResponse { - try { - $response = $this->httpClient->delete("{$this->baseUrl}/workspace/$workspaceId/files", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => [ - 'f' => $filenames - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } + return $this->deleteFilesAsync($authToken, $workspaceId, $filenames)->wait(); + } + + /** + * Asynchronously delete one or more files in a workspace + * + * @param string $authToken + * @param int $workspaceId + * @param array $filenames + * @return PromiseInterface resolves to {@see FileDeletionResponses} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function deleteFilesAsync( + string $authToken, + int $workspaceId, + array $filenames + ): PromiseInterface { + $promise = $this->httpClient->deleteAsync("{$this->baseUrl}/workspace/$workspaceId/files", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => [ + 'f' => $filenames + ] + ]); - $body = $response->getBody()->getContents(); - $data = json_decode($body); + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - return new FileDeletionResponse($data); + return new FileDeletionResponse($data); + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -179,31 +229,44 @@ class TestcenterApiClient * @throws ApiException * @throws TestcenterConnectorException */ - public function addAWorkspace(string $authToken, string $name) + public function addAWorkspace(string $authToken, string $name): ?int + { + return $this->addAWorkspaceAsync($authToken, $name)->wait(); + } + + /** + * Asynchronously add a new workspace to the testcenter + * + * @param string $authToken + * @param string $name + * @return PromiseInterface resolves to workspace id (int) or null or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function addAWorkspaceAsync(string $authToken, string $name): PromiseInterface { $body = [ 'name' => $name ]; - try { - $response = $this->httpClient->put($this->baseUrl . '/workspace', [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => $body - ]); - } catch (GuzzleException $e) { + $promise = $this->httpClient->putAsync($this->baseUrl . '/workspace', [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => $body + ]); + + return $promise->then(function (ResponseInterface $response) { + // check if workspace id is returned (version 15.1.7+) + $body = $response->getBody()->getContents(); + $workspaceId = filter_var($body, FILTER_VALIDATE_INT); + + if ($workspaceId !== false) { + return $workspaceId; + } else { + return null; + } + }, function (GuzzleException $e) { $this->handleException($e); - } - - // check if workspace id is returned (version 15.1.7+) - $body = $response->getBody()->getContents(); - $workspaceId = filter_var($body, FILTER_VALIDATE_INT); - - if ($workspaceId !== false) { - return $workspaceId; - } else { - return null; - } + }); } /** @@ -216,26 +279,38 @@ class TestcenterApiClient */ public function getAListOfWorkspaces(string $authToken): array { - try { - $response = $this->httpClient->get($this->baseUrl . '/workspaces', [ - 'headers' => [ - 'AuthToken' => $authToken - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } + return $this->getAListOfWorkspacesAsync($authToken)->wait(); + } - $body = $response->getBody()->getContents(); - $data = json_decode($body); + /** + * Asynchronously get an array of all workspaces in the testcenter + * + * @param string $authToken super admin authentication token + * @return PromiseInterface resolves to array of {@see Workspace} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function getAListOfWorkspacesAsync(string $authToken): PromiseInterface + { + $promise = $this->httpClient->getAsync($this->baseUrl . '/workspaces', [ + 'headers' => [ + 'AuthToken' => $authToken + ] + ]); - $workspaces = []; + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - foreach ($data as $workspaceData) { - $workspaces[] = new Workspace($workspaceData); - } + $workspaces = []; + + foreach ($data as $workspaceData) { + $workspaces[] = new Workspace($workspaceData); + } - return $workspaces; + return $workspaces; + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -249,37 +324,49 @@ class TestcenterApiClient */ public function getAListOfUserWorkspaces(string $authToken, int $userId): array { - try { - $response = $this->httpClient->get("{$this->baseUrl}/user/$userId/workspaces", [ - 'headers' => [ - 'AuthToken' => $authToken - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } + return $this->getAListOfUserWorkspacesAsync($authToken, $userId)->wait(); + } - $body = $response->getBody()->getContents(); - $data = json_decode($body); + /** + * Asynchronously get a list of workspaces a user has access to + * + * @param string $authToken + * @param int $userId + * @return PromiseInterface resolves to array of {@see UserWorkspace} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function getAListOfUserWorkspacesAsync(string $authToken, int $userId): PromiseInterface + { + $promise = $this->httpClient->getAsync("{$this->baseUrl}/user/$userId/workspaces", [ + 'headers' => [ + 'AuthToken' => $authToken + ] + ]); + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - if ($data === null) { - throw new TestcenterConnectorException('Invalid json response'); - } + if ($data === null) { + throw new TestcenterConnectorException('Invalid json response'); + } - if (!is_array($data)) { - throw new TestcenterConnectorException('Expected response to be an array'); - } + if (!is_array($data)) { + throw new TestcenterConnectorException('Expected response to be an array'); + } - $workspaces = []; + $workspaces = []; - foreach ($data as $workspaceData) { - if (!is_object($workspaceData)) { - throw new TestcenterConnectorException('Expected workspace data to be an object'); + foreach ($data as $workspaceData) { + if (!is_object($workspaceData)) { + throw new TestcenterConnectorException('Expected workspace data to be an object'); + } + $workspaces[] = new UserWorkspace($workspaceData); } - $workspaces[] = new UserWorkspace($workspaceData); - } - return $workspaces; + return $workspaces; + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -294,22 +381,39 @@ class TestcenterApiClient */ public function changeUserRoles(string $authToken, int $workspaceId, array $userRoles): bool { + return $this->changeUserRolesAsync($authToken, $workspaceId, $userRoles)->wait(); + } + + /** + * Asynchronously set roles of one or multiple users in a workspace + * + * @param string $authToken + * @param int $workspaceId + * @param array $userRoles + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function changeUserRolesAsync( + string $authToken, + int $workspaceId, + array $userRoles + ): PromiseInterface { $body = [ 'u' => $userRoles ]; - try { - $this->httpClient->patch($this->baseUrl . '/workspace/' . $workspaceId . '/users', [ - 'json' => $body, - 'headers' => [ - 'AuthToken' => $authToken - ] - ]); + $promise = $this->httpClient->patchAsync($this->baseUrl . '/workspace/' . $workspaceId . '/users', [ + 'json' => $body, + 'headers' => [ + 'AuthToken' => $authToken + ] + ]); + return $promise->then(function (ResponseInterface $response) { return true; - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } /** @@ -322,20 +426,31 @@ class TestcenterApiClient */ public function getASession(string $authToken): SessionResponse { - try { - $response = $this->httpClient->get($this->baseUrl . '/session', [ - 'headers' => [ - 'AuthToken' => $authToken - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } + return $this->getASessionAsync($authToken)->wait(); + } - $body = $response->getBody()->getContents(); - $data = json_decode($body); + /** + * Asynchronously returns session data according to an authToken + * + * @param string $authToken + * @return PromiseInterface resolves to {@see SessionResponse} or rejects with {@see TestcenterConnectorException} + * or {@see ApiException} + */ + public function getASessionAsync(string $authToken): PromiseInterface + { + $promise = $this->httpClient->getAsync($this->baseUrl . '/session', [ + 'headers' => [ + 'AuthToken' => $authToken + ] + ]); + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - return new SessionResponse($data); + return new SessionResponse($data); + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -350,33 +465,49 @@ class TestcenterApiClient */ public function getReportOfItemResponses(string $authToken, int $workspaceId, array $dataIds): array { - $dataIds = implode(',', $dataIds); - try { - $response = $this->httpClient->get($this->baseUrl . '/workspace/' . $workspaceId . '/report/response', [ - 'headers' => [ - 'AuthToken' => $authToken, - 'Accept' => 'application/json' - ], - 'query' => [ - 'dataIds' => $dataIds - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } - - $body = $response->getBody()->getContents(); - $data = json_decode($body); + return $this->getReportOfItemResponsesAsync($authToken, $workspaceId, $dataIds)->wait(); + } - if ($data !== null) { - $responses = array_map(function ($responsesData) { - return new UnitResponse($responsesData); - }, $data); - } else { - $responses = []; - } + /** + * Asynchronously get responses from a workspace for a list of test groups + * + * @param string $authToken + * @param int $workspaceId + * @param string[] $dataIds + * @return PromiseInterface resolves to array of {@see UnitResponse} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function getReportOfItemResponsesAsync( + string $authToken, + int $workspaceId, + array $dataIds + ): PromiseInterface { + $dataIds = implode(',', $dataIds); + $promise = $this->httpClient->getAsync($this->baseUrl . '/workspace/' . $workspaceId . '/report/response', [ + 'headers' => [ + 'AuthToken' => $authToken, + 'Accept' => 'application/json' + ], + 'query' => [ + 'dataIds' => $dataIds + ] + ]); + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); + + if ($data !== null) { + $responses = array_map(function ($responsesData) { + return new UnitResponse($responsesData); + }, $data); + } else { + $responses = []; + } - return $responses; + return $responses; + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -391,34 +522,49 @@ class TestcenterApiClient */ public function getReportOfLogs(string $authToken, int $workspaceId, array $dataIds): array { - try { - $response = $this->httpClient->get($this->baseUrl . '/workspace/' . $workspaceId . '/report/log', [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'query' => [ - 'dataIds' => implode(',', $dataIds) - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } - - $logEntries = []; - - $body = $response->getBody()->getContents(); - $data = json_decode($body); + return $this->getReportOfLogsAsync($authToken, $workspaceId, $dataIds)->wait(); + } - // testcenter returns an empty body if there are no log entries instead of an empty array - if ($data === null) { - $logEntries = []; - } else { - $logEntries = array_map(function ($entryData) { - return new LogEntry($entryData); - }, $data); - } + /** + * Asynchronously get logs for login groups in a given workspace + * + * @param string $authToken + * @param int $workspaceId + * @param string[] $dataIds + * @return PromiseInterface resolves to array of {@see LogEntry} or rejects with {@see TestcenterConnectorException} + * or {@see ApiException} + */ + public function getReportOfLogsAsync( + string $authToken, + int $workspaceId, + array $dataIds + ): PromiseInterface { + $promise = $this->httpClient->getAsync($this->baseUrl . '/workspace/' . $workspaceId . '/report/log', [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'query' => [ + 'dataIds' => implode(',', $dataIds) + ] + ]); + + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); + + // testcenter returns an empty body if there are no log entries instead of an empty array + if ($data === null) { + $logEntries = []; + } else { + $logEntries = array_map(function ($entryData) { + return new LogEntry($entryData); + }, $data); + } - return $logEntries; + return $logEntries; + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -433,24 +579,40 @@ class TestcenterApiClient */ public function addAUser(string $authToken, string $username, string $password): bool { + return $this->addAUserAsync($authToken, $username, $password)->wait(); + } + + /** + * Asynchronously add a new user + * + * @param string $authToken + * @param string $username + * @param string $password + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function addAUserAsync( + string $authToken, + string $username, + string $password + ): PromiseInterface { $body = [ 'n' => $username, 'p' => $password ]; - try { - //Sending a PUT request without saving the return value - $response = $this->httpClient->put("{$this->baseUrl}/user", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => $body - ]); + $promise = $this->httpClient->putAsync("{$this->baseUrl}/user", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => $body + ]); + return $promise->then(function (ResponseInterface $response) { return true; - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } /** @@ -463,42 +625,54 @@ class TestcenterApiClient */ public function getAListOfUsers(string $authToken): array { - try { - $response = $this->httpClient->get("{$this->baseUrl}/users", [ - 'headers' => [ - 'AuthToken' => $authToken - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } - - $body = $response->getBody()->getContents(); - $data = json_decode($body); + return $this->getAListOfUsersAsync($authToken)->wait(); + } - if ($data === null) { - throw new TestcenterConnectorException('Invalid json response'); - } + /** + * Asynchronously get a list of all registered users + * + * @param string $authToken + * @return PromiseInterface resolves to array of {@see User} or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function getAListOfUsersAsync(string $authToken): PromiseInterface + { + $promise = $this->httpClient->getAsync("{$this->baseUrl}/users", [ + 'headers' => [ + 'AuthToken' => $authToken + ] + ]); - if (!is_array($data)) { - throw new TestcenterConnectorException('Expected array response'); - } + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - $users = []; + if ($data === null) { + throw new TestcenterConnectorException('Invalid json response'); + } - foreach ($data as $userData) { - if (!is_object($userData)) { - throw new TestcenterConnectorException('Expected object user data'); + if (!is_array($data)) { + throw new TestcenterConnectorException('Expected array response'); } - $users[] = new User($userData); - } + $users = []; + + foreach ($data as $userData) { + if (!is_object($userData)) { + throw new TestcenterConnectorException('Expected object user data'); + } - return $users; + $users[] = new User($userData); + } + + return $users; + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** - * Change the password of an user + * Change the password of a user * * @param string $authToken * @param int $userId @@ -509,20 +683,34 @@ class TestcenterApiClient */ public function changeUserPassword(string $authToken, int $userId, string $newPassword): bool { - try { - $this->httpClient->patch("{$this->baseUrl}/user/$userId/password", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => [ - 'p' => $newPassword - ] - ]); + return $this->changeUserPasswordAsync($authToken, $userId, $newPassword)->wait(); + } + /** + * Asynchronously change the password of a user + * + * @param string $authToken + * @param int $userId + * @param string $newPassword + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function changeUserPasswordAsync(string $authToken, int $userId, string $newPassword): PromiseInterface + { + $promise = $this->httpClient->patchAsync("{$this->baseUrl}/user/$userId/password", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => [ + 'p' => $newPassword + ] + ]); + + return $promise->then(function (ResponseInterface $response) { return true; - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } /** @@ -538,20 +726,40 @@ class TestcenterApiClient */ public function changeSuperAdminStatus(string $authToken, int $userId, bool $newStatus, string $password): bool { - try { - $newStatus = $newStatus ? 'on' : 'off'; - $response = $this->httpClient->patch("{$this->baseUrl}/user/$userId/super-admin/$newStatus", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => [ - 'p' => $password - ] - ]); + return $this->changeSuperAdminStatusAsync($authToken, $userId, $newStatus, $password)->wait(); + } + + /** + * Asynchronously change the super admin status of a user + * + * @param string $authToken + * @param int $userId + * @param bool $newStatus + * @param string $password + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function changeSuperAdminStatusAsync( + string $authToken, + int $userId, + bool $newStatus, + string $password + ): PromiseInterface { + $newStatus = $newStatus ? 'on' : 'off'; + $promise = $this->httpClient->patchAsync("{$this->baseUrl}/user/$userId/super-admin/$newStatus", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => [ + 'p' => $password + ] + ]); + + return $promise->then(function (ResponseInterface $response) { return true; - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } /** @@ -565,21 +773,32 @@ class TestcenterApiClient */ public function deleteSomeUsers(string $authToken, array $userIds): bool { - try { - //Sending a DELETE request without saving the return value - $this->httpClient->delete("{$this->baseUrl}/users", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => [ - 'u' => $userIds - ] - ]); + return $this->deleteSomeUsersAsync($authToken, $userIds)->wait(); + } + + /** + * Asynchronously delete one or more users + * @param string $authToken + * @param array $userIds + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function deleteSomeUsersAsync(string $authToken, array $userIds): PromiseInterface + { + $promise = $this->httpClient->deleteAsync("{$this->baseUrl}/users", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => [ + 'u' => $userIds + ] + ]); + return $promise->then(function (ResponseInterface $response) { return true; - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } /** @@ -592,25 +811,39 @@ class TestcenterApiClient * @throws TestcenterConnectorException */ public function deleteSomeWorkspaces(string $authToken, array $workspaceIds): bool + { + return $this->deleteSomeWorkspacesAsync($authToken, $workspaceIds)->wait(); + } + + /** + * Asynchronously delete one or many workspaces + * + * @param string $authToken + * @param array $workspaceIds + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function deleteSomeWorkspacesAsync(string $authToken, array $workspaceIds): PromiseInterface { $requestBody = [ 'ws' => $workspaceIds ]; - try { - $response = $this->httpClient->delete("{$this->baseUrl}/workspaces", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => $requestBody - ]); + $promise = $this->httpClient->deleteAsync("{$this->baseUrl}/workspaces", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => $requestBody + ]); + return $promise->then(function (ResponseInterface $response) { return ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300); - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } + /** * Rename a workspace * @@ -622,24 +855,37 @@ class TestcenterApiClient * @throws TestcenterConnectorException */ public function renameAWorkspace(string $authToken, int $workspaceId, string $name): bool + { + return $this->renameAWorkspaceAsync($authToken, $workspaceId, $name)->wait(); + } + + /** + * Asynchronously rename a workspace + * + * @param string $authToken + * @param int $workspaceId + * @param string $name + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function renameAWorkspaceAsync(string $authToken, int $workspaceId, string $name): PromiseInterface { $body = [ 'name' => $name ]; - try { - //Sending a PATCH request without saving the return value - $this->httpClient->patch("{$this->baseUrl}/workspace/$workspaceId", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => $body - ]); + $promise = $this->httpClient->patchAsync("{$this->baseUrl}/workspace/$workspaceId", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => $body + ]); + return $promise->then(function (ResponseInterface $response) { return true; - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } /** @@ -653,25 +899,38 @@ class TestcenterApiClient */ public function getResults(string $authToken, int $workspaceId): array { - try { - $response = $this->httpClient->get("{$this->baseUrl}/workspace/$workspaceId/results", [ - 'headers' => [ - 'AuthToken' => $authToken - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } + return $this->getResultsAsync($authToken, $workspaceId)->wait(); + } - $body = $response->getBody()->getContents(); - $data = json_decode($body); + /** + * Asynchronously get statistical results from a workspace + * + * @param string $authToken + * @param int $workspaceId + * @return PromiseInterface resolves to array of {@see Result} or rejects with {@see TestcenterConnectorException} + * or {@see ApiException} + */ + public function getResultsAsync(string $authToken, int $workspaceId): PromiseInterface + { + $promise = $this->httpClient->getAsync("{$this->baseUrl}/workspace/$workspaceId/results", [ + 'headers' => [ + 'AuthToken' => $authToken + ] + ]); - $results = []; - foreach ($data as $resultData) { - $results[] = new Result($resultData); - } + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - return $results; + $results = []; + foreach ($data as $resultData) { + $results[] = new Result($resultData); + } + + return $results; + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -686,28 +945,39 @@ class TestcenterApiClient */ public function getReportOfSystemChecks(string $authToken, int $workspaceId, array $dataIds): array { - try { - $response = $this->httpClient->get("{$this->baseUrl}/workspace/$workspaceId/report/sys-check", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'query' => [ - 'dataIds' => implode(',', $dataIds) - ] - ]); - } catch (GuzzleException $e) { - $this->handleException($e); - } - - $body = $response->getBody()->getContents(); - $data = json_decode($body); + return $this->getReportOfSystemChecksAsync($authToken, $workspaceId, $dataIds)->wait(); + } + /** + * Asynchronously returns a System Check report + * + * @param string $authToken + * @param int $workspaceId + * @param string[] $dataIds + * @return PromiseInterface resolves to array of {@see SysCheckReport} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function getReportOfSystemChecksAsync(string $authToken, int $workspaceId, array $dataIds): PromiseInterface + { + $promise = $this->httpClient->getAsync("{$this->baseUrl}/workspace/$workspaceId/report/sys-check", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'query' => [ + 'dataIds' => implode(',', $dataIds) + ] + ]); - $reports = array_map(function ($reportData) { - return new SysCheckReport($reportData); - }, $data); + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - return $reports; + return array_map(function ($reportData) { + return new SysCheckReport($reportData); + }, $data); + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -718,20 +988,30 @@ class TestcenterApiClient * @throws ApiException * @throws TestcenterConnectorException */ - public function getSystemConfig() + public function getSystemConfig(): SystemConfigResponse { - try { - $response = $this->httpClient->get("{$this->baseUrl}/system/config"); - } catch (GuzzleException $e) { - $this->handleException($e); - } + return $this->getSystemConfigAsync()->wait(); + } - $body = $response->getBody()->getContents(); - $data = json_decode($body); + /** + * Asynchronously returns publicly available parts of system config: + * version number, customTexts for UI, broadcastingService infos, serverTimestamp + * + * @return PromiseInterface resolves to {@see SystemConfigResponse} or rejects with + * {@see TestcenterConnectorException} or {@see ApiException} + */ + public function getSystemConfigAsync(): PromiseInterface + { + $promise = $this->httpClient->getAsync("{$this->baseUrl}/system/config"); - $config = new SystemConfigResponse($data); + return $promise->then(function (ResponseInterface $response) { + $body = $response->getBody()->getContents(); + $data = json_decode($body); - return $config; + return new SystemConfigResponse($data); + }, function (GuzzleException $e) { + $this->handleException($e); + }); } /** @@ -746,21 +1026,34 @@ class TestcenterApiClient */ public function deleteData(string $authToken, int $workspaceId, array $groups): bool { - try { - //Sending a DELETE request without saving the return value - $this->httpClient->delete("{$this->baseUrl}/workspace/$workspaceId/responses", [ - 'headers' => [ - 'AuthToken' => $authToken - ], - 'json' => [ - 'groups' => $groups - ] - ]); + return $this->deleteDataAsync($authToken, $workspaceId, $groups)->wait(); + } + + /** + * Asynchronously delete responses from a workspace + * + * @param string $authToken + * @param int $workspaceId + * @param string[] $groups + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} or + * {@see ApiException} + */ + public function deleteDataAsync(string $authToken, int $workspaceId, array $groups): PromiseInterface + { + $promise = $this->httpClient->deleteAsync("{$this->baseUrl}/workspace/$workspaceId/responses", [ + 'headers' => [ + 'AuthToken' => $authToken + ], + 'json' => [ + 'groups' => $groups + ] + ]); + return $promise->then(function (ResponseInterface $response) { return true; - } catch (GuzzleException $e) { + }, function (GuzzleException $e) { $this->handleException($e); - } + }); } /** diff --git a/src/MultiTestcenterConnector.php b/src/MultiTestcenterConnector.php index 34ef1241da72fcc85fe24f675520652db8497a1a..77cb0f43521a9ab621643bee03a29529ac52e42f 100644 --- a/src/MultiTestcenterConnector.php +++ b/src/MultiTestcenterConnector.php @@ -3,10 +3,59 @@ namespace Kompetenztestde\TestcenterConnector; use Exception; +use Kompetenztestde\TestcenterConnector\Api\Schemas\FileDeletionResponse; +use Kompetenztestde\TestcenterConnector\Api\Schemas\FileUploadResponse; +use Kompetenztestde\TestcenterConnector\Api\Schemas\UserRole; +use Kompetenztestde\TestcenterConnector\Models\File; +use Kompetenztestde\TestcenterConnector\Models\TestGroup; +use Kompetenztestde\TestcenterConnector\Models\TestInterface; +use Kompetenztestde\TestcenterConnector\Models\Workspace; +use Kompetenztestde\TestcenterConnector\Xml\XmlGenerator; +use Throwable; +use GuzzleHttp\Client; +use GuzzleHttp\Promise\Utils; use LogicException; use BadMethodCallException; use Kompetenztestde\TestcenterConnector\Exceptions\TestcenterConnectorException; +// phpcs:disable +/** + * Wrapper class for {@see TestcenterConnector} to communicate with multiple testcenter instances in parallel + * + * Async methods are called in parallel other methods have to get called one after another. When working with multiple + * testcenter instances the use of async methods is recommended for improved performance. + * + * On success the methods return an associative array of the return values of each instance with the instance base url + * as keys. If any call fails a {@see TestcenterConnectorException} is thrown + * + * @method FileUploadResponse[] addTestGroup(int|string $workspace, TestGroup $group, string $bookletId, XmlGenerator $xmlGenerator = null) + * @method FileUploadResponse[] addTestGroupAsync(int|string $workspace, TestGroup $group, string $bookletId, XmlGenerator $xmlGenerator = null) + * @method int[] addWorkspace(string $name, ?bool $setRole = false) + * @method int[] addWorkspaceAsync(string $name, ?bool $setRole = false) + * @method Workspace[] getWorkspaces() + * @method Workspace[] getWorkspacesAsync() + * @method bool[] deleteWorkspace(int|string[] $workspaces) + * @method bool[] deleteWorkspaceAsync(int|string[] $workspaces) + * @method FileUploadResponse[] addTest(int|string $workspace, TestInterface $test) + * @method array getGroupResults(int|string $workspace, string $groupId) + * @method array getGroupResultsAsync(int|string $workspace, string $groupId) + * @method bool[] deleteUsers(int|string[] $users) + * @method bool[] addUser(string $username, string $password) + * @method int[] addSuperAdmin(string $username, string $password) + * @method array getUsers() + * @method bool[] renameWorkspace(int|string $workspace, string $name) + * @method bool[] deleteData(int|string $workspace, string[] $groups) + * @method array getSystemCheckReport(int|string $workspace, string[] $dataIds) + * @method array getResults(int|string $workspace) + * @method array getResultsAsync(int|string $workspace) + * @method array getWorkspacesByUser(int|string $user) + * @method bool[] changeUserRoles(int|string $workspace, UserRole[] $userRoles) + * @method array getLogs(int|string $workspace, string[] $groupIds) + * @method array getLogsAsync(int|string $workspace, string[] $groupIds) + * @method FileDeletionResponse[] deleteFiles(int|string $workspace, File[] $files) + * @method bool[] changeUserPassword(int|string $user, string $newPassword) + */ +// phpcs:enable class MultiTestcenterConnector { /** @@ -20,11 +69,17 @@ class MultiTestcenterConnector */ public function __construct(?array $instanceConfigs, array $testcenterConnectors = null) { + $guzzleClient = new Client(); if ($instanceConfigs !== null) { foreach ($instanceConfigs as $config) { $this->connectors[] = new TestcenterConnector( $config->getUser(), - $config->getBaseUrl() + $config->getBaseUrl(), + null, + null, + null, + null, + $guzzleClient ); } } elseif ($testcenterConnectors !== null) { @@ -41,20 +96,38 @@ class MultiTestcenterConnector { $results = []; $errors = []; - foreach ($this->connectors as $connector) { - if (method_exists($connector, $method)) { - try { - $results[$connector->getBaseUrl()] = call_user_func_array([$connector, $method], $args); - } catch (Exception $e) { - $errors[$connector->getBaseUrl()] = "Error: " . $e->getMessage(); + + if (preg_match('/.*Async$/', $method)) { + $promises = []; + + foreach ($this->connectors as $connector) { + if (method_exists($connector, $method)) { + $promises[$connector->getBaseUrl()] = call_user_func_array([$connector, $method], $args); + } else { + throw new BadMethodCallException("Method $method does not exist in TestcenterConnector."); + } + } + try { + $results = Utils::unwrap($promises); + } catch (Throwable $e) { + throw new TestcenterConnectorException("Errors occurred: " . print_r($e, true)); + } + } else { + foreach ($this->connectors as $connector) { + if (method_exists($connector, $method)) { + try { + $results[$connector->getBaseUrl()] = call_user_func_array([$connector, $method], $args); + } catch (Exception $e) { + $errors[$connector->getBaseUrl()] = "Error: " . $e->getMessage(); + } + } else { + throw new BadMethodCallException("Method $method does not exist in TestcenterConnector."); } - } else { - throw new BadMethodCallException("Method $method does not exist in TestcenterConnector."); } - } - if (!empty($errors)) { - throw new TestcenterConnectorException("Errors occurred: " . print_r($errors, true)); + if (!empty($errors)) { + throw new TestcenterConnectorException("Errors occurred: " . print_r($errors, true)); + } } return $results; diff --git a/src/TestcenterConnector.php b/src/TestcenterConnector.php index 8669cc7fd809bc08225762f897e302913000ebb4..246f7bc5607f5834914548c1df6a0119fad6b328 100644 --- a/src/TestcenterConnector.php +++ b/src/TestcenterConnector.php @@ -3,11 +3,20 @@ namespace Kompetenztestde\TestcenterConnector; use Exception; +use GuzzleHttp\Client; +use GuzzleHttp\Promise\FulfilledPromise; +use GuzzleHttp\Promise\PromiseInterface; +use GuzzleHttp\Promise\Promise; +use GuzzleHttp\Promise\RejectedPromise; use Kompetenztestde\TestcenterConnector\Api\Schemas\Result; +use Kompetenztestde\TestcenterConnector\Api\Schemas\SessionResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\SysCheckReport; +use Kompetenztestde\TestcenterConnector\Api\Schemas\SystemConfigResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\UnitResponse; use Kompetenztestde\TestcenterConnector\Models\TestGroup; +use Kompetenztestde\TestcenterConnector\Models\Workspace; use LogicException; +use Throwable; use ZipArchive; use Kompetenztestde\TestcenterConnector\Api\Schemas\FileDeletionResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\FileUploadResponse; @@ -63,14 +72,15 @@ class TestcenterConnector TestcenterApiClient $apiClient = null, string $authToken = null, string $authenticatedUsername = null, - callable $authTokenChangedCallback = null + callable $authTokenChangedCallback = null, + Client $guzzleClient = null ) { if ($apiClient === null && $baseUrl === null) { throw new LogicException('Either apiClient or baseUrl arguments are needed.'); } if ($apiClient === null) { - $this->apiClient = new TestcenterApiClient($baseUrl); + $this->apiClient = new TestcenterApiClient($baseUrl, $guzzleClient); } else { $this->apiClient = $apiClient; } @@ -96,31 +106,68 @@ class TestcenterConnector Models\TestGroup $group, string $bookletId, XmlGenerator $xmlGenerator = null - ) { + ): FileUploadResponse { + return $this->addTestGroupAsync($workspace, $group, $bookletId, $xmlGenerator)->wait(); + } + + /** + * Asynchronously create a new group of testtakers and monitor logins for a booklet + * + * @param int|string $workspace ID or name of the workspace to create the group in + * @param TestGroup $group group to create + * @param string $bookletId ID of the booklet the group should be assigned to + * @param XmlGenerator|null $xmlGenerator optional xml generator instance (for testing purposes) + * @return PromiseInterface resolves to {@see FileUploadResponse} or rejects with + * {@see TestcenterConnectorException} + */ + public function addTestGroupAsync( + $workspace, + Models\TestGroup $group, + string $bookletId, + XmlGenerator $xmlGenerator = null + ): PromiseInterface { + $generatedTesttakers = null; + if ($xmlGenerator === null) { $xmlGenerator = new XmlGenerator(); } - try { - $config = $this->apiClient->getSystemConfig(); - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } - $version = isset($config) ? $config->getVersion() : '15.1.4'; - - // generate testtakers xml - $xmlGroup = $this->getXmlTestGroup($group, $bookletId); - $testtakers = $xmlGenerator->generateTesttakersXml($xmlGroup, $version); - - // upload testtakers xml - try { - $this->setAuthToken(); - $workspaceId = $this->getWorkspaceId($workspace); - $filename = 'testtakers-' . $group->getId() . '.xml'; - return $this->apiClient->uploadFile($this->authToken, $workspaceId, $filename, $testtakers); - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } + return $this->apiClient->getSystemConfigAsync() + ->then( + function ( + SystemConfigResponse $config + ) use ( + $group, + $bookletId, + $xmlGenerator, + $workspace, + &$generatedTesttakers + ) { + $version = $config->getVersion() ?? '15.1.4'; + + // generate testtakers xml + $xmlGroup = $this->getXmlTestGroup($group, $bookletId); + $generatedTesttakers = $xmlGenerator->generateTesttakersXml($xmlGroup, $version); + + // upload testtakers xml + return $this->setAuthTokenAsync(); + } + ) + ->then(function () use ($workspace, $group, &$generatedTesttakers) { + $workspaceId = $this->getWorkspaceId($workspace); + $filename = 'testtakers-' . $group->getId() . '.xml'; + return $this->apiClient->uploadFileAsync( + $this->authToken, + $workspaceId, + $filename, + $generatedTesttakers + ); + }) + ->then(function (FileUploadResponse $response) { + return $response; + }, function ($e) { + $this->handleAsyncError($e); + }); } /** @@ -133,32 +180,57 @@ class TestcenterConnector */ public function addWorkspace(string $name, bool $setRole = false): int { - try { - $this->setAuthToken(); - - $workspaceId = $this->apiClient->addAWorkspace($this->authToken, $name); - - if ($workspaceId === null) { - $workspaceId = $this->getWorkspaceId($name); - } - - if ($setRole) { - $userId = $this->getUserId($this->user->getUsername()); - $success = $this->apiClient->changeUserRoles( - $this->authToken, - $workspaceId, - [new UserRole($userId, UserRole::RW)] - ); + return $this->addWorkspaceAsync($name, $setRole)->wait(); + } + /** + * Asynchronously create a new workspace + * + * @param string $name Name of the new workspace (must be unique) + * @param bool $setRole set RW role for the current user for the new workspace (default: false) + * @return PromiseInterface resolves to workspace id (int) or rejects with {@see TestcenterConnectorException} + */ + public function addWorkspaceAsync(string $name, bool $setRole = false): PromiseInterface + { + $createdWorkspaceId = null; + return $this->setAuthTokenAsync() + ->then(function () use ($name) { + return $this->apiClient->addAWorkspaceAsync($this->authToken, $name); + }) + ->then(function ($workspaceId) use ($name) { + if ($workspaceId === null) { + return $this->getWorkspaceIdAsync($name); + } + return $workspaceId; + }) + ->then(function ($workspaceId) use ($setRole, &$createdWorkspaceId) { + $createdWorkspaceId = $workspaceId; + if ($setRole) { + return $this->getUserIdAsync($this->user->getUsername()); + } + return true; + }) + ->then(function ($userId) use (&$createdWorkspaceId, $setRole) { + if ($setRole) { + return $this->apiClient->changeUserRolesAsync( + $this->authToken, + $createdWorkspaceId, + [new UserRole($userId, UserRole::RW)] + ); + } + return true; + }) + ->then(function ($success) use (&$createdWorkspaceId) { if (!$success) { - throw new TestcenterConnectorException('Failed to set RW role for new workspace for current user.'); + throw new TestcenterConnectorException( + 'Failed to set RW role for new workspace for current user.' + ); } - } - return $workspaceId; - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } + return $createdWorkspaceId; + }, function ($e) { + $this->handleAsyncError($e); + }); } /** @@ -169,17 +241,28 @@ class TestcenterConnector */ public function getWorkspaces(): array { - try { - $this->setAuthToken(); - - $workspaces = $this->apiClient->getAListOfWorkspaces($this->authToken); - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } + return $this->getWorkspacesAsync()->wait(); + } - return array_map(function ($workspace) { - return new Models\Workspace($workspace->getId(), $workspace->getName()); - }, $workspaces); + /** + * Asynchronously get a list of all workspaces + * + * @return PromiseInterface resolves to array of {@see Workspace} on success or rejects with + * {@see TestcenterConnectorException} + */ + public function getWorkspacesAsync(): PromiseInterface + { + return $this->setAuthTokenAsync() + ->then(function () { + return $this->apiClient->getAListOfWorkspacesAsync($this->authToken); + }) + ->then(function ($workspaces) { + return array_map(function ($workspace) { + return new Models\Workspace($workspace->getId(), $workspace->getName()); + }, $workspaces); + }, function ($e) { + $this->handleAsyncError($e); + }); } /** @@ -191,13 +274,29 @@ class TestcenterConnector */ public function deleteWorkspace(array $workspaces): bool { - try { - $this->setAuthToken(); - $workspaceIds = $this->getWorkspaceIds($workspaces); - return $this->apiClient->deleteSomeWorkspaces($this->authToken, $workspaceIds); - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } + return $this->deleteWorkspaceAsync($workspaces)->wait(); + } + + /** + * Asynchronously delete workspaces + * + * @param int|string[] $workspaces array of workspace ids or names to delete + * @return PromiseInterface resolves to true on success or rejects with {@see TestcenterConnectorException} + */ + public function deleteWorkspaceAsync(array $workspaces): PromiseInterface + { + return $this->setAuthTokenAsync() + ->then(function () use ($workspaces) { + return $this->getWorkspaceIdsAsync($workspaces); + }) + ->then(function ($workspaceIds) { + return $this->apiClient->deleteSomeWorkspacesAsync($this->authToken, $workspaceIds); + }) + ->then(function ($success) { + return $success; + }, function ($e) { + $this->handleAsyncError($e); + }); } /** @@ -264,13 +363,31 @@ class TestcenterConnector */ public function getGroupResults($workspace, string $groupId): array { - try { - $this->setAuthToken(); - $workspaceId = $this->getWorkspaceId($workspace); - return $this->apiClient->getReportOfItemResponses($this->authToken, $workspaceId, [$groupId]); - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } + return $this->getGroupResultsAsync($workspace, $groupId)->wait(); + } + + /** + * Asynchronously get results of a single group + * + * @param int|string $workspace id or name of the workspace to get results from + * @param string $groupId id of the test group to get results from + * @return PromiseInterface resolves to array of {@see UnitResponse} on success or rejects with + * {@see TestcenterConnectorException} + */ + public function getGroupResultsAsync($workspace, string $groupId): PromiseInterface + { + return $this->setAuthTokenAsync() + ->then(function () use ($workspace) { + return $this->getWorkspaceIdAsync($workspace); + }) + ->then(function ($workspaceId) use ($groupId) { + return $this->apiClient->getReportOfItemResponsesAsync($this->authToken, $workspaceId, [$groupId]); + }) + ->then(function ($responses) { + return $responses; + }, function ($e) { + $this->handleAsyncError($e); + }); } private function getXmlTestGroup(Models\TestGroup $group, string $bookletId): Xml\TestGroup @@ -312,7 +429,7 @@ class TestcenterConnector } } - /** + /** * Adds an user * * @param string $username name of the new user @@ -468,7 +585,7 @@ class TestcenterConnector } /** - * Retrieves a list of unit- and booklet results for a given workspace and groups + * Retrieves a list of unit- and booklet results for a given workspace * * @param int|string $workspace id or name of the workspace * @return Result[] @@ -476,14 +593,29 @@ class TestcenterConnector */ public function getResults($workspace): array { - try { - $this->setAuthToken(); - $workspaceId = $this->getWorkspaceId($workspace); - $reports = $this->apiClient->getResults($this->authToken, $workspaceId); - return $reports; - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } + return $this->getResultsAsync($workspace)->wait(); + } + + /** + * Asynchronously retrieves a list of unit- and booklet results for a given workspace + * + * @param int|string $workspace id or name of the workspace + * @return PromiseInterface resolves to array of {@see Result} or rejects with {@see TestcenterConnectorException} + */ + public function getResultsAsync($workspace): PromiseInterface + { + return $this->setAuthTokenAsync() + ->then(function () use ($workspace) { + return $this->getWorkspaceIdAsync($workspace); + }) + ->then(function (int $workspaceId) { + return $this->apiClient->getResultsAsync($this->authToken, $workspaceId); + }) + ->then(function ($results) { + return $results; + }, function ($e) { + $this->handleAsyncError($e); + }); } /** @@ -533,13 +665,30 @@ class TestcenterConnector */ public function getLogs($workspace, array $groupIds): array { - try { - $this->setAuthToken(); - $workspaceId = $this->getWorkspaceId($workspace); - return $this->apiClient->getReportOfLogs($this->authToken, $workspaceId, $groupIds); - } catch (ApiException $e) { - throw new TestcenterConnectorException('API Exception: ' . $e); - } + return $this->getLogsAsync($workspace, $groupIds)->wait(); + } + + /** + * Asynchronously get logs of a test group in a workspace + * + * @param int|string $workspace id or name of the workspace + * @param string[] $groupIds ids of the test groups to get logs from + * @return PromiseInterface resolves to array of {@see LogEntry} or rejects with {@see TestcenterConnectorException} + */ + public function getLogsAsync($workspace, array $groupIds): PromiseInterface + { + return $this->setAuthTokenAsync() + ->then(function () use ($workspace) { + return $this->getWorkspaceId($workspace); + }) + ->then(function (int $workspaceId) use ($groupIds) { + return $this->apiClient->getReportOfLogsAsync($this->authToken, $workspaceId, $groupIds); + }) + ->then(function ($logs) { + return $logs; + }, function ($e) { + $this->handleAsyncError($e); + }); } /** @@ -599,45 +748,59 @@ class TestcenterConnector */ private function setAuthToken(): void { - if (!$this->hasRunningSession()) { - switch ($this->user->getRole()) { - case User::ADMIN_ROLE: - $sessionResponse = $this->apiClient->startAdminSession( - $this->user->getUsername(), - $this->user->getPassword() - ); - break; - case User::LOGIN_ROLE: - throw new Exception("Not implemented"); - default: - throw new TestcenterConnectorException("{$this->user->getRole()} is not an allowed user role."); - } + $this->setAuthTokenAsync()->wait(); + } + + private function setAuthTokenAsync(): PromiseInterface + { + return $this->hasRunningSessionAsync() + ->then(function (bool $result) { + if (!$result) { + switch ($this->user->getRole()) { + case User::ADMIN_ROLE: + return $this->apiClient->startAdminSessionAsync( + $this->user->getUsername(), + $this->user->getPassword() + ); + case User::LOGIN_ROLE: + throw new Exception("Not implemented"); + default: + throw new TestcenterConnectorException( + "{$this->user->getRole()} is not an allowed user role." + ); + } + } + return null; + }) + ->then(function ($sessionResponse) { + if (!$sessionResponse) { + return; + } - $this->authToken = $sessionResponse->getToken(); - $this->authenticatedUsername = $sessionResponse->getDisplayName(); + $this->authToken = $sessionResponse->getToken(); + $this->authenticatedUsername = $sessionResponse->getDisplayName(); - if ($this->authTokenChangedCallback !== null) { - call_user_func($this->authTokenChangedCallback, $this->authToken); - } - } + if ($this->authTokenChangedCallback !== null) { + call_user_func($this->authTokenChangedCallback, $this->authToken); + } + }); } - /** - * @return bool - * @throws TestcenterConnectorException - */ - private function hasRunningSession(): bool + private function hasRunningSessionAsync(): PromiseInterface { if ($this->authToken === null || $this->user->getUsername() !== $this->authenticatedUsername) { - return false; + return new FulfilledPromise(false); } - try { - $sessionResponse = $this->apiClient->getASession($this->authToken); - return $sessionResponse->getToken() === $this->authToken; - } catch (ApiException $e) { - return false; - } + return $this->apiClient->getASessionAsync($this->authToken) + ->then( + function (SessionResponse $sessionResponse) { + return $sessionResponse->getToken() === $this->authToken; + }, + function (ApiException $e) { + return false; + } + ); } /** @@ -649,20 +812,29 @@ class TestcenterConnector * @throws TestcenterConnectorException */ private function getWorkspaceId($workspace): int + { + return $this->getWorkspaceIdAsync($workspace)->wait(); + } + + private function getWorkspaceIdAsync($workspace): PromiseInterface { if (is_string($workspace)) { - $workspaces = $this->apiClient->getAListOfWorkspaces($this->authToken); - foreach ($workspaces as $currentWorkspace) { - if ($currentWorkspace->getName() === $workspace) { - return $currentWorkspace->getId(); - } - } + return $this->apiClient->getAListOfWorkspacesAsync($this->authToken) + ->then(function ($workspaces) use ($workspace) { + foreach ($workspaces as $currentWorkspace) { + if ($currentWorkspace->getName() === $workspace) { + return $currentWorkspace->getId(); + } + } - throw new TestcenterConnectorException("Workspace with name '$workspace' does not exist."); + throw new TestcenterConnectorException("Workspace with name '$workspace' does not exist."); + }); } elseif (is_int($workspace)) { - return $workspace; + return new FulfilledPromise($workspace); } else { - throw new LogicException('workspace must be either int or string'); + return new Promise(function () { + throw new LogicException('workspace must be either int or string'); + }); } } @@ -670,42 +842,61 @@ class TestcenterConnector * Get ids for an array of workspaces * * @param int|string[] $workspaces ids or names of workspaces - * @return int[] - * @throws ApiException - * @throws TestcenterConnectorException + * @return PromiseInterface resolves to array of workspace ids (int) or rejects with + * {@see TestcenterConnectorException} or {@see LogicException} */ - private function getWorkspaceIds($workspaces): array + private function getWorkspaceIdsAsync($workspaces): PromiseInterface { - $instanceWorkspaces = null; - $workspaceIds = []; - - foreach ($workspaces as $workspace) { - if (is_string($workspace)) { - if ($instanceWorkspaces === null) { - $instanceWorkspaces = $this->apiClient->getAListOfWorkspaces($this->authToken); - } - - $workspaceId = null; - foreach ($instanceWorkspaces as $currentWorkspace) { - if ($currentWorkspace->getName() === $workspace) { - $workspaceId = $currentWorkspace->getId(); - break; + if (!$this->containsWorkspaceName($workspaces)) { + return new FulfilledPromise($workspaces); + } + + return $this->apiClient->getAListOfWorkspacesAsync($this->authToken) + ->then(function ($instanceWorkspaces) use ($workspaces) { + $workspaceIds = []; + + foreach ($workspaces as $workspace) { + if (is_string($workspace)) { + $workspaceId = null; + foreach ($instanceWorkspaces as $instanceWorkspace) { + if ($instanceWorkspace->getName() === $workspace) { + $workspaceId = $instanceWorkspace->getId(); + break; + } + } + + if ($workspaceId !== null) { + $workspaceIds[] = $workspaceId; + } else { + throw new TestcenterConnectorException("Workspace with name '$workspace' does not exist."); + } + } elseif (is_int($workspace)) { + $workspaceIds[] = $workspace; + } else { + throw new LogicException('workspace must be either int or string'); } } - if ($workspaceId !== null) { - $workspaceIds[] = $workspaceId; - } else { - throw new TestcenterConnectorException("Workspace with name '$workspace' does not exist."); - } - } elseif (is_int($workspace)) { - $workspaceIds[] = $workspace; - } else { - throw new LogicException('workspace must be either int or string'); + return $workspaceIds; + }, function ($e) { + $this->handleAsyncError($e); + }); + } + + /** + * Check if an array of workspaces contains a workspace by name + * + * @param int|string[] $workspaces array of workspace ids or names + * @return bool true if at least one instance is not an integer, false if all are integers + */ + private function containsWorkspaceName($workspaces): bool + { + foreach ($workspaces as $workspace) { + if (!is_int($workspace)) { + return true; } } - - return $workspaceIds; + return false; } /** @@ -718,19 +909,38 @@ class TestcenterConnector */ private function getUserId($user): int { - if (is_string($user)) { - $users = $this->apiClient->getAListOfUsers($this->authToken); - foreach ($users as $currentUser) { - if ($currentUser->getName() === $user) { - return $currentUser->getId(); - } - } + return $this->getUserIdAsync($user)->wait(); + } - throw new TestcenterConnectorException("User with name '$user' does not exist."); + /** + * Asynchronously get a users id + * + * @param int|string $user id or name of a user + * @return PromiseInterface resolves to user id (int) or rejects with {@see TestcenterConnectorException} or + * {@see LogicException} + */ + private function getUserIdAsync($user): PromiseInterface + { + if (is_string($user)) { + return $this->apiClient->getAListOfUsersAsync($this->authToken) + ->then(function ($users) use ($user) { + foreach ($users as $currentUser) { + if ($currentUser->getName() === $user) { + return $currentUser->getId(); + } + } + return null; + }) + ->then(function ($userId) use ($user) { + if ($userId === null) { + throw new TestcenterConnectorException("User with name '$user' does not exist."); + } + return $userId; + }); } elseif (is_int($user)) { - return $user; + return new FulfilledPromise($user); } else { - throw new LogicException('user must be either int or string'); + return new RejectedPromise(new LogicException('user must be either int or string')); } } @@ -775,4 +985,21 @@ class TestcenterConnector return $userIds; } + + /** + * Handle an error received in a promise's then block + * + * @throws Throwable + * @throws TestcenterConnectorException + */ + private function handleAsyncError($error) + { + if ($error instanceof ApiException) { + throw new TestcenterConnectorException('API Exception: ' . $error); + } elseif ($error instanceof Throwable) { + throw $error; + } else { + throw new Exception($error); + } + } } diff --git a/tests/TestcenterConnectorTest.php b/tests/TestcenterConnectorTest.php index ab554c0458d334ad7ed29d819100b34954f38757..0a4b67aa3c99819153c9eb4652134797668442d0 100644 --- a/tests/TestcenterConnectorTest.php +++ b/tests/TestcenterConnectorTest.php @@ -3,12 +3,15 @@ namespace Kompetenztestde\TestcenterConnector; use Generator; +use GuzzleHttp\Promise\FulfilledPromise; +use GuzzleHttp\Promise\Promise; use GuzzleHttp\Psr7\Response; use Kompetenztestde\TestcenterConnector\Api\Schemas\FileDeletionResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\FileUploadResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\LogEntry; use Kompetenztestde\TestcenterConnector\Api\Schemas\SessionResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\StartSessionResponse; +use Kompetenztestde\TestcenterConnector\Api\Schemas\SystemConfigResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\UnitResponse; use Kompetenztestde\TestcenterConnector\Api\Schemas\UserRole; use Kompetenztestde\TestcenterConnector\Api\Schemas\UserWorkspace; @@ -90,30 +93,27 @@ class TestcenterConnectorTest extends TestCase ->method('generateTesttakersXml') ->willReturn($this->testtakersContent); - $startSessionResponse = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ] - ); + $this->successfulLogin(); $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->with( - $this->identicalTo($this->user->getUsername()), - $this->identicalTo($this->user->getPassword()) - ) - ->willReturn($startSessionResponse); - - $this->apiClient->expects($this->once()) - ->method('uploadFile') + ->method('uploadFileAsync') ->with( $this->identicalTo($this->authToken), $this->identicalTo($this->workspaceId), $this->identicalTo('testtakers-test-group.xml'), $this->testtakersContent ) - ->willReturn(new FileUploadResponse([])); + ->willReturn(new FulfilledPromise(new FileUploadResponse([]))); + + $configResponse = new SystemConfigResponse( + (object) [ + 'version' => '15.5.0' + ] + ); + + $this->apiClient->expects($this->once()) + ->method('getSystemConfigAsync') + ->willReturn(new FulfilledPromise($configResponse)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $connector->addTestGroup($this->workspaceId, $this->group, $this->bookletId, $this->xmlGenerator); @@ -125,7 +125,8 @@ class TestcenterConnectorTest extends TestCase new Pupil('login1') ]; $group = new TestGroup('test-group', 'Test Group', $logins, 'grouppassword'); - $expectedGroup = new XmlTestGroup($this->group->getId(), + $expectedGroup = new XmlTestGroup( + $this->group->getId(), $this->group->getLabel(), [ new XmlTestLogin('grouppassword-login1', null, XmlLoginMode::RUN_HOT_RETURN) @@ -138,20 +139,21 @@ class TestcenterConnectorTest extends TestCase ->with($this->equalTo($expectedGroup)) ->willReturn($this->testtakersContent); - $startSessionResponse = new StartSessionResponse( + $this->successfulLogin(); + + $this->apiClient->expects($this->once()) + ->method('uploadFileAsync') + ->willReturn(new FulfilledPromise(new FileUploadResponse([]))); + + $configResponse = new SystemConfigResponse( (object) [ - 'token' => $this->authToken, - 'displayName' => 'super' + 'version' => '15.5.0' ] ); $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); - - $this->apiClient->expects($this->once()) - ->method('uploadFile') - ->willReturn(new FileUploadResponse([])); + ->method('getSystemConfigAsync') + ->willReturn(new FulfilledPromise($configResponse)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $connector->addTestGroup($this->workspaceId, $group, 'test-booklet', $this->xmlGenerator); @@ -166,30 +168,17 @@ class TestcenterConnectorTest extends TestCase ->method('generateTesttakersXml') ->willReturn($this->testtakersContent); - $startSessionResponse = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ] - ); - - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->with( - $this->identicalTo('super'), - $this->identicalTo('user123') - ) - ->willReturn($startSessionResponse); + $this->successfulLogin(); $this->apiClient->expects($this->exactly(2)) - ->method('uploadFile') + ->method('uploadFileAsync') ->with( $this->identicalTo($this->authToken), $this->identicalTo($this->workspaceId), $this->identicalTo('testtakers-test-group.xml'), $this->testtakersContent ) - ->willReturn(new FileUploadResponse([])); + ->willReturn(new FulfilledPromise(new FileUploadResponse([]))); $sessionResponse = new SessionResponse( (object) [ @@ -199,9 +188,19 @@ class TestcenterConnectorTest extends TestCase ); $this->apiClient->expects($this->once()) - ->method('getASession') + ->method('getASessionAsync') ->with($this->identicalTo($this->authToken)) - ->willReturn($sessionResponse); + ->willReturn(new FulfilledPromise($sessionResponse)); + + $configResponse = new SystemConfigResponse( + (object) [ + 'version' => '15.5.0' + ] + ); + + $this->apiClient->expects($this->any()) + ->method('getSystemConfigAsync') + ->willReturn(new FulfilledPromise($configResponse)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $connector->addTestGroup($this->workspaceId, $this->group, $this->bookletId, $this->xmlGenerator); @@ -218,37 +217,38 @@ class TestcenterConnectorTest extends TestCase ->method('generateTesttakersXml') ->willReturn($this->testtakersContent); - $startSessionResponse = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ] - ); + $this->successfulLogin(); $this->apiClient->expects($this->exactly(2)) - ->method('startAdminSession') - ->with( - $this->identicalTo('super'), - $this->identicalTo('user123') - ) - ->willReturn($startSessionResponse); - - $this->apiClient->expects($this->exactly(2)) - ->method('uploadFile') + ->method('uploadFileAsync') ->with( $this->identicalTo($this->authToken), $this->identicalTo($this->workspaceId), $this->identicalTo('testtakers-test-group.xml'), $this->testtakersContent ) - ->willReturn(new FileUploadResponse([])); + ->willReturn(new FulfilledPromise(new FileUploadResponse([]))); + + $sessionResponse = new Promise(function () { + throw new ApiException("Expired", 409); + }); $this->apiClient->expects($this->once()) - ->method('getASession') + ->method('getASessionAsync') ->with( $this->identicalTo($this->authToken) ) - ->willThrowException(new ApiException("Expired", 409)); + ->willReturn($sessionResponse); + + $configResponse = new SystemConfigResponse( + (object) [ + 'version' => '15.5.0' + ] + ); + + $this->apiClient->expects($this->any()) + ->method('getSystemConfigAsync') + ->willReturn(new FulfilledPromise($configResponse)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $connector->addTestGroup($this->workspaceId, $this->group, $this->bookletId, $this->xmlGenerator); @@ -257,23 +257,15 @@ class TestcenterConnectorTest extends TestCase public function testAddWorkspace(): void { - $startSessionResponse = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); + $this->successfulLogin(); $this->apiClient->expects($this->once()) - ->method('addAWorkspace') + ->method('addAWorkspaceAsync') ->with( $this->equalTo($this->authToken), $this->equalTo('test-workspace') ) - ->willReturn(2); + ->willReturn(new FulfilledPromise(2)); $this->apiClient->expects($this->never())->method('changeUserRoles'); @@ -285,40 +277,34 @@ class TestcenterConnectorTest extends TestCase public function testAddWorkspaceSetRole(): void { - $startSessionResponse = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); + $this->successfulLogin(); $this->apiClient->expects($this->once()) - ->method('addAWorkspace') + ->method('addAWorkspaceAsync') ->with( $this->equalTo($this->authToken), $this->equalTo('test-workspace') ) - ->willReturn(2); + ->willReturn(new FulfilledPromise(2)); + + $users = [new \Kompetenztestde\TestcenterConnector\Api\Schemas\User((object) [ + 'name' => 'super', + 'id' => 1 + ])]; $this->apiClient->expects($this->once()) - ->method('getAListOfUsers') + ->method('getAListOfUsersAsync') ->with($this->authToken) - ->willReturn([new \Kompetenztestde\TestcenterConnector\Api\Schemas\User((object) [ - 'name' => 'super', - 'id' => 1 - ])]); + ->willReturn(new FulfilledPromise($users)); $this->apiClient->expects($this->once()) - ->method('changeUserRoles') + ->method('changeUserRolesAsync') ->with( $this->authToken, 2, [new UserRole(1, UserRole::RW)] ) - ->willReturn(true); + ->willReturn(new FulfilledPromise(true)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $workspaceId = $connector->addWorkspace('test-workspace', true); @@ -328,23 +314,15 @@ class TestcenterConnectorTest extends TestCase public function testAddWorkspaceLegacy(): void { - $startSessionResponse = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); + $this->successfulLogin(); $this->apiClient->expects($this->once()) - ->method('addAWorkspace') + ->method('addAWorkspaceAsync') ->with( $this->equalTo($this->authToken), $this->equalTo('test-workspace') ) - ->willReturn(null); + ->willReturn(new FulfilledPromise(null)); $workspaces = [ new Workspace( @@ -362,9 +340,9 @@ class TestcenterConnectorTest extends TestCase ]; $this->apiClient->expects($this->once()) - ->method('getAListOfWorkspaces') + ->method('getAListOfWorkspacesAsync') ->with($this->equalTo($this->authToken)) - ->willReturn($workspaces); + ->willReturn(new FulfilledPromise($workspaces)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $workspaceId = $connector->addWorkspace('test-workspace'); @@ -374,13 +352,7 @@ class TestcenterConnectorTest extends TestCase public function testGetWorkspaces(): void { - $startSessionResponse = new StartSessionResponse((object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ]); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); + $this->successfulLogin(); $workspaces = [ new Workspace((object) [ @@ -394,8 +366,8 @@ class TestcenterConnectorTest extends TestCase ]; $this->apiClient->expects($this->once()) - ->method('getAListOfWorkspaces') - ->willReturn($workspaces); + ->method('getAListOfWorkspacesAsync') + ->willReturn(new FulfilledPromise($workspaces)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $workspaces = $connector->getWorkspaces(); @@ -409,20 +381,15 @@ class TestcenterConnectorTest extends TestCase public function testDeleteWorkspace(): void { - $startSessionResponse = new StartSessionResponse((object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ]); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); + $this->successfulLogin(); $this->apiClient->expects($this->once()) - ->method('deleteSomeWorkspaces') + ->method('deleteSomeWorkspacesAsync') ->with( $this->equalTo($this->authToken), $this->equalTo([1]) - ); + ) + ->willReturn(new FulfilledPromise(true)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $connector->deleteWorkspace([1]); @@ -430,16 +397,10 @@ class TestcenterConnectorTest extends TestCase public function testDeleteWorkspaceError(): void { - $startSessionResponse = new StartSessionResponse((object) [ - 'token' => $this->authToken, - 'displayName' => 'super' - ]); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); + $this->successfulLogin(); $this->apiClient->expects($this->once()) - ->method('deleteSomeWorkspaces') + ->method('deleteSomeWorkspacesAsync') ->with( $this->equalTo($this->authToken), $this->equalTo([1]) @@ -472,13 +433,7 @@ class TestcenterConnectorTest extends TestCase ])); - $startSessionResponse = new StartSessionResponse( - (object) ['token' => $this->authToken, 'displayName' => 'super'] - ); - - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($startSessionResponse); + $this->successfulLogin(); $this->apiClient->expects($this->once()) ->method('uploadFile') @@ -516,24 +471,16 @@ class TestcenterConnectorTest extends TestCase ) ]; - $response = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => $this->user->getUsername() - ] - ); + $this->successfulLogin(); $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($response); - $this->apiClient->expects($this->once()) - ->method('getReportOfItemResponses') + ->method('getReportOfItemResponsesAsync') ->with( $this->equalTo($this->authToken), $this->equalTo(1), $this->equalTo(['test-group']) ) - ->willReturn($testResponses); + ->willReturn(new FulfilledPromise($testResponses)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $results = $connector->getGroupResults(1, 'test-group'); @@ -543,15 +490,7 @@ class TestcenterConnectorTest extends TestCase public function testGetWorkspacesByUser(): void { - $response = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => $this->user->getUsername() - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($response); + $this->successfulLogin(); $workspaces = [ new UserWorkspace( @@ -587,15 +526,7 @@ class TestcenterConnectorTest extends TestCase public function testChangeUserRoles(): void { - $response = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => $this->user->getUsername() - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($response); + $this->successfulLogin(); $userRoles = [ new UserRole( @@ -624,15 +555,7 @@ class TestcenterConnectorTest extends TestCase public function testGetLogs(): void { - $response = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => $this->user->getUsername() - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($response); + $this->successfulLogin(); $logs = [ new LogEntry( @@ -648,13 +571,13 @@ class TestcenterConnectorTest extends TestCase ) ]; $this->apiClient->expects($this->once()) - ->method('getReportOfLogs') + ->method('getReportOfLogsAsync') ->with( $this->equalTo($this->authToken), $this->equalTo(1), $this->equalTo(['test_group']) ) - ->willReturn($logs); + ->willReturn(new FulfilledPromise($logs)); $connector = new TestcenterConnector($this->user, null, $this->apiClient); $returnedLogs = $connector->getLogs(1, ['test_group']); @@ -664,15 +587,7 @@ class TestcenterConnectorTest extends TestCase public function testDeleteFiles(): void { - $response = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => $this->user->getUsername() - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($response); + $this->successfulLogin(); $deletionResponse = new FileDeletionResponse( (object) [ @@ -709,15 +624,7 @@ class TestcenterConnectorTest extends TestCase public function testChangeUserPassword(): void { - $response = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => $this->user->getUsername() - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($response); + $this->successfulLogin(); $this->apiClient->expects($this->once()) ->method('changeUserPassword') @@ -736,15 +643,7 @@ class TestcenterConnectorTest extends TestCase public function testAddSuperAdmin(): void { - $response = new StartSessionResponse( - (object) [ - 'token' => $this->authToken, - 'displayName' => $this->user->getUsername() - ] - ); - $this->apiClient->expects($this->once()) - ->method('startAdminSession') - ->willReturn($response); + $this->successfulLogin(); $this->apiClient->expects($this->once()) ->method('addAUser') @@ -817,4 +716,15 @@ class TestcenterConnectorTest extends TestCase yield $key => $item; } } -} \ No newline at end of file + + private function successfulLogin() + { + $startSessionResponse = new StartSessionResponse((object) [ + 'token' => $this->authToken, + 'displayName' => $this->user->getUsername() + ]); + $this->apiClient->expects($this->atLeastOnce()) + ->method('startAdminSessionAsync') + ->willReturn(new FulfilledPromise($startSessionResponse)); + } +}