public function testOrchestrationRunWithTasksError()
 {
     // create orchestration
     $orchestration = $this->client->createOrchestration(sprintf('%s %s', self::TESTING_ORCHESTRATION_NAME, uniqid()));
     $this->assertArrayHasKey('id', $orchestration, "Result of API command 'createOrchestration' should contain new created orchestration ID");
     $this->assertArrayHasKey('crontabRecord', $orchestration, "Result of API command 'createOrchestration' should return orchestration info");
     // update tasks
     $url = 'https://syrup.keboola.com/timeout/asynchronous';
     $sapiTask = new OrchestrationTask();
     $sapiTask->setActive(true)->setContinueOnFailure(false)->setComponent(null)->setComponentUrl($url);
     $tasks = $this->client->updateTasks($orchestration['id'], array($sapiTask));
     $this->assertCount(1, $tasks, sprintf("Result of API command 'updateTasks' should return %i tasks", 1));
     // new
     $sapiTask->setComponentUrl('https://syrup.keboola.com/timeout/timer');
     try {
         $this->client->runOrchestration($orchestration['id'], array(), array($sapiTask->toArray()));
         $this->fail('Orchestration run with different tasks should produce errors');
     } catch (ClientErrorResponseException $e) {
         $response = $e->getResponse()->json();
         $this->assertArrayHasKey('message', $response);
         $this->assertArrayHasKey('code', $response);
         $this->assertArrayHasKey('status', $response);
         $this->assertRegExp('/different from orchestration task/ui', $response['message']);
         $this->assertEquals('warning', $response['status']);
         $this->assertEquals('JOB_VALIDATION', $response['code']);
     }
 }
 public function testOrchestrationsPhaseNames()
 {
     // create orchestration
     $options = array('crontabRecord' => '1 1 1 1 1', 'tasks' => array(0 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "first phase", 'actionParameters' => array('delay' => 180)), 2 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => null, 'actionParameters' => array('delay' => 5)), 3 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "0", 'actionParameters' => array('delay' => 5)), 4 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "", 'actionParameters' => array('delay' => 5))));
     $orchestration = $this->client->createOrchestration(sprintf('%s %s', self::TESTING_ORCHESTRATION_NAME, uniqid()), $options);
     $this->assertArrayHasKey('id', $orchestration, "Result of API command 'createOrchestration' should contain new created orchestration ID");
     $this->assertArrayHasKey('tasks', $orchestration, "Result of API command 'createOrchestration' should contain new created orchestration ID");
     $this->assertArrayHasKey('crontabRecord', $orchestration, "Result of API command 'createOrchestration' should return orchestration info");
     $this->assertArrayHasKey('nextScheduledTime', $orchestration, "Result of API command 'createOrchestration' should return orchestration info");
     $tasks = $orchestration['tasks'];
     $this->assertCount(4, $tasks);
     $this->assertArrayHasKey('phase', $tasks[0]);
     $this->assertEquals('first phase', $tasks[0]['phase']);
     $this->assertArrayHasKey('phase', $tasks[1]);
     $this->assertNull($tasks[1]['phase']);
     $this->assertArrayHasKey('phase', $tasks[2]);
     $this->assertNotNull($tasks[2]['phase']);
     $this->assertEquals(0, $tasks[2]['phase']);
     $this->assertArrayHasKey('phase', $tasks[3]);
     $this->assertNull($tasks[3]['phase']);
     // update orchestration
     $options = array('crontabRecord' => '1 1 1 1 1', 'tasks' => array(0 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "first phase", 'actionParameters' => array('delay' => 180)), 1 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "first phase", 'actionParameters' => array('delay' => 30)), 2 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => null, 'actionParameters' => array('delay' => 5)), 3 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "0", 'actionParameters' => array('delay' => 5)), 4 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "", 'actionParameters' => array('delay' => 5))));
     $orchestration = $this->client->updateOrchestration($orchestration['id'], $options);
     $this->assertArrayHasKey('id', $orchestration, "Result of API command 'createOrchestration' should contain new created orchestration ID");
     $this->assertArrayHasKey('tasks', $orchestration, "Result of API command 'createOrchestration' should contain new created orchestration ID");
     $this->assertArrayHasKey('crontabRecord', $orchestration, "Result of API command 'createOrchestration' should return orchestration info");
     $this->assertArrayHasKey('nextScheduledTime', $orchestration, "Result of API command 'createOrchestration' should return orchestration info");
     $tasks = $orchestration['tasks'];
     $this->assertCount(5, $tasks);
     $this->assertArrayHasKey('phase', $tasks[0]);
     $this->assertEquals('first phase', $tasks[0]['phase']);
     $this->assertArrayHasKey('phase', $tasks[1]);
     $this->assertEquals('first phase', $tasks[1]['phase']);
     $this->assertArrayHasKey('phase', $tasks[2]);
     $this->assertNull($tasks[2]['phase']);
     $this->assertArrayHasKey('phase', $tasks[3]);
     $this->assertNotNull($tasks[3]['phase']);
     $this->assertEquals(0, $tasks[3]['phase']);
     $this->assertArrayHasKey('phase', $tasks[4]);
     $this->assertNull($tasks[4]['phase']);
     // orchestrations tasks
     $tasks = $this->client->updateTasks($orchestration['id'], $this->createTestData());
     // orchestration detail
     $orchestration = $this->client->getOrchestration($orchestration['id']);
     $this->assertArrayHasKey('id', $orchestration, "Result of API command 'getOrchestration' should contain new created orchestration ID");
     $this->assertArrayHasKey('crontabRecord', $orchestration, "Result of API command 'getOrchestration' should return orchestration info");
     $this->assertArrayHasKey('nextScheduledTime', $orchestration, "Result of API command 'getOrchestration' should return orchestration info");
     // orchestration update
     $crontabRecord = '* * * * *';
     $active = false;
     $options = array('active' => $active, 'crontabRecord' => $crontabRecord, 'tasks' => array(0 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "first phase", 'actionParameters' => array('delay' => 180)), 1 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "first phase", 'actionParameters' => array('delay' => 30)), 2 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => null, 'actionParameters' => array('delay' => 5)), 3 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "0", 'actionParameters' => array('delay' => 5)), 4 => array('componentUrl' => 'https://syrup.keboola.com/timeout/jobs', 'active' => true, 'phase' => "", 'actionParameters' => array('delay' => 5))));
     $orchestration = $this->client->updateOrchestration($orchestration['id'], $options);
     $this->assertArrayHasKey('id', $orchestration, "Result of API command 'updateOrchestration' should contain new created orchestration ID");
     $this->assertArrayHasKey('crontabRecord', $orchestration, "Result of API command 'updateOrchestration' should return orchestration info");
     $this->assertArrayHasKey('nextScheduledTime', $orchestration, "Result of API command 'updateOrchestration' should return orchestration info");
     $this->assertArrayHasKey('active', $orchestration, "Result of API command 'updateOrchestration' should return orchestration info");
     $this->assertArrayHasKey('tasks', $orchestration, "Result of API command 'updateOrchestration' should return orchestration info");
     $this->assertEquals($active, $orchestration['active'], "Result of API command 'updateOrchestration' should return disabled orchestration");
     $this->assertEquals($crontabRecord, $orchestration['crontabRecord'], "Result of API command 'updateOrchestration' should return modified orchestration");
     $tasks = $orchestration['tasks'];
     $this->assertCount(5, $tasks);
     $this->assertArrayHasKey('phase', $tasks[0]);
     $this->assertEquals('first phase', $tasks[0]['phase']);
     $this->assertArrayHasKey('phase', $tasks[1]);
     $this->assertEquals('first phase', $tasks[1]['phase']);
     $this->assertArrayHasKey('phase', $tasks[2]);
     $this->assertNull($tasks[2]['phase']);
     $this->assertArrayHasKey('phase', $tasks[3]);
     $this->assertNotNull($tasks[3]['phase']);
     $this->assertEquals(0, $tasks[3]['phase']);
     $this->assertArrayHasKey('phase', $tasks[4]);
     $this->assertNull($tasks[4]['phase']);
     // enqueue job
     $job = $this->client->runOrchestration($orchestration['id']);
     $this->assertArrayHasKey('id', $job, "Result of API command 'createJob' should contain new created job ID");
     $this->assertArrayHasKey('orchestrationId', $job, "Result of API command 'createJob' should return job info");
     $this->assertArrayHasKey('status', $job, "Result of API command 'createJob' should return job info");
     $this->assertEquals('waiting', $job['status'], "Result of API command 'createJob' should return new waiting job");
     $this->assertEquals($orchestration['id'], $job['orchestrationId'], "Result of API command 'createJob' should return new waiting job for given orchestration");
     // wait for processing job
     while (!in_array($job['status'], array('ok', 'success', 'error', 'warn'))) {
         sleep(5);
         $job = $this->client->getJob($job['id']);
         $this->assertArrayHasKey('status', $job, "Result of API command 'getJob' should return job info");
     }
     // phases and tasks results in response
     $this->assertArrayHasKey('results', $job, "Result of API command 'getJob' should return results");
     $results = $job['results'];
     $this->assertArrayHasKey('tasks', $results, "Result of API command 'getJob' should return tasks results");
     $this->assertArrayHasKey('phases', $results, "Result of API command 'getJob' should return phases results");
     $this->assertEquals('success', $job['status'], "Result of API command 'getJob' should return job with success status");
     $this->assertCount(4, $results['phases']);
     $this->assertCount(5, $results['tasks']);
     // task status
     $successCount = 0;
     foreach ($results['tasks'] as $taskResult) {
         $this->assertArrayHasKey('status', $taskResult, "Task result should contains execution status");
         if ($taskResult['status'] === 'success') {
             $successCount++;
         }
     }
     $this->assertEquals(5, $successCount, "All executed tasks should have 'success' status");
     // task execution order
     $i = 0;
     $taskOrder = array();
     foreach ($results['tasks'] as $taskResult) {
         $taskOrder[$taskResult['id']] = $i;
         $i++;
     }
     $i = 0;
     foreach ($results['phases'] as $phase) {
         foreach ($phase as $taskResult) {
             $this->assertEquals($i, $taskOrder[$taskResult['id']], "Tasks in tasks result and phases result should have same order");
             $i++;
         }
     }
     // parallel job processing
     $phase = $results['phases'][0];
     $task1Start = new \DateTime($phase[0]['startTime']);
     $task1End = new \DateTime($phase[0]['endTime']);
     $task2Start = new \DateTime($phase[1]['startTime']);
     $task2End = new \DateTime($phase[1]['endTime']);
     $validTime = false;
     if ($task1Start->getTimestamp() < $task2Start->getTimestamp()) {
         if ($task1End->getTimestamp() > $task2End->getTimestamp()) {
             $validTime = true;
         }
     }
     $this->assertTrue($validTime, 'First phase should have parallel processed tasks');
 }