|
| 1 | +.. _setup-checks: |
| 2 | + |
| 3 | +============ |
| 4 | +Setup checks |
| 5 | +============ |
| 6 | + |
| 7 | +Setup checks allow to test specific functionality of the server and report issues with configuration |
| 8 | +early to the administrators to prevent run time issues. |
| 9 | + |
| 10 | +One example for setup checks is the JavaScript Modules test that ensures the server is able to |
| 11 | +serve ``.mjs`` files correctly, which is needed for apps that use modern JavaScript for their UI. |
| 12 | +Any issue with the configuration would be reported to the administrator, either on the web interface (admin setting), |
| 13 | +or when running the ``occ setupchecks`` command, before a user experience the issue. |
| 14 | + |
| 15 | +Register a setup check |
| 16 | +---------------------- |
| 17 | + |
| 18 | +Setup checks are registered within the registration context of the app bootstrap: |
| 19 | + |
| 20 | +.. code-block:: php |
| 21 | +
|
| 22 | + <?php |
| 23 | + declare(strict_types=1); |
| 24 | +
|
| 25 | + namespace OCA\MyApp\AppInfo; |
| 26 | +
|
| 27 | + class Application extends App implements IBootstrap { |
| 28 | +
|
| 29 | + public function register(IRegistrationContext $context): void { |
| 30 | + // Other registration |
| 31 | + $context->registerSetupCheck(JavaScriptModules::class); |
| 32 | + } |
| 33 | +
|
| 34 | + // ... |
| 35 | +
|
| 36 | + } |
| 37 | +
|
| 38 | +Define a setup check |
| 39 | +-------------------- |
| 40 | + |
| 41 | +Defining a custom setup check is done by simply implementing ``OCP\SetupCheck\SetupResult``, |
| 42 | +for this example we will create a check that ensures the Nextcloud instance is not running in debug mode. |
| 43 | + |
| 44 | +.. code-block:: php |
| 45 | +
|
| 46 | + <?php |
| 47 | + declare(strict_types=1); |
| 48 | +
|
| 49 | + namespace OCA\MyApp\SetupChecks; |
| 50 | +
|
| 51 | + use OCP\IConfig; |
| 52 | + use OCP\IL10N; |
| 53 | + use OCP\SetupCheck\ISetupCheck; |
| 54 | + use OCP\SetupCheck\SetupResult; |
| 55 | +
|
| 56 | + class DebugModeSetupCheck implements ISetupCheck { |
| 57 | + public function __construct( |
| 58 | + private IL10N $l10n, |
| 59 | + private IConfig $config, |
| 60 | + ) { |
| 61 | + } |
| 62 | +
|
| 63 | + public function getName(): string { |
| 64 | + return $this->l10n->t('Debug mode'); |
| 65 | + } |
| 66 | +
|
| 67 | + public function getCategory(): string { |
| 68 | + return 'system'; |
| 69 | + } |
| 70 | +
|
| 71 | + public function run(): SetupResult { |
| 72 | + if ($this->config->getSystemValueBool('debug', false)) { |
| 73 | + return SetupResult::warning($this->l10n->t('This instance is running in debug mode. Only enable this for local development and not in production environments.')); |
| 74 | + } else { |
| 75 | + return SetupResult::success($this->l10n->t('Debug mode is disabled.')); |
| 76 | + } |
| 77 | + } |
| 78 | + } |
| 79 | +
|
| 80 | +
|
| 81 | +First it is required to provide a name, the name which should summarize the check and should be provided as a user visible, thus translated string. |
| 82 | + |
| 83 | +.. code-block:: php |
| 84 | +
|
| 85 | + public function getName(): string { |
| 86 | + // This is user visible and thus should be translated |
| 87 | + return $this->l10n->t('Debug mode'); |
| 88 | + } |
| 89 | +
|
| 90 | +
|
| 91 | +Setup checks are grouped by category, the category should be one of |
| 92 | + |
| 93 | +- ``security``: Related to the security of the instance |
| 94 | +- ``accounts``: Related to user accounts |
| 95 | +- ``system``: System status Related |
| 96 | +- Custom category: Will be merged into system. Examples for existing custom categories are ``network`` and ``database``. |
| 97 | + |
| 98 | +.. code-block:: php |
| 99 | +
|
| 100 | + public function getCategory(): string { |
| 101 | + return 'system'; |
| 102 | + } |
| 103 | +
|
| 104 | +
|
| 105 | +The most important part is the ``run`` function. |
| 106 | +This function should perform the test and report the result as a ``OCP\SetupCheck\SetupResult``. |
| 107 | +Available severity level are: |
| 108 | + |
| 109 | +- ``SetupResult::success``: Test succeeded no action needed. |
| 110 | +- ``SetupResult::info``: No action required but it can not be guaranteed that the check passed (e.g. missing precondition for running the test). |
| 111 | +- ``SetupResult::warning``: The test failed but the result is not fatal, yet the administrator should be warned about this. |
| 112 | +- ``SetupResult::error``: The test failed and some functionality is not available or might be broken. |
| 113 | + |
| 114 | +It is also possible to add a link to documentation to ease administrators solving the issue. |
| 115 | +The link is simply passed as the second parameter to the ``SetupResult``. |
| 116 | + |
| 117 | +Additionally it is also possible to use rich objects (``OCP\RichObjectStrings``) for formatting the message, |
| 118 | +in this case the third parameter should contain the rich object parameters. |
| 119 | + |
| 120 | +.. note:: |
| 121 | + Please be aware that setup checks could be ran from both, |
| 122 | + the web frontend and from the CLI. Meaning they might use different ``php.ini`` files. |
| 123 | + |
| 124 | +.. code-block:: php |
| 125 | +
|
| 126 | + public function run(): SetupResult { |
| 127 | + if ($this->config->getSystemValueBool('debug', false)) { |
| 128 | + return SetupResult::warning($this->l10n->t('This instance is running in debug mode. Only enable this for local development and not in production environments.')); |
| 129 | + } else { |
| 130 | + return SetupResult::success($this->l10n->t('Debug mode is disabled.')); |
| 131 | + } |
| 132 | + } |
| 133 | +
|
| 134 | +
|
| 135 | +Running HTTP requests against the server |
| 136 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 137 | + |
| 138 | +As mentioned in the initial example it is sometimes needed to run HTTP requests |
| 139 | +for a setup check, to ensure configuration is working correctly. |
| 140 | +To ease writing tests like that we provide the ``CheckServerResponseTrait`` trait. |
| 141 | + |
| 142 | +The ``run`` function of the JavaScript modules setup check could look like: |
| 143 | + |
| 144 | +.. code-block:: php |
| 145 | +
|
| 146 | + public function run(): SetupResult { |
| 147 | + // This is a real existing file |
| 148 | + $testFile = $this->urlGenerator->linkTo('settings', 'js/esm-test.mjs'); |
| 149 | +
|
| 150 | + $noResponse = true; |
| 151 | + foreach ($this->runRequest('HEAD', $testFile) as $response) { |
| 152 | + $noResponse = false; |
| 153 | + if (preg_match('/(text|application)\/javascript/i', $response->getHeader('Content-Type'))) { |
| 154 | + return SetupResult::success(); |
| 155 | + } |
| 156 | + } |
| 157 | +
|
| 158 | + if ($noResponse) { |
| 159 | + return SetupResult::warning($this->l10n->t('Unable to run check for JavaScript support.') . "\n" . $this->serverConfigHelp()); |
| 160 | + } |
| 161 | + return SetupResult::error($this->l10n->t('Your webserver does not serve `.mjs` files using the JavaScript MIME type. This will break some apps by preventing browsers from executing the JavaScript files.')); |
| 162 | + } |
| 163 | +
|
| 164 | +The ``runRequest`` is provided by the ``CheckServerResponseTrait``, it accepts a HTTP request method |
| 165 | +as the first parameter (in this example ``HEAD``) and an URL with an absolute path, so meaning |
| 166 | +the full path but no host set, like provided when using the URL generator. One example string would be ``nextcloud/apps/settings/js/esm-test.mjs``. |
| 167 | +Internally the function requests that URL on all possible URLs (using the current host, the trusted domains and the cli overwrite URL), |
| 168 | +and then yields a result for each request. |
| 169 | + |
| 170 | +``CheckServerResponseTrait::serverConfigHelp`` provides information about |
| 171 | +common pitfalls that prevent HTTP requests against the current server. |
| 172 | +If no response is yielded from the ``runRequest`` method then this information should be included. |
0 commit comments