Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Jetpack_Cxn_Tests often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Jetpack_Cxn_Tests, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 21 | class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base { |
||
| 22 | |||
| 23 | /** |
||
| 24 | * Jetpack_Cxn_Tests constructor. |
||
| 25 | */ |
||
| 26 | public function __construct() { |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Helper function to look up the expected master user and return the local WP_User. |
||
| 68 | * |
||
| 69 | * @return WP_User Jetpack's expected master user. |
||
| 70 | */ |
||
| 71 | protected function helper_retrieve_local_master_user() { |
||
| 75 | |||
| 76 | /** |
||
| 77 | * Is Jetpack even connected and supposed to be talking to WP.com? |
||
| 78 | */ |
||
| 79 | protected function helper_is_jetpack_connected() { |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Retrieve the `blog_token` if it exists. |
||
| 85 | * |
||
| 86 | * @return object|false |
||
| 87 | */ |
||
| 88 | protected function helper_get_blog_token() { |
||
| 91 | |||
| 92 | /** |
||
| 93 | * Returns a support url based on using a development version. |
||
| 94 | */ |
||
| 95 | protected function helper_get_support_url() { |
||
| 100 | |||
| 101 | /** |
||
| 102 | * Gets translated support text. |
||
| 103 | */ |
||
| 104 | protected function helper_get_support_text() { |
||
| 107 | |||
| 108 | /** |
||
| 109 | * Gets translated text to enable outbound requests. |
||
| 110 | * |
||
| 111 | * @param string $protocol Either 'HTTP' or 'HTTPS'. |
||
| 112 | * |
||
| 113 | * @return string The translated text. |
||
| 114 | */ |
||
| 115 | protected function helper_enable_outbound_requests( $protocol ) { |
||
| 126 | |||
| 127 | /** |
||
| 128 | * Returns 30 for use with a filter. |
||
| 129 | * |
||
| 130 | * To allow time for WP.com to run upstream testing, this function exists to increase the http_request_timeout value |
||
| 131 | * to 30. |
||
| 132 | * |
||
| 133 | * @return int 30 |
||
| 134 | */ |
||
| 135 | public static function increase_timeout() { |
||
| 138 | |||
| 139 | /** |
||
| 140 | * The test verifies the blog token exists. |
||
| 141 | * |
||
| 142 | * @return array |
||
| 143 | */ |
||
| 144 | protected function test__blog_token_if_exists() { |
||
| 145 | View Code Duplication | if ( ! $this->helper_is_jetpack_connected() ) { |
|
| 146 | return self::skipped_test( |
||
| 147 | array( |
||
| 148 | 'name' => __FUNCTION__, |
||
| 149 | 'short_description' => __( 'Jetpack is not connected. No blog token to check.', 'jetpack' ), |
||
| 150 | ) |
||
| 151 | ); |
||
| 152 | } |
||
| 153 | $blog_token = $this->helper_get_blog_token(); |
||
| 154 | |||
| 155 | View Code Duplication | if ( $blog_token ) { |
|
| 156 | $result = self::passing_test( array( 'name' => __FUNCTION__ ) ); |
||
| 157 | } else { |
||
| 158 | $result = self::failing_test( |
||
| 159 | array( |
||
| 160 | 'name' => __FUNCTION__, |
||
| 161 | 'short_description' => __( 'Blog token is missing.', 'jetpack' ), |
||
| 162 | 'action' => admin_url( 'admin.php?page=jetpack#/dashboard' ), |
||
| 163 | 'action_label' => __( 'Disconnect your site from WordPress.com, and connect it again.', 'jetpack' ), |
||
| 164 | ) |
||
| 165 | ); |
||
| 166 | } |
||
| 167 | |||
| 168 | return $result; |
||
| 169 | } |
||
| 170 | |||
| 171 | /** |
||
| 172 | * Test if Jetpack is connected. |
||
| 173 | */ |
||
| 174 | protected function test__check_if_connected() { |
||
| 175 | $name = __FUNCTION__; |
||
| 176 | |||
| 177 | View Code Duplication | if ( ! $this->helper_get_blog_token() ) { |
|
| 178 | return self::skipped_test( |
||
| 179 | array( |
||
| 180 | 'name' => $name, |
||
| 181 | 'short_description' => __( 'Blog token is missing.', 'jetpack' ), |
||
| 182 | ) |
||
| 183 | ); |
||
| 184 | } |
||
| 185 | |||
| 186 | if ( $this->helper_is_jetpack_connected() ) { |
||
| 187 | $result = self::passing_test( |
||
| 188 | array( |
||
| 189 | 'name' => $name, |
||
| 190 | 'label' => __( 'Your site is connected to Jetpack', 'jetpack' ), |
||
| 191 | 'long_description' => sprintf( |
||
| 192 | '<p>%1$s</p>' . |
||
| 193 | '<p><span class="dashicons pass"><span class="screen-reader-text">%2$s</span></span> %3$s</p>', |
||
| 194 | __( 'A healthy connection ensures Jetpack essential services are provided to your WordPress site, such as Stats and Site Security.', 'jetpack' ), |
||
| 195 | /* translators: Screen reader text indicating a test has passed */ |
||
| 196 | __( 'Passed', 'jetpack' ), |
||
| 197 | __( 'Your site is connected to Jetpack.', 'jetpack' ) |
||
| 198 | ), |
||
| 199 | ) |
||
| 200 | ); |
||
| 201 | } elseif ( ( new Status() )->is_offline_mode() ) { |
||
| 202 | $result = self::skipped_test( |
||
| 203 | array( |
||
| 204 | 'name' => $name, |
||
| 205 | 'short_description' => __( 'Jetpack is in Offline Mode:', 'jetpack' ) . ' ' . Jetpack::development_mode_trigger_text(), |
||
| 206 | ) |
||
| 207 | ); |
||
| 208 | } else { |
||
| 209 | $result = self::failing_test( |
||
| 210 | array( |
||
| 211 | 'name' => $name, |
||
| 212 | 'short_description' => __( 'Your site is not connected to Jetpack', 'jetpack' ), |
||
| 213 | 'action' => admin_url( 'admin.php?page=jetpack#/dashboard' ), |
||
| 214 | 'action_label' => __( 'Reconnect your site now', 'jetpack' ), |
||
| 215 | 'long_description' => sprintf( |
||
| 216 | '<p>%1$s</p>' . |
||
| 217 | '<p><span class="dashicons fail"><span class="screen-reader-text">%2$s</span></span> %3$s<strong> %4$s</strong></p>', |
||
| 218 | __( 'A healthy connection ensures Jetpack essential services are provided to your WordPress site, such as Stats and Site Security.', 'jetpack' ), |
||
| 219 | /* translators: screen reader text indicating a test failed */ |
||
| 220 | __( 'Error', 'jetpack' ), |
||
| 221 | __( 'Your site is not connected to Jetpack.', 'jetpack' ), |
||
| 222 | __( 'We recommend reconnecting Jetpack.', 'jetpack' ) |
||
| 223 | ), |
||
| 224 | ) |
||
| 225 | ); |
||
| 226 | } |
||
| 227 | |||
| 228 | return $result; |
||
| 229 | } |
||
| 230 | |||
| 231 | /** |
||
| 232 | * Test that the master user still exists on this site. |
||
| 233 | * |
||
| 234 | * @return array Test results. |
||
| 235 | */ |
||
| 236 | protected function test__master_user_exists_on_site() { |
||
| 263 | |||
| 264 | /** |
||
| 265 | * Test that the master user has the manage options capability (e.g. is an admin). |
||
| 266 | * |
||
| 267 | * Generic calls from WP.com execute on Jetpack as the master user. If it isn't an admin, random things will fail. |
||
| 268 | * |
||
| 269 | * @return array Test results. |
||
| 270 | */ |
||
| 271 | protected function test__master_user_can_manage_options() { |
||
| 299 | |||
| 300 | /** |
||
| 301 | * Test that the PHP's XML library is installed. |
||
| 302 | * |
||
| 303 | * While it should be installed by default, increasingly in PHP 7, some OSes require an additional php-xml package. |
||
| 304 | * |
||
| 305 | * @return array Test results. |
||
| 306 | */ |
||
| 307 | protected function test__xml_parser_available() { |
||
| 324 | |||
| 325 | /** |
||
| 326 | * Test that the server is able to send an outbound http communication. |
||
| 327 | * |
||
| 328 | * @return array Test results. |
||
| 329 | */ |
||
| 330 | View Code Duplication | protected function test__outbound_http() { |
|
| 348 | |||
| 349 | /** |
||
| 350 | * Test that the server is able to send an outbound https communication. |
||
| 351 | * |
||
| 352 | * @return array Test results. |
||
| 353 | */ |
||
| 354 | View Code Duplication | protected function test__outbound_https() { |
|
| 372 | |||
| 373 | /** |
||
| 374 | * Check for an IDC. |
||
| 375 | * |
||
| 376 | * @return array Test results. |
||
| 377 | */ |
||
| 378 | protected function test__identity_crisis() { |
||
| 409 | |||
| 410 | /** |
||
| 411 | * Tests blog and current user's token against wp.com's check-token-health endpoint. |
||
| 412 | * |
||
| 413 | * @since 9.0.0 |
||
| 414 | * |
||
| 415 | * @return array Test results. |
||
| 416 | */ |
||
| 417 | protected function test__token_health() { |
||
| 453 | |||
| 454 | /** |
||
| 455 | * Tests connection status against wp.com's test-connection endpoint. |
||
| 456 | * |
||
| 457 | * @todo: Compare with the wpcom_self_test. We only need one of these. |
||
| 458 | * |
||
| 459 | * @return array Test results. |
||
| 460 | */ |
||
| 461 | protected function test__wpcom_connection_test() { |
||
| 462 | $name = __FUNCTION__; |
||
| 463 | |||
| 464 | $status = new Status(); |
||
| 465 | View Code Duplication | if ( ! Jetpack::is_active() || $status->is_offline_mode() || $status->is_staging_site() || ! $this->pass ) { |
|
| 466 | return self::skipped_test( array( 'name' => $name ) ); |
||
| 467 | } |
||
| 468 | |||
| 469 | add_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) ); |
||
| 470 | $response = Client::wpcom_json_api_request_as_blog( |
||
| 471 | sprintf( '/jetpack-blogs/%d/test-connection', Jetpack_Options::get_option( 'id' ) ), |
||
| 472 | Client::WPCOM_JSON_API_VERSION |
||
| 473 | ); |
||
| 474 | remove_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) ); |
||
| 475 | |||
| 476 | View Code Duplication | if ( is_wp_error( $response ) ) { |
|
| 477 | return self::failing_test( |
||
| 478 | array( |
||
| 479 | 'name' => $name, |
||
| 480 | /* translators: %1$s is the error code, %2$s is the error message */ |
||
| 481 | 'short_description' => sprintf( __( 'Connection test failed (#%1$s: %2$s)', 'jetpack' ), $response->get_error_code(), $response->get_error_message() ), |
||
| 482 | 'action_label' => $this->helper_get_support_text(), |
||
| 483 | 'action' => $this->helper_get_support_url(), |
||
| 484 | ) |
||
| 485 | ); |
||
| 486 | } |
||
| 487 | |||
| 488 | $body = wp_remote_retrieve_body( $response ); |
||
| 489 | View Code Duplication | if ( ! $body ) { |
|
| 490 | return self::failing_test( |
||
| 491 | array( |
||
| 492 | 'name' => $name, |
||
| 493 | 'short_description' => __( 'Connection test failed (empty response body)', 'jetpack' ) . wp_remote_retrieve_response_code( $response ), |
||
| 494 | 'action_label' => $this->helper_get_support_text(), |
||
| 495 | 'action' => $this->helper_get_support_url(), |
||
| 496 | ) |
||
| 497 | ); |
||
| 498 | } |
||
| 499 | |||
| 500 | if ( 404 === wp_remote_retrieve_response_code( $response ) ) { |
||
| 501 | return self::skipped_test( |
||
| 502 | array( |
||
| 503 | 'name' => $name, |
||
| 504 | 'short_description' => __( 'The WordPress.com API returned a 404 error.', 'jetpack' ), |
||
| 505 | ) |
||
| 506 | ); |
||
| 507 | } |
||
| 508 | |||
| 509 | $result = json_decode( $body ); |
||
| 510 | $is_connected = ! empty( $result->connected ); |
||
| 511 | $message = $result->message . ': ' . wp_remote_retrieve_response_code( $response ); |
||
| 512 | |||
| 513 | if ( $is_connected ) { |
||
| 514 | return self::passing_test( array( 'name' => $name ) ); |
||
| 515 | } else { |
||
| 516 | return self::failing_test( |
||
| 517 | array( |
||
| 518 | 'name' => $name, |
||
| 519 | 'short_description' => $message, |
||
| 520 | 'action_label' => $this->helper_get_support_text(), |
||
| 521 | 'action' => $this->helper_get_support_url(), |
||
| 522 | ) |
||
| 523 | ); |
||
| 524 | } |
||
| 525 | } |
||
| 526 | |||
| 527 | /** |
||
| 528 | * Tests the port number to ensure it is an expected value. |
||
| 529 | * |
||
| 530 | * We expect that sites on be on one of: |
||
| 531 | * port 80, |
||
| 532 | * port 443 (https sites only), |
||
| 533 | * the value of JETPACK_SIGNATURE__HTTP_PORT, |
||
| 534 | * unless the site is intentionally on a different port (e.g. example.com:8080 is the site's URL). |
||
| 535 | * |
||
| 536 | * If the value isn't one of those and the site's URL doesn't include a port, then the signature verification will fail. |
||
| 537 | * |
||
| 538 | * This happens most commonly on sites with reverse proxies, so the edge (e.g. Varnish) is running on 80/443, but nginx |
||
| 539 | * or Apache is responding internally on a different port (e.g. 81). |
||
| 540 | * |
||
| 541 | * @return array Test results |
||
| 542 | */ |
||
| 543 | protected function test__server_port_value() { |
||
| 596 | |||
| 597 | /** |
||
| 598 | * Full Sync Health Test. |
||
| 599 | * |
||
| 600 | * Sync Disabled: Results in a skipped test |
||
| 601 | * Not In Progress : Results in a skipped test |
||
| 602 | * In Progress: Results in skipped test w/ status in CLI |
||
| 603 | */ |
||
| 604 | protected function test__full_sync_health() { |
||
| 668 | |||
| 669 | /** |
||
| 670 | * Sync Health Tests. |
||
| 671 | * |
||
| 672 | * Disabled: Results in a failing test (recommended) |
||
| 673 | * Delayed: Results in failing test (recommended) |
||
| 674 | * Error: Results in failing test (critical) |
||
| 675 | */ |
||
| 676 | protected function test__sync_health() { |
||
| 817 | |||
| 818 | /** |
||
| 819 | * Calls to WP.com to run the connection diagnostic testing suite. |
||
| 820 | * |
||
| 821 | * Intentionally added last as it will be skipped if any local failed conditions exist. |
||
| 822 | * |
||
| 823 | * @since 7.1.0 |
||
| 824 | * @since 7.9.0 Timeout waiting for a WP.com response no longer fails the test. Test is marked skipped instead. |
||
| 825 | * |
||
| 826 | * @return array Test results. |
||
| 827 | */ |
||
| 828 | protected function last__wpcom_self_test() { |
||
| 871 | } |
||
| 872 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.