| <?php |
| /** |
| * Copyright 2007 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * Unit tests for the PushTask class. |
| * |
| */ |
| |
| namespace google\appengine\api\taskqueue; |
| |
| use google\appengine\api\taskqueue\PushTask; |
| use google\appengine\testing\ApiProxyTestBase; |
| use google\appengine\TaskQueueAddRequest\RequestMethod; |
| use google\appengine\TaskQueueBulkAddRequest; |
| use google\appengine\TaskQueueBulkAddResponse; |
| use google\appengine\TaskQueueServiceError\ErrorCode; |
| |
| $mockTime = 12345.6; |
| |
| // This mocks out PHP's microtime() function. |
| function microtime($get_as_float = false) { |
| if (!$get_as_float) { |
| die('microtime called with get_as_float=false'); |
| } |
| global $mockTime; |
| return $mockTime; |
| } |
| |
| class PushTaskTest extends ApiProxyTestBase { |
| |
| /** |
| * Override time() in current namespace for testing. |
| */ |
| public function setUp() { |
| parent::setUp(); |
| $this->_SERVER = $_SERVER; |
| } |
| |
| public function tearDown() { |
| $_SERVER = $this->_SERVER; |
| parent::tearDown(); |
| } |
| |
| private static function buildBulkAddRequest() { |
| $req = new TaskQueueBulkAddRequest(); |
| $task = $req->addAddRequest(); |
| $task->setQueueName('default'); |
| $task->setTaskName(''); |
| $task->setUrl('/someUrl'); |
| global $mockTime; |
| $task->setEtaUsec($mockTime * 1e6); |
| $task->setMethod(RequestMethod::POST); |
| return $req; |
| } |
| |
| public function testConstructorUrlWrongType() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'url_path must be a string. Actual type: integer'); |
| $task = new PushTask(999, ['key' => 'some value']); |
| } |
| |
| public function testConstructorUrlEmpty() { |
| $this->setExpectedException('\InvalidArgumentException', |
| "url_path must begin with '/'."); |
| $task = new PushTask('', ['key' => 'some value']); |
| } |
| |
| public function testConstructorUrlWithoutLeadingSlash() { |
| $this->setExpectedException('\InvalidArgumentException', |
| "url_path must begin with '/'."); |
| $task = new PushTask('wrong', ['key' => 'some value']); |
| } |
| |
| public function testConstructorUrlMustNotContainQueryString() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'query strings not allowed in url_path.'); |
| $task = new PushTask('/someurl?'); |
| } |
| |
| public function testConstructorQueryDataWrongType() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'query_data must be an array. Actual type: string'); |
| $task = new PushTask('/myUrl', 'abc'); |
| } |
| |
| public function testConstructorOptionsWrongType() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'options must be an array. Actual type: integer'); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], 123); |
| } |
| |
| public function testConstructorUnknownOptions() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'Invalid options supplied: nonsense'); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['nonsense' => 123]); |
| } |
| |
| public function testConstructorInvalidMethod() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'Invalid method: POSTIT'); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['method' => 'POSTIT']); |
| } |
| |
| public function testConstructorInvalidName() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'name must be a string. Actual type: integer'); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['name' => 55]); |
| } |
| |
| public function testConstructorNameTooLong() { |
| $name = str_repeat('a', 501); |
| $this->setExpectedException('\InvalidArgumentException', |
| 'name exceeds maximum length of 500. First 1000 ' . |
| 'characters of name: ' . $name); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['name' => $name]); |
| } |
| |
| public function testConstructorNameMaxLength() { |
| // Just tests that this doesn't throw an exception. |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['name' => str_repeat('a', 500)]); |
| } |
| |
| public function testConstructorNameBadCharacters() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'name must match pattern: ' . PushTask::NAME_PATTERN . '. name: @'); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['name' => '@']); |
| } |
| |
| public function testConstructorInvalidDelaySeconds() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'delay_seconds must be a numeric type.'); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['delay_seconds' => 'a few']); |
| } |
| |
| public function testConstructorNegativeDelaySeconds() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'delay_seconds must be between 0 and ' . PushTask::MAX_DELAY_SECONDS . |
| ' (30 days). delay_seconds: -1'); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['delay_seconds' => -1]); |
| } |
| |
| public function testConstructorDelaySecondsTooBig() { |
| $delay = 1 + 30 * 86400; |
| $this->setExpectedException('\InvalidArgumentException', |
| 'delay_seconds must be between 0 and ' . PushTask::MAX_DELAY_SECONDS . |
| ' (30 days). delay_seconds: ' . $delay); |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['delay_seconds' => $delay]); |
| } |
| |
| public function testConstructorMaxDelaySecond() { |
| // Just tests that a 30 day delay_seconds doesn't throw an exception. |
| $task = new PushTask('/someUrl', ['key' => 'some value'], |
| ['delay_seconds' => 30 * 86400]); |
| } |
| |
| public function testConstructorUrlTooBig() { |
| $url = '/' . str_repeat('b', 2083); |
| $this->setExpectedException( |
| '\InvalidArgumentException', |
| 'URL length greater than maximum of ' . PushTask::MAX_URL_LENGTH) . |
| '. URL: ' . $url; |
| $t = new PushTask($url); |
| } |
| |
| public function testConstructorHeaderWrongType() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'header must be a string. Actual type: double'); |
| $t = new PushTask('/some-url', ['user-key' => 'user-data'], |
| ['header' => 50.0]); |
| } |
| |
| public function testConstructorHeaderWithoutColon() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'Each header must contain a colon. Header: bad-header!'); |
| $t = new PushTask('/some-url', ['user-key' => 'user-data'], |
| ['header' => 'bad-header!']); |
| } |
| |
| public function testConstructorInvalidContentType() { |
| $this->setExpectedException('\InvalidArgumentException', |
| 'Content-type header may not be specified as it is set by the task.'); |
| $t = new PushTask('/some-url', ['user-key' => 'user-data'], |
| ['header' => 'content-type: application/pdf']); |
| } |
| |
| public function testAddInvalidQueue() { |
| $this->setExpectedException('\InvalidArgumentException'); |
| (new PushTask('/someUrl'))->add(999); |
| } |
| |
| public function testAddTaskTooBig() { |
| $this->setExpectedException( |
| '\google\appengine\api\taskqueue\TaskQueueException', |
| 'Task greater than maximum size of ' . PushTask::MAX_TASK_SIZE_BYTES); |
| // Althought 102400 is the max size, it's for the serialized proto which |
| // includes the URL etc. |
| (new PushTask('/someUrl', ['field' => str_repeat('a', 102395)]))->add(); |
| } |
| |
| public function testPushTaskSimplestAdd() { |
| $req = self::buildBulkAddRequest(); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| $task_result = $resp->addTaskResult(); |
| $task_result->setResult(ErrorCode::OK); |
| $task_result->setChosenTaskName('fred'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| $task_name = (new PushTask('/someUrl'))->add(); |
| $this->assertEquals('fred', $task_name); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskSimpleAddWithQueryData() { |
| $query_data = ['key' => 'some value']; |
| $req = self::buildBulkAddRequest(); |
| $req->getAddRequest(0)->setBody(http_build_query($query_data)); |
| $header = $req->getAddRequest(0)->addHeader(); |
| $header->setKey('content-type'); |
| $header->setValue('application/x-www-form-urlencoded'); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| (new PushTask('/someUrl', $query_data))->add(); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskAddToNonDefaultQueue() { |
| $req = self::buildBulkAddRequest(); |
| $req->getAddRequest(0)->setQueueName('myqueue'); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| (new PushTask('/someUrl'))->add('myqueue'); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskAddBasicGetRequest() { |
| $req = self::buildBulkAddRequest(); |
| $req->getAddRequest(0)->setMethod(RequestMethod::GET); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| (new PushTask('/someUrl', [], ['method' => 'GET']))->add(); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskAddGetRequestWithQueryData() { |
| $req = self::buildBulkAddRequest(); |
| $req->getAddRequest(0)->setMethod(RequestMethod::GET); |
| $req->getAddRequest(0)->setUrl('/someUrl?aKey=aValue'); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| $task = new PushTask('/someUrl', ['aKey' => 'aValue'], ['method' => 'GET']); |
| $task->add(); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskWithNameAndETA() { |
| $req = self::buildBulkAddRequest(); |
| $add_req = $req->getAddRequest(0); |
| $add_req->setTaskName('customTaskName'); |
| $add_req->setEtaUsec($add_req->getEtaUsec() + 5 * 1e6); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| $task = new PushTask('/someUrl', [], |
| ['delay_seconds' => 5, 'name' => 'customTaskName']); |
| $task_name = $task->add(); |
| $this->assertEquals('customTaskName', $task_name); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskAddWithHeader() { |
| $req = self::buildBulkAddRequest(); |
| $add_req = $req->getAddRequest(0); |
| $header = $add_req->addHeader(); |
| $header->setKey('custom-header'); |
| $header->setValue('54321'); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| $task_result = $resp->addTaskResult(); |
| $task_result->setResult(ErrorCode::OK); |
| $task_result->setChosenTaskName('fred'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| $task_name = (new PushTask('/someUrl', [], |
| ['header' => 'custom-header: 54321']))->add(); |
| $this->assertEquals('fred', $task_name); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskAddWithHeaderAndQueryData() { |
| $query_data = ['key' => 'some value']; |
| $req = self::buildBulkAddRequest(); |
| $add_req = $req->getAddRequest(0); |
| $add_req->setBody(http_build_query($query_data)); |
| |
| $header = $add_req->addHeader(); |
| $header->setKey('content-type'); |
| $header->setValue('application/x-www-form-urlencoded'); |
| $header = $add_req->addHeader(); |
| $header->setKey('custom-header'); |
| $header->setValue('xyz'); |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| (new PushTask('/someUrl', $query_data, |
| ['header' => 'custom-header: xyz']))->add(); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testPushTaskAddWithTwoHeaders() { |
| $req = self::buildBulkAddRequest(); |
| $add_req = $req->getAddRequest(0); |
| $header = $add_req->addHeader(); |
| $header->setKey('custom-header'); |
| $header->setValue('54321'); |
| $header = $add_req->addHeader(); |
| $header->setKey('another-custom-header'); |
| $header->setValue('abc'); |
| |
| |
| $resp = new TaskQueueBulkAddResponse(); |
| $task_result = $resp->addTaskResult(); |
| $task_result->setResult(ErrorCode::OK); |
| $task_result->setChosenTaskName('fred'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $resp); |
| |
| $task_name = (new PushTask('/someUrl', [], |
| ['header' => "custom-header: 54321\r\n" . |
| 'another-custom-header: abc']))->add(); |
| $this->assertEquals('fred', $task_name); |
| $this->apiProxyMock->verify(); |
| } |
| |
| public function testUnknownQueueError() { |
| $req = self::buildBulkAddRequest(); |
| $exception = new \google\appengine\runtime\ApplicationError( |
| ErrorCode::UNKNOWN_QUEUE, 'message'); |
| |
| $this->setExpectedException( |
| '\google\appengine\api\taskqueue\TaskQueueException', |
| 'Unknown queue'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $exception); |
| |
| (new PushTask('/someUrl'))->add(); |
| } |
| |
| public function testTransientError() { |
| $req = self::buildBulkAddRequest(); |
| $exception = new \google\appengine\runtime\ApplicationError( |
| ErrorCode::TRANSIENT_ERROR, 'message'); |
| |
| $this->setExpectedException( |
| '\google\appengine\api\taskqueue\TransientTaskQueueException'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $exception); |
| |
| (new PushTask('/someUrl'))->add(); |
| } |
| |
| public function testPermissionDeniedError() { |
| $req = self::buildBulkAddRequest(); |
| $exception = new \google\appengine\runtime\ApplicationError( |
| ErrorCode::PERMISSION_DENIED, 'message'); |
| |
| $this->setExpectedException( |
| '\google\appengine\api\taskqueue\TaskQueueException', |
| 'Permission Denied'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $exception); |
| |
| (new PushTask('/someUrl'))->add(); |
| } |
| |
| public function testTombstonedTaskError() { |
| $req = self::buildBulkAddRequest(); |
| $exception = new \google\appengine\runtime\ApplicationError( |
| ErrorCode::TOMBSTONED_TASK, 'message'); |
| |
| $this->setExpectedException( |
| '\google\appengine\api\taskqueue\TaskAlreadyExistsException'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $exception); |
| |
| (new PushTask('/someUrl'))->add(); |
| } |
| |
| public function testTaskAlreadyExistsError() { |
| $req = self::buildBulkAddRequest(); |
| $exception = new \google\appengine\runtime\ApplicationError( |
| ErrorCode::TASK_ALREADY_EXISTS, 'message'); |
| |
| $this->setExpectedException( |
| '\google\appengine\api\taskqueue\TaskAlreadyExistsException'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $exception); |
| |
| (new PushTask('/someUrl'))->add(); |
| } |
| |
| public function testTaskInvalidQueueModeError() { |
| $req = self::buildBulkAddRequest(); |
| $exception = new \google\appengine\runtime\ApplicationError( |
| ErrorCode::INVALID_QUEUE_MODE, 'message'); |
| |
| $this->setExpectedException( |
| '\google\appengine\api\taskqueue\TaskQueueException', |
| 'Cannot add a PushTask to a pull queue.'); |
| |
| $this->apiProxyMock->expectCall('taskqueue', 'BulkAdd', $req, $exception); |
| |
| (new PushTask('/someUrl'))->add(); |
| } |
| } |