Index: docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi.module =================================================================== --- docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi.module (revision 52526) +++ docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi.module (working copy) @@ -424,6 +424,13 @@ if (!empty($security_review_results)) { $additional_data['security_review'] = $security_review_results['security_review']; } + + // Collect user-contributed custom tests. + $custom_tests_results = acquia_spi_test_collect(); + if (!empty($custom_tests_results)) { + $additional_data['custom_tests'] = $custom_tests_results; + } + $spi_data = module_invoke_all('acquia_spi_get'); if (!empty($spi_data)) { foreach ($spi_data as $name => $data) { Index: docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.admin.inc =================================================================== --- docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.admin.inc (revision 0) +++ docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.admin.inc (working copy) @@ -0,0 +1,165 @@ + t('Module'),'field' => 'module_name'), + array('data' => t('Test Name'),'field' => 'test_name'), + array('data' => t('Field Name'), 'field' => 'field_name'), + array('data' => t('Current Value')), + array('data' => t('Message')), + array('data' => t('Action')), + ); + + $query = db_select('acquia_spi_test_error', 'a') + ->fields('a', array('eid', 'module_name','test_name', 'field_name', 'value',)) + ->extend('PagerDefault') + ->limit(25) + ->extend('TableSort') + ->orderByHeader($header); + + $rows = array(); + foreach ($query->execute() as $failure) { + $failure = (array) $failure; + $row = array( + check_plain($failure['module_name']), + check_plain($failure['test_name']), + check_plain($failure['field_name']), + check_plain($failure['value']), + t(check_plain(acquia_spi_test_message_generate($failure['field_name'], $failure['value']))), + l('Delete', 'admin/reports/acquia-spi-errors/delete/' . $failure['eid']), + ); + $rows[$failure['eid']] = $row; + } + + $form['table'] = array( + '#type' => 'tableselect', + '#header' => $header, + '#options' => $rows, + '#empty' => t('No content available.'), + ); + $form['pager'] = array( + '#theme' => 'pager' + ); + + // Delete buttons. + $form['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete selected'), + '#submit' => array('acquia_spi_test_clear_error_submit'), + ); + $form['delete_all'] = array( + '#type' => 'submit', + '#value' => t('Delete all'), + '#submit' => array('acquia_spi_test_clear_error_submit'), + ); + + return $form; +} + +/** + * Form validation handler for acquia_spi_test_admin_form(). + * + */ +function acquia_spi_test_error_form_validate($form, $form_state) { + + // Collect all selected values. + $selected = array_filter($form_state['values']['table']); + + if ($form_state['values']['op'] == t('Delete selected') && empty($selected)) { + form_set_error('type', t('You must select at least one item to delete.')); + } +} + +/** + * Form submission handler for acquia_spi_test_admin_form(). + * + */ +function acquia_spi_test_clear_error_submit($form, $form_state) { + + $op = $form_state['values']['op']; + switch ($op) { + // Clear the specified by error id(s). + case t('Delete selected'): + $delete = array_filter($form_state['values']['table']); + db_delete('acquia_spi_test_error') + ->condition('eid', $delete) + ->execute(); + drupal_set_message(t('The selected test errors were cleared.')); + break; + + // Clear all errors. + case t('Delete all'): + db_delete('acquia_spi_test_error') + ->execute(); + drupal_set_message(t('All test errors were cleared.')); + break; + } +} + +/** + * Generates a message detailing the source of the error. + * + * @param string $field_name + * The name of the parameter with the error. + * @param mixed $value + * The current value of the parameter. + * + * @return $string $message + * The error that needs to be resolved within the custom test. + * + */ +function acquia_spi_test_message_generate($field_name, $value) { + + $categories = acquia_spi_test_valid_categories(); + $severities = acquia_spi_test_valid_severities(); + + switch ($field_name) { + case 'category': + $message = 'Value must be a string and one of: ' . str_replace('_', ' ', implode(', ', $categories)); + break; + + case 'solved': + $message = 'Value must be a boolean.'; + break; + + case 'severity': + $message = 'Value must be an integer and set to one of: ' . implode(', ', $severities); + break; + + default: + $message = 'Value must be a string.'; + break; + } + + return $message; +} + +/** + * Deletes a single item from the error table. + * + * @param int $eid + * The unique identifier of the error to remove. + * + */ +function acquia_spi_test_admin_delete($eid) { + + $result = db_delete('acquia_spi_test_error') + ->condition('eid', $eid) + ->execute(); + + drupal_goto('admin/reports/acquia-spi-errors'); +} Index: docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.api.php =================================================================== --- docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.api.php (revision 0) +++ docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.api.php (working copy) @@ -0,0 +1,35 @@ + array( + 'description' => 'This example test is useful.', + 'solved_message' => 'The test was successful', + 'failed_message' => 'The test has failed', + 'solved' => TRUE, + 'fix_details' => 'Please resolve this issue using this fix information.', + 'category' => 'best_practices', + 'severity' => 0, + ), + ); +} Index: docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.info =================================================================== --- docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.info (revision 0) +++ docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.info (working copy) @@ -0,0 +1,7 @@ +name = Acquia SPI User-Contributed Tests +description = "Send data for custom tests within your Drupal site (status, info, debugging, etc...) to the Acquia Network." +package = Acquia Network Connector +php = 5.0 +core = 7.x +dependencies[] = acquia_agent +dependencies[] = acquia_spi Index: docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.install =================================================================== --- docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.install (revision 0) +++ docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.install (working copy) @@ -0,0 +1,94 @@ + 'A log of Acquia SPI custom tests which failed validation.', + 'fields' => array( + 'eid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Unique event ID.', + ), + 'module_name' => array( + 'description' => 'The name of the module containing the failed test.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'test_name' => array( + 'description' => 'The name of the failed test.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'field_name' => array( + 'description' => 'The name of the field which failed validation.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'value' => array( + 'description' => 'The value of the field which failed validation.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + ), + 'primary key' => array('eid'), + 'indexes' => array( + 'module_name' => array('module_name'), + 'field_name' => array('field_name'), + ), + ); + + return $schema; +} + +/** + * Implements hook_requirements(). + * + */ +function acquia_spi_test_requirements($phase) { + $requirements = array(); + + switch ($phase) { + case 'runtime': + $result = acquia_spi_test_status(); + + if (!empty($result)) { + $modules = implode(', ', array_keys($result)); + $requirements['acquia_spi_test'] = array( + 'title' => 'Acquia Network SPI User-Contributed Tests', + 'description' => 'Custom tests within the following module(s) have ' . l('failed validation', 'admin/reports/acquia-spi-errors') . ' and will not be sent: ' . $modules, + 'value' => t('Failed'), + 'severity' => REQUIREMENT_ERROR, + ); + } + else { + $modules = implode(', ', module_implements('acquia_spi_test')); + $requirements['acquia_spi_test'] = array( + 'title' => 'Acquia Network SPI Custom Tests', + 'description' => t('Data is structured properly and is sending from: @modules', array('@modules' => $modules)), + 'value' => t('Validated'), + 'severity' => REQUIREMENT_OK, + ); + } + break; + } + + return $requirements; +} Index: docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.module =================================================================== --- docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.module (revision 0) +++ docroot/sites/all/modules/contrib/acquia_connector/acquia_spi/acquia_spi_test/acquia_spi_test.module (working copy) @@ -0,0 +1,208 @@ + t('Acquia SPI Custom Test Errors'), + 'page arguments' => array('acquia_spi_test_error_form'), + 'page callback' => 'drupal_get_form', + 'access arguments' => array('administer acquia spi data'), + // 'access callback' => '_acquia_spi_send_access', + 'file' => 'acquia_spi_test.admin.inc', + 'weight' => 100 + ); + $items['admin/reports/acquia-spi-errors/delete'] = array( + 'page callback' => 'acquia_spi_test_admin_delete', + 'access arguments' => array('administer acquia spi data'), + 'file' => 'acquia_spi_test.admin.inc', + 'type' => MENU_CALLBACK, + ); + + return $items; +} + +/** + * Implements hook_permissions(). + * + */ +function acquia_spi_test_permission() { + return array( + 'administer acquia spi data' => array( + 'title' => t('Administer Acquia SPI Data'), + 'description' => t('Configure Acquia SPI Data settings.'), + 'restrict access' => TRUE, + ), + ); +} + +/** + * Implements hook_modules_enabled(). + * + */ +function acquia_spi_test_modules_enabled($modules) { + + foreach ($modules as $module) { + if (function_exists($module . '_acquia_spi_test')) { + drupal_set_message(t("A new invokation of hook_acquia_spi_test() has been detected in @module.", array('@module' => $module))); + watchdog('acquia agent', t("A new invokation of hook_acquia_spi_test() has been detected in @module.", array('@module' => $module))); + } + } +} + +/** + * Collects all user-contributed test results that pass validation. + * + * @return array $custom_data + * An associative array containing properly formatted user-contributed tests. + * + */ +function acquia_spi_test_collect() { + + $custom_data = array(); + + // Collect all custom data provided by hook_insight_custom_data(). + $collections = module_invoke_all('acquia_spi_test'); + + foreach ($collections as $test_name => $test_params) { + $result = acquia_spi_test_validate(array($test_name => $test_params)); + + if ($result['result']) { + $custom_data[$test_name] = $test_params; + } + } + + return $custom_data; +} + +/** + * Determines the status of all user-contributed tests and logs any failures to + * a tracking table. + * + * @return array $custom_data + * An associative array containing any tests which failed validation. + * + */ +function acquia_spi_test_status() { + + $custom_data = array(); + + // Iterate through modules which contain hook_acquia_spi_test(). + foreach (module_implements('acquia_spi_test') as $module) { + $function = $module . '_acquia_spi_test'; + if (function_exists($function)) { + $result = acquia_spi_test_validate($function()); + + if (!$result['result']) { + $custom_data[$module] = $result; + + foreach ($result['failure'] as $test_name => $test_failures) { + foreach ($test_failures as $test_param => $test_value) { + db_insert('acquia_spi_test_error') + ->fields(array( + 'module_name' => $module, + 'field_name' => $test_param, + 'test_name' => $test_name, + 'value' => $test_value['value'], + )) + ->execute(); + } + } + } + } + } + + return $custom_data; +} + +/** + * Validates data from callbacks. + * + * @param array $collection + * An associative array containing a collection of user-contributed tests. + * + * @return array + * An associative array containing the validation result of the given tests, + * along with any failed parameters. + * + */ +function acquia_spi_test_validate($collection) { + + $result = TRUE; + $check_result_value = array(); + + // Load valid categories and severities. + $categories = acquia_spi_test_valid_categories(); + $severities = acquia_spi_test_valid_severities(); + + foreach ($collection as $machine_name => $tests) { + foreach ($tests as $check_name => $check_value) { + $check_name = strtolower($check_name); + $check_value = (is_string($check_value)) ? strtolower($check_value) : $check_value; + + // Validate the data inputs for each check. + switch ($check_name) { + case 'category': + if (!is_string($check_value) || !in_array($check_value, $categories)) { + $type = gettype($check_value); + $check_result_value['failed'][$machine_name][$check_name]['value'] = "$check_value ($type)"; + } + break; + + case 'solved': + if (!is_bool($check_value)) { + $type = gettype($check_value); + $check_result_value['failed'][$machine_name][$check_name]['value'] = "$check_value ($type)"; + } + break; + + case 'severity': + if (!is_int($check_value) || !in_array($check_value, $severities)) { + $type = gettype($check_value); + $check_result_value['failed'][$machine_name][$check_name]['value'] = "$check_value ($type)"; + } + break; + + default: + if (!is_string($check_value)) { + $type = gettype($check_value); + $check_result_value['failed'][$machine_name][$check_name]['value'] = "$check_value ($type)"; + } + break; + } + } + } + + // If there were any failures, the test has failed. Into exile it must go. + if (!empty($check_result_value)) { + $result = FALSE; + } + + return array('result' => $result, 'failure' => (isset($check_result_value['failed'])) ? $check_result_value['failed'] : array()); +} + +/** + * Returns all valid test categories. + * + */ +function acquia_spi_test_valid_categories() { + return array('performance', 'security', 'best_practices'); +} + +/** + * Returns all valid test severities. + * + */ +function acquia_spi_test_valid_severities() { + return array(0, 1, 2, 4, 8, 16, 32, 64, 128); +}