Skip to content

Commit e859d4f

Browse files
LaunchDarklyReleaseBoteli-darklyhroederldLaunchDarklyCIbwoskow-ld
authored
prepare 4.2.4 release (#165)
* fix for ch22995 - include prereq value in event even if prereq is off * cache flag data in allFlags * rm unused imports * add option to reduce front-end metadata for untracked flags * add ability to load flags from a file * linter * data completeness * more data fixes * more data fixes * more data fixes * readme link * rm unused parameters * fix incorrect doc comment * add DynamoDB integration * fix test config * fix string check * readme * fix test data * factor out base class, implement caching, make configuration simpler * fix comment * rm unused const * can't scope constants * linter * add Consul integration * typo * regenerate lockfile using PHP 5.5 * we need at least version 2.1 of the Consul package * update lockfile * rm comment * remove lockfile * add delay for creating test table * move feature requester code into Integrations namespace * linter * misc test fixes * fix apc/apcu calls * fix comment * fix deprecated caching store classes * better caching abstraction * typo * linter * fix namespaces * fix tests * doc fixes * move a bunch more stuff * misc cleanup * add test for not having any flags * restore documentation for deprecated properties * version 3.5.0 * revert accidental commit * add experimentation event overrides for rules and fallthrough * linter * misc fixes * misc test fixes * Hr/ch34492/waitonconsul (#39) * add step to wait on Consul * coerce user attributes to strings when necessary, don't send events without valid users * explanatory comments * add release script (version update only) * use newer readme footer format * support metric value in track() * linter * update method description * add param to skip db tests, update docs for new repo name * wrong method name * add tests for rollout calculations, + misc test cleanup * misc doc fixes * misc doc fixes * update package name (#45) * add test for cached get all * typo * revert bugfix to test the test * reinstate bugfix * mix fixes, rename file * fix filename * misc cleanup * linter * misc fixes * test state cleanup * linter + fix filename in instructions * misc CI fixes, don't try to install phpredis in 5.6 * don't let user fall outside of last bucket in rollout * PHP 5.5 requires even null properties to be defined * minor cleanup * more accurate changelog text regarding phpredis * Add circle jobs for newer PHP versions. * Revert "Add circle jobs for newer PHP versions." This reverts commit 8939cb2. * implement doc generation with phpDocumentor 3 (prerelease), clean up doc tags (#50) * Add CI jobs for PHP 7.3 + 7.4 (#51) * ensure events aren't sent if send_events is false * clarify test with comment * make prefix concatenation in DynamoDB consistent with other SDKs * fix test * fix PHP 5.5 CI build by pinning Composer version (#54) * Updating warning log in Identify to not say Track was called (#56) * Removed the guides link * add alias functionality and some related tests * Revert "add alias functionality and some related tests" This reverts commit 2bf1cba. * add alias events support (#57) * add alias function to LDClient * add `contextKind` to events that require the new field * add tests for alias and contextKind * merge exp-alloc * drop support for EOL php versions and update deps (#60) * fix test class * remove database integrations from SDK (#63) * add type hints to FeatureRequesterBase methods * fix PHPRedis logic for prefix & custom client, add unit tests (#64) * add psalm lints and php hints (#62) * remove deprecated members (#65) * change default base URL to sdk.launchdarkly.com * move non-public classes into Impl namespace (#66) * add CI job for PHP 8.0 (#69) * use phpDocumentor 3 + misc doc comment cleanup (#68) * Updates docs URLs * pin Psalm to 4.9.2 to prevent a spurious linting error (#71) * use Releaser v2 config + add badge links in readme (#72) * use Releaser v2 config + add badge links in readme * fix badge URL * use Releaser PHP project template (#73) * use Releaser PHP project template * exclude implementation classes from docs * remove obsolete line that's no longer used because $seed is computed elsewhere * remove obsolete VERSION file * Fix test confirming send_events = false is honored (#78) * Minor cleanup and consistency changes (#79) * Add integration test for curl event publisher (#77) * Curl honor connect_timeout (#81) * Set required connect_timeout option in test (#82) * Add Windows support for "Curl" publisher (#80) * Add cs-check to build process (#83) * Don't treat numeric strings as numbers (#84) * Decrease psalm error level (#85) * added TestData, FlagBuilder; added TestDataTest; started implementing FlagBuilder methods * made props protected, made basic build method, made variations method with tests * continued implementing test data and tests for test data * implemented varationForAllUsers, valueForAllUsers, and variationForUsers along with corresponding tests * reorganized functions, added needed classes and functions, left some bodys blank to complete later, implemeted others, organized tests, added missing assertions * broken - transitioning build to return a FeatureFlag, finished implementing some methods * reverted build to return array, implemented getFeature and getAllFeatures methods in FeatureRequester interface for TestData * fixed build, implemented FeatureRequester, added simple test case * Event attribute filtering is overly aggressively (#86) If you try to create a custom attribute with a value of 0, our event serialization code would filter that out because `0 != null` is false. However, it is reasonable to expect that a user might want to provide the value of 0 as a custom value. The code has been updated to only exclude explicitly null values. * Account for traffic allocation on all flags (#87) * finished FlagRuleBuilder implementation; fixed psalm errors; improved comment blocks to adhere better to phpdoc; fixed formatting errors in both TestData and TestDataTest * fixed php-cs-fixer warnings in TestDataTest.php * Apply suggestions from code review Co-authored-by: Matthew M. Keeler <[email protected]> * replace use of array_push with append operator; standardized capitalization of booleans including in code blogs; other formatting adjustments * remove array_splice() implementation of existing user key removal due to breakage in unit tests * converted variationForUser to use array_splice but fixed issue caused by pass by reference instead of pass by value * fixed missing indexes required to decode FlagBuilder into a FeatureFlag using the decode() method * split off TestData\FlagBuilder and TestData\FlagRuleBuilder from TestData; add test coverage for TestData class * additional cleanup; added missing type hint; minor refactoring * remove special handling of singleton arrays in FlagBuilder::variations() * run php-cs-fixer on TestData-related files * started writing repetitive tests using the phpunit @dataProvider feature * swapped positions of expected and actual in dataProvider-driven test * fix typos in code in comment blocks * Apply whitespace fixes from code review Co-authored-by: Matthew M. Keeler <[email protected]> * split unwieldy tests in TestDataTest into separate tests; address TODO item * added annotations to dataProvider-driven tests * changed _isBooleanFlag() implementation to use strict equality * Add unit test to verify `in` operator in TestData (#89) * Add support for psr/log 2 and 3 (#91) * Adds link to Relay Proxy docs * master -> main * Add support for Guzzle 6.3 (#93) * Use setVersion on update of a changed flag (#161) - in TestData::update when flag is being copied from previous version - use setVersion rather than ['version'] to avoid generated error - associated unit test to update an initial flag, change the flag and update it again - unit-tested using docker for php 7.3, 7.4, 8.0, 8.1 Co-authored-by: Colin Henwood <[email protected]> * Add support for monolog 3.0 (#94) * fix base URI concatenation so path isn't lost * fix JSON output for empty allFlagsState result * lint * also fix base URIs for events * fix JSON output for empty allFlagsState result (#97) * fix base URI concatenation so path isn't lost (#96) * fix base URI concatenation so path isn't lost * also fix base URIs for events * implement contract test service (#95) * change test service to not require Docker, enable tests in CI (#100) Co-authored-by: Eli Bishop <[email protected]> Co-authored-by: Eli Bishop <[email protected]> Co-authored-by: hroederld <[email protected]> Co-authored-by: LaunchDarklyCI <[email protected]> Co-authored-by: Ben Woskow <[email protected]> Co-authored-by: Ben Woskow <[email protected]> Co-authored-by: Gavin Whelan <[email protected]> Co-authored-by: elliot <[email protected]> Co-authored-by: Elliot Haisley <[email protected]> Co-authored-by: Harpo Roeder <[email protected]> Co-authored-by: LaunchDarklyReleaseBot <[email protected]> Co-authored-by: Ember Stevens <[email protected]> Co-authored-by: ember-stevens <[email protected]> Co-authored-by: Matthew M. Keeler <[email protected]> Co-authored-by: charukiewicz <[email protected]> Co-authored-by: Joey Malinowski <[email protected]> Co-authored-by: Christian Charukiewicz <[email protected]> Co-authored-by: Matthew M. Keeler <[email protected]> Co-authored-by: Colin Henwood <[email protected]> Co-authored-by: Colin Henwood <[email protected]>
1 parent 952f335 commit e859d4f

File tree

16 files changed

+541
-17
lines changed

16 files changed

+541
-17
lines changed

.circleci/config.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ jobs:
5353

5454
environment:
5555
LD_INCLUDE_INTEGRATION_TESTS: 1
56+
TEST_HARNESS_PARAMS: -junit build/contract-tests-output/junit-results.xml
5657

5758
docker:
5859
- image: cimg/php:<<parameters.php-version>>
@@ -90,10 +91,23 @@ jobs:
9091
- run:
9192
name: run tests
9293
command: php -d xdebug.mode=coverage vendor/bin/phpunit
93-
enviroment:
94+
environment:
9495
XDEBUG_MODE: coverage
9596

97+
- run:
98+
name: build contract test service
99+
command: make build-contract-tests
100+
- run:
101+
name: start contract test service
102+
command: make start-contract-test-service
103+
background: true
104+
- run:
105+
name: run contract tests
106+
command: mkdir -p build/contract-tests-output && make run-contract-tests
107+
96108
- store_test_results:
97109
path: build/phpunit
110+
- store_test_results:
111+
path: build/contract-tests-output
98112
- store_artifacts:
99113
path: build/phpunit

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/vendor/
2+
/test-service/vendor/
23
/doc/
34
*.iml
45
composer.phar

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ By default, this test suite does not include any integration test that relies on
3939
```
4040
docker run --rm -p 8080:8080 wiremock/wiremock
4141
```
42+
43+
To run the SDK contract test suite in Linux (see [`test-service/README.md`](./test-service/README.md)):
44+
45+
```bash
46+
make contract-tests
47+
```

Makefile

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
TEMP_TEST_OUTPUT=/tmp/sse-contract-test-service.log
3+
4+
# TEST_HARNESS_PARAMS can be set to add -skip parameters for any contract tests that cannot yet pass
5+
# Explanation of current skips:
6+
# - "secondary": In the PHP SDK this is not an addressable attribute for clauses; in other
7+
# SDKs, it is. This was underspecified in the past; in future major versions, the other
8+
# SDKs and the contract tests will be in line with the PHP behavior.
9+
# - "date - bad syntax", "semver - bad type": The PHP SDK has insufficiently strict
10+
# validation for these types. We will definitely fix this in 5.0 but may or may not
11+
# address it in 4.x, since it does not prevent any valid values from working.
12+
TEST_HARNESS_PARAMS := $(TEST_HARNESS_PARAMS) \
13+
-skip 'evaluation/parameterized/secondary' \
14+
-skip 'evaluation/parameterized/operators - date - bad syntax' \
15+
-skip 'evaluation/parameterized/operators - semver - bad type'
16+
17+
build-contract-tests:
18+
@cd test-service && composer install --no-progress
19+
20+
start-contract-test-service: build-contract-tests
21+
@cd test-service && php -S localhost:8000 index.php
22+
23+
start-contract-test-service-bg:
24+
@echo "Test service output will be captured in $(TEMP_TEST_OUTPUT)"
25+
@make start-contract-test-service >$(TEMP_TEST_OUTPUT) 2>&1 &
26+
27+
run-contract-tests:
28+
@curl -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/main/downloader/run.sh \
29+
| VERSION=v1 PARAMS="-url http://localhost:8000 -debug -stop-service-at-end $(TEST_HARNESS_PARAMS)" sh
30+
31+
contract-tests: build-contract-tests start-contract-test-service-bg run-contract-tests
32+
33+
.PHONY: build-contract-tests start-contract-test-service start-contract-test-service-bg run-contract-tests contract-tests

src/LaunchDarkly/FeatureFlagsState.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,17 @@ public function toValuesMap(): array
149149
public function jsonSerialize(): array
150150
{
151151
$ret = array_replace([], $this->_flagValues);
152-
$metaMap = [];
153-
foreach ($this->_flagMetadata as $key => $meta) {
154-
$meta = array_replace([], $meta);
155-
if (isset($meta['reason'])) {
156-
$meta['reason'] = $meta['reason']->jsonSerialize();
152+
if (count($this->_flagMetadata) === 0) {
153+
$metaMap = new \stdClass(); // using object rather than array ensures the JSON value is {}, not []
154+
} else {
155+
$metaMap = [];
156+
foreach ($this->_flagMetadata as $key => $meta) {
157+
$meta = array_replace([], $meta);
158+
if (isset($meta['reason'])) {
159+
$meta['reason'] = $meta['reason']->jsonSerialize();
160+
}
161+
$metaMap[$key] = $meta;
157162
}
158-
$metaMap[$key] = $meta;
159163
}
160164
$ret['$flagsState'] = $metaMap;
161165
$ret['$valid'] = $this->_valid;

src/LaunchDarkly/Impl/Integrations/CurlEventPublisher.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ public function __construct(string $sdkKey, array $options = [])
4141
{
4242
$this->_sdkKey = $sdkKey;
4343

44-
$eventsUri = LDClient::DEFAULT_EVENTS_URI;
45-
if (isset($options['events_uri'])) {
46-
$eventsUri = $options['events_uri'];
44+
$baseUri = $options['events_uri'] ?? null;
45+
if (!$baseUri) {
46+
$baseUri = LDClient::DEFAULT_EVENTS_URI;
4747
}
48+
$eventsUri = \LaunchDarkly\Impl\Util::adjustBaseUri($baseUri);
49+
4850
$url = parse_url(rtrim($eventsUri, '/'));
4951
$this->_host = $url['host'] ?? '';
5052
$this->_ssl = ($url['scheme'] ?? '') === 'https';

src/LaunchDarkly/Impl/Integrations/GuzzleEventPublisher.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ public function __construct(string $sdkKey, array $options = [])
2828
{
2929
$this->_sdkKey = $sdkKey;
3030
$this->_logger = $options['logger'];
31-
if (isset($options['events_uri'])) {
32-
$this->_eventsUri = $options['events_uri'];
33-
} else {
34-
$this->_eventsUri = LDClient::DEFAULT_EVENTS_URI;
31+
32+
$baseUri = $options['events_uri'] ?? null;
33+
if (!$baseUri) {
34+
$baseUri = LDClient::DEFAULT_EVENTS_URI;
3535
}
36+
$this->_eventsUri = \LaunchDarkly\Impl\Util::adjustBaseUri($baseUri);
37+
3638
$this->_requestOptions = [
3739
'headers' => [
3840
'Content-Type' => 'application/json',
@@ -53,7 +55,7 @@ public function publish(string $payload): bool
5355
try {
5456
$options = $this->_requestOptions;
5557
$options['body'] = $payload;
56-
$response = $client->request('POST', '/bulk', $options);
58+
$response = $client->request('POST', 'bulk', $options);
5759
} catch (\Exception $e) {
5860
$this->_logger->warning("GuzzleEventPublisher::publish caught $e");
5961
return false;

src/LaunchDarkly/Impl/Integrations/GuzzleFeatureRequester.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
*/
2222
class GuzzleFeatureRequester implements FeatureRequester
2323
{
24-
const SDK_FLAGS = "/sdk/flags";
25-
const SDK_SEGMENTS = "/sdk/segments";
24+
const SDK_FLAGS = "sdk/flags";
25+
const SDK_SEGMENTS = "sdk/segments";
2626
/** @var Client */
2727
private $_client;
2828
/** @var LoggerInterface */
@@ -32,6 +32,8 @@ class GuzzleFeatureRequester implements FeatureRequester
3232

3333
public function __construct(string $baseUri, string $sdkKey, array $options)
3434
{
35+
$baseUri = \LaunchDarkly\Impl\Util::adjustBaseUri($baseUri);
36+
3537
$this->_logger = $options['logger'];
3638
$stack = HandlerStack::create();
3739
if (class_exists('\Kevinrob\GuzzleCache\CacheMiddleware')) {

src/LaunchDarkly/Impl/Util.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
*/
1414
class Util
1515
{
16+
public static function adjustBaseUri(string $uri): string
17+
{
18+
if (substr($uri, strlen($uri) - 1, 1) == '/') {
19+
return $uri;
20+
}
21+
return $uri . '/'; // ensures that subpaths are concatenated correctly
22+
}
23+
1624
public static function dateTimeToUnixMillis(DateTime $dateTime): int
1725
{
1826
$timeStampSeconds = (int)$dateTime->getTimestamp();

test-service/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SDK contract test service
2+
3+
This directory contains an implementation of the cross-platform SDK testing protocol defined by https://github.com/launchdarkly/sdk-test-harness. See that project's `README` for details of this protocol, and the kinds of SDK capabilities that are relevant to the contract tests. This code should not need to be updated unless the SDK has added or removed such capabilities.
4+
5+
To run these tests locally, run `make contract-tests` from the SDK project root directory. This downloads the correct version of the test harness tool automatically.
6+
7+
Or, to test against an in-progress local version of the test harness, run `make start-contract-test-service` from the SDK project root directory; then, in the root directory of the `sdk-test-harness` project, build the test harness and run it from the command line.
8+
9+
The test service is designed to be run by any web server; PHP's built-in development server is adequate. The server must be configured to run `index.php` for all requests. The environment variable `LD_TEST_SERVICE_DATA_DIR` can be set, if desired, to point to a specific file path where the test service can store data; otherwise it will create a directory under `/tmp`.

0 commit comments

Comments
 (0)