Skip to content

Commit 43076be

Browse files
authored
Production release v20240528.0 (#5613)
Production release v20240528.0
2 parents 056e190 + 5dd61e6 commit 43076be

10 files changed

+236
-10
lines changed

.github/actions/run-wp-tests/action.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ runs:
122122
"${PHPUNIT}" ${OPTIONS}
123123
124124
- name: Upload coverage report
125-
uses: codecov/codecov-action@v4.3.1
125+
uses: codecov/codecov-action@v4.4.1
126126
with:
127127
files: ${{ inputs.coverage-file }}
128128
flags: ${{ inputs.coverage-flags }}

integrations/enterprise-search.php

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/**
3+
* Integration: Enterprise Search.
4+
*
5+
* @package Automattic\VIP\Integrations
6+
*/
7+
8+
namespace Automattic\VIP\Integrations;
9+
10+
/**
11+
* Loads Enterprise Search VIP Integration.
12+
*/
13+
class EnterpriseSearchIntegration extends Integration {
14+
15+
/**
16+
* The version of Enterprise Search to load.
17+
*
18+
* @var string
19+
*/
20+
protected string $version = '1.0';
21+
22+
/**
23+
* Returns `true` if Enterprise Search is already available e.g. customer code. We will use
24+
* this function to prevent loading of integration again from platform side.
25+
*/
26+
public function is_loaded(): bool {
27+
return class_exists( \Automattic\VIP\Search\Search::class );
28+
}
29+
30+
/**
31+
* Loads the plugin.
32+
*/
33+
public function load(): void {
34+
// Return if the integration is already loaded.
35+
//
36+
// In activate() method we do make sure to not activate the integration if its already loaded
37+
// but still adding it here as a safety measure i.e. if load() is called directly.
38+
if ( $this->is_loaded() ) {
39+
return;
40+
}
41+
42+
// Load the version of the plugin that should be set to the latest version, otherwise if it's not found, fallback to the one in MU.
43+
$load_path = WPVIP_MU_PLUGIN_DIR . '/vip-integrations/vip-enterprise-search-' . $this->version . '/src/search.php';
44+
$use_versions = false; // Remove this once we are ready to use the versioned plugin.
45+
if ( $use_versions && file_exists( $load_path ) ) {
46+
require_once $load_path;
47+
} else {
48+
require_once __DIR__ . '/../search/search.php';
49+
}
50+
}
51+
52+
/**
53+
* Configure `Enterprise Search` for VIP Platform.
54+
*/
55+
public function configure(): void {
56+
if ( $this->is_es_credentials_set() ) {
57+
return;
58+
}
59+
60+
add_action( 'vip_search_loaded', array( $this, 'vip_set_es_credentials' ) );
61+
}
62+
63+
/**
64+
* Set the Elasticsearch credentials.
65+
*/
66+
public function vip_set_es_credentials(): void {
67+
$config = $this->get_config();
68+
if ( isset( $config['username'] ) && isset( $config['password'] ) ) {
69+
define( 'VIP_ELASTICSEARCH_USERNAME', $config['username'] );
70+
define( 'VIP_ELASTICSEARCH_PASSWORD', $config['password'] );
71+
}
72+
}
73+
74+
private function is_es_credentials_set(): bool {
75+
$username_defined = defined( 'VIP_ELASTICSEARCH_USERNAME' ) && constant( 'VIP_ELASTICSEARCH_USERNAME' );
76+
$password_defined = defined( 'VIP_ELASTICSEARCH_PASSWORD' ) && constant( 'VIP_ELASTICSEARCH_PASSWORD' );
77+
return $username_defined && $password_defined;
78+
}
79+
}

integrations/integration-vip-config.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,14 @@ public function get_site_status() {
135135
* Get site config.
136136
*
137137
* @return array
138-
*
139-
* @private
140138
*/
141139
public function get_site_config() {
142140
if ( is_multisite() ) {
143141
$config = $this->get_value_from_config( 'network_sites', 'config' );
142+
// If network site config is not found then fallback to env config if it exists
143+
if ( empty( $config ) && true === $this->get_value_from_config( 'env', 'cascade_config' ) ) {
144+
$config = $this->get_value_from_config( 'env', 'config' );
145+
}
144146
} else {
145147
$config = $this->get_value_from_config( 'env', 'config' );
146148
}

jetpack.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Plugin URI: https://jetpack.com
55
* Description: Security, performance, and marketing tools made by WordPress experts. Jetpack keeps your site protected so you can focus on more important things.
66
* Author: Automattic
7-
* Version: 13.4.2
7+
* Version: 13.4.3
88
* Author URI: https://jetpack.com
99
* License: GPL2+
1010
* Text Domain: jetpack
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
/**
3+
* Test: Enterprise Search Integration.
4+
*
5+
* @package Automattic\VIP\Integrations
6+
*/
7+
8+
namespace Automattic\VIP\Integrations;
9+
10+
use PHPUnit\Framework\MockObject\MockObject;
11+
use WP_UnitTestCase;
12+
use Automattic\Test\Constant_Mocker;
13+
14+
use function Automattic\Test\Utils\get_class_property_as_public;
15+
16+
// phpcs:disable Squiz.Commenting.ClassComment.Missing, Squiz.Commenting.FunctionComment.Missing, Squiz.Commenting.VariableComment.Missing
17+
18+
class VIP_EnterpriseSearch_Integration_Test extends WP_UnitTestCase {
19+
private string $slug = 'enterprise-search';
20+
21+
public function tearDown(): void {
22+
parent::tearDown();
23+
24+
Constant_Mocker::clear();
25+
}
26+
27+
public function test_is_loaded_returns_true_if_es_exist(): void {
28+
require_once __DIR__ . '/../../search/search.php';
29+
30+
$es_integration = new EnterpriseSearchIntegration( $this->slug );
31+
$this->assertTrue( $es_integration->is_loaded() );
32+
}
33+
34+
public function test__load_call_returns_without_requiring_class_if_es_is_already_loaded(): void {
35+
/**
36+
* Integration mock.
37+
*
38+
* @var MockObject|EnterpriseSearchIntegration
39+
*/
40+
$es_integration_mock = $this->getMockBuilder( EnterpriseSearchIntegration::class )->setConstructorArgs( [ 'enterprise-search' ] )->onlyMethods( [ 'is_loaded' ] )->getMock();
41+
$es_integration_mock->expects( $this->once() )->method( 'is_loaded' )->willReturn( true );
42+
$preload_state = class_exists( '\Automattic\VIP\Search\Search' );
43+
44+
$es_integration_mock->load();
45+
46+
$this->assertEquals( $preload_state, class_exists( '\Automattic\VIP\Search\Search' ) );
47+
}
48+
49+
public function test__load_call_if_class_not_exist(): void {
50+
/**
51+
* Integration mock.
52+
*
53+
* @var MockObject|EnterpriseSearchIntegration
54+
*/
55+
$es_integration_mock = $this->getMockBuilder( EnterpriseSearchIntegration::class )->setConstructorArgs( [ 'enterprise-search' ] )->onlyMethods( [ 'is_loaded' ] )->getMock();
56+
$es_integration_mock->expects( $this->once() )->method( 'is_loaded' )->willReturn( false );
57+
$existing_value = class_exists( '\Automattic\VIP\Search\Search' );
58+
59+
$es_integration_mock->load();
60+
61+
if ( ! $existing_value ) {
62+
$this->assertTrue( class_exists( '\Automattic\VIP\Search\Search' ) );
63+
}
64+
}
65+
66+
public function test__configure_action(): void {
67+
$credentials = [
68+
'username' => 'test-username',
69+
'password' => 'foo-bar',
70+
];
71+
$es_integration = new EnterpriseSearchIntegration( $this->slug );
72+
$es_integration->configure();
73+
74+
get_class_property_as_public( Integration::class, 'options' )->setValue( $es_integration, [
75+
'config' => $credentials,
76+
] );
77+
78+
do_action( 'vip_search_loaded' );
79+
80+
$this->assertEquals( 10, has_action( 'vip_search_loaded', [ $es_integration, 'vip_set_es_credentials' ] ) );
81+
$this->assertEquals( constant( 'VIP_ELASTICSEARCH_USERNAME' ), $credentials['username'] );
82+
$this->assertEquals( constant( 'VIP_ELASTICSEARCH_PASSWORD' ), $credentials['password'] );
83+
}
84+
85+
public function test__should_not_configure_if_es_constants_are_already_present(): void {
86+
Constant_Mocker::define( 'VIP_ELASTICSEARCH_USERNAME', 'baz' );
87+
Constant_Mocker::define( 'VIP_ELASTICSEARCH_PASSWORD', '123' );
88+
89+
$credentials = [
90+
'username' => 'test-username',
91+
'password' => 'foo-bar',
92+
];
93+
$es_integration = new EnterpriseSearchIntegration( $this->slug );
94+
get_class_property_as_public( Integration::class, 'options' )->setValue( $es_integration, [
95+
'config' => $credentials,
96+
] );
97+
$es_integration->configure();
98+
99+
100+
$this->assertEquals( false, has_action( 'vip_search_loaded', [ $es_integration, 'vip_set_es_credentials' ] ) );
101+
$this->assertEquals( Constant_Mocker::constant( 'VIP_ELASTICSEARCH_USERNAME' ), 'baz' );
102+
$this->assertEquals( Constant_Mocker::constant( 'VIP_ELASTICSEARCH_PASSWORD' ), '123' );
103+
}
104+
}

tests/integrations/test-integration-vip-config.php

+22
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,28 @@ public function test__get_site_config_returns_value_from_network_site_config():
231231
);
232232
}
233233

234+
public function test__get_site_config_with_cascading_config(): void {
235+
if ( ! is_multisite() ) {
236+
$this->markTestSkipped( 'Only valid for multisite.' );
237+
}
238+
239+
$this->do_test_get_site_config(
240+
[
241+
'env' => [
242+
'status' => Env_Integration_Status::ENABLED,
243+
'config' => array( 'env-config' ),
244+
'cascade_config' => true,
245+
],
246+
'network_sites' => [
247+
'1' => [
248+
'status' => Env_Integration_Status::ENABLED,
249+
],
250+
],
251+
],
252+
array( 'env-config' ),
253+
);
254+
}
255+
234256
/**
235257
* Helper function for testing `get_site_config`.
236258
*

tests/integrations/test-parsely.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use PHPUnit\Framework\MockObject\MockObject;
1111
use WP_UnitTestCase;
12+
use Automattic\Test\Constant_Mocker;
1213

1314
use function Automattic\Test\Utils\get_class_property_as_public;
1415

@@ -32,11 +33,11 @@ public function test__load_call_returns_without_setting_constant_if_parsely_is_a
3233
*/
3334
$parsely_integration_mock = $this->getMockBuilder( ParselyIntegration::class )->setConstructorArgs( [ 'parsely' ] )->onlyMethods( [ 'is_loaded' ] )->getMock();
3435
$parsely_integration_mock->expects( $this->once() )->method( 'is_loaded' )->willReturn( true );
35-
$preload_state = defined( 'VIP_PARSELY_ENABLED' );
36+
$preload_state = Constant_Mocker::defined( 'VIP_PARSELY_ENABLED' );
3637

3738
$parsely_integration_mock->load();
3839

39-
$this->assertEquals( $preload_state, defined( 'VIP_PARSELY_ENABLED' ) );
40+
$this->assertEquals( $preload_state, Constant_Mocker::defined( 'VIP_PARSELY_ENABLED' ) );
4041
}
4142

4243
public function test__load_call_is_setting_the_enabled_constant_if_no_constant_is_defined(): void {
@@ -47,14 +48,14 @@ public function test__load_call_is_setting_the_enabled_constant_if_no_constant_i
4748
*/
4849
$parsely_integration_mock = $this->getMockBuilder( ParselyIntegration::class )->setConstructorArgs( [ 'parsely' ] )->onlyMethods( [ 'is_loaded' ] )->getMock();
4950
$parsely_integration_mock->expects( $this->once() )->method( 'is_loaded' )->willReturn( false );
50-
$existing_value = defined( 'VIP_PARSELY_ENABLED' ) ? VIP_PARSELY_ENABLED : null;
51+
$existing_value = Constant_Mocker::defined( 'VIP_PARSELY_ENABLED' ) ? Constant_Mocker::constant( 'VIP_PARSELY_ENABLED' ) : null;
5152

5253
$parsely_integration_mock->load();
5354

5455
if ( is_null( $existing_value ) || $existing_value ) {
55-
$this->assertTrue( VIP_PARSELY_ENABLED );
56+
$this->assertTrue( Constant_Mocker::constant( 'VIP_PARSELY_ENABLED' ) );
5657
} else {
57-
$this->assertFalse( defined( 'VIP_PARSELY_ENABLED' ) );
58+
$this->assertFalse( Constant_Mocker::defined( 'VIP_PARSELY_ENABLED' ) );
5859
}
5960
}
6061

tests/mock-constants.php

+16
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,19 @@ function constant( $constant ) {
232232
return Constant_Mocker::constant( $constant );
233233
}
234234
}
235+
236+
namespace Automattic\VIP\Integrations {
237+
use Automattic\Test\Constant_Mocker;
238+
239+
function define( $constant, $value ) {
240+
return Constant_Mocker::define( $constant, $value );
241+
}
242+
243+
function defined( $constant ) {
244+
return Constant_Mocker::defined( $constant );
245+
}
246+
247+
function constant( $constant ) {
248+
return Constant_Mocker::constant( $constant );
249+
}
250+
}

vip-integrations.php

+2
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
require_once __DIR__ . '/integrations/block-data-api.php';
2323
require_once __DIR__ . '/integrations/parsely.php';
2424
require_once __DIR__ . '/integrations/vip-governance.php';
25+
require_once __DIR__ . '/integrations/enterprise-search.php';
2526

2627
// Register VIP integrations here.
2728
IntegrationsSingleton::instance()->register( new BlockDataApiIntegration( 'block-data-api' ) );
2829
IntegrationsSingleton::instance()->register( new ParselyIntegration( 'parsely' ) );
2930
IntegrationsSingleton::instance()->register( new VipGovernanceIntegration( 'vip-governance' ) );
31+
IntegrationsSingleton::instance()->register( new EnterpriseSearchIntegration( 'enterprise-search' ) );
3032
// @codeCoverageIgnoreEnd
3133

3234
/**

0 commit comments

Comments
 (0)