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 duplication: true
filter: 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 sudo: false
language: php language: php
php: php:
- 5.3
- 5.4
- 5.5 - 5.5
- 5.6 - 5.6
- 7.0 - 7.0
env: env:
- DB=MYSQL CORE_RELEASE=3.2 - DB=MYSQL CORE_RELEASE=4
- DB=PGSQL CORE_RELEASE=4
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
before_script: before_script:
- composer self-update || true - 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 - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss
- cd ~/builds/ss - cd ~/builds/ss
- composer install - 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 <?php
// use SilverStripe\EnvironmentCheck\EnvironmentCheckSuite;
// // These power dev/health, which can be used by load balancers and other such systems // // These power dev/health, which can be used by load balancers and other such systems
// EnvironmentCheckSuite::register('health', 'DatabaseCheck'); // 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 Name: environmentcheckroutes
After: 'framework/*','cms/*' After:
- 'framework/*'
- 'cms/*'
--- ---
Director: SilverStripe\Control\Director:
rules: rules:
'health/check': 'DevHealthController' 'health/check': 'Silverstripe\EnvironmentCheck\Controllers\DevHealthController'
'dev/check/$Suite': 'DevCheckController' '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/). 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] ## [1.2.0]
* Fix broken badges * Fix broken badges

View File

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

138
readme.md
View File

@ -1,6 +1,6 @@
# SilverStripe Environment Checker Module # 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 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) [![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) [![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` - 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) * `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? ## Aren't these just unit tests?
Almost, but not really. Environment checks differ from unit tests in two important ways: 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 ### 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 ```php
EnvironmentCheckSuite::register('health', 'DatabaseCheck', "Can we connect to the database?"); EnvironmentCheckSuite::register('health', 'DatabaseCheck', 'Can we connect to the database?');
EnvironmentCheckSuite::register('check', 'URLCheck("")', "Is the homepage accessible?"); EnvironmentCheckSuite::register('check', 'URLCheck("")', 'Is the homepage accessible?');
``` ```
### Activating Via Config ### 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. Register your checks on the `EnvironmentCheckSuite`. The same named check may be used multiple times.
```yaml ```yaml
EnvironmentCheckSuite: SilverStripe\EnvironmentCheck\EnvironmentCheckSuite:
registered_checks: registered_checks:
db: db:
definition: 'DatabaseCheck("Page")' 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: by some other module. Just set the "state" property of the check to "disabled" like this:
```yaml ```yaml
EnvironmentCheckSuite: SilverStripe\EnvironmentCheck\EnvironmentCheckSuite:
registered_checks: registered_checks:
db: db:
state: disabled state: disabled
@ -77,7 +86,7 @@ EnvironmentCheckSuite:
This can be used to check that PHP modules or features are installed. This can be used to check that PHP modules or features are installed.
* `FileWriteableCheck`: Check that the given file is writeable. * `FileWriteableCheck`: Check that the given file is writeable.
* `FileAgeCheck`: Checks for the maximum age of one or more files or folders. * `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. like static caches, as well as for backup files and folders.
* `ExternalURLCheck`: Checks that one or more URLs are reachable via HTTP. * `ExternalURLCheck`: Checks that one or more URLs are reachable via HTTP.
* `SMTPConnectCheck`: Checks if the SMTP connection configured through PHP.ini works as expected. * `SMTPConnectCheck`: Checks if the SMTP connection configured through PHP.ini works as expected.
@ -86,23 +95,23 @@ EnvironmentCheckSuite:
## Monitoring Checks ## Monitoring Checks
Checks will return an appropriate HTTP status code, so are easy to hook into common uptime montoring 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: You can also have the environment checker email results with the following configuration:
```yml ```yml
EnvironmentChecker: SilverStripe\EnvironmentCheck\EnvironmentChecker:
email_results: true email_results: true
to_email_address: support@test.com to_email_address: support@test.com
from_email_address: admin@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. Errors can be logged via the standard SilverStripe PSR-3 compatible logging. Each check will cause an individual log
You can choose to enable logging separately for warnings and errors, entry. You can choose to enable logging separately for warnings and errors, identified through the
identified through the result of `EnvironmentCheck->check()`. result of `EnvironmentCheck->check()`.
```yml ```yml
EnvironmentChecker: SilverStripe\EnvironmentCheck\EnvironmentChecker:
log_results_warning: true log_results_warning: true
log_results_error: 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 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: You can enable basic authentication by defining the following in your environment:
define('ENVCHECK_BASICAUTH_USERNAME', 'test'); ```php
define('ENVCHECK_BASICAUTH_PASSWORD', 'password'); 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 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. match the ones defined the username and password defined in the environment, access will be granted to the page.
## Adding more checks ## 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 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: * 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 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. * 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. 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 ```php
class MyGatewayCheck implements EnvironmentCheck { use SilverStripe\EnvironmentCheck\EnvironmentCheck;
protected $checkTable;
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 Once you have created your custom check class, don't forget to register it in a check suite
:::php ```php
EnvironmentCheckSuite::register('check', 'MyGatewayCheck', "Can I connect to the gateway?"); EnvironmentCheckSuite::register('check', 'MyGatewayCheck', 'Can I connect to the gateway?');
```
### Using other environment check suites ### 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 { ```php
function index() { use SilverStripe\Control\Controller;
$e = new EnvironmentChecker('health', 'Site health');
return $e; class DevHealth extends Controller
} {
} function index()
{
If you wish to embed an environment check suite in another, you can use the following call. $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` will contain a `EnvironmentCheckSuiteResult` object
* `$result->ShouldPass()`: Return a boolean of whether or not the tests passed. * `$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 ## 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 <?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 * Check that the connection to the database is working, by ensuring that the table exists and that
* the table contains some records. * the table contains some records.
*
* @package environmentcheck
*/ */
class DatabaseCheck implements EnvironmentCheck class DatabaseCheck implements EnvironmentCheck
{ {
@ -13,28 +20,28 @@ class DatabaseCheck implements EnvironmentCheck
* *
* @param string $checkTable * @param string $checkTable
*/ */
public function __construct($checkTable = "Member") public function __construct($checkTable = 'Member')
{ {
$this->checkTable = $checkTable; $this->checkTable = $checkTable;
} }
/** /**
* @inheritdoc * {@inheritDoc}
* *
* @return array * @return array
*/ */
public function check() 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"); return array(EnvironmentCheck::ERROR, "$this->checkTable not present in the database");
} }
$count = DB::query("SELECT COUNT(*) FROM \"$this->checkTable\"")->value(); $count = DB::query("SELECT COUNT(*) FROM \"$this->checkTable\"")->value();
if ($count > 0) { if ($count > 0) {
return array(EnvironmentCheck::OK, ""); return array(EnvironmentCheck::OK, '');
} else {
return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records");
} }
return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records");
} }
} }

View File

@ -1,12 +1,18 @@
<?php <?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/** /**
* Checks that one or more URLs are reachable via HTTP. * 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, * 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. * 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: * 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> * <code>EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?");</code>
*
* @package environmentcheck
*/ */
class ExternalURLCheck implements EnvironmentCheck class ExternalURLCheck implements EnvironmentCheck
{ {
@ -33,7 +39,7 @@ class ExternalURLCheck implements EnvironmentCheck
} }
/** /**
* @inheritdoc * {@inheritDoc}
* *
* @return array * @return array
*/ */
@ -52,7 +58,7 @@ class ExternalURLCheck implements EnvironmentCheck
foreach ($chs as $ch) { foreach ($chs as $ch) {
curl_multi_add_handle($mh, $ch); curl_multi_add_handle($mh, $ch);
} }
$active = null; $active = null;
// Execute the handles // Execute the handles
do { do {
@ -95,12 +101,12 @@ class ExternalURLCheck implements EnvironmentCheck
curl_multi_remove_handle($mh, $ch); curl_multi_remove_handle($mh, $ch);
} }
curl_multi_close($mh); curl_multi_close($mh);
if ($hasError) { if ($hasError) {
return array(EnvironmentCheck::ERROR, implode(', ', $msgs)); 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 <?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. * 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", * 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' * "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. * // Checks /assets/calculator_files/calculator.json exists and is valid json file.
* EnvironmentCheckSuite::register('check', 'FileAccessibilityAndValidationCheck("' . BASE_PATH . '/assets/calculator_files/calculator.json", * 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' * "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")', * EnvironmentCheckSuite::register('check', 'FileAccessibilityAndValidationCheck("' . BASE_PATH . '/assets/calculator_files/calculator.json")',
* 'Check a calculator.json exists only' * 'Check a calculator.json exists only'
* ); * );
*
* @package environmentcheck
*/ */
class FileAccessibilityAndValidationCheck implements EnvironmentCheck class FileAccessibilityAndValidationCheck implements EnvironmentCheck
{ {
@ -60,12 +67,12 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
public function __construct($path, $fileTypeValidateFunc = 'noVidation', $checkType = null) public function __construct($path, $fileTypeValidateFunc = 'noVidation', $checkType = null)
{ {
$this->path = $path; $this->path = $path;
$this->fileTypeValidateFunc = ($fileTypeValidateFunc)? $fileTypeValidateFunc:'noVidation'; $this->fileTypeValidateFunc = ($fileTypeValidateFunc)? $fileTypeValidateFunc : 'noVidation';
$this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE; $this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE;
} }
/** /**
* @inheritdoc * {@inheritDoc}
* *
* @return array * @return array
*/ */
@ -91,9 +98,9 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
// If at least one file was valid, count as passed // If at least one file was valid, count as passed
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) { if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
$validFileList = "\n"; $validFileList = PHP_EOL;
foreach ($validFiles as $vf) { foreach ($validFiles as $vf) {
$validFileList .= $vf."\n"; $validFileList .= $vf . PHP_EOL;
} }
if ($fileTypeValidateFunc == 'noVidation') { if ($fileTypeValidateFunc == 'noVidation') {
$checkReturn = array( $checkReturn = array(
@ -103,16 +110,20 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
} else { } else {
$checkReturn = array( $checkReturn = array(
EnvironmentCheck::OK, 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 { } else {
if (count($invalidFiles) == 0) { if (count($invalidFiles) == 0) {
$checkReturn = array(EnvironmentCheck::OK, 'All files valideted'); $checkReturn = array(EnvironmentCheck::OK, 'All files valideted');
} else { } else {
$invalidFileList = "\n"; $invalidFileList = PHP_EOL;
foreach ($invalidFiles as $vf) { foreach ($invalidFiles as $vf) {
$invalidFileList .= $vf."\n"; $invalidFileList .= $vf . PHP_EOL;
} }
if ($fileTypeValidateFunc == 'noVidation') { if ($fileTypeValidateFunc == 'noVidation') {
@ -123,7 +134,11 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
} else { } else {
$checkReturn = array( $checkReturn = array(
EnvironmentCheck::ERROR, 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)); $json = json_decode(file_get_contents($file));
if (!$json) { if (!$json) {
return false; return false;
} else {
return true;
} }
return true;
} }
/** /**

View File

@ -1,23 +1,30 @@
<?php <?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. * 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. * like static caches, as well as for backup files and folders.
* Does NOT check for existence of a file (will silently fail). * Does NOT check for existence of a file (will silently fail).
* *
* Examples: * Examples:
* // Checks that Requirements::combine_files() has regenerated files in the last 24h * // Checks that Requirements::combine_files() has regenerated files in the last 24h
* EnvironmentCheckSuite::register( * EnvironmentCheckSuite::register(
* 'check', * 'check',
* 'FileAgeCheck("' . ASSETS_PATH . '/_combined_files/*.js' . '", "-1 day", '>', " . FileAgeCheck::CHECK_ALL) . "' * '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 * // Checks that at least one backup folder has been created in the last 24h
* EnvironmentCheckSuite::register( * EnvironmentCheckSuite::register(
* 'check', * 'check',
* 'FileAgeCheck("' . BASE_PATH . '/../backups/*' . '", "-1 day", '>', " . FileAgeCheck::CHECK_SINGLE) . "' * 'FileAgeCheck("' . BASE_PATH . '/../backups/*' . '", "-1 day", '>', " . FileAgeCheck::CHECK_SINGLE) . "'
* ); * );
*
* @package environmentcheck
*/ */
class FileAgeCheck implements EnvironmentCheck class FileAgeCheck implements EnvironmentCheck
{ {
@ -30,7 +37,7 @@ class FileAgeCheck implements EnvironmentCheck
* @var int * @var int
*/ */
const CHECK_ALL = 2; const CHECK_ALL = 2;
/** /**
* Absolute path to a file or folder, compatible with glob(). * Absolute path to a file or folder, compatible with glob().
* *
@ -83,13 +90,13 @@ class FileAgeCheck implements EnvironmentCheck
} }
/** /**
* @inheritdoc * {@inheritDoc}
* *
* @return array * @return array
*/ */
public function check() public function check()
{ {
$cutoffTime = strtotime($this->relativeAge, SS_Datetime::now()->Format('U')); $cutoffTime = strtotime($this->relativeAge, DBDatetime::now()->Format('U'));
$files = $this->getFiles(); $files = $this->getFiles();
$invalidFiles = array(); $invalidFiles = array();
$validFiles = array(); $validFiles = array();
@ -105,12 +112,15 @@ class FileAgeCheck implements EnvironmentCheck
$invalidFiles[] = $file; $invalidFiles[] = $file;
if ($this->checkType == self::CHECK_ALL) { if ($this->checkType == self::CHECK_ALL) {
return array( return array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
sprintf( sprintf(
'File "%s" doesn\'t match age check (compare %s: %s, actual: %s)', 'File "%s" doesn\'t match age check (compare %s: %s, actual: %s)',
$file, $this->compareOperand, date('c', $cutoffTime), date('c', $fileTime) $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 at least one file was valid, count as passed
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) { if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
return array(EnvironmentCheck::OK, ''); 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 <?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/** /**
* Check that the given file is writable. * Check that the given file is writable.
*
* @package environmentcheck
*/ */
class FileWriteableCheck implements EnvironmentCheck class FileWriteableCheck implements EnvironmentCheck
{ {
@ -19,7 +25,7 @@ class FileWriteableCheck implements EnvironmentCheck
} }
/** /**
* @inheritdoc * {@inheritDoc}
* *
* @return array * @return array
*/ */
@ -30,13 +36,13 @@ class FileWriteableCheck implements EnvironmentCheck
} else { } else {
$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path); $filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path);
} }
if (file_exists($filename)) { if (file_exists($filename)) {
$isWriteable = is_writeable($filename); $isWriteable = is_writeable($filename);
} else { } else {
$isWriteable = is_writeable(dirname($filename)); $isWriteable = is_writeable(dirname($filename));
} }
if (!$isWriteable) { if (!$isWriteable) {
if (function_exists('posix_getgroups')) { if (function_exists('posix_getgroups')) {
$userID = posix_geteuid(); $userID = posix_geteuid();
@ -45,10 +51,11 @@ class FileWriteableCheck implements EnvironmentCheck
$currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename)); $currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename));
$currentOwner = posix_getpwuid($currentOwnerID); $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']) { if ($user['name'] == $currentOwner['name']) {
$message .= "We recommend that you make the file writeable."; $message .= 'We recommend that you make the file writeable.';
} else { } else {
$groups = posix_getgroups(); $groups = posix_getgroups();
$groupList = array(); $groupList = array();
@ -59,19 +66,22 @@ class FileWriteableCheck implements EnvironmentCheck
} }
} }
if ($groupList) { 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"; . "\n\nFor example:\nchmod g+w $filename\nchgrp " . $groupList[0] . " $filename";
} else { } 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 { } else {
$message = "The webserver user needs to be able to write to this file:\n$filename"; $message = "The webserver user needs to be able to write to this file:\n$filename";
} }
return array(EnvironmentCheck::ERROR, $message); return array(EnvironmentCheck::ERROR, $message);
} }
return array(EnvironmentCheck::OK,''); return array(EnvironmentCheck::OK, '');
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,9 +1,16 @@
<?php <?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\Control\Director;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/** /**
* Check that a given URL is functioning, by default, the homepage. * Check that a given URL is functioning, by default, the homepage.
* *
* Note that Director::test() will be used rather than a CURL check. * Note that Director::test() will be used rather than a CURL check.
*
* @package environmentcheck
*/ */
class URLCheck implements EnvironmentCheck class URLCheck implements EnvironmentCheck
{ {
@ -16,7 +23,7 @@ class URLCheck implements EnvironmentCheck
* @var string * @var string
*/ */
protected $testString; protected $testString;
/* /*
* @param string $url The URL to check, relative to the site (homepage is ''). * @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. * @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 * @return array
* * @throws HTTPResponse_Exception
* @throws SS_HTTPResponse_Exception
*/ */
public function check() public function check()
{ {
@ -48,11 +54,10 @@ class URLCheck implements EnvironmentCheck
EnvironmentCheck::WARNING, EnvironmentCheck::WARNING,
sprintf('Success retrieving "%s", but string "%s" not found', $this->url, $this->testString) 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 <?php
namespace SilverStripe\EnvironmentCheck\Controllers;
use SilverStripe\Control\Controller;
use SilverStripe\EnvironmentCheck\EnvironmentChecker;
/**
* Class DevCheckController
*
* @package environmentcheck
*/
class DevCheckController extends Controller class DevCheckController extends Controller
{ {
/** /**
@ -17,11 +27,11 @@ class DevCheckController extends Controller
private static $permission = 'ADMIN'; private static $permission = 'ADMIN';
/** /**
* @param SS_HTTPRequest $request * @param HTTPRequest $request
* *
* @return EnvironmentChecker * @return EnvironmentChecker
* *
* @throws SS_HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function index($request) public function index($request)
{ {

View File

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

View File

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

View File

@ -1,5 +1,15 @@
<?php <?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. * Represents a suite of environment checks.
* Specific checks can be registered against a named instance of EnvironmentCheckSuite. * Specific checks can be registered against a named instance of EnvironmentCheckSuite.
@ -18,6 +28,8 @@
* - mycheck * - mycheck
* *
* $result = EnvironmentCheckSuite::inst('health')->run(); * $result = EnvironmentCheckSuite::inst('health')->run();
*
* @package environmentcheck
*/ */
class EnvironmentCheckSuite extends Object class EnvironmentCheckSuite extends Object
{ {
@ -77,10 +89,10 @@ class EnvironmentCheckSuite extends Object
// Existing named checks can be disabled by setting their 'state' to 'disabled'. // Existing named checks can be disabled by setting their 'state' to 'disabled'.
// This is handy for disabling checks mandated by modules. // This is handy for disabling checks mandated by modules.
if (!empty($check['state']) && $check['state']==='disabled') { if (!empty($check['state']) && $check['state'] === 'disabled') {
continue; continue;
} }
// Add the check to this suite. // Add the check to this suite.
$this->push($check['definition'], $check['title']); $this->push($check['definition'], $check['title']);
} }
@ -114,6 +126,7 @@ class EnvironmentCheckSuite extends Object
* Get instances of all the environment checks. * Get instances of all the environment checks.
* *
* @return array * @return array
* @throws InvalidArgumentException
*/ */
protected function checkInstances() protected function checkInstances()
{ {
@ -125,7 +138,9 @@ class EnvironmentCheckSuite extends Object
if ($checkInst instanceof EnvironmentCheck) { if ($checkInst instanceof EnvironmentCheck) {
$output[] = array($checkInst, $checkTitle); $output[] = array($checkInst, $checkTitle);
} else { } 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) { } elseif ($checkClass instanceof EnvironmentCheck) {
$output[] = array($checkClass, $checkTitle); $output[] = array($checkClass, $checkTitle);
@ -184,6 +199,7 @@ class EnvironmentCheckSuite extends Object
if (!is_array($names)) { if (!is_array($names)) {
$names = array($names); $names = array($names);
} }
foreach ($names as $name) { foreach ($names as $name) {
self::inst($name)->push($check, $title); self::inst($name)->push($check, $title);
} }
@ -197,106 +213,3 @@ class EnvironmentCheckSuite extends Object
self::$instances = array(); 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 <?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. * Provides an interface for checking the given EnvironmentCheckSuite.
*
* @package environmentcheck
*/ */
class EnvironmentChecker extends RequestHandler class EnvironmentChecker extends RequestHandler
{ {
@ -43,24 +62,24 @@ class EnvironmentChecker extends RequestHandler
private static $email_results = false; 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; 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; 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 * @param string $checkSuiteName
@ -69,7 +88,7 @@ class EnvironmentChecker extends RequestHandler
public function __construct($checkSuiteName, $title) public function __construct($checkSuiteName, $title)
{ {
parent::__construct(); parent::__construct();
$this->checkSuiteName = $checkSuiteName; $this->checkSuiteName = $checkSuiteName;
$this->title = $title; $this->title = $title;
} }
@ -77,7 +96,7 @@ class EnvironmentChecker extends RequestHandler
/** /**
* @param string $permission * @param string $permission
* *
* @throws SS_HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function init($permission = 'ADMIN') public function init($permission = 'ADMIN')
{ {
@ -85,24 +104,23 @@ class EnvironmentChecker extends RequestHandler
if (defined('ENVCHECK_BASICAUTH_USERNAME') && defined('ENVCHECK_BASICAUTH_PASSWORD')) { if (defined('ENVCHECK_BASICAUTH_USERNAME') && defined('ENVCHECK_BASICAUTH_PASSWORD')) {
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
// authenticate the input user/pass with the configured credentials // authenticate the input user/pass with the configured credentials
if ( if (!(
!(
$_SERVER['PHP_AUTH_USER'] == ENVCHECK_BASICAUTH_USERNAME $_SERVER['PHP_AUTH_USER'] == ENVCHECK_BASICAUTH_USERNAME
&& $_SERVER['PHP_AUTH_PW'] == ENVCHECK_BASICAUTH_PASSWORD && $_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\""); $response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
// Exception is caught by RequestHandler->handleRequest() and will halt further execution // 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); $e->setResponse($response);
throw $e; throw $e;
} }
} else { } else {
$response = new SS_HTTPResponse(null, 401); $response = new HTTPResponse(null, 401);
$response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\""); $response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
// Exception is caught by RequestHandler->handleRequest() and will halt further execution // 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); $e->setResponse($response);
throw $e; throw $e;
} }
@ -119,9 +137,9 @@ class EnvironmentChecker extends RequestHandler
* *
* @return bool * @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) { if (!$member) {
$member = Member::currentUser(); $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 // 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 on CLI. Access to this controller is always allowed in "dev-mode", or of the user is ADMIN.
if ( if (Director::isDev()
Director::isDev()
|| Director::is_cli() || Director::is_cli()
|| empty($permission) || empty($permission)
|| Permission::checkMember($member, $permission) || Permission::checkMember($member, $permission)
@ -149,20 +166,19 @@ class EnvironmentChecker extends RequestHandler
if ($results && is_array($results)) { if ($results && is_array($results)) {
if (!min($results)) { if (!min($results)) {
return false; return false;
} else {
return true;
} }
return true;
} }
return false; return false;
} }
/** /**
* @return SS_HTTPResponse * @return HTTPResponse
*/ */
public function index() public function index()
{ {
$response = new SS_HTTPResponse; $response = new HTTPResponse;
$result = EnvironmentCheckSuite::inst($this->checkSuiteName)->run(); $result = EnvironmentCheckSuite::inst($this->checkSuiteName)->run();
if (!$result->ShouldPass()) { if (!$result->ShouldPass()) {
@ -170,14 +186,19 @@ class EnvironmentChecker extends RequestHandler
} }
$resultText = $result->customise(array( $resultText = $result->customise(array(
"URL" => Director::absoluteBaseURL(), 'URL' => Director::absoluteBaseURL(),
"Title" => $this->title, 'Title' => $this->title,
"Name" => $this->checkSuiteName, 'Name' => $this->checkSuiteName,
"ErrorCode" => $this->errorCode, 'ErrorCode' => $this->errorCode,
))->renderWith("EnvironmentChecker"); ))->renderWith(__CLASS__);
if ($this->config()->email_results && !$result->ShouldPass()) { 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(); $email->send();
} }
@ -197,8 +218,7 @@ class EnvironmentChecker extends RequestHandler
} }
// output the result as JSON if requested // output the result as JSON if requested
if ( if ($this->getRequest()->getExtension() == 'json'
$this->getRequest()->getExtension() == 'json'
|| strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false || strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false
) { ) {
$response->setBody($result->toJSON()); $response->setBody($result->toJSON());
@ -207,17 +227,19 @@ class EnvironmentChecker extends RequestHandler
} }
$response->setBody($resultText); $response->setBody($resultText);
return $response; return $response;
} }
/** /**
* Sends a log entry to the configured PSR-3 LoggerInterface
*
* @param string $message * @param string $message
* @param int $level * @param int $level
*/ */
public function log($message, $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) public static function set_from_email_address($from)
{ {
Deprecation::notice('2.0', 'Use config API instead'); 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() public static function get_from_email_address()
{ {
Deprecation::notice('2.0', 'Use config API instead'); 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) public static function set_to_email_address($to)
{ {
Deprecation::notice('2.0', 'Use config API instead'); 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() public static function get_to_email_address()
{ {
Deprecation::notice('2.0', 'Use config API instead'); 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) public static function set_email_results($results)
{ {
Deprecation::notice('2.0', 'Use config API instead'); 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() public static function get_email_results()
{ {
Deprecation::notice('2.0', 'Use config API instead'); 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; margin-top: -10px;
font-size: 10px; font-size: 10px;
} }
h1 { h1 {
font-size: 30px; font-size: 30px;
margin-bottom: 3px; margin-bottom: 3px;
@ -21,11 +21,11 @@
font-size: 16px; font-size: 16px;
margin: 2px 0 10px 8px; margin: 2px 0 10px 8px;
} }
p { p {
margin-left: 10px; margin-left: 10px;
} }
table { table {
border-collapse: collapse; border-collapse: collapse;
} }
@ -44,7 +44,7 @@
table tr:nth-child(odd) td { table tr:nth-child(odd) td {
background-color: #ddd; background-color: #ddd;
} }
.OK { .OK {
color: green; color: green;
} }
@ -59,23 +59,23 @@
</style> </style>
</head> </head>
<body> <body>
<h1 class="$Status">$Title: $Status</h1> <h1 class="$Status">$Title: $Status</h1>
<h2 class="website">Site: $URL</h2> <h2 class="website">Site: $URL</h2>
<table> <table>
<tr><th>Check</th> <th>Status</th> <th>Message</th></tr> <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> <tr><td>$Check</td> <td class="$Status">$Status</td> <td>$Message.XML</td></tr>
<% end_loop %> <% end_loop %>
</table> </table>
<% if ShouldPass %> <% if $ShouldPass %>
<p>Site is available</p> <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> <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 %> <% else %>
<% if Name == check %> <% if $Name == "check" %>
<p><b>A subsystem of the site is unavailable, but the site remains operational</b></p> <p><b>A subsystem of the site is unavailable, but the site remains operational</b></p>
<% else %> <% else %>
<p><b>Site is not available</b></p> <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 <?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 * @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/ */
class ExternalURLCheckTest extends SapphireTest class ExternalURLCheckTest extends SapphireTest
{ {
@ -13,7 +23,7 @@ class ExternalURLCheckTest extends SapphireTest
$expected = array( $expected = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'Success retrieving "http://missing-site/" (Code: 404)', 'Success retrieving "http://missing-site/" (Code: 404)'
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());

View File

@ -1,7 +1,17 @@
<?php <?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 * @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/ */
class FileWritableCheckTest extends SapphireTest class FileWritableCheckTest extends SapphireTest
{ {
@ -11,7 +21,7 @@ class FileWritableCheckTest extends SapphireTest
$expected = array( $expected = array(
EnvironmentCheck::OK, EnvironmentCheck::OK,
'', ''
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());

View File

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

View File

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

View File

@ -1,7 +1,17 @@
<?php <?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 * @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/ */
class URLCheckTest extends SapphireTest class URLCheckTest extends SapphireTest
{ {
@ -11,7 +21,7 @@ class URLCheckTest extends SapphireTest
$expected = array( $expected = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'Error retrieving "foo" (Code: 404)', 'Error retrieving "foo" (Code: 404)'
); );
$this->assertEquals($expected, $check->check()); $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 <?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 * @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/ */
class DevHealthControllerTest extends SapphireTest class DevHealthControllerTest extends SapphireTest
{ {
/**
* {@inheritDoc}
* @var array
*/
protected $usesDatabase = true; protected $usesDatabase = true;
public function testIndexCreatesChecker() public function testIndexCreatesChecker()
{ {
$controller = new DevHealthController(); $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 // we need to fake authenticated access as BasicAuth::requireLogin doesn't like empty
// permission type strings, which is what health check uses. // 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_USER'] = 'foo';
$_SERVER['PHP_AUTH_PW'] = 'bar'; $_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 <?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 class EnvironmentCheckerTest extends SapphireTest
{ {
/**
* {@inheritDoc}
* @var bool
*/
protected $usesDatabase = true; protected $usesDatabase = true;
/**
* {@inheritDoc}
*/
public function setUpOnce() public function setUpOnce()
{ {
parent::setUpOnce(); parent::setUpOnce();
Phockito::include_hamcrest(); 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() public function setUp()
{ {
parent::setUp(); parent::setUp();
@ -17,6 +49,9 @@ class EnvironmentCheckerTest extends SapphireTest
Config::nest(); Config::nest();
} }
/**
* {@inheritDoc}
*/
public function tearDown() public function tearDown()
{ {
Config::unnest(); Config::unnest();
@ -26,11 +61,11 @@ class EnvironmentCheckerTest extends SapphireTest
public function testOnlyLogsWithErrors() public function testOnlyLogsWithErrors()
{ {
Config::inst()->update('EnvironmentChecker', 'log_results_warning', true); Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_warning', true);
Config::inst()->update('EnvironmentChecker', 'log_results_error', true); Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', true);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckNoErrors()); EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckNoErrors());
$checker = Phockito::spy( $checker = Phockito::spy(
'EnvironmentChecker', 'SilverStripe\\EnvironmentCheck\\EnvironmentChecker',
'test suite', 'test suite',
'test' 'test'
); );
@ -42,12 +77,12 @@ class EnvironmentCheckerTest extends SapphireTest
public function testLogsWithWarnings() public function testLogsWithWarnings()
{ {
Config::inst()->update('EnvironmentChecker', 'log_results_warning', true); Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_warning', true);
Config::inst()->update('EnvironmentChecker', 'log_results_error', false); Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', false);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings()); EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings());
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors()); EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors());
$checker = Phockito::spy( $checker = Phockito::spy(
'EnvironmentChecker', 'SilverStripe\\EnvironmentCheck\\EnvironmentChecker',
'test suite', 'test suite',
'test' 'test'
); );
@ -60,12 +95,12 @@ class EnvironmentCheckerTest extends SapphireTest
public function testLogsWithErrors() public function testLogsWithErrors()
{ {
Config::inst()->update('EnvironmentChecker', 'log_results_error', false); Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', false);
Config::inst()->update('EnvironmentChecker', 'log_results_error', true); Config::inst()->update('SilverStripe\\EnvironmentCheck\\EnvironmentChecker', 'log_results_error', true);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings()); EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings());
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors()); EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors());
$checker = Phockito::spy( $checker = Phockito::spy(
'EnvironmentChecker', 'SilverStripe\\EnvironmentCheck\\EnvironmentChecker',
'test suite', 'test suite',
'test' 'test'
); );
@ -89,7 +124,7 @@ class EnvironmentCheckerTest_CheckWarnings implements EnvironmentCheck, TestOnly
{ {
public function check() 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() 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());
}
}