diff --git a/modules/restful_example/plugins/restful/db_query/variable/1.0/RestfulQueryVariable.class.php b/modules/restful_example/plugins/restful/db_query/variable/1.0/RestfulQueryVariable.class.php deleted file mode 100644 index 084cba07..00000000 --- a/modules/restful_example/plugins/restful/db_query/variable/1.0/RestfulQueryVariable.class.php +++ /dev/null @@ -1,24 +0,0 @@ - array( - 'property' => 'name', - ), - 'value' => array( - 'property' => 'value', - ), - ); - } - -} diff --git a/modules/restful_example/plugins/restful/db_query/variable/1.0/variable__1_0.inc b/modules/restful_example/plugins/restful/db_query/variable/1.0/variable__1_0.inc deleted file mode 100644 index b16f84c1..00000000 --- a/modules/restful_example/plugins/restful/db_query/variable/1.0/variable__1_0.inc +++ /dev/null @@ -1,14 +0,0 @@ - t('Variable'), - 'description' => t('Export the "Variable" table.'), - 'resource' => 'variables', - 'class' => 'RestfulQueryVariable', - 'data_provider_options' => array( - 'table_name' => 'variable', - 'id_column' => 'name', - ), - 'authentication_types' => TRUE, - 'authentication_optional' => TRUE, -); diff --git a/modules/restful_example/plugins/restful/db_query/watchdog/1.0/RestfulWatchdogResource.class.php b/modules/restful_example/plugins/restful/db_query/watchdog/1.0/RestfulWatchdogResource.class.php new file mode 100644 index 00000000..d7bf3aab --- /dev/null +++ b/modules/restful_example/plugins/restful/db_query/watchdog/1.0/RestfulWatchdogResource.class.php @@ -0,0 +1,45 @@ + 'wid', + ); + + $public_fields['log_type'] = array( + 'property' => 'type', + ); + + $public_fields['log_text'] = array( + 'property' => 'message', + ); + + $public_fields['log_variables'] = array( + 'property' => 'variables', + ); + + $public_fields['log_level'] = array( + 'property' => 'severity', + ); + + $public_fields['log_path'] = array( + 'property' => 'location', + ); + + return $public_fields; + } + + /** + * {@inheritdoc} + */ + public function access() { + $account = $this->getAccount(); + return user_access('view site reports', $account); + } +} diff --git a/modules/restful_example/plugins/restful/db_query/watchdog/1.0/watchdog.inc b/modules/restful_example/plugins/restful/db_query/watchdog/1.0/watchdog.inc new file mode 100644 index 00000000..b8a26976 --- /dev/null +++ b/modules/restful_example/plugins/restful/db_query/watchdog/1.0/watchdog.inc @@ -0,0 +1,14 @@ + t('Watchdog entries'), + 'resource' => 'watchdog', + 'name' => 'watchdog', + 'data_provider_options' => array( + 'table_name' => 'watchdog', + 'id_column' => 'wid', + ), + 'description' => t('Expose watchdog entries to the REST API.'), + 'class' => 'RestfulWatchdogResource', + 'authentication_types' => TRUE, +); diff --git a/modules/restful_example/plugins/restful/variable/1.0/RestfulVariableResource.class.php b/modules/restful_example/plugins/restful/variable/1.0/RestfulVariableResource.class.php new file mode 100644 index 00000000..6d478fac --- /dev/null +++ b/modules/restful_example/plugins/restful/variable/1.0/RestfulVariableResource.class.php @@ -0,0 +1,32 @@ + array( + 'property' => 'name', + ), + 'variable_value' => array( + 'property' => 'value', + ), + ); + } + + /** + * {@inheritdoc} + */ + public function access() { + $account = $this->getAccount(); + return user_access('adminsiter site configuration', $account); + } + +} diff --git a/modules/restful_example/plugins/restful/variable/1.0/variable__1_0.inc b/modules/restful_example/plugins/restful/variable/1.0/variable__1_0.inc new file mode 100644 index 00000000..f7406b28 --- /dev/null +++ b/modules/restful_example/plugins/restful/variable/1.0/variable__1_0.inc @@ -0,0 +1,12 @@ + t('Variable'), + 'description' => t('Expose site variables to the REST API.'), + 'resource' => 'variables', + 'class' => 'RestfulVariableResource', + 'authentication_types' => TRUE, + 'render_cache' => array( + 'render' => TRUE, + ), +); diff --git a/modules/restful_token_auth/tests/RestfulTokenAuthenticationTestCase.test b/modules/restful_token_auth/tests/RestfulTokenAuthenticationTestCase.test index a23a9684..6291af53 100644 --- a/modules/restful_token_auth/tests/RestfulTokenAuthenticationTestCase.test +++ b/modules/restful_token_auth/tests/RestfulTokenAuthenticationTestCase.test @@ -11,13 +11,12 @@ class RestfulTokenAuthenticationTestCase extends DrupalWebTestCase { return array( 'name' => 'Token Authentication', 'description' => 'Test the request authentication with a token.', - 'group' => 'Restful', + 'group' => 'RESTful', ); } function setUp() { parent::setUp('restful_example', 'restful_token_auth', 'entityreference'); - restful_create_field_refresh_token(); } /** diff --git a/plugins/restful/RestfulDataProviderDbQuery.php b/plugins/restful/RestfulDataProviderDbQuery.php index 9e624185..780ab3a3 100644 --- a/plugins/restful/RestfulDataProviderDbQuery.php +++ b/plugins/restful/RestfulDataProviderDbQuery.php @@ -75,6 +75,20 @@ public function setTableName($table_name) { $this->tableName = $table_name; } + /** + * @return string + **/ + public function getPrimary() { + return $this->primary; + } + + /** + * @param string $primary + **/ + public function setPrimary($primary) { + $this->primary = $primary; + } + /** * Constructs a RestfulDataProviderDbQuery object. * @@ -112,7 +126,9 @@ public function defaultSortInfo() { $sorts = array(); foreach ($this->getIdColumn() as $column) { if (!empty($this->getPublicFields[$column])) { + // Sort by the first ID column that is a public field. $sorts[$column] = 'ASC'; + break; } } return $sorts; @@ -230,7 +246,8 @@ public function getQueryCount() { public function getTotalCount() { return intval($this ->getQueryCount() - ->execute()); + ->execute() + ->fetchField()); } /** @@ -341,11 +358,6 @@ protected function replace($id) { * {@inheritdoc} */ public function update($id, $full_replace = FALSE) { - $query = db_update($this->getTableName()); - foreach ($this->getIdColumn() as $index => $column) { - $query->condition($column, current($this->getColumnFromIds(array($id), $index))); - } - // Build the update array. $request = $this->getRequest(); static::cleanRequest($request); @@ -353,10 +365,13 @@ public function update($id, $full_replace = FALSE) { $original_request = $request; $public_fields = $this->getPublicFields(); - $fields = array(); + + $id_columns = $this->getIdColumn(); + + $record = array(); foreach ($public_fields as $public_field_name => $info) { + // Ignore passthrough public fields. if (!empty($info['create_or_update_passthrough'])) { - // Allow passing the value in the request. unset($original_request[$public_field_name]); continue; } @@ -365,33 +380,39 @@ public function update($id, $full_replace = FALSE) { if ($this->isPrimaryField($info['property'])) { continue; } - // Check if the public property is set in the payload. - if (!isset($request[$public_field_name])) { - if ($full_replace) { - $fields[$info['property']] = NULL; - } + + if (isset($request[$public_field_name])) { + $record[$info['property']] = $request[$public_field_name]; } - else { - $fields[$info['property']] = $request[$public_field_name]; + // For unset fields on full updates, pass NULL to drupal_write_record(). + elseif ($full_replace) { + $record[$info['property']] = NULL; } unset($original_request[$public_field_name]); $save = TRUE; } + // No request was sent. if (!$save) { - // No request was sent. throw new \RestfulBadRequestException('No values were sent with the request.'); } - if ($original_request) { - // Request had illegal values. + // If the original request is not empty, then illegal values are present. + if (!empty($original_request)) { $error_message = format_plural(count($original_request), 'Property @names is invalid.', 'Property @names are invalid.', array('@names' => implode(', ', array_keys($original_request)))); throw new \RestfulBadRequestException($error_message); } - // Once the update array is built, execute the query. - $query->fields($fields)->execute(); + // Add the id column values into the record. + foreach ($this->getIdColumn() as $index => $column) { + $record[$column] = current($this->getColumnFromIds(array($id), $index)); + } + + // Once the record is built, write it. + if (!drupal_write_record($this->getTableName(), $record, $id_columns)) { + throw new \RestfulServiceUnavailable('Record could not be updated to the database.'); + } // Clear the rendered cache before calling the view method. $this->clearRenderedCache(array( @@ -399,28 +420,27 @@ public function update($id, $full_replace = FALSE) { 'cl' => implode(',', $this->getIdColumn()), 'id' => $id, )); - return $this->view($id, TRUE); + + return $this->view($id); } /** * {@inheritdoc} */ public function create() { - $query = db_insert($this->getTableName()); - - // Build the update array. $request = $this->getRequest(); static::cleanRequest($request); $save = FALSE; $original_request = $request; $public_fields = $this->getPublicFields(); - $fields = array(); - $id_values = array_fill(0, count($this->getIdColumn()), FALSE); + $id_columns = $this->getIdColumn(); + + $record = array(); foreach ($public_fields as $public_field_name => $info) { + // Ignore passthrough public fields. if (!empty($info['create_or_update_passthrough'])) { - // Allow passing the value in the request. unset($original_request[$public_field_name]); continue; } @@ -431,46 +451,38 @@ public function create() { continue; } - // Check if the public property is set in the payload. - if (($index = array_search($info['property'], $this->getIdColumn())) !== FALSE) { - $id_values[$index] = $request[$public_field_name]; - } - if (isset($request[$public_field_name])) { - $fields[$info['property']] = $request[$public_field_name]; + $record[$info['property']] = $request[$public_field_name]; } unset($original_request[$public_field_name]); $save = TRUE; } + // No request was sent. if (!$save) { - // No request was sent. throw new \RestfulBadRequestException('No values were sent with the request.'); } - if ($original_request) { - // Request had illegal values. + // If the original request is not empty, then illegal values are present. + if (!empty($original_request)) { $error_message = format_plural(count($original_request), 'Property @names is invalid.', 'Property @names are invalid.', array('@names' => implode(', ', array_keys($original_request)))); throw new \RestfulBadRequestException($error_message); } - $passed_id = NULL; - - // If we have the full primary key passed use it. - if (count(array_filter($id_values)) == count($id_values)) { - $passed_id = implode(self::COLUMN_IDS_SEPARATOR, $id_values); - } + // Once the record is built, write it and view it. + if (drupal_write_record($this->getTableName(), $record)) { + // Handle multiple id columns. + $id_values = array(); + foreach ($id_columns as $id_column) { + $id_values[$id_column] = $record[$id_column]; + } + $id = implode(self::COLUMN_IDS_SEPARATOR, $id_values); - // Once the update array is built, execute the query. - if ($id = $query->fields($fields)->execute()) { - return $this->view($id, TRUE); + return $this->view($id); } + return; - // Some times db_insert() does not know how to get the ID. - if ($passed_id) { - return $this->view($passed_id); - } } /** diff --git a/plugins/restful/RestfulDataProviderVariable.php b/plugins/restful/RestfulDataProviderVariable.php new file mode 100644 index 00000000..234dcb75 --- /dev/null +++ b/plugins/restful/RestfulDataProviderVariable.php @@ -0,0 +1,283 @@ + 'ASC'); + } + + /** + * {@inheritdoc} + */ + public function getVariablesForList() { + // Map name and value to an indexed array structure. + foreach ($GLOBALS['conf'] as $variable_name => $variable_value) { + $variables[] = array( + 'name' => $variable_name, + 'value' => $variable_value, + ); + } + + // Apply pagination and sorting. + $this->applyListSort($variables); + $this->applyListPagination($variables); + + return $variables; + } + + /** + * Sort the list of variables. + * + * This data provider does not handle compound sorts; the last sort defined + * will be the one to take effect. + * + * @param array $variables + * An indexed array containing elements that represent each variable, each + * containing a name and a value. + */ + protected function applyListSort(array &$variables) { + $public_fields = $this->getPublicFields(); + + // Get the sorting options from the request object. + $sorts = $this->parseRequestForListSort(); + + $sorts = $sorts ? $sorts : $this->defaultSortInfo(); + + foreach ($sorts as $public_field_name => $direction) { + if (isset($public_fields[$public_field_name]['property'])) { + $property_name = $public_fields[$public_field_name]['property']; + // Only sort by name if it's different than Drupal's default. + if ($property_name == 'name' && $direction == 'DESC') { + $variables = array_reverse($variables); + } + } + } + + return $variables; + } + + /** + * Set correct page for the index within the array of variables. + * + * Determine the page that should be seen. Page 1 is actually index 0. + * + * @param array $variables + * An array keyed by variable name, valued by unserialized variable value. + * + * @throws \RestfulBadRequestException + */ + protected function applyListPagination(array &$variables) { + list($offset, $range) = $this->parseRequestForListPagination(); + $variables = array_slice($variables, $offset, $range); + } + + /** + * Returns the total count of all variables. + */ + public function getTotalCount() { + return count($GLOBALS['conf']); + } + + /** + * {@inheritdoc} + */ + public function index() { + $variables = $this->getVariablesForList(); + $return = array(); + foreach ($variables as $variable) { + $return[] = $this->mapVariableToPublicFields($variable); + } + + return $return; + } + + /** + * View a variable or multiple variables. + * + * @param string $name_string + * A string of variable names, separated by commas. + */ + public function view($name_string) { + $names = array_unique(array_filter(explode(',', $name_string))); + + $output = array(); + foreach ($names as $name) { + $output[] = $this->viewVariable($name); + } + + return $output; + } + + /** + * View a single variable. + * + * @param string $name_string + * A string of variable names, separated by commas. + */ + public function viewVariable($name) { + // Caching is done on the individual variables. + $cache_id = array( + 'tb' => 'variable', + 'id' => $name, + ); + $cached_data = $this->getRenderedCache($cache_id); + if (!empty($cached_data->data)) { + return $cached_data->data; + } + + $variable['name'] = $name; + $variable['value'] = variable_get($name); + + $return = $this->mapVariableToPublicFields($variable); + $this->setRenderedCache($return, $cache_id); + + return $return; + } + + /** + * Alias for $this->variableSet(). + * + * @param string $name + * The name of the variable to set a value for. + */ + public function replace($name) { + return $this->variableSet($name, TRUE); + } + + /** + * Alias for $this->variableSet(). + * + * The data structures of variable values are all different, therefore it's + * impossible to do a partial update in a generic way. + * + * @param string $name + * The name of the variable to set a value for. + * @param boolean $full_replace + * Completely replace variable values with supplied values. + */ + public function update($name, $full_replace = FALSE) { + return $this->variableSet($name, FALSE); + } + + /** + * Alias for $this->variableSet(). + */ + public function create() { + return $this->variableSet(); + } + + /** + * Sets a variable value. + * + * If no variable name is provided in the function call, such as for POST + * requests, then this method will get the name from the request body. + * + * @param string $name + * The name of the variable to set a value for. + * @param boolean $full_replace + * Completely replace variable values with supplied values. + */ + public function variableSet($name = NULL, $full_replace = TRUE) { + $request = $this->getRequest(); + static::cleanRequest($request); + + // Retrieve the name and value from the request, if present. + $public_fields = $this->getPublicFields(); + + // Set initial empty value for replace and create contexts. + if ($full_replace) { + $value = ''; + } + + foreach ($public_fields as $public_property => $info) { + // Set the name from the request if it wasn't provided. + if ($info['property'] == 'name' + && isset($request[$public_property]) + && empty($name)) { + $name = $request[$public_property]; + } + // Overwrite empty $value with value from the request, if given. + if ($info['property'] == 'value' && isset($request[$public_property])) { + $value = $request[$public_property]; + } + } + + if (isset($name)) { + if (isset($value)) { + variable_set($name, $value); + + // Clear the rendered cache before calling the view method. + $this->clearRenderedCache(array( + 'tb' => 'variable', + 'id' => $name, + )); + } + // Update contexts could have no value set; if so, do nothing. + + return $this->view($name); + } + else { + // We are in a create context with no name supplied. + throw new RestfulBadRequestException('No name property supplied'); + } + } + + /** + * {@inheritdoc} + */ + public function remove($name) { + variable_del($name); + $this->setHttpHeaders('Status', 204); + } + + /** + * Maps variable names and values to public fields. + * + * @param array $variable + * An array containing the name and value of the variable. + */ + public function mapVariableToPublicFields($variable) { + foreach ($this->getPublicFields() as $public_field_name => $info) { + if (!empty($info['property'])) { + if (isset($info['property']) && $info['property'] == 'name') { + $public_field_value = $variable['name']; + } + elseif (isset($info['property']) && $info['property'] == 'value') { + $public_field_value = $variable['value']; + } + else { + throw new RestfulBadRequestException("The only possible properties for the variable resource are 'name' and 'value'."); + } + } + // If no property is supplied, execute a callback, if given. + elseif ($info['callback']) { + $public_field_value = static::executeCallback($info['callback'], array($name)); + } + + // Modify the public field value using a process callback, if supplied. + if ($public_field_value && $info['process_callbacks']) { + foreach ($info['process_callbacks'] as $process_callback) { + $public_field_value = static::executeCallback($process_callback, array($public_field_value)); + } + } + + $return[$public_field_name] = $public_field_value; + } + + return $return; + } +} diff --git a/restful.info b/restful.info index 8240aa9e..b1765b02 100644 --- a/restful.info +++ b/restful.info @@ -22,6 +22,8 @@ files[] = plugins/restful/RestfulDataProviderDbQuery.php files[] = plugins/restful/RestfulDataProviderDbQueryInterface.php files[] = plugins/restful/RestfulDataProviderEFQ.php files[] = plugins/restful/RestfulDataProviderEFQInterface.php +files[] = plugins/restful/RestfulDataProviderVariable.php +files[] = plugins/restful/RestfulDataProviderVariableInterface.php files[] = plugins/restful/RestfulDataProviderInterface.php files[] = plugins/restful/RestfulEntityBase.php files[] = plugins/restful/RestfulEntityBaseMultipleBundles.php @@ -65,6 +67,7 @@ files[] = tests/RestfulCsrfTokenTestCase.test files[] = tests/RestfulCurlBaseTestCase.test files[] = tests/RestfulDataProviderCToolsPluginsTestCase.test files[] = tests/RestfulDbQueryTestCase.test +files[] = tests/RestfulVariableTestCase.test files[] = tests/RestfulDiscoveryTestCase.test files[] = tests/RestfulEntityAndPropertyAccessTestCase.test files[] = tests/RestfulEntityUserAccessTestCase.test diff --git a/tests/RestfulDbQueryTestCase.test b/tests/RestfulDbQueryTestCase.test index 7899e494..4b670018 100644 --- a/tests/RestfulDbQueryTestCase.test +++ b/tests/RestfulDbQueryTestCase.test @@ -30,22 +30,25 @@ class RestfulDbQueryTestCase extends DrupalWebTestCase { */ function setUp() { parent::setUp('restful_test'); - - // Create the table to populate and query. - $schema = _restful_test_schema(); - db_create_table($this->tableName, $schema[$this->tableName]); } /** * Test authenticating a user. */ function testCrudOperations() { + $randomInt = intval(mt_rand(1, 100)); + $randomString = $this->randomName(); + $randomSerialized = serialize(array( + 'key1' => $randomInt, + 'key2' => $randomString, + )); + // Populate the table with some values. $mock_data = array( - 'str_field' => $this->randomName(), - 'int_field' => intval(mt_rand(1, 100)), + 'str_field' => $randomString, + 'int_field' => $randomInt, + 'serialized_field' => $randomSerialized, ); - $mock_data['serialized_field'] = serialize($mock_data); $id = db_insert($this->tableName) ->fields($mock_data) ->execute(); @@ -56,35 +59,59 @@ class RestfulDbQueryTestCase extends DrupalWebTestCase { // Get the handler. $handler = restful_get_restful_handler('db_query_test'); - // Testing read + // Testing read context. $result = $handler->get($id); $result = $result[0]; + $this->assertEqual($result['string'], $mock_data['str_field'], 'The record was retrieved successfully.'); $this->assertEqual($result['integer'], $mock_data['int_field'], 'The record was retrieved successfully.'); $this->assertEqual($result['serialized'], $mock_data['serialized_field'], 'The record was retrieved successfully.'); - // Testing update + // Testing update context. $mock_data2 = array( - 'integer' => $mock_data['int_field'], 'string' => $this->randomName(), ); - $handler->put($id, $mock_data2); + + $handler->patch($id, $mock_data2); $result = $handler->get($id); - // Remove nullified fields. - $result = array_filter($result[0]); - unset($result['id']); - $this->assertEqual($result, $mock_data2, 'The record was updated with PUT successfully.'); - - $mock_data3 = $mock_data2; - $mock_data3['string'] = $this->randomName(); - unset($mock_data3['integer']); - $handler->patch($id, $mock_data3); + + $expected = array( + // ID should be unchanged. + 'id' => $id, + // String should be the string that we updated. + 'string' => $mock_data2['string'], + // Serialized value should be unchanged. + 'serialized' => $randomSerialized, + // Integer value should be unchanged. + 'integer' => $randomInt, + ); + + // We expect that only the string field has changed. + $this->assertEqual($result[0], $expected, 'The record was updated with PUT successfully.'); + + + // Testing replace context. + $mock_data3 = array( + 'string' => $this->randomName(), + ); + $handler->put($id, $mock_data3); $result = $handler->get($id); - $result = array_filter($result[0]); - unset($result['id']); - $this->assertEqual($result, array_merge($mock_data2, $mock_data3), 'The record was updated with PATCH successfully.'); - // Testing delete + $expected = array( + // ID should be unchanged. + 'id' => $id, + // String should be the string that we PUT. + 'string' => $mock_data3['string'], + // Serialized field should be null. + 'serialized' => 'N;', + // Integer field should be default value from schema. + 'integer' => 0, + ); + + // We expect that only the supplied fields are present. + $this->assertEqual($result[0], $expected, 'The record was updated with PATCH successfully.'); + + // Testing delete context. $handler->delete($id); $count = db_select($this->tableName) ->countQuery() @@ -92,20 +119,34 @@ class RestfulDbQueryTestCase extends DrupalWebTestCase { ->fetchField(); $this->assertEqual($count, 0, 'The record was deleted successfully.'); - // Testing create - $mock_data4 = $mock_data2; - $mock_data4['serialized'] = serialize($mock_data4); + // Testing create context. + $mock_data4 = array( + 'string' => $randomString, + 'integer' => $randomInt, + 'serialized' => array( + 'key1' => $randomInt, + 'key2' => $randomString, + ) + ); $handler->post('', $mock_data4); + $count = db_select($this->tableName) ->countQuery() ->execute() ->fetchField(); $this->assertEqual($count, 1, 'The record was created.'); - // Testing list. + // Testing listing for read context. $result = $handler->get(); + + // The created record should match our input. + $expected = $mock_data4; + // Account for serialization. + $expected['serialized'] = $randomSerialized; + // Account for not knowing the ID of the new entity beforehand. unset($result[0]['id']); - $this->assertEqual($result, array($mock_data4), 'All the content listed successfully.'); + + $this->assertEqual($result[0], $expected, 'All the content listed successfully.'); // Testing filters. $mock_data5 = array( @@ -116,6 +157,7 @@ class RestfulDbQueryTestCase extends DrupalWebTestCase { db_insert($this->tableName) ->fields($mock_data5) ->execute(); + $mock_data6 = array( 'str_field' => $this->randomName(), 'int_field' => 102, diff --git a/tests/RestfulPassThroughTestCase.test b/tests/RestfulPassThroughTestCase.test index 9fca007c..2b077796 100644 --- a/tests/RestfulPassThroughTestCase.test +++ b/tests/RestfulPassThroughTestCase.test @@ -24,10 +24,6 @@ class RestfulPassThroughTestCase extends RestfulCurlBaseTestCase { function setUp() { parent::setUp('restful_test', 'restful_example'); - - // Create the table to populate and query. - $schema = _restful_test_schema(); - db_create_table($this->tableName, $schema[$this->tableName]); } /** diff --git a/tests/RestfulVariableTestCase.test b/tests/RestfulVariableTestCase.test new file mode 100644 index 00000000..cc19e9c3 --- /dev/null +++ b/tests/RestfulVariableTestCase.test @@ -0,0 +1,163 @@ + 'Variable', + 'description' => 'Test the variable data provider.', + 'group' => 'RESTful', + ); + } + + /** + * Operations before the testing begins. + */ + function setUp() { + parent::setUp('restful_example'); + } + + /** + * Test authenticating a user. + */ + function testCrudOperations() { + // Set up random content and resource handler. + $randomString = $this->randomName(); + $handler = restful_get_restful_handler('variables'); + + // Populate the test environment with variables. + $random_numbers = array(); + for ($i = 0; $i < 6; $i++) { + $random_numbers[] = intval(mt_rand(1, 100)); + variable_set('variable_' . $i, array('test_data' => $random_numbers[$i])); + } + + $this->assertTrue(variable_get('variable_5'), 'The variables have been set.'); + + // Testing read. + $results = $handler->get('variable_5'); + + $expected = array('test_data' => $random_numbers[5]); + + $this->assertEqual($results[0]['variable_name'], 'variable_5', 'The variable name was successfully retrieved.'); + $this->assertEqual($results[0]['variable_value'], $expected, 'The variable value was successfully retrieved.'); + + // Testing read context listing. + $results = $handler->get(); + $inResults = FALSE; + + foreach ($results as $result) { + if ($result['variable_name'] == 'variable_5') { + $inResults = TRUE; + } + } + $this->assertTrue($inResults, 'All the content listed successfully.'); + + + + // Testing sort for read context. + + // Set a variable that will probably sort last. + variable_set('zzzzz', 'some value'); + + // Find the last variable name, which will probably be the one we just set. + $request = array( + 'sort' => '-variable_name', + ); + $results = $handler->get('', $request); + $last_variable_name = $results[0]['variable_name']; + + // Generate a variable name that will always sort last. + $new_variable_name = 'zzz'; + while (strcmp($new_variable_name, $last_variable_name) <= 0) { + $new_variable_name .= 'z'; + } + + variable_set($new_variable_name, array('key' => $randomString)); + + $request = array( + 'sort' => '-variable_name', + ); + $results = $handler->get('', $request); + + $expected = array( + 'variable_name' => $new_variable_name, + 'variable_value' => array('key' => $randomString), + ); + + $this->assertEqual($results[0], $expected, 'List is sorted correctly.'); + + // Testing create. + $request = array( + 'variable_name' => 'created_variable', + 'variable_value' => $randomString, + ); + $handler->post('', $request); + $results = $handler->get('created_variable'); + + $this->assertEqual($results[0]['variable_name'], 'created_variable', 'The variable was created.'); + $this->assertEqual($results[0]['variable_value'], $randomString, 'The created variable value is present.'); + + // Testing update. + $request = array( + 'variable_name' => 'created_variable' + ); + $handler->patch('created_variable', $request); + $results = $handler->get('created_variable'); + + // Fields that are not supplied should not be updated. + $this->assertEqual($results[0]['variable_value'], $randomString, 'The variable value was not updated.'); + + // Testing replace. + $handler->put('created_variable', $request); + $results = $handler->get('created_variable'); + + // Fields that are not supplied should be NULL. + $this->assertFalse($results[0]['variable_value'], 'The variable value was removed.'); + + // Testing delete. + $handler->delete('created_variable'); + $deleted = !variable_get('created_variable'); + $this->assertTrue($deleted); + } + + /** + * Test the render cache. + */ + public function testRenderCache() { + // Create a test variable. + $handler = restful_get_restful_handler('variables'); + + $request = array( + 'variable_name' => 'test_variable_cache', + 'variable_value' => TRUE, + ); + $handler->post('', $request); + $created = variable_get('test_variable_cache'); + $this->assertNotNull($created, 'The cache variable has been created.'); + + // Populate the cache entries. + $account = $this->drupalCreateUser(); + $handler->setAccount($account); + $handler->get('test_variable_cache'); + + // Get the cache value. + $cache = $handler->getCacheController(); + $version = $handler->getVersion(); + $cid = 'v'. $version['major'] . '.' . $version['minor'] . '::variables::uu' . $account->uid . '::patb:variable::id:' . 'test_variable_cache'; + $cache_data = $cache->get($cid); + + $this->assertNotNull($cache_data->data, 'Cache data is present.'); + $this->assertEqual($cache_data->data['variable_name'], 'test_variable_cache', 'The variable name was retrieved from the cache.'); + $this->assertEqual($cache_data->data['variable_value'], TRUE, 'The variable value was retrieved from the cache.'); + } + +} diff --git a/tests/modules/restful_test/restful_test.install b/tests/modules/restful_test/restful_test.install index 69b46161..c53b4e01 100644 --- a/tests/modules/restful_test/restful_test.install +++ b/tests/modules/restful_test/restful_test.install @@ -54,5 +54,37 @@ function restful_test_schema() { 'primary key' => array('pid'), ); + // Defining table via hook_install() due to drupal_write_record(). + $schema['restful_test_db_query'] = array( + 'description' => 'Table for DbQuery testing.', + 'fields' => array( + 'id' => array( + 'description' => 'The primary identifier for a record.', + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'str_field' => array( + 'description' => 'String piece of data.', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), + 'int_field' => array( + 'description' => 'An int piece of data.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + 'serialized_field' => array( + 'description' => 'An serialized piece of data.', + 'type' => 'blob', + 'serialize' => TRUE, + ), + ), + 'primary key' => array('id'), + ); + return $schema; } diff --git a/tests/modules/restful_test/restful_test.module b/tests/modules/restful_test/restful_test.module index 8b869388..56f319af 100644 --- a/tests/modules/restful_test/restful_test.module +++ b/tests/modules/restful_test/restful_test.module @@ -417,49 +417,6 @@ function restful_test_create_node_with_tags() { return $node; } -/** - * Instead of implementing hook_schema use this helper function. - * - * In order to not to delay all tests using the test module. Only create the - * table when necessary. - * - * @return array - * A Schema API definition. - */ -function _restful_test_schema() { - $schema['restful_test_db_query'] = array( - - 'description' => 'Table for DbQuery testing.', - 'fields' => array( - 'id' => array( - 'description' => 'The primary identifier for a record.', - 'type' => 'serial', - 'unsigned' => TRUE, - ), - 'str_field' => array( - 'description' => 'String piece of data.', - 'type' => 'varchar', - 'length' => 32, - 'not null' => TRUE, - 'default' => '', - ), - 'int_field' => array( - 'description' => 'An int piece of data.', - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - ), - 'serialized_field' => array( - 'description' => 'An serialized piece of data.', - 'type' => 'blob', - 'serialize' => TRUE, - ), - ), - 'primary key' => array('id'), - ); - return $schema; -} - /** * Implements hook_entity_info(). */