SilverStripe 4.x compatibility (#38)

* Update composer constraint for 4.x compat

* 4.x compatibility: Rename "code" to "src" and add PSR-4 autoloading

* Restructure code and tests for PSR-4

* Implement namespaces

* Implement namespaced throughout

* PSR-2 formatting updates, separate Result from CheckSuite, implement PSR-3 logging, fix tests

* FIX Routes and template location

* Update readme. Allow check classes to be namespaced or not.

* Add entry to changelog

* FIX Ensure DatabaseCheckTest always has a member. Allow strings or objects for $check in the suite

* Update readme to be clearer about passing checks with or without namespaces

* Revert namespace checking and implement Injector aliases instead. Update readme.
This commit is contained in:
Robbie Averill 2017-01-05 11:16:12 +13:00 committed by Damian Mooyman
parent 1f6ba594a6
commit 254ed4801f
37 changed files with 778 additions and 404 deletions

View File

@ -6,4 +6,4 @@ checks:
duplication: true
filter:
paths: [code/*, tests/*]
paths: [src/*, tests/*]

View File

@ -1,33 +1,21 @@
# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details
# See https://github.com/silverstripe/silverstripe-travis-support for setup details
sudo: false
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
env:
- DB=MYSQL CORE_RELEASE=3.2
matrix:
include:
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3.1
- php: 5.6
env: DB=PGSQL CORE_RELEASE=3.2
allow_failures:
- php: 7.0
- DB=MYSQL CORE_RELEASE=4
- DB=PGSQL CORE_RELEASE=4
before_script:
- composer self-update || true
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
- git clone git://github.com/silverstripe/silverstripe-travis-support.git ~/travis-support
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss
- cd ~/builds/ss
- composer install

29
.upgrade.yml Normal file
View File

@ -0,0 +1,29 @@
mappings:
EnvironmentCheck: SilverStripe\EnvironmentCheck\EnvironmentCheck
EnvironmentChecker: SilverStripe\EnvironmentCheck\EnvironmentChecker
EnvironmentCheckSuite: SilverStripe\EnvironmentCheck\EnvironmentCheckSuite
EnvironmentCheckSuiteResult: SilverStripe\EnvironmentCheck\EnvironmentCheckSuiteResult
DatabaseCheck: SilverStripe\EnvironmentCheck\Checks\DatabaseCheck
ExternalURLCheck: SilverStripe\EnvironmentCheck\Checks\ExternalURLCheck
FileAccessibilityAndValidationCheck: SilverStripe\EnvironmentCheck\Checks\FileAccessibilityAndValidationCheck
FileAgeCheck: SilverStripe\EnvironmentCheck\Checks\FileAgeCheck
FileWriteableCheck: SilverStripe\EnvironmentCheck\Checks\FileWriteableCheck
HasClassCheck: SilverStripe\EnvironmentCheck\Checks\HasClassCheck
HasFunctionCheck: SilverStripe\EnvironmentCheck\Checks\HasFunctionCheck
SMTPConnectCheck: SilverStripe\EnvironmentCheck\Checks\SMTPConnectCheck
SolrIndexCheck: SilverStripe\EnvironmentCheck\Checks\SolrIndexCheck
URLCheck: SilverStripe\EnvironmentCheck\Checks\URLCheck
DevCheckController: SilverStripe\EnvironmentCheck\Controllers\DevCheckController
DevHealthController: SilverStripe\EnvironmentCheck\Controllers\DevHealthController
EnvironmentCheckerTest: SilverStripe\EnvironmentCheck\Tests\EnvironmentCheckerTest
EnvironmentCheckerTest_CheckNoErrors: SilverStripe\EnvironmentCheck\Tests\EnvironmentCheckerTest_CheckNoErrors
EnvironmentCheckerTest_CheckWarnings: SilverStripe\EnvironmentCheck\Tests\EnvironmentCheckerTest_CheckWarnings
EnvironmentCheckerTest_CheckErrors: SilverStripe\EnvironmentCheck\Tests\EnvironmentCheckerTest_CheckErrors
DatabaseCheckTest: SilverStripe\EnvironmentCheck\Tests\Checks\DatabaseCheckTest
ExternalURLCheckTest: SilverStripe\EnvironmentCheck\Tests\Checks\ExternalURLCheckTest
FileWritableCheckTest: SilverStripe\EnvironmentCheck\Tests\Checks\FileWritableCheckTest
HasClassCheckTest: SilverStripe\EnvironmentCheck\Tests\Checks\HasClassCheckTest
HasFunctionCheckTest: SilverStripe\EnvironmentCheck\Tests\Checks\HasFunctionCheckTest
URLCheckTest: SilverStripe\EnvironmentCheck\Tests\Checks\URLCheckTest
DevCheckControllerTest: SilverStripe\EnvironmentCheck\Tests\Controllers\DevCheckControllerTest
DevHealthControllerTest: SilverStripe\EnvironmentCheck\Tests\Controllers\DevHealthControllerTest

View File

@ -1,5 +1,7 @@
<?php
// use SilverStripe\EnvironmentCheck\EnvironmentCheckSuite;
// // These power dev/health, which can be used by load balancers and other such systems
// EnvironmentCheckSuite::register('health', 'DatabaseCheck');

24
_config/injector.yml Normal file
View File

@ -0,0 +1,24 @@
---
Name: environmentcheckinjector
---
SilverStripe\Core\Injector\Injector:
DatabaseCheck:
class: SilverStripe\EnvironmentCheck\Checks\DatabaseCheck
ExternalURLCheck:
class: SilverStripe\EnvironmentCheck\Checks\ExternalURLCheck
FileAccessibilityAndValidationCheck:
class: SilverStripe\EnvironmentCheck\Checks\FileAccessibilityAndValidationCheck
FileAgeCheck:
class: SilverStripe\EnvironmentCheck\Checks\FileAgeCheck
FileWriteableCheck:
class: SilverStripe\EnvironmentCheck\Checks\FileWriteableCheck
HasClassCheck:
class: SilverStripe\EnvironmentCheck\Checks\HasClassCheck
HasFunctionCheck:
class: SilverStripe\EnvironmentCheck\Checks\HasFunctionCheck
SMTPConnectCheck:
class: SilverStripe\EnvironmentCheck\Checks\SMTPConnectCheck
SolrIndexCheck:
class: SilverStripe\EnvironmentCheck\Checks\SolrIndexCheck
URLCheck:
class: SilverStripe\EnvironmentCheck\Checks\URLCheck

View File

@ -1,9 +1,11 @@
---
Name: environmentcheckroutes
After: 'framework/*','cms/*'
After:
- 'framework/*'
- 'cms/*'
---
Director:
SilverStripe\Control\Director:
rules:
'health/check': 'DevHealthController'
'dev/check/$Suite': 'DevCheckController'
'health/check': 'Silverstripe\EnvironmentCheck\Controllers\DevHealthController'
'dev/check/$Suite': 'Silverstripe\EnvironmentCheck\Controllers\DevCheckController'

View File

@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [2.0.0] - unreleased
* Minimum versions required:
* SilverStripe 4.x
* PHP 5.5+
* PHP 7 supported
## [1.2.0]
* Fix broken badges

View File

@ -1,31 +1,34 @@
{
"name": "silverstripe/environmentcheck",
"description": "Provides an API for building environment tests",
"license": "BSD-3-Clause",
"type": "silverstripe-module",
"keywords": ["silverstripe", "testing", "environment", "check"],
"authors": [
{
"name": "Will Rossiter",
"email": "will@fullscreen.io"
},
{
"name": "Sam Minnee",
"email": "sam@silverstripe.com"
}
],
"require":
{
"silverstripe/framework": "~3.1"
},
"require-dev":
{
"hafriedlander/phockito": "dev-master"
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"license": "BSD-3-Clause"
"name": "silverstripe/environmentcheck",
"description": "Provides an API for building environment tests",
"license": "BSD-3-Clause",
"type": "silverstripe-module",
"keywords": ["silverstripe", "testing", "environment", "check"],
"authors": [
{
"name": "Will Rossiter",
"email": "will@fullscreen.io"
},
{
"name": "Sam Minnee",
"email": "sam@silverstripe.com"
}
],
"require": {
"silverstripe/framework": "^4.0@dev"
},
"require-dev": {
"hafriedlander/phockito": "dev-master"
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"SilverStripe\\EnvironmentCheck\\": "src/",
"SilverStripe\\EnvironmentCheck\\Tests\\": "tests/"
}
}
}

138
readme.md
View File

@ -1,6 +1,6 @@
# SilverStripe Environment Checker Module
[![Build Status](http://img.shields.io/travis/silverstripe-labs/silverstripe-environmentcheck.svg?style=flat-square)](https://travis-ci.org/silverstripe-labs/silverstripe-environmentcheck)
[![Build Status](http://img.shields.io/travis/silverstripe/silverstripe-environmentcheck.svg?style=flat-square)](https://travis-ci.org/silverstripe/silverstripe-environmentcheck)
[![Code Quality](http://img.shields.io/scrutinizer/g/silverstripe-labs/silverstripe-environmentcheck.svg?style=flat-square)](https://scrutinizer-ci.com/g/silverstripe-labs/silverstripe-environmentcheck)
[![Code Coverage](http://img.shields.io/scrutinizer/coverage/g/silverstripe-labs/silverstripe-environmentcheck.svg?style=flat-square)](https://scrutinizer-ci.com/g/silverstripe-labs/silverstripe-environmentcheck)
[![Version](http://img.shields.io/packagist/v/silverstripe/environmentcheck.svg?style=flat-square)](https://packagist.org/packages/silverstripe/environmentcheck)
@ -12,6 +12,13 @@ This module adds an API for running environment checks to your API.
* `dev/check` - An admin-only URL that performs a more comprehensive set of checks. This could be tied to a deployment system, for example.
* `dev/check/<suite>` - Check a specific suite (admin only)
## Requirements
* SilverStripe 4.x
* PHP 5.5+
For SilverStripe 3.x support, please use a `1.x` tagged release.
## Aren't these just unit tests?
Almost, but not really. Environment checks differ from unit tests in two important ways:
@ -29,11 +36,13 @@ You'll also need to run `/dev/build`.
### Activating Directly
Register checks in your own `_config.php` - see the `_config.php` in this module for some defaults.
Register checks in your own `_config.php` - see the `_config.php` in this module for some defaults. Don't forget to
either use a fully-qualified (namespaced) class name for `EnvironmentCheckSuite`, or `use` (import) the namespaced class
first.
```php
EnvironmentCheckSuite::register('health', 'DatabaseCheck', "Can we connect to the database?");
EnvironmentCheckSuite::register('check', 'URLCheck("")', "Is the homepage accessible?");
EnvironmentCheckSuite::register('health', 'DatabaseCheck', 'Can we connect to the database?');
EnvironmentCheckSuite::register('check', 'URLCheck("")', 'Is the homepage accessible?');
```
### Activating Via Config
@ -41,7 +50,7 @@ EnvironmentCheckSuite::register('check', 'URLCheck("")', "Is the homepage access
Register your checks on the `EnvironmentCheckSuite`. The same named check may be used multiple times.
```yaml
EnvironmentCheckSuite:
SilverStripe\EnvironmentCheck\EnvironmentCheckSuite:
registered_checks:
db:
definition: 'DatabaseCheck("Page")'
@ -61,7 +70,7 @@ You can also disable checks configured this way. This is handy if you want to ov
by some other module. Just set the "state" property of the check to "disabled" like this:
```yaml
EnvironmentCheckSuite:
SilverStripe\EnvironmentCheck\EnvironmentCheckSuite:
registered_checks:
db:
state: disabled
@ -77,7 +86,7 @@ EnvironmentCheckSuite:
This can be used to check that PHP modules or features are installed.
* `FileWriteableCheck`: Check that the given file is writeable.
* `FileAgeCheck`: Checks for the maximum age of one or more files or folders.
Useful for files which should be frequently auto-generated,
Useful for files which should be frequently auto-generated,
like static caches, as well as for backup files and folders.
* `ExternalURLCheck`: Checks that one or more URLs are reachable via HTTP.
* `SMTPConnectCheck`: Checks if the SMTP connection configured through PHP.ini works as expected.
@ -86,23 +95,23 @@ EnvironmentCheckSuite:
## Monitoring Checks
Checks will return an appropriate HTTP status code, so are easy to hook into common uptime montoring
solutions like pingdom.com.
solutions like pingdom.com.
You can also have the environment checker email results with the following configuration:
```yml
EnvironmentChecker:
SilverStripe\EnvironmentCheck\EnvironmentChecker:
email_results: true
to_email_address: support@test.com
from_email_address: admin@test.com
```
Errors can be logged via the standard SilverStripe logging. Each check will cause an individual log entry.
You can choose to enable logging separately for warnings and errors,
identified through the result of `EnvironmentCheck->check()`.
Errors can be logged via the standard SilverStripe PSR-3 compatible logging. Each check will cause an individual log
entry. You can choose to enable logging separately for warnings and errors, identified through the
result of `EnvironmentCheck->check()`.
```yml
EnvironmentChecker:
SilverStripe\EnvironmentCheck\EnvironmentChecker:
log_results_warning: true
log_results_error: true
```
@ -116,71 +125,88 @@ an administrator on the site.
You may wish to have an automated service check `dev/check` periodically, but not want to open it up for public access.
You can enable basic authentication by defining the following in your environment:
define('ENVCHECK_BASICAUTH_USERNAME', 'test');
define('ENVCHECK_BASICAUTH_PASSWORD', 'password');
```php
define('ENVCHECK_BASICAUTH_USERNAME', 'test');
define('ENVCHECK_BASICAUTH_PASSWORD', 'password');
```
Now if you access `dev/check` in a browser it will pop up a basic auth popup, and if the submitted username and password
match the ones defined the username and password defined in the environment, access will be granted to the page.
## Adding more checks
To add more checks, you should put additional `EnvironmentCheckSuite::register` calls into your `_config.php`. See the `_config.php` file of this module for examples.
To add more checks, you should put additional `EnvironmentCheckSuite::register` calls into your `_config.php`.
See the `_config.php` file of this module for examples.
```php
EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?");
EnvironmentCheckSuite::register('check', 'HasFunctionCheck("imagecreatetruecolor")', "Does PHP have GD2 support?");
```
:::php
EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?");
EnvironmentCheckSuite::register('check', 'HasFunctionCheck("imagecreatetruecolor")', "Does PHP have GD2 support?");
The first argument is the name of the check suite. There are two built-in check suites, "health", and "check", corresponding to the `health/check` and `dev/check` URLs. If you wish, you can create your own check suites and execute them on other URLs. You can also add a check to more than one suite by passing the first argument as an array.
The module comes bundled with a few checks in `DefaultHealthChecks.php`. However, to test your own application, you probably want to write custom checks.
To test your own application, you probably want to write custom checks:
* Implement the `EnvironmentCheck` interface
* Implement the `SilverStripe\EnvironmentCheck\EnvironmentCheck` interface
* Define the `check()` function, which returns a 2 element array:
* The first element is one of `EnvironmentCheck::OK`, `EnvironmentCheck::WARNING`, `EnvironmentCheck::ERROR`, depending on the status of the check
* The second element is a string describing the response.
Here is a simple example of how you might create a check to test your own code. In this example, we are checking that an instance of the `MyGateway` class will return "foo" when `call()` is called on it. Testing interfaces with 3rd party systems is a common use case for custom environment checks.
:::php
class MyGatewayCheck implements EnvironmentCheck {
protected $checkTable;
```php
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
class MyGatewayCheck implements EnvironmentCheck
{
protected $checkTable;
function check()
{
$g = new \MyGateway;
$response = $g->call();
$expectedResponse = 'foo';
if($response == null) {
return array(EnvironmentCheck::ERROR, "MyGateway didn't return a response");
} else if($response != $expectedResponse) {
return array(EnvironmentCheck::WARNING, "MyGateway returned unexpected response $response");
}
return array(EnvironmentCheck::OK, '');
}
}
```
function check() {
$g = new MyGateway;
$response = $g->call();
$expectedResponse = "foo";
if($response == null) {
return array(EnvironmentCheck::ERROR, "MyGateway didn't return a response");
} else if($response != $expectedResponse) {
return array(EnvironmentCheck::WARNING, "MyGateway returned unexpected response $response");
} else {
return array(EnvironmentCheck::OK, "");
}
}
}
Once you have created your custom check class, don't forget to register it in a check suite
:::php
EnvironmentCheckSuite::register('check', 'MyGatewayCheck', "Can I connect to the gateway?");
```php
EnvironmentCheckSuite::register('check', 'MyGatewayCheck', 'Can I connect to the gateway?');
```
### Using other environment check suites
If you want to use the same UI as `health/check` and dev/check, you can create an `EnvironmentChecker` object. This class is a `RequestHandler` and so can be returned from an action handler. The first argument to the `EnvironmentChecker` constructor is the suite name. For example:
If you want to use the same UI as `health/check` and `dev/check`, you can create an `EnvironmentChecker` object. This class is a `RequestHandler` and so can be returned from an action handler. The first argument to the `EnvironmentChecker` constructor is the suite name. For example:
class DevHealth extends Controller {
function index() {
$e = new EnvironmentChecker('health', 'Site health');
return $e;
}
}
If you wish to embed an environment check suite in another, you can use the following call.
```php
use SilverStripe\Control\Controller;
class DevHealth extends Controller
{
function index()
{
$e = new EnvironmentChecker('health', 'Site health');
return $e;
}
}
```
If you wish to embed an environment check suite in another, you can use the following call:
```php
$result = EnvironmentCheckSuite::inst('health')->run();
```
$result = EnvironmentCheckSuite::inst("health")->run();
`$result` will contain a `EnvironmentCheckSuiteResult` object
* `$result->ShouldPass()`: Return a boolean of whether or not the tests passed.
@ -197,4 +223,4 @@ All methods, with `public` visibility, are part of the public API. All other met
## Reporting Issues
Please [create an issue](http://github.com/silverstripe-labs/silverstripe-environmentcheck/issues) for any bugs you've found, or features you're missing.
Please [create an issue](http://github.com/silverstripe/silverstripe-environmentcheck/issues) for any bugs you've found, or features you're missing.

View File

@ -1,8 +1,15 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\ORM\DB;
/**
* Check that the connection to the database is working, by ensuring that the table exists and that
* the table contains some records.
*
* @package environmentcheck
*/
class DatabaseCheck implements EnvironmentCheck
{
@ -13,28 +20,28 @@ class DatabaseCheck implements EnvironmentCheck
*
* @param string $checkTable
*/
public function __construct($checkTable = "Member")
public function __construct($checkTable = 'Member')
{
$this->checkTable = $checkTable;
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
public function check()
{
if (!DB::getConn()->hasTable($this->checkTable)) {
if (!DB::get_schema()->hasTable($this->checkTable)) {
return array(EnvironmentCheck::ERROR, "$this->checkTable not present in the database");
}
$count = DB::query("SELECT COUNT(*) FROM \"$this->checkTable\"")->value();
if ($count > 0) {
return array(EnvironmentCheck::OK, "");
} else {
return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records");
return array(EnvironmentCheck::OK, '');
}
return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records");
}
}

View File

@ -1,12 +1,18 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Checks that one or more URLs are reachable via HTTP.
* Note that the HTTP connectivity can just be verified from the server to the remote URL,
* it can still fail if the URL in question is requested by the client, e.g. through an iframe.
*
*
* Requires curl to present, so ensure to check it before with the following:
* <code>EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?");</code>
*
* @package environmentcheck
*/
class ExternalURLCheck implements EnvironmentCheck
{
@ -33,7 +39,7 @@ class ExternalURLCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
@ -52,7 +58,7 @@ class ExternalURLCheck implements EnvironmentCheck
foreach ($chs as $ch) {
curl_multi_add_handle($mh, $ch);
}
$active = null;
// Execute the handles
do {
@ -95,12 +101,12 @@ class ExternalURLCheck implements EnvironmentCheck
curl_multi_remove_handle($mh, $ch);
}
curl_multi_close($mh);
if ($hasError) {
return array(EnvironmentCheck::ERROR, implode(', ', $msgs));
} else {
return array(EnvironmentCheck::OK, implode(', ', $msgs));
}
return array(EnvironmentCheck::OK, implode(', ', $msgs));
}
/**

View File

@ -1,5 +1,10 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\ORM\Versioning\Versioned;
/**
* Checks for the accessibility and file type validation of one or more files or folders.
*
@ -8,16 +13,18 @@
* EnvironmentCheckSuite::register('check', 'FileAccessibilityAndValidationCheck("' . BASE_PATH . '/assets/calculator_files/*.json",
* "jsonValidate", '.FileAccessibilityAndValidationCheck::CHECK_ALL.')', 'Check a json file exist and are all valid json files'
* );
*
*
* // Checks /assets/calculator_files/calculator.json exists and is valid json file.
* EnvironmentCheckSuite::register('check', 'FileAccessibilityAndValidationCheck("' . BASE_PATH . '/assets/calculator_files/calculator.json",
* "jsonValidate", '.FileAccessibilityAndValidationCheck::CHECK_SINGLE.')', 'Check a calculator.json exists and is valid json file'
* );
*
* // Check only existence
* // Check only existence
* EnvironmentCheckSuite::register('check', 'FileAccessibilityAndValidationCheck("' . BASE_PATH . '/assets/calculator_files/calculator.json")',
* 'Check a calculator.json exists only'
* );
*
* @package environmentcheck
*/
class FileAccessibilityAndValidationCheck implements EnvironmentCheck
{
@ -60,12 +67,12 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
public function __construct($path, $fileTypeValidateFunc = 'noVidation', $checkType = null)
{
$this->path = $path;
$this->fileTypeValidateFunc = ($fileTypeValidateFunc)? $fileTypeValidateFunc:'noVidation';
$this->fileTypeValidateFunc = ($fileTypeValidateFunc)? $fileTypeValidateFunc : 'noVidation';
$this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE;
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
@ -91,9 +98,9 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
// If at least one file was valid, count as passed
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
$validFileList = "\n";
$validFileList = PHP_EOL;
foreach ($validFiles as $vf) {
$validFileList .= $vf."\n";
$validFileList .= $vf . PHP_EOL;
}
if ($fileTypeValidateFunc == 'noVidation') {
$checkReturn = array(
@ -103,16 +110,20 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
} else {
$checkReturn = array(
EnvironmentCheck::OK,
sprintf('At least these file(s) passed file type validate function "%s": %s', $fileTypeValidateFunc, $validFileList)
sprintf(
'At least these file(s) passed file type validate function "%s": %s',
$fileTypeValidateFunc,
$validFileList
)
);
}
} else {
if (count($invalidFiles) == 0) {
$checkReturn = array(EnvironmentCheck::OK, 'All files valideted');
} else {
$invalidFileList = "\n";
$invalidFileList = PHP_EOL;
foreach ($invalidFiles as $vf) {
$invalidFileList .= $vf."\n";
$invalidFileList .= $vf . PHP_EOL;
}
if ($fileTypeValidateFunc == 'noVidation') {
@ -123,7 +134,11 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
} else {
$checkReturn = array(
EnvironmentCheck::ERROR,
sprintf('File(s) not passing the file type validate function "%s": %s', $fileTypeValidateFunc, $invalidFileList)
sprintf(
'File(s) not passing the file type validate function "%s": %s',
$fileTypeValidateFunc,
$invalidFileList
)
);
}
}
@ -156,9 +171,8 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
$json = json_decode(file_get_contents($file));
if (!$json) {
return false;
} else {
return true;
}
return true;
}
/**

View File

@ -1,23 +1,30 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\ORM\FieldType\DBDatetime;
/**
* Checks for the maximum age of one or more files or folders.
* Useful for files which should be frequently auto-generated,
* Useful for files which should be frequently auto-generated,
* like static caches, as well as for backup files and folders.
* Does NOT check for existence of a file (will silently fail).
*
* Examples:
* // Checks that Requirements::combine_files() has regenerated files in the last 24h
* EnvironmentCheckSuite::register(
* 'check',
* 'FileAgeCheck("' . ASSETS_PATH . '/_combined_files/*.js' . '", "-1 day", '>', " . FileAgeCheck::CHECK_ALL) . "'
* 'check',
* 'FileAgeCheck("' . ASSETS_PATH . '/_combined_files/*.js' . '", "-1 day", '>', " . FileAgeCheck::CHECK_ALL) . "'
* );
*
*
* // Checks that at least one backup folder has been created in the last 24h
* EnvironmentCheckSuite::register(
* 'check',
* 'FileAgeCheck("' . BASE_PATH . '/../backups/*' . '", "-1 day", '>', " . FileAgeCheck::CHECK_SINGLE) . "'
* 'check',
* 'FileAgeCheck("' . BASE_PATH . '/../backups/*' . '", "-1 day", '>', " . FileAgeCheck::CHECK_SINGLE) . "'
* );
*
* @package environmentcheck
*/
class FileAgeCheck implements EnvironmentCheck
{
@ -30,7 +37,7 @@ class FileAgeCheck implements EnvironmentCheck
* @var int
*/
const CHECK_ALL = 2;
/**
* Absolute path to a file or folder, compatible with glob().
*
@ -83,13 +90,13 @@ class FileAgeCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
public function check()
{
$cutoffTime = strtotime($this->relativeAge, SS_Datetime::now()->Format('U'));
$cutoffTime = strtotime($this->relativeAge, DBDatetime::now()->Format('U'));
$files = $this->getFiles();
$invalidFiles = array();
$validFiles = array();
@ -105,12 +112,15 @@ class FileAgeCheck implements EnvironmentCheck
$invalidFiles[] = $file;
if ($this->checkType == self::CHECK_ALL) {
return array(
EnvironmentCheck::ERROR,
sprintf(
'File "%s" doesn\'t match age check (compare %s: %s, actual: %s)',
$file, $this->compareOperand, date('c', $cutoffTime), date('c', $fileTime)
)
);
EnvironmentCheck::ERROR,
sprintf(
'File "%s" doesn\'t match age check (compare %s: %s, actual: %s)',
$file,
$this->compareOperand,
date('c', $cutoffTime),
date('c', $fileTime)
)
);
}
}
}
@ -119,16 +129,14 @@ class FileAgeCheck implements EnvironmentCheck
// If at least one file was valid, count as passed
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
return array(EnvironmentCheck::OK, '');
} else {
if (count($invalidFiles) == 0) {
return array(EnvironmentCheck::OK, '');
} else {
return array(
EnvironmentCheck::ERROR,
sprintf('No files matched criteria (%s %s)', $this->compareOperand, date('c', $cutoffTime))
);
}
}
if (count($invalidFiles) == 0) {
return array(EnvironmentCheck::OK, '');
}
return array(
EnvironmentCheck::ERROR,
sprintf('No files matched criteria (%s %s)', $this->compareOperand, date('c', $cutoffTime))
);
}
/**

View File

@ -1,7 +1,13 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check that the given file is writable.
*
* @package environmentcheck
*/
class FileWriteableCheck implements EnvironmentCheck
{
@ -19,7 +25,7 @@ class FileWriteableCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
@ -30,13 +36,13 @@ class FileWriteableCheck implements EnvironmentCheck
} else {
$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path);
}
if (file_exists($filename)) {
$isWriteable = is_writeable($filename);
} else {
$isWriteable = is_writeable(dirname($filename));
}
if (!$isWriteable) {
if (function_exists('posix_getgroups')) {
$userID = posix_geteuid();
@ -45,10 +51,11 @@ class FileWriteableCheck implements EnvironmentCheck
$currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename));
$currentOwner = posix_getpwuid($currentOwnerID);
$message = "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe file is currently owned by '$currentOwner[name]'. ";
$message = "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe file is "
. "currently owned by '$currentOwner[name]'. ";
if ($user['name'] == $currentOwner['name']) {
$message .= "We recommend that you make the file writeable.";
$message .= 'We recommend that you make the file writeable.';
} else {
$groups = posix_getgroups();
$groupList = array();
@ -59,19 +66,22 @@ class FileWriteableCheck implements EnvironmentCheck
}
}
if ($groupList) {
$message .= " We recommend that you make the file group-writeable and change the group to one of these groups:\n - ". implode("\n - ", $groupList)
$message .= " We recommend that you make the file group-writeable and change the group to "
. "one of these groups:\n - " . implode("\n - ", $groupList)
. "\n\nFor example:\nchmod g+w $filename\nchgrp " . $groupList[0] . " $filename";
} else {
$message .= " There is no user-group that contains both the web-server user and the owner of this file. Change the ownership of the file, create a new group, or temporarily make the file writeable by everyone during the install process.";
$message .= " There is no user-group that contains both the web-server user and the owner "
. "of this file. Change the ownership of the file, create a new group, or temporarily "
. "make the file writeable by everyone during the install process.";
}
}
} else {
$message = "The webserver user needs to be able to write to this file:\n$filename";
}
return array(EnvironmentCheck::ERROR, $message);
}
return array(EnvironmentCheck::OK,'');
return array(EnvironmentCheck::OK, '');
}
}

View File

@ -1,7 +1,13 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check that the given class exists.
*
* @package environmentcheck
*/
class HasClassCheck implements EnvironmentCheck
{
@ -19,7 +25,7 @@ class HasClassCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
@ -27,8 +33,7 @@ class HasClassCheck implements EnvironmentCheck
{
if (class_exists($this->className)) {
return array(EnvironmentCheck::OK, 'Class ' . $this->className.' exists');
} else {
return array(EnvironmentCheck::ERROR, 'Class ' . $this->className.' doesn\'t exist');
}
return array(EnvironmentCheck::ERROR, 'Class ' . $this->className.' doesn\'t exist');
}
}

View File

@ -1,7 +1,13 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check that the given function exists.
*
* @package environmentcheck
*/
class HasFunctionCheck implements EnvironmentCheck
{
@ -19,16 +25,15 @@ class HasFunctionCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
public function check()
{
if (function_exists($this->functionName)) {
return array(EnvironmentCheck::OK, $this->functionName.'() exists');
} else {
return array(EnvironmentCheck::ERROR, $this->functionName.'() doesn\'t exist');
return array(EnvironmentCheck::OK, $this->functionName . '() exists');
}
return array(EnvironmentCheck::ERROR, $this->functionName . '() doesn\'t exist');
}
}

View File

@ -1,9 +1,15 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Checks if the SMTP connection configured through PHP.ini works as expected.
*
* Only checks socket connection with HELO command, not actually sending the email.
*
* @package environmentcheck
*/
class SMTPConnectCheck implements EnvironmentCheck
{
@ -35,7 +41,7 @@ class SMTPConnectCheck implements EnvironmentCheck
if (!$this->host) {
$this->host = 'localhost';
}
$this->port = ($port) ? $port : ini_get('smtp_port');
if (!$this->port) {
$this->port = 25;
@ -45,7 +51,7 @@ class SMTPConnectCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
@ -64,7 +70,7 @@ class SMTPConnectCheck implements EnvironmentCheck
if (substr($response, 0, 3) != '220') {
return array(
EnvironmentCheck::ERROR,
sprintf("Invalid mail server response: %s", $response)
sprintf('Invalid mail server response: %s', $response)
);
}

View File

@ -1,9 +1,15 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check the availability of all Solr indexes of given class.
*
* If there are no indexes of given class found, the returned status will still be "OK".
*
* @package environmentcheck
*/
class SolrIndexCheck implements EnvironmentCheck
{
@ -21,7 +27,7 @@ class SolrIndexCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*/
@ -29,15 +35,18 @@ class SolrIndexCheck implements EnvironmentCheck
{
$brokenCores = array();
if (!class_exists('Solr')) {
/**
* @todo Revisit this when silverstripe/fulltextsearch has 4.x compat
*/
if (!class_exists('\\Solr')) {
return array(
EnvironmentCheck::ERROR,
'Class `Solr` not found. Is the fulltextsearch module installed?'
);
}
$service = Solr::service();
foreach (Solr::get_indexes($this->indexClass) as $index) {
$service = \Solr::service();
foreach (\Solr::get_indexes($this->indexClass) as $index) {
$core = $index->getIndexName();
if (!$service->coreIsActive($core)) {
$brokenCores[] = $core;

View File

@ -1,9 +1,16 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\Control\Director;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check that a given URL is functioning, by default, the homepage.
*
*
* Note that Director::test() will be used rather than a CURL check.
*
* @package environmentcheck
*/
class URLCheck implements EnvironmentCheck
{
@ -16,7 +23,7 @@ class URLCheck implements EnvironmentCheck
* @var string
*/
protected $testString;
/*
* @param string $url The URL to check, relative to the site (homepage is '').
* @param string $testString An optional piece of text to search for on the homepage.
@ -28,11 +35,10 @@ class URLCheck implements EnvironmentCheck
}
/**
* @inheritdoc
* {@inheritDoc}
*
* @return array
*
* @throws SS_HTTPResponse_Exception
* @throws HTTPResponse_Exception
*/
public function check()
{
@ -48,11 +54,10 @@ class URLCheck implements EnvironmentCheck
EnvironmentCheck::WARNING,
sprintf('Success retrieving "%s", but string "%s" not found', $this->url, $this->testString)
);
} else {
return array(
EnvironmentCheck::OK,
sprintf('Success retrieving "%s"', $this->url)
);
}
return array(
EnvironmentCheck::OK,
sprintf('Success retrieving "%s"', $this->url)
);
}
}

View File

@ -1,5 +1,15 @@
<?php
namespace SilverStripe\EnvironmentCheck\Controllers;
use SilverStripe\Control\Controller;
use SilverStripe\EnvironmentCheck\EnvironmentChecker;
/**
* Class DevCheckController
*
* @package environmentcheck
*/
class DevCheckController extends Controller
{
/**
@ -17,11 +27,11 @@ class DevCheckController extends Controller
private static $permission = 'ADMIN';
/**
* @param SS_HTTPRequest $request
* @param HTTPRequest $request
*
* @return EnvironmentChecker
*
* @throws SS_HTTPResponse_Exception
* @throws HTTPResponse_Exception
*/
public function index($request)
{

View File

@ -1,5 +1,15 @@
<?php
namespace SilverStripe\EnvironmentCheck\Controllers;
use SilverStripe\Control\Controller;
use SilverStripe\EnvironmentCheck\EnvironmentChecker;
/**
* Class DevHealthController
*
* @package environmentcheck
*/
class DevHealthController extends Controller
{
/**
@ -12,7 +22,7 @@ class DevHealthController extends Controller
/**
* @return EnvironmentChecker
*
* @throws SS_HTTPResponse_Exception
* @throws HTTPResponse_Exception
*/
public function index()
{

View File

@ -1,18 +1,22 @@
<?php
namespace SilverStripe\EnvironmentCheck;
/**
* Interface for environment checks
*
*
* An environment check is a test that can be performed on a live environment. They differ from
* unit tests in that they are designed to check the state of the environment/server, rather than
* the code.
*
*
* Environment checks should *never* alter production data.
*
*
* Some things you might make environment checks for:
* - Can I access the database?
* - Are the right PHP modules installed?
* - Are the file permissions correct?
*
* @package environmentcheck
*/
interface EnvironmentCheck
{

View File

@ -1,5 +1,15 @@
<?php
namespace SilverStripe\EnvironmentCheck;
use Exception;
use InvalidArgumentException;
use SilverStripe\Core\Object;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\ORM\ArrayList;
use SilverStripe\View\ArrayData;
use SilverStripe\View\ViewableData;
/**
* Represents a suite of environment checks.
* Specific checks can be registered against a named instance of EnvironmentCheckSuite.
@ -18,6 +28,8 @@
* - mycheck
*
* $result = EnvironmentCheckSuite::inst('health')->run();
*
* @package environmentcheck
*/
class EnvironmentCheckSuite extends Object
{
@ -77,10 +89,10 @@ class EnvironmentCheckSuite extends Object
// Existing named checks can be disabled by setting their 'state' to 'disabled'.
// This is handy for disabling checks mandated by modules.
if (!empty($check['state']) && $check['state']==='disabled') {
if (!empty($check['state']) && $check['state'] === 'disabled') {
continue;
}
// Add the check to this suite.
$this->push($check['definition'], $check['title']);
}
@ -114,6 +126,7 @@ class EnvironmentCheckSuite extends Object
* Get instances of all the environment checks.
*
* @return array
* @throws InvalidArgumentException
*/
protected function checkInstances()
{
@ -125,7 +138,9 @@ class EnvironmentCheckSuite extends Object
if ($checkInst instanceof EnvironmentCheck) {
$output[] = array($checkInst, $checkTitle);
} else {
throw new InvalidArgumentException("Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck");
throw new InvalidArgumentException(
"Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck"
);
}
} elseif ($checkClass instanceof EnvironmentCheck) {
$output[] = array($checkClass, $checkTitle);
@ -184,6 +199,7 @@ class EnvironmentCheckSuite extends Object
if (!is_array($names)) {
$names = array($names);
}
foreach ($names as $name) {
self::inst($name)->push($check, $title);
}
@ -197,106 +213,3 @@ class EnvironmentCheckSuite extends Object
self::$instances = array();
}
}
/**
* A single set of results from running an EnvironmentCheckSuite
*/
class EnvironmentCheckSuiteResult extends ViewableData
{
/**
* @var ArrayList
*/
protected $details;
/**
* @var int
*/
protected $worst = 0;
public function __construct()
{
parent::__construct();
$this->details = new ArrayList();
}
/**
* @param int $status
* @param string $message
* @param string $checkIdentifier
*/
public function addResult($status, $message, $checkIdentifier)
{
$this->details->push(new ArrayData(array(
'Check' => $checkIdentifier,
'Status' => $this->statusText($status),
'StatusCode' => $status,
'Message' => $message,
)));
$this->worst = max($this->worst, $status);
}
/**
* Returns true if there are no errors.
*
* @return bool
*/
public function ShouldPass()
{
return $this->worst <= EnvironmentCheck::WARNING;
}
/**
* Returns overall (i.e. worst) status as a string.
*
* @return string
*/
public function Status()
{
return $this->statusText($this->worst);
}
/**
* Returns detailed status information about each check.
*
* @return ArrayList
*/
public function Details()
{
return $this->details;
}
/**
* Convert the final result status and details to JSON.
*
* @return string
*/
public function toJSON()
{
$result = array(
'Status' => $this->Status(),
'ShouldPass' => $this->ShouldPass(),
'Checks' => array()
);
foreach ($this->details as $detail) {
$result['Checks'][] = $detail->toMap();
}
return json_encode($result);
}
/**
* Return a text version of a status code.
*
* @return string
*/
protected function statusText($status)
{
switch ($status) {
case EnvironmentCheck::ERROR: return "ERROR";
case EnvironmentCheck::WARNING: return "WARNING";
case EnvironmentCheck::OK: return "OK";
case 0: return "NO CHECKS";
default: throw new InvalidArgumentException("Bad environment check status '$status'");
}
}
}

View File

@ -0,0 +1,125 @@
<?php
namespace SilverStripe\EnvironmentCheck;
use InvalidArgumentException;
use SilverStripe\ORM\ArrayList;
use SilverStripe\View\ArrayData;
use SilverStripe\View\ViewableData;
/**
* A single set of results from running an EnvironmentCheckSuite
*
* @package environmentcheck
*/
class EnvironmentCheckSuiteResult extends ViewableData
{
/**
* @var ArrayList
*/
protected $details;
/**
* @var int
*/
protected $worst = 0;
public function __construct()
{
parent::__construct();
$this->details = new ArrayList();
}
/**
* @param int $status
* @param string $message
* @param string $checkIdentifier
*/
public function addResult($status, $message, $checkIdentifier)
{
$this->details->push(new ArrayData(array(
'Check' => $checkIdentifier,
'Status' => $this->statusText($status),
'StatusCode' => $status,
'Message' => $message,
)));
$this->worst = max($this->worst, $status);
}
/**
* Returns true if there are no errors.
*
* @return bool
*/
public function ShouldPass()
{
return $this->worst <= EnvironmentCheck::WARNING;
}
/**
* Returns overall (i.e. worst) status as a string.
*
* @return string
*/
public function Status()
{
return $this->statusText($this->worst);
}
/**
* Returns detailed status information about each check.
*
* @return ArrayList
*/
public function Details()
{
return $this->details;
}
/**
* Convert the final result status and details to JSON.
*
* @return string
*/
public function toJSON()
{
$result = array(
'Status' => $this->Status(),
'ShouldPass' => $this->ShouldPass(),
'Checks' => array()
);
foreach ($this->details as $detail) {
$result['Checks'][] = $detail->toMap();
}
return json_encode($result);
}
/**
* Return a text version of a status code.
*
* @param int $status
* @return string
* @throws InvalidArgumentException
*/
protected function statusText($status)
{
switch ($status) {
case EnvironmentCheck::ERROR:
return 'ERROR';
break;
case EnvironmentCheck::WARNING:
return 'WARNING';
break;
case EnvironmentCheck::OK:
return 'OK';
break;
case 0:
return 'NO CHECKS';
break;
default:
throw new InvalidArgumentException("Bad environment check status '$status'");
break;
}
}
}

View File

@ -1,7 +1,26 @@
<?php
namespace SilverStripe\EnvironmentCheck;
use Psr\Log\LogLevel;
use SilverStripe\Control\Director;
use SilverStripe\Control\Email\Email;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Control\RequestHandler;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Deprecation;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheckSuite;
use SilverStripe\Security\BasicAuth;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
/**
* Provides an interface for checking the given EnvironmentCheckSuite.
*
* @package environmentcheck
*/
class EnvironmentChecker extends RequestHandler
{
@ -43,24 +62,24 @@ class EnvironmentChecker extends RequestHandler
private static $email_results = false;
/**
* @var bool Log results via {@link SS_Log}
* @var bool Log results via {@link \Psr\Log\LoggerInterface}
*/
private static $log_results_warning = false;
/**
* @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::WARN
* @var string Maps to {@link \Psr\Log\LogLevel} levels. Defaults to LogLevel::WARNING
*/
private static $log_results_warning_level = 4;
private static $log_results_warning_level = LogLevel::WARNING;
/**
* @var bool Log results via {@link SS_Log}
* @var bool Log results via a {@link \Psr\Log\LoggerInterface}
*/
private static $log_results_error = false;
/**
* @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::ALERT
* @var int Maps to {@link \Psr\Log\LogLevel} levels. Defaults to LogLevel::ALERT
*/
private static $log_results_error_level = 1;
private static $log_results_error_level = LogLevel::ALERT;
/**
* @param string $checkSuiteName
@ -69,7 +88,7 @@ class EnvironmentChecker extends RequestHandler
public function __construct($checkSuiteName, $title)
{
parent::__construct();
$this->checkSuiteName = $checkSuiteName;
$this->title = $title;
}
@ -77,7 +96,7 @@ class EnvironmentChecker extends RequestHandler
/**
* @param string $permission
*
* @throws SS_HTTPResponse_Exception
* @throws HTTPResponse_Exception
*/
public function init($permission = 'ADMIN')
{
@ -85,24 +104,23 @@ class EnvironmentChecker extends RequestHandler
if (defined('ENVCHECK_BASICAUTH_USERNAME') && defined('ENVCHECK_BASICAUTH_PASSWORD')) {
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
// authenticate the input user/pass with the configured credentials
if (
!(
if (!(
$_SERVER['PHP_AUTH_USER'] == ENVCHECK_BASICAUTH_USERNAME
&& $_SERVER['PHP_AUTH_PW'] == ENVCHECK_BASICAUTH_PASSWORD
)
) {
$response = new SS_HTTPResponse(null, 401);
$response = new HTTPResponse(null, 401);
$response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
// Exception is caught by RequestHandler->handleRequest() and will halt further execution
$e = new SS_HTTPResponse_Exception(null, 401);
$e = new HTTPResponse_Exception(null, 401);
$e->setResponse($response);
throw $e;
}
} else {
$response = new SS_HTTPResponse(null, 401);
$response = new HTTPResponse(null, 401);
$response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
// Exception is caught by RequestHandler->handleRequest() and will halt further execution
$e = new SS_HTTPResponse_Exception(null, 401);
$e = new HTTPResponse_Exception(null, 401);
$e->setResponse($response);
throw $e;
}
@ -119,9 +137,9 @@ class EnvironmentChecker extends RequestHandler
*
* @return bool
*
* @throws SS_HTTPResponse_Exception
* @throws HTTPResponse_Exception
*/
public function canAccess($member = null, $permission = "ADMIN")
public function canAccess($member = null, $permission = 'ADMIN')
{
if (!$member) {
$member = Member::currentUser();
@ -133,8 +151,7 @@ class EnvironmentChecker extends RequestHandler
// We allow access to this controller regardless of live-status or ADMIN permission only
// if on CLI. Access to this controller is always allowed in "dev-mode", or of the user is ADMIN.
if (
Director::isDev()
if (Director::isDev()
|| Director::is_cli()
|| empty($permission)
|| Permission::checkMember($member, $permission)
@ -149,20 +166,19 @@ class EnvironmentChecker extends RequestHandler
if ($results && is_array($results)) {
if (!min($results)) {
return false;
} else {
return true;
}
return true;
}
return false;
}
/**
* @return SS_HTTPResponse
* @return HTTPResponse
*/
public function index()
{
$response = new SS_HTTPResponse;
$response = new HTTPResponse;
$result = EnvironmentCheckSuite::inst($this->checkSuiteName)->run();
if (!$result->ShouldPass()) {
@ -170,14 +186,19 @@ class EnvironmentChecker extends RequestHandler
}
$resultText = $result->customise(array(
"URL" => Director::absoluteBaseURL(),
"Title" => $this->title,
"Name" => $this->checkSuiteName,
"ErrorCode" => $this->errorCode,
))->renderWith("EnvironmentChecker");
'URL' => Director::absoluteBaseURL(),
'Title' => $this->title,
'Name' => $this->checkSuiteName,
'ErrorCode' => $this->errorCode,
))->renderWith(__CLASS__);
if ($this->config()->email_results && !$result->ShouldPass()) {
$email = new Email($this->config()->from_email_address, $this->config()->to_email_address, $this->title, $resultText);
$email = new Email(
$this->config()->from_email_address,
$this->config()->to_email_address,
$this->title,
$resultText
);
$email->send();
}
@ -197,8 +218,7 @@ class EnvironmentChecker extends RequestHandler
}
// output the result as JSON if requested
if (
$this->getRequest()->getExtension() == 'json'
if ($this->getRequest()->getExtension() == 'json'
|| strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false
) {
$response->setBody($result->toJSON());
@ -207,17 +227,19 @@ class EnvironmentChecker extends RequestHandler
}
$response->setBody($resultText);
return $response;
}
/**
* Sends a log entry to the configured PSR-3 LoggerInterface
*
* @param string $message
* @param int $level
*/
public function log($message, $level)
{
SS_Log::log($message, $level);
Injector::inst()->get('Logger')->log($level, $message);
}
/**
@ -237,7 +259,7 @@ class EnvironmentChecker extends RequestHandler
public static function set_from_email_address($from)
{
Deprecation::notice('2.0', 'Use config API instead');
Config::inst()->update('EnvironmentChecker', 'from_email_address', $from);
Config::inst()->update(__CLASS__, 'from_email_address', $from);
}
/**
@ -247,7 +269,7 @@ class EnvironmentChecker extends RequestHandler
public static function get_from_email_address()
{
Deprecation::notice('2.0', 'Use config API instead');
return Config::inst()->get('EnvironmentChecker', 'from_email_address');
return Config::inst()->get(__CLASS__, 'from_email_address');
}
/**
@ -257,7 +279,7 @@ class EnvironmentChecker extends RequestHandler
public static function set_to_email_address($to)
{
Deprecation::notice('2.0', 'Use config API instead');
Config::inst()->update('EnvironmentChecker', 'to_email_address', $to);
Config::inst()->update(__CLASS__, 'to_email_address', $to);
}
/**
@ -267,7 +289,7 @@ class EnvironmentChecker extends RequestHandler
public static function get_to_email_address()
{
Deprecation::notice('2.0', 'Use config API instead');
return Config::inst()->get('EnvironmentChecker', 'to_email_address');
return Config::inst()->get(__CLASS__, 'to_email_address');
}
/**
@ -277,7 +299,7 @@ class EnvironmentChecker extends RequestHandler
public static function set_email_results($results)
{
Deprecation::notice('2.0', 'Use config API instead');
Config::inst()->update('EnvironmentChecker', 'email_results', $results);
Config::inst()->update(__CLASS__, 'email_results', $results);
}
/**
@ -287,6 +309,6 @@ class EnvironmentChecker extends RequestHandler
public static function get_email_results()
{
Deprecation::notice('2.0', 'Use config API instead');
return Config::inst()->get('EnvironmentChecker', 'email_results');
return Config::inst()->get(__CLASS__, 'email_results');
}
}

View File

@ -10,7 +10,7 @@
margin-top: -10px;
font-size: 10px;
}
h1 {
font-size: 30px;
margin-bottom: 3px;
@ -21,11 +21,11 @@
font-size: 16px;
margin: 2px 0 10px 8px;
}
p {
margin-left: 10px;
}
table {
border-collapse: collapse;
}
@ -44,7 +44,7 @@
table tr:nth-child(odd) td {
background-color: #ddd;
}
.OK {
color: green;
}
@ -59,23 +59,23 @@
</style>
</head>
<body>
<h1 class="$Status">$Title: $Status</h1>
<h2 class="website">Site: $URL</h2>
<table>
<tr><th>Check</th> <th>Status</th> <th>Message</th></tr>
<% loop Details %>
<% loop $Details %>
<tr><td>$Check</td> <td class="$Status">$Status</td> <td>$Message.XML</td></tr>
<% end_loop %>
</table>
<% if ShouldPass %>
<% if $ShouldPass %>
<p>Site is available</p>
<p class="subtext">(you may check for the presence of the text 'Site is available' rather than an HTTP $ErrorCode error on this page, if you prefer.)</p>
<% else %>
<% if Name == check %>
<% if $Name == "check" %>
<p><b>A subsystem of the site is unavailable, but the site remains operational</b></p>
<% else %>
<p><b>Site is not available</b></p>

View File

@ -0,0 +1,40 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\EnvironmentCheck\Checks\DatabaseCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\Security\Member;
/**
* Class DatabaseCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class DatabaseCheckTest extends SapphireTest
{
/**
* {@inheritDoc}
* @var bool
*/
protected $usesDatabase = true;
public function testCheckReportsValidConnection()
{
$member = new Member;
$member->FirstName = 'Bob';
$member->write();
$check = new DatabaseCheck();
$expected = array(
EnvironmentCheck::OK,
''
);
$this->assertEquals($expected, $check->check());
}
}

View File

@ -1,7 +1,17 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\EnvironmentCheck\Checks\ExternalURLCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Class ExternalURLCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class ExternalURLCheckTest extends SapphireTest
{
@ -13,7 +23,7 @@ class ExternalURLCheckTest extends SapphireTest
$expected = array(
EnvironmentCheck::ERROR,
'Success retrieving "http://missing-site/" (Code: 404)',
'Success retrieving "http://missing-site/" (Code: 404)'
);
$this->assertEquals($expected, $check->check());

View File

@ -1,7 +1,17 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use SilverStripe\EnvironmentCheck\Checks\FileWriteableCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\Dev\SapphireTest;
/**
* Class FileWritableCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class FileWritableCheckTest extends SapphireTest
{
@ -11,7 +21,7 @@ class FileWritableCheckTest extends SapphireTest
$expected = array(
EnvironmentCheck::OK,
'',
''
);
$this->assertEquals($expected, $check->check());

View File

@ -1,7 +1,17 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\EnvironmentCheck\Checks\HasClassCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Class HasClassCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class HasClassCheckTest extends SapphireTest
{
@ -11,7 +21,7 @@ class HasClassCheckTest extends SapphireTest
$expected = array(
EnvironmentCheck::ERROR,
'Class foo doesn\'t exist',
'Class foo doesn\'t exist'
);
$this->assertEquals($expected, $check->check());

View File

@ -1,7 +1,17 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use SilverStripe\EnvironmentCheck\Checks\HasFunctionCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\Dev\SapphireTest;
/**
* Class HasFunctionCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class HasFunctionCheckTest extends SapphireTest
{
@ -11,7 +21,7 @@ class HasFunctionCheckTest extends SapphireTest
$expected = array(
EnvironmentCheck::ERROR,
'foo() doesn\'t exist',
'foo() doesn\'t exist'
);
$this->assertEquals($expected, $check->check());
@ -23,7 +33,7 @@ class HasFunctionCheckTest extends SapphireTest
$expected = array(
EnvironmentCheck::OK,
'class_exists() exists',
'class_exists() exists'
);
$this->assertEquals($expected, $check->check());

View File

@ -1,7 +1,17 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use SilverStripe\EnvironmentCheck\Checks\URLCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\Dev\SapphireTest;
/**
* Class URLCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class URLCheckTest extends SapphireTest
{
@ -11,7 +21,7 @@ class URLCheckTest extends SapphireTest
$expected = array(
EnvironmentCheck::ERROR,
'Error retrieving "foo" (Code: 404)',
'Error retrieving "foo" (Code: 404)'
);
$this->assertEquals($expected, $check->check());

View File

@ -0,0 +1,32 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Controllers;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\EnvironmentCheck\Controllers\DevCheckController;
/**
* Class DevCheckControllerTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class DevCheckControllerTest extends SapphireTest
{
/**
* {@inheritDoc}
* @var array
*/
protected $usesDatabase = true;
public function testIndexCreatesChecker()
{
$controller = new DevCheckController();
$request = new HTTPRequest('GET', 'example.com');
$this->assertInstanceOf('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', $controller->index($request));
}
}

View File

@ -1,17 +1,31 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Controllers;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\EnvironmentCheck\Controllers\DevHealthController;
/**
* Class DevHealthControllerTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class DevHealthControllerTest extends SapphireTest
{
/**
* {@inheritDoc}
* @var array
*/
protected $usesDatabase = true;
public function testIndexCreatesChecker()
{
$controller = new DevHealthController();
$request = new SS_HTTPRequest('GET', 'example.com');
$request = new HTTPRequest('GET', 'example.com');
// we need to fake authenticated access as BasicAuth::requireLogin doesn't like empty
// permission type strings, which is what health check uses.
@ -22,6 +36,6 @@ class DevHealthControllerTest extends SapphireTest
$_SERVER['PHP_AUTH_USER'] = 'foo';
$_SERVER['PHP_AUTH_PW'] = 'bar';
$this->assertInstanceOf('EnvironmentChecker', $controller->index($request));
$this->assertInstanceOf('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', $controller->index($request));
}
}

View File

@ -1,18 +0,0 @@
<?php
/**
* @mixin PHPUnit_Framework_TestCase
*/
class DevCheckControllerTest extends SapphireTest
{
protected $usesDatabase = true;
public function testIndexCreatesChecker()
{
$controller = new DevCheckController();
$request = new SS_HTTPRequest('GET', 'example.com');
$this->assertInstanceOf('EnvironmentChecker', $controller->index($request));
}
}

View File

@ -1,15 +1,47 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests;
use Phockito;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\EnvironmentCheck\EnvironmentCheckSuite;
/**
* Class EnvironmentCheckerTest
*
* @package environmentcheck
*/
class EnvironmentCheckerTest extends SapphireTest
{
/**
* {@inheritDoc}
* @var bool
*/
protected $usesDatabase = true;
/**
* {@inheritDoc}
*/
public function setUpOnce()
{
parent::setUpOnce();
Phockito::include_hamcrest();
$logger = Injector::inst()->get('Logger');
if ($logger instanceof \Monolog\Logger) {
// It logs to stderr by default - disable
$logger->pushHandler(new \Monolog\Handler\NullHandler);
}
}
/**
* {@inheritDoc}
*/
public function setUp()
{
parent::setUp();
@ -17,6 +49,9 @@ class EnvironmentCheckerTest extends SapphireTest
Config::nest();
}
/**
* {@inheritDoc}
*/
public function tearDown()
{
Config::unnest();
@ -26,11 +61,11 @@ class EnvironmentCheckerTest extends SapphireTest
public function testOnlyLogsWithErrors()
{
Config::inst()->update('EnvironmentChecker', 'log_results_warning', true);
Config::inst()->update('EnvironmentChecker', 'log_results_error', true);
Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_warning', true);
Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', true);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckNoErrors());
$checker = Phockito::spy(
'EnvironmentChecker',
'SilverStripe\\EnvironmentCheck\\EnvironmentChecker',
'test suite',
'test'
);
@ -42,12 +77,12 @@ class EnvironmentCheckerTest extends SapphireTest
public function testLogsWithWarnings()
{
Config::inst()->update('EnvironmentChecker', 'log_results_warning', true);
Config::inst()->update('EnvironmentChecker', 'log_results_error', false);
Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_warning', true);
Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', false);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings());
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors());
$checker = Phockito::spy(
'EnvironmentChecker',
'SilverStripe\\EnvironmentCheck\\EnvironmentChecker',
'test suite',
'test'
);
@ -60,12 +95,12 @@ class EnvironmentCheckerTest extends SapphireTest
public function testLogsWithErrors()
{
Config::inst()->update('EnvironmentChecker', 'log_results_error', false);
Config::inst()->update('EnvironmentChecker', 'log_results_error', true);
Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', false);
Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', true);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings());
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors());
$checker = Phockito::spy(
'EnvironmentChecker',
'SilverStripe\\EnvironmentCheck\\EnvironmentChecker',
'test suite',
'test'
);
@ -89,7 +124,7 @@ class EnvironmentCheckerTest_CheckWarnings implements EnvironmentCheck, TestOnly
{
public function check()
{
return array(EnvironmentCheck::WARNING, "test warning");
return array(EnvironmentCheck::WARNING, 'test warning');
}
}
@ -97,6 +132,6 @@ class EnvironmentCheckerTest_CheckErrors implements EnvironmentCheck, TestOnly
{
public function check()
{
return array(EnvironmentCheck::ERROR, "test error");
return array(EnvironmentCheck::ERROR, 'test error');
}
}

View File

@ -1,19 +0,0 @@
<?php
/**
* @mixin PHPUnit_Framework_TestCase
*/
class DatabaseCheckTest extends SapphireTest
{
public function testCheckReportsValidConnection()
{
$check = new DatabaseCheck();
$expected = array(
EnvironmentCheck::OK,
'',
);
$this->assertEquals($expected, $check->check());
}
}