From ae53f5dd2a4b3a13fdb811b036fd9d08d4824349 Mon Sep 17 00:00:00 2001 From: Julien Maurel Date: Mon, 30 Dec 2024 11:03:42 +0100 Subject: [PATCH 01/27] Add php 8.4 compatibility --- .ci/packer_cache.sh | 3 +- .ci/shared.sh | 2 +- .github/workflows/loop.yml | 1 + .github/workflows/phpt.yml | 1 + .github/workflows/test.yml | 2 + agent/native/CMakeLists.txt | 3 +- .../building/dependencies/php84/conandata.yml | 37 ++++++++++++ .../building/dependencies/php84/conanfile.py | 56 +++++++++++++++++++ agent/native/loader/code/phpdetection.cpp | 5 +- composer.json | 2 +- docs/setup.asciidoc | 2 +- docs/supported-technologies.asciidoc | 2 +- packaging/post-install.sh | 5 +- packaging/test/docker-compose.yml | 38 +++++++++++++ .../GenerateUnpackScriptsTest.php | 2 +- 15 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 agent/native/building/dependencies/php84/conandata.yml create mode 100644 agent/native/building/dependencies/php84/conanfile.py diff --git a/.ci/packer_cache.sh b/.ci/packer_cache.sh index 12b96fead..3b947b728 100755 --- a/.ci/packer_cache.sh +++ b/.ci/packer_cache.sh @@ -15,6 +15,7 @@ php:8.0-fpm php:8.1-fpm php:8.2-fpm php:8.3-fpm +php:8.4-fpm ruby:2.7.1-alpine3.12 ubuntu:20.04 " @@ -26,7 +27,7 @@ if [ -x "$(command -v docker)" ]; then # Make sure list of PHP versions supported by the Elastic APM PHP Agent is in sync. # See the comment in .ci/shared.sh - for version in 7.2 7.3 7.4 8.0 8.1 8.2 8.3 + for version in 7.2 7.3 7.4 8.0 8.1 8.2 8.3 8.4 do PHP_VERSION=${version} make -f .ci/Makefile prepare || true DOCKERFILE=Dockerfile.alpine PHP_VERSION=${version} make -f .ci/Makefile prepare || true diff --git a/.ci/shared.sh b/.ci/shared.sh index 63963943e..6d1641581 100644 --- a/.ci/shared.sh +++ b/.ci/shared.sh @@ -16,7 +16,7 @@ set -e # *) docker-compose.yml in packaging/test # -export ELASTIC_APM_PHP_TESTS_SUPPORTED_PHP_VERSIONS=(7.2 7.3 7.4 8.0 8.1 8.2 8.3) +export ELASTIC_APM_PHP_TESTS_SUPPORTED_PHP_VERSIONS=(7.2 7.3 7.4 8.0 8.1 8.2 8.3 8.4) export ELASTIC_APM_PHP_TESTS_SUPPORTED_LINUX_NATIVE_PACKAGE_TYPES=(apk deb rpm) export ELASTIC_APM_PHP_TESTS_SUPPORTED_LINUX_PACKAGE_TYPES=("${ELASTIC_APM_PHP_TESTS_SUPPORTED_LINUX_NATIVE_PACKAGE_TYPES[@]}" tar) diff --git a/.github/workflows/loop.yml b/.github/workflows/loop.yml index a5b7169d8..871f45137 100644 --- a/.github/workflows/loop.yml +++ b/.github/workflows/loop.yml @@ -23,6 +23,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" dockerfile: - "Dockerfile" - "Dockerfile.alpine" diff --git a/.github/workflows/phpt.yml b/.github/workflows/phpt.yml index 9dd4c8fe5..7cd3bc569 100644 --- a/.github/workflows/phpt.yml +++ b/.github/workflows/phpt.yml @@ -28,6 +28,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" steps: # - uses: actions/checkout@v4 # - name: Fetch and extract latest release of apm-agent-php diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e65acb668..ff735b233 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,6 +58,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" data: ${{ fromJson(needs.setup-build-matrix.outputs.matrix-combinations).include }} env: PHP_VERSION: ${{ matrix.php-version }} @@ -94,6 +95,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" dockerfile: - "Dockerfile" - "Dockerfile.alpine" diff --git a/agent/native/CMakeLists.txt b/agent/native/CMakeLists.txt index 2758c03c8..22252ec7b 100644 --- a/agent/native/CMakeLists.txt +++ b/agent/native/CMakeLists.txt @@ -43,7 +43,7 @@ include(elastic_conan_debugsymbols) # Install project dependencies -set(_supported_php_versions 72 73 74 80 81 82 83) +set(_supported_php_versions 72 73 74 80 81 82 83 84) function(get_php_api_from_release php_version ret_val) block(SCOPE_FOR VARIABLES) @@ -54,6 +54,7 @@ function(get_php_api_from_release php_version ret_val) set(_php_release_81 20210902) set(_php_release_82 20220829) set(_php_release_83 20230831) + set(_php_release_84 20240924) set(${ret_val} ${_php_release_${php_version}}) return(PROPAGATE ${ret_val}) diff --git a/agent/native/building/dependencies/php84/conandata.yml b/agent/native/building/dependencies/php84/conandata.yml new file mode 100644 index 000000000..55abcef12 --- /dev/null +++ b/agent/native/building/dependencies/php84/conandata.yml @@ -0,0 +1,37 @@ +name: "php-headers-84" +version: "1.0" +php_source_version: 8.4.1 + +sources: + 7.2.34: + linux: + - url: "https://www.php.net/distributions/php-7.2.34.tar.gz" + contentsRoot: "php-7.2.34" + 7.3.33: + linux: + - url: "https://www.php.net/distributions/php-7.3.33.tar.gz" + contentsRoot: "php-7.3.33" + 7.4.33: + linux: + - url: "https://www.php.net/distributions/php-7.4.33.tar.gz" + contentsRoot: "php-7.4.33" + 8.0.28: + linux: + - url: "https://www.php.net/distributions/php-8.0.28.tar.gz" + contentsRoot: "php-8.0.28" + 8.1.18: + linux: + - url: "https://www.php.net/distributions/php-8.1.18.tar.gz" + contentsRoot: "php-8.1.18" + 8.2.5: + linux: + - url: "https://www.php.net/distributions/php-8.2.5.tar.gz" + contentsRoot: "php-8.2.5" + 8.3.2: + linux: + - url: "https://www.php.net/distributions/php-8.3.2.tar.gz" + contentsRoot: "php-8.3.2" + 8.4.1: + linux: + - url: "https://www.php.net/distributions/php-8.4.1.tar.gz" + contentsRoot: "php-8.4.1" diff --git a/agent/native/building/dependencies/php84/conanfile.py b/agent/native/building/dependencies/php84/conanfile.py new file mode 100644 index 000000000..2f1ec5fcc --- /dev/null +++ b/agent/native/building/dependencies/php84/conanfile.py @@ -0,0 +1,56 @@ +import os +import shutil + +from conans import tools, ConanFile, AutoToolsBuildEnvironment + +class PhpHeadersForPHP81Conan(ConanFile): + description = "PHP headers package required to build Elastic APM agent without additional PHP dependencies" + license = "The PHP License, version 3.01" + homepage = "https://php.net/" + url = "https://php.net/" + author = "pawel.filipczak@elastic.co" + + settings = "os", "compiler", "build_type", "arch" + platform = "linux" + + def init(self): + self.name = self.conan_data["name"] + self.version = self.conan_data["version"] # version of the package + self.php_version = self.conan_data["php_source_version"] # version of the PHP to build + self.source_temp_dir = "php-src" + + def requirements(self): + self.requires("libxml2/2.9.9") + self.requires("sqlite3/3.29.0") + + def source(self): + for source in self.conan_data["sources"][self.php_version][self.platform]: + + if "contentsRoot" in source: + # small hack - it can't contain custom fields, so we're removing it from source (got an unexpected keyword argument) + contentRoot = source["contentsRoot"] + del source["contentsRoot"] + tools.get(**source) + os.rename(contentRoot, self.source_temp_dir) + else: + self.output.error("Could not find 'contentsRoot' in conandata.yml") + raise Exception("Could not find 'contentsRoot' in conandata.yml") + + def build(self): + with tools.chdir(os.path.join(self.source_folder, self.source_temp_dir)): + buildEnv = AutoToolsBuildEnvironment(self) + envVariables = buildEnv.vars + envVariables['ac_cv_php_xml2_config_path'] = os.path.join(self.deps_cpp_info["libxml2"].rootpath, "bin/xml2-config") + envVariables['LIBXML_LIBS'] = os.path.join(self.deps_cpp_info["libxml2"].rootpath, self.deps_cpp_info["libxml2"].libdirs[0]) + envVariables['LIBXML_CFLAGS'] = "-I{}".format(os.path.join(self.deps_cpp_info["libxml2"].rootpath, self.deps_cpp_info["libxml2"].includedirs[0])) + envVariables['SQLITE_LIBS'] = os.path.join(self.deps_cpp_info["sqlite3"].rootpath, self.deps_cpp_info["sqlite3"].libdirs[0]) + envVariables['SQLITE_CFLAGS'] = "-I{}".format(os.path.join(self.deps_cpp_info["sqlite3"].rootpath, self.deps_cpp_info["sqlite3"].includedirs[0])) + self.run("./buildconf --force") + buildEnv.configure(args=[""], vars=envVariables, build=False, host=False) + + def package(self): + source = os.path.join(self.source_folder, self.source_temp_dir) + self.copy("*.h", src=source, dst='include', keep_path=True) + + def package_id(self): + del self.info.settings.compiler.version diff --git a/agent/native/loader/code/phpdetection.cpp b/agent/native/loader/code/phpdetection.cpp index 5f618308d..42f58e653 100644 --- a/agent/native/loader/code/phpdetection.cpp +++ b/agent/native/loader/code/phpdetection.cpp @@ -56,9 +56,10 @@ bool isThreadSafe() { std::tuple getZendModuleApiVersion(std::string_view zendVersion) { using namespace std::string_view_literals; - constexpr size_t knownVersionsCount = 16; + constexpr size_t knownVersionsCount = 17; constexpr std::array, knownVersionsCount> knownPhpVersions {{ + {"4.4"sv, 20240924, true}, // PHP 8.4 {"4.3"sv, 20230831, true}, // PHP 8.3 {"4.2"sv, 20220829, true}, // PHP 8.2 {"4.1"sv, 20210902, true}, // PHP 8.1 @@ -91,4 +92,4 @@ std::tuple getZendModuleApiVersion(std::string_view -} \ No newline at end of file +} diff --git a/composer.json b/composer.json index 8ca7db8c5..d7635e117 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ { "name": "Sergey Kleyman" } ], "require": { - "php": "^7.2||8.0.*||8.1.*||8.2.*||8.3.*", + "php": "^7.2||8.0.*||8.1.*||8.2.*||8.3.*||8.4.*" "ext-json": "*", "ext-pcntl": "*", "psr/log": "^1.0" diff --git a/docs/setup.asciidoc b/docs/setup.asciidoc index fb4d27024..0d1f26347 100644 --- a/docs/setup.asciidoc +++ b/docs/setup.asciidoc @@ -18,7 +18,7 @@ NOTE: Experimentally, we also provide packages for the ARM64 architecture - plea [discrete] ==== PHP -The agent supports PHP versions 7.2-8.3. +The agent supports PHP versions 7.2-8.4. [discrete] ==== curl diff --git a/docs/supported-technologies.asciidoc b/docs/supported-technologies.asciidoc index c5bb09069..4537ef199 100644 --- a/docs/supported-technologies.asciidoc +++ b/docs/supported-technologies.asciidoc @@ -21,7 +21,7 @@ Experimentally, we also provide packages for the ARM64 architecture - please not [[supported-php-versions]] === PHP versions -The agent supports PHP versions 7.2-8.3. +The agent supports PHP versions 7.2-8.4. [float] [[unsupported-php-sapis]] diff --git a/packaging/post-install.sh b/packaging/post-install.sh index c40f5da2f..472af4852 100755 --- a/packaging/post-install.sh +++ b/packaging/post-install.sh @@ -205,11 +205,12 @@ function is_php_supported() { [ "${PHP_MAJOR_MINOR}" == "8.0" ] || \ [ "${PHP_MAJOR_MINOR}" == "8.1" ] || \ [ "${PHP_MAJOR_MINOR}" == "8.2" ] || \ - [ "${PHP_MAJOR_MINOR}" == "8.3" ] + [ "${PHP_MAJOR_MINOR}" == "8.3" ] || \ + [ "${PHP_MAJOR_MINOR}" == "8.4" ] then return 0 else - echo 'Failed. The supported PHP versions are 7.2-8.3.' + echo 'Failed. The supported PHP versions are 7.2-8.4.' return 1 fi } diff --git a/packaging/test/docker-compose.yml b/packaging/test/docker-compose.yml index f738f3e97..82a977e55 100644 --- a/packaging/test/docker-compose.yml +++ b/packaging/test/docker-compose.yml @@ -1,5 +1,13 @@ version: "3" services: + deb-fpm-php84: + image: elasticobservability/apm-agent-php-dev:packages-test-deb-fpm-php-8.4-0.0.1 + build: + context: ubuntu + dockerfile: fpm/Dockerfile + args: + - PHP_VERSION=8.4 + - SEL_DISTRO=bullseye deb-fpm-php83: image: elasticobservability/apm-agent-php-dev:packages-test-deb-fpm-php-8.3-0.0.1 build: @@ -54,6 +62,14 @@ services: + deb-apache-php84: + image: elasticobservability/apm-agent-php-dev:packages-test-deb-apache-php-8.4-0.0.1 + build: + context: ubuntu + dockerfile: apache/Dockerfile + args: + - PHP_VERSION=8.4 + - SEL_DISTRO=bullseye deb-apache-php83: image: elasticobservability/apm-agent-php-dev:packages-test-deb-apache-php-8.3-0.0.1 build: @@ -106,6 +122,14 @@ services: - PHP_VERSION=7.2 + deb-php84: + image: elasticobservability/apm-agent-php-dev:packages-test-deb-php-8.4-0.0.1 + build: + context: ubuntu + dockerfile: Dockerfile + args: + - PHP_VERSION=8.4 + - SEL_DISTRO=bullseye deb-php83: image: elasticobservability/apm-agent-php-dev:packages-test-deb-php-8.3-0.0.1 build: @@ -157,6 +181,13 @@ services: args: - PHP_VERSION=7.2 + rpm-php84: + image: elasticobservability/apm-agent-php-dev:packages-test-rpm-php-8.4-0.0.3 + build: + context: centos + dockerfile: Dockerfile + args: + - PHP_VERSION=8.4 rpm-php83: image: elasticobservability/apm-agent-php-dev:packages-test-rpm-php-8.3-0.0.3 build: @@ -207,6 +238,13 @@ services: args: - PHP_VERSION=7.2 + apk-php83: + image: elasticobservability/apm-agent-php-dev:packages-test-apk-php-8.4-0.0.1 + build: + context: alpine + dockerfile: Dockerfile + args: + - PHP_VERSION=8.4 apk-php83: image: elasticobservability/apm-agent-php-dev:packages-test-apk-php-8.3-0.0.1 build: diff --git a/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php b/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php index c5f82c498..bad13a6d4 100644 --- a/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php +++ b/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php @@ -52,7 +52,7 @@ final class GenerateUnpackScriptsTest extends ComponentTestCaseBase implements L private const PHP_VERSION_7_4 = '7.4'; // Make sure list of PHP versions supported by the Elastic APM PHP Agent is in sync. // See the comment in .ci/shared.sh - private const SUPPORTED_PHP_VERSIONS = ['7.2', '7.3', self::PHP_VERSION_7_4, '8.0', '8.1', '8.2', '8.3']; + private const SUPPORTED_PHP_VERSIONS = ['7.2', '7.3', self::PHP_VERSION_7_4, '8.0', '8.1', '8.2', '8.3', '8.4']; private const LINUX_PACKAGE_TYPE_DEB = 'deb'; private const LINUX_PACKAGE_TYPE_RPM = 'rpm'; From 87833022b1bd43fcd642d13ae401f0601182b012 Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Fri, 10 Jan 2025 11:30:05 +0100 Subject: [PATCH 02/27] Fixed missing comma in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d7635e117..26bcb2d5b 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ { "name": "Sergey Kleyman" } ], "require": { - "php": "^7.2||8.0.*||8.1.*||8.2.*||8.3.*||8.4.*" + "php": "^7.2||8.0.*||8.1.*||8.2.*||8.3.*||8.4.*", "ext-json": "*", "ext-pcntl": "*", "psr/log": "^1.0" From a6024069bc3a74dfa7170fe5b3760e7a629c6808 Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Fri, 10 Jan 2025 11:33:37 +0100 Subject: [PATCH 03/27] Removed deprecated E_STRICT --- agent/native/ext/tests_util/tests_util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/native/ext/tests_util/tests_util.php b/agent/native/ext/tests_util/tests_util.php index 0b3a60f67..b7528ae83 100644 --- a/agent/native/ext/tests_util/tests_util.php +++ b/agent/native/ext/tests_util/tests_util.php @@ -21,7 +21,7 @@ declare(strict_types=1); -error_reporting(E_ALL | E_STRICT); +error_reporting(E_ALL); function elasticApmOnAssertFailure(string $condDesc, string $expr, $actual, $expected) { From 327179858194f1e830fdddfd0bb0726d80185cd8 Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Fri, 10 Jan 2025 11:52:44 +0100 Subject: [PATCH 04/27] Updated phpstan --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 26bcb2d5b..f4046a6ea 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,8 @@ "php-ds/php-ds": "^1.4.1", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.10.14", - "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan": "2.0.2", + "phpstan/phpstan-phpunit": "^2.0.1", "phpunit/phpunit": "^8.5||^9.5", "react/async": "^3.0", "react/http": "^1.6", From e0c0b2a46b534d90fba0aca8dd58312be4c0280e Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Fri, 10 Jan 2025 13:12:31 +0100 Subject: [PATCH 05/27] Downgraded phpstan to latest supporting php 7.2 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f4046a6ea..150e3e171 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,8 @@ "php-ds/php-ds": "^1.4.1", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "2.0.2", - "phpstan/phpstan-phpunit": "^2.0.1", + "phpstan/phpstan": "^1.12", + "phpstan/phpstan-phpunit": "^1.4", "phpunit/phpunit": "^8.5||^9.5", "react/async": "^3.0", "react/http": "^1.6", From f63e5e2f234e2a1f9b360faf1a30bd9f7d68fd9b Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Fri, 10 Jan 2025 15:50:03 +0100 Subject: [PATCH 06/27] Fixed issues reported by phpstan --- .../Impl/AutoInstrument/CurlHandleWrappedTrait.php | 1 + .../TransactionForExtensionRequest.php | 1 + .../ElasticApm/Impl/Config/IniRawSnapshotSource.php | 1 + agent/php/ElasticApm/Impl/InferredSpansManager.php | 13 ++++++++----- .../ElasticApm/Impl/Log/LoggableToJsonEncodable.php | 1 + .../ComponentTests/ConfigSettingTest.php | 1 + .../UnitTests/InferredSpansBuilderTest.php | 1 + .../Deserialization/DeserializationException.php | 2 +- .../Util/Deserialization/DeserializationUtil.php | 2 +- .../ServerApiSchemaValidationException.php | 2 +- .../ElasticApmTests/Util/DummyExceptionForTests.php | 2 +- .../Util/InvalidEventDataException.php | 2 +- tests/ElasticApmTests/Util/TestCaseBase.php | 3 ++- tests/ElasticApmTests/Util/TextUtilForTests.php | 1 + 14 files changed, 22 insertions(+), 11 deletions(-) diff --git a/agent/php/ElasticApm/Impl/AutoInstrument/CurlHandleWrappedTrait.php b/agent/php/ElasticApm/Impl/AutoInstrument/CurlHandleWrappedTrait.php index 094c542bd..3080869f5 100644 --- a/agent/php/ElasticApm/Impl/AutoInstrument/CurlHandleWrappedTrait.php +++ b/agent/php/ElasticApm/Impl/AutoInstrument/CurlHandleWrappedTrait.php @@ -100,6 +100,7 @@ public function setOpt(int $option, $value): bool public function asInt(): int { + /** @phpstan-ignore-next-line */ return is_resource($this->curlHandle) ? intval($this->curlHandle) : spl_object_id($this->curlHandle); } diff --git a/agent/php/ElasticApm/Impl/AutoInstrument/TransactionForExtensionRequest.php b/agent/php/ElasticApm/Impl/AutoInstrument/TransactionForExtensionRequest.php index 85102126b..c3ab63af7 100644 --- a/agent/php/ElasticApm/Impl/AutoInstrument/TransactionForExtensionRequest.php +++ b/agent/php/ElasticApm/Impl/AutoInstrument/TransactionForExtensionRequest.php @@ -572,6 +572,7 @@ private function discoverStartTime(float $requestInitStartTime): float return $requestInitStartTime; } + /** @phpstan-ignore-next-line */ $serverRequestTimeInSeconds = floatval($serverRequestTimeAsString); $serverRequestTimeInMicroseconds = $serverRequestTimeInSeconds * TimeUtil::NUMBER_OF_MICROSECONDS_IN_SECOND; if ($requestInitStartTime < $serverRequestTimeInMicroseconds) { diff --git a/agent/php/ElasticApm/Impl/Config/IniRawSnapshotSource.php b/agent/php/ElasticApm/Impl/Config/IniRawSnapshotSource.php index 56970a272..1ce0ebf40 100644 --- a/agent/php/ElasticApm/Impl/Config/IniRawSnapshotSource.php +++ b/agent/php/ElasticApm/Impl/Config/IniRawSnapshotSource.php @@ -79,6 +79,7 @@ private static function iniValueToString($iniValue): string return $iniValue ? 'true' : 'false'; } + /** @phpstan-ignore-next-line */ return strval($iniValue); } } diff --git a/agent/php/ElasticApm/Impl/InferredSpansManager.php b/agent/php/ElasticApm/Impl/InferredSpansManager.php index b8a316e04..433d9d086 100644 --- a/agent/php/ElasticApm/Impl/InferredSpansManager.php +++ b/agent/php/ElasticApm/Impl/InferredSpansManager.php @@ -205,11 +205,14 @@ private function onNewCurrentTransactionHasBegun(Transaction $transaction): void ($assertProxy = Assert::ifEnabled()) && $assertProxy->that($this->onCurrentSpanChangedCallback === null) && $assertProxy->withContext('$this->onCurrentSpanChangedCallback === null', ['this' => $this]); - $this->currentTransaction->onCurrentSpanChanged->add( - $this->onCurrentSpanChangedCallback = function (?Span $span): void { - $this->onCurrentSpanChanged($span); - } - ); + + if ($this->currentTransaction !== null) { + $this->currentTransaction->onCurrentSpanChanged->add( + $this->onCurrentSpanChangedCallback = function (?Span $span): void { + $this->onCurrentSpanChanged($span); + } + ); + } $this->builder = new InferredSpansBuilder($this->tracer); $this->state = self::STATE_RUNNING; diff --git a/agent/php/ElasticApm/Impl/Log/LoggableToJsonEncodable.php b/agent/php/ElasticApm/Impl/Log/LoggableToJsonEncodable.php index 895dd255c..923eaa29c 100644 --- a/agent/php/ElasticApm/Impl/Log/LoggableToJsonEncodable.php +++ b/agent/php/ElasticApm/Impl/Log/LoggableToJsonEncodable.php @@ -108,6 +108,7 @@ public static function convert($value, int $depth) return self::convertObject($value, $depth); } + /** @phpstan-ignore-next-line */ return [LogConsts::TYPE_KEY => DbgUtil::getType($value), LogConsts::VALUE_AS_STRING_KEY => strval($value)]; } diff --git a/tests/ElasticApmTests/ComponentTests/ConfigSettingTest.php b/tests/ElasticApmTests/ComponentTests/ConfigSettingTest.php index a7b553b45..a7ff0240e 100644 --- a/tests/ElasticApmTests/ComponentTests/ConfigSettingTest.php +++ b/tests/ElasticApmTests/ComponentTests/ConfigSettingTest.php @@ -228,6 +228,7 @@ public function dataProviderForTestAllWaysToSetConfig(): iterable $optRawVal = str_replace("\n", "\t", $optRawVal); } $optExpectedVal = $optExpectedVal ?? AllOptionsMetadata::get()[$optName]->defaultValue(); + /** @phpstan-ignore-next-line */ yield [$agentConfigSourceKind, $optName, strval($optRawVal), $optExpectedVal]; } } diff --git a/tests/ElasticApmTests/UnitTests/InferredSpansBuilderTest.php b/tests/ElasticApmTests/UnitTests/InferredSpansBuilderTest.php index bfacb222a..28e43bc26 100644 --- a/tests/ElasticApmTests/UnitTests/InferredSpansBuilderTest.php +++ b/tests/ElasticApmTests/UnitTests/InferredSpansBuilderTest.php @@ -337,6 +337,7 @@ function (TracerBuilderForTests $tracerBuilder) use ($inputOptions): void { // Enable span stack trace collection for span with any duration $tracerBuilder->withConfig(OptionNames::SPAN_STACK_TRACE_MIN_DURATION, '0'); foreach ($inputOptions as $optName => $optVal) { + /** @phpstan-ignore-next-line */ $tracerBuilder->withConfig($optName, strval($optVal)); } } diff --git a/tests/ElasticApmTests/Util/Deserialization/DeserializationException.php b/tests/ElasticApmTests/Util/Deserialization/DeserializationException.php index 6d0501d2f..cca039288 100644 --- a/tests/ElasticApmTests/Util/Deserialization/DeserializationException.php +++ b/tests/ElasticApmTests/Util/Deserialization/DeserializationException.php @@ -28,7 +28,7 @@ class DeserializationException extends RuntimeException { - public function __construct(string $message, int $code = 0, Throwable $previous = null) + public function __construct(string $message, int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/tests/ElasticApmTests/Util/Deserialization/DeserializationUtil.php b/tests/ElasticApmTests/Util/Deserialization/DeserializationUtil.php index fff1e4594..af90208e6 100644 --- a/tests/ElasticApmTests/Util/Deserialization/DeserializationUtil.php +++ b/tests/ElasticApmTests/Util/Deserialization/DeserializationUtil.php @@ -43,7 +43,7 @@ public static function buildUnknownKeyException($key): DeserializationException return DeserializationUtil::buildException('Unknown key: ' . $key); } - public static function buildException(?string $msgDetails = null, int $code = 0, Throwable $previous = null): DeserializationException + public static function buildException(?string $msgDetails = null, int $code = 0, ?Throwable $previous = null): DeserializationException { $msgStart = 'Deserialization failed'; if ($msgDetails !== null) { diff --git a/tests/ElasticApmTests/Util/Deserialization/ServerApiSchemaValidationException.php b/tests/ElasticApmTests/Util/Deserialization/ServerApiSchemaValidationException.php index 02945b045..5b53c6c58 100644 --- a/tests/ElasticApmTests/Util/Deserialization/ServerApiSchemaValidationException.php +++ b/tests/ElasticApmTests/Util/Deserialization/ServerApiSchemaValidationException.php @@ -28,7 +28,7 @@ class ServerApiSchemaValidationException extends RuntimeException { - public function __construct(string $message, int $code = 0, Throwable $previous = null) + public function __construct(string $message, int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/tests/ElasticApmTests/Util/DummyExceptionForTests.php b/tests/ElasticApmTests/Util/DummyExceptionForTests.php index 577e8c8db..00f1f19e6 100644 --- a/tests/ElasticApmTests/Util/DummyExceptionForTests.php +++ b/tests/ElasticApmTests/Util/DummyExceptionForTests.php @@ -31,7 +31,7 @@ class DummyExceptionForTests extends RuntimeException public const NAMESPACE = __NAMESPACE__; public const FQ_CLASS_NAME = __CLASS__; - public function __construct(string $message, int $code = 0, Throwable $previous = null) + public function __construct(string $message, int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/tests/ElasticApmTests/Util/InvalidEventDataException.php b/tests/ElasticApmTests/Util/InvalidEventDataException.php index 4571ece0b..6dc3198f4 100644 --- a/tests/ElasticApmTests/Util/InvalidEventDataException.php +++ b/tests/ElasticApmTests/Util/InvalidEventDataException.php @@ -28,7 +28,7 @@ class InvalidEventDataException extends RuntimeException { - public function __construct(string $message, int $code = 0, Throwable $previous = null) + public function __construct(string $message, int $code = 0, ?Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/tests/ElasticApmTests/Util/TestCaseBase.php b/tests/ElasticApmTests/Util/TestCaseBase.php index e121509d3..986b72c6c 100644 --- a/tests/ElasticApmTests/Util/TestCaseBase.php +++ b/tests/ElasticApmTests/Util/TestCaseBase.php @@ -85,7 +85,7 @@ public static function assertThrows( string $class, callable $execute, string $message = '', - callable $inspect = null + ?callable $inspect = null ): void { try { $execute(); @@ -140,6 +140,7 @@ public static function assertSameEx($expected, $actual, string $message = ''): v return is_float($value) || is_int($value); }; if ($isNumeric($expected) && $isNumeric($actual) && (is_float($expected) !== is_float($actual))) { + /** @phpstan-ignore-next-line */ self::assertSame(floatval($expected), floatval($actual), $message); } else { self::assertSame($expected, $actual, $message); diff --git a/tests/ElasticApmTests/Util/TextUtilForTests.php b/tests/ElasticApmTests/Util/TextUtilForTests.php index 57ca99839..c9ffd7ca4 100644 --- a/tests/ElasticApmTests/Util/TextUtilForTests.php +++ b/tests/ElasticApmTests/Util/TextUtilForTests.php @@ -123,6 +123,7 @@ public static function combineWithSeparatorIfNotEmpty(string $separator, string */ public static function emptyIfNull($input): string { + /** @phpstan-ignore-next-line */ return $input === null ? '' : strval($input); } } From af8641870bfc36e8b7fc67357a00d3c8b3d3751e Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Fri, 10 Jan 2025 16:26:20 +0100 Subject: [PATCH 07/27] Fixed issues reported by phpstan --- tests/bootstrap.php | 2 +- tests/polyfills/load.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 795658bf1..7ea01209e 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -21,7 +21,7 @@ declare(strict_types=1); -error_reporting(E_ALL | E_STRICT); +error_reporting(E_ALL); use ElasticApmTests\TestsRootDir; diff --git a/tests/polyfills/load.php b/tests/polyfills/load.php index 4abcd45bd..8b99a2f7e 100644 --- a/tests/polyfills/load.php +++ b/tests/polyfills/load.php @@ -21,7 +21,7 @@ declare(strict_types=1); -error_reporting(E_ALL | E_STRICT); +error_reporting(E_ALL); if (!function_exists('array_key_first')) { require __DIR__ . '/array_key_first.php'; From 092327fe6571154bcaca8f6fafe3078a9c1389ea Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Mon, 13 Jan 2025 12:44:22 +0200 Subject: [PATCH 08/27] Adapted expected stack trace to PHP 8.4 --- .../Util/StackTraceFrameExpectations.php | 36 +++++++++++++++++-- tests/ElasticApmTests/Util/TestCaseBase.php | 13 +++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php index cf4b8f4b9..05c0407e1 100644 --- a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php +++ b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php @@ -38,6 +38,9 @@ final class StackTraceFrameExpectations extends ExpectationsBase /** @var Optional */ public $function; + /** @var bool */ + public $isFunctionNameRegex = false; + /** @var Optional */ public $lineno; @@ -101,9 +104,32 @@ public static function fromStandaloneFunction(string $fileName, int $lineNumber, return $result; } + private static function convertFunctionNameToRegPattern(string $text): string + { + $result = $text; + $result = str_replace('\\', '\\\\', $result); + $result = str_replace('{', '\\{', $result); + $result = str_replace('}', '\\}', $result); + $result = str_replace('(', '\\(', $result); + $result = str_replace(')', '\\)', $result); + return '/^' . $result . '$/'; + } + public static function fromClosure(string $fileName, int $lineNumber, ?string $namespace, string $class, bool $isStatic): self { - $result = self::fromClassMethodUnknownLocation($class, $isStatic, ($namespace === null ? '' : ($namespace . '\\')) . '{closure}'); + // Before PHP 8.4: ElasticApmTests\\TestsSharedCode\\SpanStackTraceTestSharedCode::ElasticApmTests\\TestsSharedCode\\{closure} + // PHP 8.4: ElasticApmTests\\TestsSharedCode\\SpanStackTraceTestSharedCode::{closure:ElasticApmTests\\TestsSharedCode\\SpanStackTraceTestSharedCode::allSpanCreatingApis():207} + if (PHP_VERSION_ID < 80400) { + $result = self::fromClassMethodUnknownLocation($class, $isStatic, ($namespace === null ? '' : ($namespace . '\\')) . '{closure}'); + } else { + $result = self::fromClassMethodUnknownLocation($class, $isStatic, '{closure:' . $class . '::__METHOD__():__LINE__}'); + $regex = self::convertFunctionNameToRegPattern($result->function->getValue()); + $regex = str_replace('__METHOD__', '[a-zA-Z0-9]+', $regex); + $regex = str_replace('__LINE__', '[0-9]+', $regex); + $result->function->setValue($regex); + $result->isFunctionNameRegex = true; + } + $result->filename->setValue($fileName); $result->lineno->setValue($lineNumber); return $result; @@ -143,7 +169,13 @@ public function assertMatches(StackTraceFrame $actual): void $dbgCtx->add(['this' => $this]); TestCaseBase::assertSameExpectedOptional($this->filename, $actual->filename); - TestCaseBase::assertSameExpectedOptional($this->function, $actual->function); + if ($this->isFunctionNameRegex) { + if ($this->function->isValueSet()) { + TestCaseBase::assertMatchesRegularExpression($this->function->getValue(), $actual->function); + } + } else { + TestCaseBase::assertSameExpectedOptional($this->function, $actual->function); + } TestCaseBase::assertSameExpectedOptional($this->lineno, $actual->lineno); } } diff --git a/tests/ElasticApmTests/Util/TestCaseBase.php b/tests/ElasticApmTests/Util/TestCaseBase.php index 986b72c6c..c4bb48eb5 100644 --- a/tests/ElasticApmTests/Util/TestCaseBase.php +++ b/tests/ElasticApmTests/Util/TestCaseBase.php @@ -1133,6 +1133,19 @@ public static function assertContainsEx($needle, iterable $haystack, string $mes } } + /** + * @inheritDoc + */ + public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void + { + try { + Assert::assertMatchesRegularExpression($pattern, $string, $message); + } catch (AssertionFailedError $ex) { + self::addMessageStackToException($ex); + throw $ex; + } + } + public static function assertDirectoryDoesNotExist(string $directory, string $message = ''): void { /** From 2fc39b70a0ca5fb20a900542d31328c2902b1827 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Mon, 13 Jan 2025 13:22:53 +0200 Subject: [PATCH 09/27] Fixed static checks --- .../Util/StackTraceFrameExpectations.php | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php index 05c0407e1..284f3fedf 100644 --- a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php +++ b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php @@ -39,7 +39,7 @@ final class StackTraceFrameExpectations extends ExpectationsBase public $function; /** @var bool */ - public $isFunctionNameRegex = false; + public $isFunctionRegex = false; /** @var Optional */ public $lineno; @@ -123,11 +123,13 @@ public static function fromClosure(string $fileName, int $lineNumber, ?string $n $result = self::fromClassMethodUnknownLocation($class, $isStatic, ($namespace === null ? '' : ($namespace . '\\')) . '{closure}'); } else { $result = self::fromClassMethodUnknownLocation($class, $isStatic, '{closure:' . $class . '::__METHOD__():__LINE__}'); - $regex = self::convertFunctionNameToRegPattern($result->function->getValue()); - $regex = str_replace('__METHOD__', '[a-zA-Z0-9]+', $regex); - $regex = str_replace('__LINE__', '[0-9]+', $regex); - $result->function->setValue($regex); - $result->isFunctionNameRegex = true; + $expectedFunc = $result->function->getValue(); + TestCaseBase::assertNotNull($expectedFunc); + $expectedFuncRegex = self::convertFunctionNameToRegPattern($expectedFunc); + $expectedFuncRegex = str_replace('__METHOD__', '[a-zA-Z0-9]+', $expectedFuncRegex); + $expectedFuncRegex = str_replace('__LINE__', '[0-9]+', $expectedFuncRegex); + $result->function->setValue($expectedFuncRegex); + $result->isFunctionRegex = true; } $result->filename->setValue($fileName); @@ -169,9 +171,16 @@ public function assertMatches(StackTraceFrame $actual): void $dbgCtx->add(['this' => $this]); TestCaseBase::assertSameExpectedOptional($this->filename, $actual->filename); - if ($this->isFunctionNameRegex) { + if ($this->isFunctionRegex) { if ($this->function->isValueSet()) { - TestCaseBase::assertMatchesRegularExpression($this->function->getValue(), $actual->function); + $expectedFuncRegex = $this->function->getValue(); + $actualFunc = $actual->function; + if ($expectedFuncRegex === null) { + TestCaseBase::assertNull($actualFunc); + } else { + TestCaseBase::assertNotNull($actualFunc); + TestCaseBase::assertMatchesRegularExpression($expectedFuncRegex, $actualFunc); + } } } else { TestCaseBase::assertSameExpectedOptional($this->function, $actual->function); From 1ff3dedfea2c84ed1a5f3f8fb8d2c40308da86ab Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Mon, 13 Jan 2025 13:31:28 +0200 Subject: [PATCH 10/27] Fixed assert missing in older PHPUnit --- tests/ElasticApmTests/Util/TestCaseBase.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ElasticApmTests/Util/TestCaseBase.php b/tests/ElasticApmTests/Util/TestCaseBase.php index c4bb48eb5..e38302186 100644 --- a/tests/ElasticApmTests/Util/TestCaseBase.php +++ b/tests/ElasticApmTests/Util/TestCaseBase.php @@ -1138,8 +1138,12 @@ public static function assertContainsEx($needle, iterable $haystack, string $mes */ public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void { + AssertMessageStack::newScope(/* out */ $dbgCtx, AssertMessageStack::funcArgs()); + try { - Assert::assertMatchesRegularExpression($pattern, $string, $message); + $pregMatchRetVal = preg_match($pattern, $string); + $dbgCtx->add(compact('pregMatchRetVal')); + Assert::assertTrue($pregMatchRetVal > 0, $message); } catch (AssertionFailedError $ex) { self::addMessageStackToException($ex); throw $ex; From 3af4114a1b62e5fc46f8862a5e7051d51b06684c Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Mon, 13 Jan 2025 14:05:31 +0200 Subject: [PATCH 11/27] Fixed StackTraceUtilTest --- tests/ElasticApmTests/Util/AssertMessageStack.php | 2 +- tests/ElasticApmTests/Util/StackTraceFrameExpectations.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ElasticApmTests/Util/AssertMessageStack.php b/tests/ElasticApmTests/Util/AssertMessageStack.php index 56883efa3..66a1ca56d 100644 --- a/tests/ElasticApmTests/Util/AssertMessageStack.php +++ b/tests/ElasticApmTests/Util/AssertMessageStack.php @@ -39,7 +39,7 @@ final class AssertMessageStack implements LoggableInterface { /** @var bool */ - private static $isEnabled = true; + private static $isEnabled = false; /** @var ?AssertMessageStack */ private static $singleton = null; diff --git a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php index 284f3fedf..2f46b5182 100644 --- a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php +++ b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php @@ -122,10 +122,11 @@ public static function fromClosure(string $fileName, int $lineNumber, ?string $n if (PHP_VERSION_ID < 80400) { $result = self::fromClassMethodUnknownLocation($class, $isStatic, ($namespace === null ? '' : ($namespace . '\\')) . '{closure}'); } else { - $result = self::fromClassMethodUnknownLocation($class, $isStatic, '{closure:' . $class . '::__METHOD__():__LINE__}'); + $result = self::fromClassMethodUnknownLocation($class, $isStatic, '{closure:__CLASS__::__METHOD__():__LINE__}'); $expectedFunc = $result->function->getValue(); TestCaseBase::assertNotNull($expectedFunc); $expectedFuncRegex = self::convertFunctionNameToRegPattern($expectedFunc); + $expectedFuncRegex = str_replace('__CLASS__', '[a-zA-Z0-9\\\\]+', $expectedFuncRegex); $expectedFuncRegex = str_replace('__METHOD__', '[a-zA-Z0-9]+', $expectedFuncRegex); $expectedFuncRegex = str_replace('__LINE__', '[0-9]+', $expectedFuncRegex); $result->function->setValue($expectedFuncRegex); From 3dbe743bad681fc45cecd882ae51709d489fbbff Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Mon, 13 Jan 2025 14:40:20 +0200 Subject: [PATCH 12/27] Revert AssertMessageStack back to enabled by default --- tests/ElasticApmTests/Util/AssertMessageStack.php | 7 ++++++- tests/ElasticApmTests/Util/PhpUnitExtensionBase.php | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/ElasticApmTests/Util/AssertMessageStack.php b/tests/ElasticApmTests/Util/AssertMessageStack.php index 66a1ca56d..634b20334 100644 --- a/tests/ElasticApmTests/Util/AssertMessageStack.php +++ b/tests/ElasticApmTests/Util/AssertMessageStack.php @@ -39,7 +39,7 @@ final class AssertMessageStack implements LoggableInterface { /** @var bool */ - private static $isEnabled = false; + private static $isEnabled = true; /** @var ?AssertMessageStack */ private static $singleton = null; @@ -187,6 +187,11 @@ public static function getContextsStack(): array return $result; } + public static function clearContextsStack(): void + { + self::ensureSingleton()->scopesStack = []; + } + public function toLog(LogStreamInterface $stream): void { $stream->toLogAs(['scopesStack count' => count($this->scopesStack), 'isEnabled' => self::$isEnabled]); diff --git a/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php b/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php index 868258ea8..ceda7fbe8 100644 --- a/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php +++ b/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php @@ -64,6 +64,7 @@ public function __construct(string $dbgProcessName) */ public function executeBeforeTest(string $test): void { + AssertMessageStack::clearContextsStack(); self::$timestampBeforeTest = AmbientContextForTests::clock()->getSystemClockCurrentTime(); ($loggerProxy = $this->logger->ifDebugLevelEnabled(__LINE__, __FUNCTION__)) && $loggerProxy->includeStackTrace()->log('', ['timestampBeforeTest' => TimeUtilForTests::timestampToLoggable(self::$timestampBeforeTest)]); From eda4ad680904214b7fd6ac8eef9d6c866c08dbed Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Mon, 13 Jan 2025 14:26:26 +0100 Subject: [PATCH 13/27] Fixed docker-compose label --- packaging/test/centos/Dockerfile | 1 - packaging/test/docker-compose.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packaging/test/centos/Dockerfile b/packaging/test/centos/Dockerfile index c8682c468..12a203703 100644 --- a/packaging/test/centos/Dockerfile +++ b/packaging/test/centos/Dockerfile @@ -25,7 +25,6 @@ RUN export PHP_VERSION_TRANSFORMED=$(echo "${PHP_VERSION}" | sed 's#\.##g') \ && yum install -y \ php \ php-mbstring \ - php-mysql \ php-mysqli \ php-pcntl \ php-posix \ diff --git a/packaging/test/docker-compose.yml b/packaging/test/docker-compose.yml index 82a977e55..d1f40dcb4 100644 --- a/packaging/test/docker-compose.yml +++ b/packaging/test/docker-compose.yml @@ -238,7 +238,7 @@ services: args: - PHP_VERSION=7.2 - apk-php83: + apk-php84: image: elasticobservability/apm-agent-php-dev:packages-test-apk-php-8.4-0.0.1 build: context: alpine From f00630332759220d564110bd94cd36cdaaa8ee4f Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Tue, 14 Jan 2025 11:54:34 +0200 Subject: [PATCH 14/27] Fixed test failures related to AssertMessageStack --- .../UtilTests/StackTraceUtilTest.php | 80 +++++++++++++------ .../Util/AssertMessageStack.php | 11 +-- .../Util/AssertMessageStackScopeAutoRef.php | 8 +- .../Util/AssertMessageStackScopeData.php | 14 +++- tests/ElasticApmTests/Util/MixedMap.php | 2 + .../Util/PhpUnitExtensionBase.php | 2 +- .../Util/StackTraceExpectations.php | 2 + .../Util/StackTraceFrameExpectations.php | 2 + tests/ElasticApmTests/Util/TestCaseBase.php | 3 + 9 files changed, 91 insertions(+), 33 deletions(-) diff --git a/tests/ElasticApmTests/UnitTests/UtilTests/StackTraceUtilTest.php b/tests/ElasticApmTests/UnitTests/UtilTests/StackTraceUtilTest.php index c08e04229..bda9daa80 100644 --- a/tests/ElasticApmTests/UnitTests/UtilTests/StackTraceUtilTest.php +++ b/tests/ElasticApmTests/UnitTests/UtilTests/StackTraceUtilTest.php @@ -85,6 +85,8 @@ public function testClosureExpections(): void $closureFrameExpections->assertMatches($actualStackTrace[0]); self::assertNull($actualStackTrace[0]->function); $thisFuncFrameExpections->assertMatches($actualStackTrace[1]); + + $dbgCtx->pop(); } public static function testStaticClosureExpections(): void @@ -143,6 +145,8 @@ public function testConvertClassAndMethodToFunctionName(?string $classicName, ?b $dbgCtx->add(['actualFuncName' => $actualFuncName]); self::assertSame($expectedFuncName, $actualFuncName); + + $dbgCtx->pop(); } /** @@ -207,6 +211,8 @@ public function testCaptureInApmFormatOneTestFame(MixedMap $testArgs): void self::assertNotNull($frame->function); self::assertStringNotContainsString(__FUNCTION__, $frame->function); } + + $dbgCtx->pop(); } /** @@ -336,6 +342,8 @@ public function testCaptureInApmFormatMultipleTestFrames(MixedMap $testArgs): vo self::assertNotNull($frame->function); self::assertStringNotContainsString(__FUNCTION__, $frame->function); } + + $dbgCtx->pop(); } /** @@ -493,6 +501,8 @@ public function testConvertPhpToApmFormat(MixedMap $testArgs): void $dbgCtx->add(['actualOutputFrames' => $actualOutputFrames]); $expectedOutput = $maxNumberOfFrames === null ? $fullExpectedOutput : array_slice($fullExpectedOutput, /* offset */ 0, /* length */ $maxNumberOfFrames); StackTraceExpectations::fromFramesExpectations($expectedOutput)->assertMatches($actualOutputFrames); + + $dbgCtx->pop(); } private const CALL_KINDS_SEQUENCE_KEY = 'call_kinds_sequence'; @@ -611,6 +621,8 @@ public function testCaptureInApmFormatOnDummyCode(MixedMap $testArgs): void $retVal = ($firstCall->callable)(...$firstCallArgs); $dbgCtx->add(['retVal' => $retVal]); StackTraceExpectations::fromFramesExpectations($retVal->expectations, /* allowToBePrefixOfActual */ true)->assertMatches($retVal->actual); + + $dbgCtx->pop(); } private const DEPTH_BEFORE_CALL_USER_FUNC_KEY = 'depth_before_call_user_func'; @@ -644,32 +656,39 @@ public function dataProviderForTestCaptureInApmFormatWithCallUserFunc(): iterabl private function helperForTestCaptureInApmFormatWithCallUserFunc(MixedMap $testArgs, int $depth, array $framesExpectations): array { AssertMessageStack::newScope(/* out */ $dbgCtx, AssertMessageStack::funcArgs()); - $thisFuncAsCallable = [__CLASS__, __FUNCTION__]; - $depthBeforeCallUserFunc = $testArgs->getInt(self::DEPTH_BEFORE_CALL_USER_FUNC_KEY); - $depthAfterCallUserFunc = $testArgs->getInt(self::DEPTH_AFTER_CALL_USER_FUNC_KEY); - self::assertLessThanOrEqual($depthBeforeCallUserFunc + $depthAfterCallUserFunc, $depth); - if ($depth === $depthBeforeCallUserFunc + $depthAfterCallUserFunc) { - $numberOfStackFramesToSkip = $testArgs->getPositiveOrZeroInt(self::NUMBER_OF_STACK_FRAMES_TO_SKIP_KEY); - array_unshift($framesExpectations, StackTraceFrameExpectations::fromLocationOnly(__FILE__, __LINE__ + 1)); - $actuallyCatpuredStackTrace = self::stackTraceUtil()->captureInApmFormat($numberOfStackFramesToSkip, /* maxNumberOfFrames */ null); - return [array_slice($framesExpectations, $numberOfStackFramesToSkip), $actuallyCatpuredStackTrace]; - } - if ($depth < $depthBeforeCallUserFunc || $depth > $depthBeforeCallUserFunc) { - array_unshift($framesExpectations, StackTraceFrameExpectations::fromClassMethod(__FILE__, __LINE__ + 1, __CLASS__, /* isStatic */ false, __FUNCTION__)); - return $this->helperForTestCaptureInApmFormatWithCallUserFunc($testArgs, $depth + 1, $framesExpectations); - } + try { + $thisFuncAsCallable = [__CLASS__, __FUNCTION__]; + $depthBeforeCallUserFunc = $testArgs->getInt(self::DEPTH_BEFORE_CALL_USER_FUNC_KEY); + $depthAfterCallUserFunc = $testArgs->getInt(self::DEPTH_AFTER_CALL_USER_FUNC_KEY); + self::assertLessThanOrEqual($depthBeforeCallUserFunc + $depthAfterCallUserFunc, $depth); + if ($depth === $depthBeforeCallUserFunc + $depthAfterCallUserFunc) { + $numberOfStackFramesToSkip = $testArgs->getPositiveOrZeroInt(self::NUMBER_OF_STACK_FRAMES_TO_SKIP_KEY); + array_unshift($framesExpectations, StackTraceFrameExpectations::fromLocationOnly(__FILE__, __LINE__ + 1)); + $actuallyCatpuredStackTrace = self::stackTraceUtil()->captureInApmFormat($numberOfStackFramesToSkip, /* maxNumberOfFrames */ null); + return [array_slice($framesExpectations, $numberOfStackFramesToSkip), $actuallyCatpuredStackTrace]; + } + if ($depth < $depthBeforeCallUserFunc || $depth > $depthBeforeCallUserFunc) { + array_unshift($framesExpectations, StackTraceFrameExpectations::fromClassMethod(__FILE__, __LINE__ + 1, __CLASS__, /* isStatic */ false, __FUNCTION__)); + return $this->helperForTestCaptureInApmFormatWithCallUserFunc($testArgs, $depth + 1, $framesExpectations); + } - self::assertSame($depthBeforeCallUserFunc, $depth); - $isCallUserFuncArrayVariant = $testArgs->getBool(self::IS_CALL_USER_FUNC_ARRAY_VARIANT_KEY); - $framesExpectationForCallToThisFuncByCallUserFunc = StackTraceFrameExpectations::fromClassMethodNoLocation(__CLASS__, /* isStatic */ false, __FUNCTION__); - $callUserFuncLine = __LINE__ + 6; - array_unshift($framesExpectations, StackTraceFrameExpectations::fromStandaloneFunction(__FILE__, $callUserFuncLine, $isCallUserFuncArrayVariant ? 'call_user_func_array' : 'call_user_func')); - array_unshift($framesExpectations, $framesExpectationForCallToThisFuncByCallUserFunc); - $callArgs = [$testArgs, $depth + 1, $framesExpectations]; - self::assertSame(__LINE__ + 2, $callUserFuncLine); - /** @var array{StackTraceFrameExpectations[], StackTraceFrame[]} $retVal */ - $retVal = $isCallUserFuncArrayVariant ? call_user_func_array($thisFuncAsCallable, $callArgs) : call_user_func($thisFuncAsCallable, ...$callArgs); - return $retVal; + self::assertSame($depthBeforeCallUserFunc, $depth); + $isCallUserFuncArrayVariant = $testArgs->getBool(self::IS_CALL_USER_FUNC_ARRAY_VARIANT_KEY); + $framesExpectationForCallToThisFuncByCallUserFunc = StackTraceFrameExpectations::fromClassMethodNoLocation(__CLASS__, /* isStatic */ false, __FUNCTION__); + $callUserFuncLine = __LINE__ + 9; // it should have the line number with call_user_func_array($thisFuncAsCallable) or call_user_func($thisFuncAsCallable) + array_unshift( + $framesExpectations, + StackTraceFrameExpectations::fromStandaloneFunction(__FILE__, $callUserFuncLine, $isCallUserFuncArrayVariant ? 'call_user_func_array' : 'call_user_func') + ); + array_unshift($framesExpectations, $framesExpectationForCallToThisFuncByCallUserFunc); + $callArgs = [$testArgs, $depth + 1, $framesExpectations]; + self::assertSame(__LINE__ + 2, $callUserFuncLine); + /** @var array{StackTraceFrameExpectations[], StackTraceFrame[]} $retVal */ + $retVal = $isCallUserFuncArrayVariant ? call_user_func_array($thisFuncAsCallable, $callArgs) : call_user_func($thisFuncAsCallable, ...$callArgs); + return $retVal; + } finally { + $dbgCtx->pop(); + } } /** @@ -678,12 +697,15 @@ private function helperForTestCaptureInApmFormatWithCallUserFunc(MixedMap $testA public function testCaptureInApmFormatWithCallUserFunc(MixedMap $testArgs): void { AssertMessageStack::newScope(/* out */ $dbgCtx, AssertMessageStack::funcArgs()); + $framesExpectations = [StackTraceFrameExpectations::fromClassMethodUnknownLocation(__CLASS__, /* isStatic */ false, 'testCaptureInApmFormatWithCallUserFunc')]; array_unshift($framesExpectations, StackTraceFrameExpectations::fromClassMethod(__FILE__, __LINE__ + 1, __CLASS__, /* isStatic */ false, 'helperForTestCaptureInApmFormatWithCallUserFunc')); $expectedActual = $this->helperForTestCaptureInApmFormatWithCallUserFunc($testArgs, /* depth */ 1, $framesExpectations); $dbgCtx->add(['expectedActual' => $expectedActual]); self::assertCount(2, $expectedActual); StackTraceExpectations::fromFramesExpectations($expectedActual[0], /* allowExpectedStackTraceToBePrefix */ true)->assertMatches($expectedActual[1]); + + $dbgCtx->pop(); } /** @@ -798,6 +820,8 @@ public function testCaptureInClassicFormatOneTestFrame(MixedMap $testArgs): void $frame = $actualCapturedStackTrace[0]; self::assertNotEquals(__FUNCTION__, $frame->function); } + + $dbgCtx->pop(); } /** @@ -943,6 +967,8 @@ public function testCaptureInClassicFormatMultipleTestFrames(MixedMap $testArgs) $frame = $actualCapturedStackTrace[$actualCapturedStackTraceFrameIndex]; self::assertNotEquals(__FUNCTION__, $frame->function); } + + $dbgCtx->pop(); } /** @@ -1078,6 +1104,8 @@ public function testConvertClassicToApmFormat(MixedMap $testArgs): void $dbgCtx->add(['actualOutputFrames' => $actualOutputFrames]); $expectedOutput = $maxNumberOfFrames === null ? $fullExpectedOutput : array_slice($fullExpectedOutput, /* offset */ 0, /* length */ $maxNumberOfFrames); StackTraceExpectations::fromFrames($expectedOutput)->assertMatches($actualOutputFrames); + + $dbgCtx->pop(); } /** @@ -1200,6 +1228,8 @@ public function testConvertThrowableTraceToApmFormat(MixedMap $testArgs): void self::assertNotNull($frame->function); self::assertStringNotContainsString(__FUNCTION__, $frame->function); } + + $dbgCtx->pop(); } public function testLimitConfigToMaxNumberOfFrames(): void diff --git a/tests/ElasticApmTests/Util/AssertMessageStack.php b/tests/ElasticApmTests/Util/AssertMessageStack.php index 634b20334..35fb1a374 100644 --- a/tests/ElasticApmTests/Util/AssertMessageStack.php +++ b/tests/ElasticApmTests/Util/AssertMessageStack.php @@ -145,12 +145,12 @@ public static function funcArgs(): array return $result; } - public function autoPopScope(AssertMessageStackScopeData $expectedTopData): void + public function popTopScope(AssertMessageStackScopeData $expectedTopScope): void { - $dbgCtx = ['this' => $this, 'expectedTopData' => $expectedTopData]; + $actualTopScope = $this->scopesStack[count($this->scopesStack) - 1]; + $dbgCtx = compact('actualTopScope', 'expectedTopScope', 'this'); Assert::assertNotEmpty($this->scopesStack, LoggableToString::convert($dbgCtx)); - $actualTopData = $this->scopesStack[count($this->scopesStack) - 1]; - Assert::assertSame($expectedTopData, $actualTopData, LoggableToString::convert($dbgCtx)); + Assert::assertSame($expectedTopScope, $actualTopScope, LoggableToString::convert($dbgCtx)); array_pop(/* ref */ $this->scopesStack); } @@ -187,9 +187,10 @@ public static function getContextsStack(): array return $result; } - public static function clearContextsStack(): void + public static function reset(): void { self::ensureSingleton()->scopesStack = []; + AssertMessageStackScopeData::$nextId = 1; } public function toLog(LogStreamInterface $stream): void diff --git a/tests/ElasticApmTests/Util/AssertMessageStackScopeAutoRef.php b/tests/ElasticApmTests/Util/AssertMessageStackScopeAutoRef.php index bc2644665..836614475 100644 --- a/tests/ElasticApmTests/Util/AssertMessageStackScopeAutoRef.php +++ b/tests/ElasticApmTests/Util/AssertMessageStackScopeAutoRef.php @@ -40,12 +40,18 @@ public function __construct(AssertMessageStack $stack, ?AssertMessageStackScopeD } public function __destruct() + { + $this->pop(); + } + + public function pop(): void { if ($this->data === null) { return; } - $this->stack->autoPopScope($this->data); + $this->stack->popTopScope($this->data); + $this->data = null; } /** diff --git a/tests/ElasticApmTests/Util/AssertMessageStackScopeData.php b/tests/ElasticApmTests/Util/AssertMessageStackScopeData.php index 3ed63b159..38b6a85d2 100644 --- a/tests/ElasticApmTests/Util/AssertMessageStackScopeData.php +++ b/tests/ElasticApmTests/Util/AssertMessageStackScopeData.php @@ -25,11 +25,18 @@ use Elastic\Apm\Impl\Log\LoggableInterface; use Elastic\Apm\Impl\Log\LogStreamInterface; +use Elastic\Apm\Impl\Util\ArrayUtil; use Elastic\Apm\Impl\Util\DbgUtil; use PHPUnit\Framework\Assert; final class AssertMessageStackScopeData implements LoggableInterface { + /** @var int */ + public static $nextId = 1; + + /** @var int */ + public $id; + /** @var Pair>[] */ public $subScopesStack; @@ -39,6 +46,10 @@ final class AssertMessageStackScopeData implements LoggableInterface */ public function __construct(string $name, array $initialCtx) { + if (self::$nextId === PHP_INT_MAX) { + self::$nextId = 1; + } + $this->id = self::$nextId++; $this->subScopesStack = [new Pair($name, $initialCtx)]; } @@ -73,6 +84,7 @@ public static function buildContextName(int $numberOfStackFramesToSkip): string public function toLog(LogStreamInterface $stream): void { - $stream->toLogAs(['subScopesStack count' => count($this->subScopesStack)]); + $name = ArrayUtil::isEmpty($this->subScopesStack) ? 'N/A' : ArrayUtilForTests::getFirstValue($this->subScopesStack)->first; + $stream->toLogAs(['ID' => $this->id, 'name' => $name, 'subScopesStack count' => count($this->subScopesStack)]); } } diff --git a/tests/ElasticApmTests/Util/MixedMap.php b/tests/ElasticApmTests/Util/MixedMap.php index 6815f8bff..26836503c 100644 --- a/tests/ElasticApmTests/Util/MixedMap.php +++ b/tests/ElasticApmTests/Util/MixedMap.php @@ -194,6 +194,7 @@ public function getNullablePositiveOrZeroInt(string $key): ?int TestCaseBase::assertGreaterThanOrEqual(0, $value); } /** @var null|positive-int|0 $value */ + $dbgCtx->pop(); return $value; } @@ -216,6 +217,7 @@ public function getPositiveOrZeroInt(string $key): int $value = $this->getInt($key); TestCaseBase::assertGreaterThanOrEqual(0, $value); /** @var positive-int|0 $value */ + $dbgCtx->pop(); return $value; } diff --git a/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php b/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php index ceda7fbe8..f917926cf 100644 --- a/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php +++ b/tests/ElasticApmTests/Util/PhpUnitExtensionBase.php @@ -64,7 +64,7 @@ public function __construct(string $dbgProcessName) */ public function executeBeforeTest(string $test): void { - AssertMessageStack::clearContextsStack(); + AssertMessageStack::reset(); self::$timestampBeforeTest = AmbientContextForTests::clock()->getSystemClockCurrentTime(); ($loggerProxy = $this->logger->ifDebugLevelEnabled(__LINE__, __FUNCTION__)) && $loggerProxy->includeStackTrace()->log('', ['timestampBeforeTest' => TimeUtilForTests::timestampToLoggable(self::$timestampBeforeTest)]); diff --git a/tests/ElasticApmTests/Util/StackTraceExpectations.php b/tests/ElasticApmTests/Util/StackTraceExpectations.php index aafa4a773..03c34c6e4 100644 --- a/tests/ElasticApmTests/Util/StackTraceExpectations.php +++ b/tests/ElasticApmTests/Util/StackTraceExpectations.php @@ -89,5 +89,7 @@ public function assertMatches(array $actual): void } else { TestCaseBase::assertSame(count($this->frames), count($actual)); } + + $dbgCtx->pop(); } } diff --git a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php index 2f46b5182..295a271b2 100644 --- a/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php +++ b/tests/ElasticApmTests/Util/StackTraceFrameExpectations.php @@ -187,5 +187,7 @@ public function assertMatches(StackTraceFrame $actual): void TestCaseBase::assertSameExpectedOptional($this->function, $actual->function); } TestCaseBase::assertSameExpectedOptional($this->lineno, $actual->lineno); + + $dbgCtx->pop(); } } diff --git a/tests/ElasticApmTests/Util/TestCaseBase.php b/tests/ElasticApmTests/Util/TestCaseBase.php index e38302186..46870b5f5 100644 --- a/tests/ElasticApmTests/Util/TestCaseBase.php +++ b/tests/ElasticApmTests/Util/TestCaseBase.php @@ -749,6 +749,7 @@ public static function assertCountAtLeast(int $expectedMinCount, $haystack): voi { AssertMessageStack::newScope(/* out */ $dbgCtx, AssertMessageStack::funcArgs()); self::assertGreaterThanOrEqual($expectedMinCount, count($haystack)); + $dbgCtx->pop(); } /** @@ -821,6 +822,8 @@ public static function assertSame($expected, $actual, string $message = ''): voi self::addMessageStackToException($ex); throw $ex; } + + $dbgCtx->pop(); } /** From ce8825557dbf5b4e8e39e726c322824495b8653c Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Tue, 14 Jan 2025 13:02:07 +0200 Subject: [PATCH 15/27] Upgrade php-ds to 1.5.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 150e3e171..923abda65 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "guzzlehttp/guzzle": "^6.5.5||^7.4.4", "justinrainbow/json-schema": "^5.2.12", "monolog/monolog": "^2.7", - "php-ds/php-ds": "^1.4.1", + "php-ds/php-ds": "^1.5.0", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "1.3.2", "phpstan/phpstan": "^1.12", From 04b34673b44b9ce1f9f93ea72255d7ae471eb579 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Tue, 14 Jan 2025 15:39:44 +0200 Subject: [PATCH 16/27] Added PHP ds extension --- packaging/test/alpine/Dockerfile | 1 + packaging/test/centos/Dockerfile | 1 + packaging/test/ubuntu/Dockerfile | 1 + packaging/test/ubuntu/apache/Dockerfile | 1 + packaging/test/ubuntu/fpm/Dockerfile | 1 + 5 files changed, 5 insertions(+) diff --git a/packaging/test/alpine/Dockerfile b/packaging/test/alpine/Dockerfile index c7163048c..afd2f1d54 100644 --- a/packaging/test/alpine/Dockerfile +++ b/packaging/test/alpine/Dockerfile @@ -15,6 +15,7 @@ RUN apk update \ wget RUN docker-php-ext-install \ + ds \ mysqli \ pcntl \ pdo_mysql \ diff --git a/packaging/test/centos/Dockerfile b/packaging/test/centos/Dockerfile index 12a203703..779519122 100644 --- a/packaging/test/centos/Dockerfile +++ b/packaging/test/centos/Dockerfile @@ -24,6 +24,7 @@ RUN export PHP_VERSION_TRANSFORMED=$(echo "${PHP_VERSION}" | sed 's#\.##g') \ && yum-config-manager --enable remi-php${PHP_VERSION_TRANSFORMED} \ && yum install -y \ php \ + php-ds \ php-mbstring \ php-mysqli \ php-pcntl \ diff --git a/packaging/test/ubuntu/Dockerfile b/packaging/test/ubuntu/Dockerfile index f0f09c668..b60ab05ff 100644 --- a/packaging/test/ubuntu/Dockerfile +++ b/packaging/test/ubuntu/Dockerfile @@ -20,6 +20,7 @@ RUN apt-get -qq update \ && rm -rf /var/lib/apt/lists/* RUN docker-php-ext-install \ + ds \ mysqli \ pcntl \ pdo_mysql \ diff --git a/packaging/test/ubuntu/apache/Dockerfile b/packaging/test/ubuntu/apache/Dockerfile index c5db6e792..239237313 100644 --- a/packaging/test/ubuntu/apache/Dockerfile +++ b/packaging/test/ubuntu/apache/Dockerfile @@ -31,6 +31,7 @@ RUN apt-get -qq -y --no-install-recommends install software-properties-common \ php${PHP_VERSION} \ libapache2-mod-php \ php${PHP_VERSION}-curl \ + php${PHP_VERSION}-ds \ php${PHP_VERSION}-mbstring \ php${PHP_VERSION}-mysql \ php${PHP_VERSION}-mysqli \ diff --git a/packaging/test/ubuntu/fpm/Dockerfile b/packaging/test/ubuntu/fpm/Dockerfile index 8c16ff31c..fdd2f2ad8 100644 --- a/packaging/test/ubuntu/fpm/Dockerfile +++ b/packaging/test/ubuntu/fpm/Dockerfile @@ -31,6 +31,7 @@ RUN apt-get -qq -y --no-install-recommends install software-properties-common \ php${PHP_VERSION} \ libapache2-mod-fcgid \ php${PHP_VERSION}-curl \ + php${PHP_VERSION}-ds \ php${PHP_VERSION}-fpm \ php${PHP_VERSION}-mbstring \ php${PHP_VERSION}-mysql \ From c1ff4324bd47771f464a2f291bdcb1e0dead5a46 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Tue, 14 Jan 2025 15:41:13 +0200 Subject: [PATCH 17/27] Fixed component tests failing because of deprecation notices --- agent/php/ElasticApm/Impl/Util/ArrayUtil.php | 19 ++-- .../php/ElasticApm/Impl/Util/PhpErrorUtil.php | 106 ++++++++++++------ .../Util/SpawnedProcessBase.php | 2 + .../Util/TestInfraHttpServerProcessBase.php | 32 +++--- .../routeToBuiltinHttpServerAppCodeHost.php | 3 + .../Util/runCliScriptAppCodeHost.php | 3 + .../ComponentTests/Util/runMockApmServer.php | 3 + .../Util/runResourcesCleaner.php | 3 + 8 files changed, 113 insertions(+), 58 deletions(-) diff --git a/agent/php/ElasticApm/Impl/Util/ArrayUtil.php b/agent/php/ElasticApm/Impl/Util/ArrayUtil.php index b79f7161d..881806d6c 100644 --- a/agent/php/ElasticApm/Impl/Util/ArrayUtil.php +++ b/agent/php/ElasticApm/Impl/Util/ArrayUtil.php @@ -33,17 +33,18 @@ final class ArrayUtil use StaticClassTrait; /** - * @param string $key - * @param array $array - * @param mixed $valueDst + * @template TKey of array-key + * @template TValue * - * @return bool + * @param TKey $key + * @param array $array + * @param TValue &$valueDst * - * @template T - * @phpstan-param T[] $array - * @phpstan-param T $valueDst + * @param-out TValue $valueDst + * + * @return bool */ - public static function getValueIfKeyExists(string $key, array $array, &$valueDst): bool + public static function getValueIfKeyExists($key, array $array, /* out */ &$valueDst): bool { if (!array_key_exists($key, $array)) { return false; @@ -54,7 +55,7 @@ public static function getValueIfKeyExists(string $key, array $array, &$valueDst } /** - * @template TKey of string|int + * @template TKey of array-key * @template TValue * * @param TKey $key diff --git a/agent/php/ElasticApm/Impl/Util/PhpErrorUtil.php b/agent/php/ElasticApm/Impl/Util/PhpErrorUtil.php index 3e6fdc727..9514823b5 100644 --- a/agent/php/ElasticApm/Impl/Util/PhpErrorUtil.php +++ b/agent/php/ElasticApm/Impl/Util/PhpErrorUtil.php @@ -32,41 +32,79 @@ final class PhpErrorUtil { use StaticClassTrait; - public static function getTypeName(int $type): ?string + /** + * @return array + */ + private static function flagsValueToNameMap(): array { - switch ($type) { - case E_ERROR: - return 'E_ERROR'; - case E_WARNING: - return 'E_WARNING'; - case E_PARSE: - return 'E_PARSE'; - case E_NOTICE: - return 'E_NOTICE'; - case E_CORE_ERROR: - return 'E_CORE_ERROR'; - case E_CORE_WARNING: - return 'E_CORE_WARNING'; - case E_COMPILE_ERROR: - return 'E_COMPILE_ERROR'; - case E_COMPILE_WARNING: - return 'E_COMPILE_WARNING'; - case E_USER_ERROR: - return 'E_USER_ERROR'; - case E_USER_WARNING: - return 'E_USER_WARNING'; - case E_USER_NOTICE: - return 'E_USER_NOTICE'; - case E_STRICT: - return 'E_STRICT'; - case E_RECOVERABLE_ERROR: - return 'E_RECOVERABLE_ERROR'; - case E_DEPRECATED: - return 'E_DEPRECATED'; - case E_USER_DEPRECATED: - return 'E_USER_DEPRECATED'; - default: - return null; + /** @var ?array $flags */ + static $flags = null; + + if ($flags === null) { + $flags = []; + $addToFlagsIfDefined = function (string $flagName, ?int $flagValue = null) use (&$flags): void { + if (defined($flagName)) { + $flagValueToUse = $flagValue ?? constant($flagName); + if (is_int($flagValueToUse)) { + $flags[$flagValueToUse] = $flagName; + } + } + }; + + $addToFlagsIfDefined('E_ERROR'); + $addToFlagsIfDefined('E_RECOVERABLE_ERROR'); + $addToFlagsIfDefined('E_WARNING'); + $addToFlagsIfDefined('E_PARSE'); + $addToFlagsIfDefined('E_NOTICE'); + // PHP 8.4: E_STRICT constant deprecated + if (PHP_VERSION_ID < 80400) { + $addToFlagsIfDefined('E_STRICT'); + } else { + $addToFlagsIfDefined('E_STRICT', /* E_STRICT: */ 2048); + } + $addToFlagsIfDefined('E_DEPRECATED'); + $addToFlagsIfDefined('E_CORE_ERROR'); + $addToFlagsIfDefined('E_CORE_WARNING'); + $addToFlagsIfDefined('E_COMPILE_ERROR'); + $addToFlagsIfDefined('E_COMPILE_WARNING'); + $addToFlagsIfDefined('E_USER_ERROR'); + $addToFlagsIfDefined('E_USER_WARNING'); + $addToFlagsIfDefined('E_USER_NOTICE'); + $addToFlagsIfDefined('E_USER_DEPRECATED'); + } + + return $flags; + } + + public static function convertErrorReportingValueToHumanReadableString(int $errorReporting): string + { + $flags = self::flagsValueToNameMap(); + $result = ''; + $appendToResult = function (string $separator, string $textToAppend) use (&$result): void { + if (!TextUtil::isEmptyString($result)) { + $result .= $separator; + } + $result .= $textToAppend; + }; + + $remaingValue = $errorReporting; + foreach ($flags as $flagValue => $flagName) { + $partToAddToResult = (($errorReporting & $flagValue) === 0 ? '~' : '') . $flagName; + $appendToResult(' & ', $partToAddToResult); + $remaingValue &= ~$flagValue; } + + if ($remaingValue !== 0) { + $appendToResult(' ', '[remaining value: ' . $remaingValue . ']'); + } + + $appendToResult(' ', '[value as int: ' . $errorReporting . ']'); + + return $result; + } + + public static function getTypeName(int $type): ?string + { + return ArrayUtil::getValueIfKeyExistsElse($type, self::flagsValueToNameMap(), null); } } diff --git a/tests/ElasticApmTests/ComponentTests/Util/SpawnedProcessBase.php b/tests/ElasticApmTests/ComponentTests/Util/SpawnedProcessBase.php index fabebbc75..9a7f23f83 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/SpawnedProcessBase.php +++ b/tests/ElasticApmTests/ComponentTests/Util/SpawnedProcessBase.php @@ -35,6 +35,7 @@ use Elastic\Apm\Impl\Util\BoolUtil; use Elastic\Apm\Impl\Util\ClassNameUtil; use Elastic\Apm\Impl\Util\ExceptionUtil; +use Elastic\Apm\Impl\Util\PhpErrorUtil; use Elastic\Apm\Impl\Util\UrlParts; use ElasticApmTests\Util\LogCategoryForTests; use PHPUnit\Framework\TestCase; @@ -61,6 +62,7 @@ protected function __construct() [ 'AmbientContext::testConfig()' => AmbientContextForTests::testConfig(), 'Environment variables' => EnvVarUtilForTests::getAll(), + 'error_reporting()' => PhpErrorUtil::convertErrorReportingValueToHumanReadableString(error_reporting()), ] ); } diff --git a/tests/ElasticApmTests/ComponentTests/Util/TestInfraHttpServerProcessBase.php b/tests/ElasticApmTests/ComponentTests/Util/TestInfraHttpServerProcessBase.php index 4064051e3..38cfeb162 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/TestInfraHttpServerProcessBase.php +++ b/tests/ElasticApmTests/ComponentTests/Util/TestInfraHttpServerProcessBase.php @@ -29,7 +29,9 @@ use Elastic\Apm\Impl\Log\Logger; use Elastic\Apm\Impl\Util\ArrayUtil; use Elastic\Apm\Impl\Util\ExceptionUtil; +use Elastic\Apm\Impl\Util\PhpErrorUtil; use ElasticApmTests\Util\LogCategoryForTests; +use ElasticApmTests\Util\TestCaseBase; use ErrorException; use Exception; use PHPUnit\Framework\Assert; @@ -72,23 +74,23 @@ public function __construct() __FILE__ )->addContext('this', $this); - set_error_handler( - function ( - int $type, - string $message, - string $srcFile, - int $srcLine - ): bool { - $msgForEx = LoggableToString::convert( - [ - 'message' => $message, - 'error type' => $type, - 'srcFile:srcLine' => $srcFile . ':' . $srcLine, - ] - ); + $prevHandler = set_error_handler( + function (int $type, string $message, string $srcFile, int $srcLine, ?array $context = null): bool { + $msgCtx = [ + 'message' => $message, + 'error type' => PhpErrorUtil::getTypeName($type) . ' (as int :' . $type . ')', + 'srcFile:srcLine' => $srcFile . ':' . $srcLine, + ]; + if ($context !== null) { + $msgCtx['context'] = $context; + } + + $msgForEx = LoggableToString::convert($msgCtx); throw new ErrorException($msgForEx, /* code: */ 0, $type, $srcFile, $srcLine); - } + }, + E_ALL & ~E_DEPRECATED ); + TestCaseBase::assertNull($prevHandler); } /** @inheritDoc */ diff --git a/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php b/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php index 6710053d8..a25a826bb 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php +++ b/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php @@ -25,6 +25,9 @@ use Elastic\Apm\ElasticApm; +// Disable deprecation notices +error_reporting(error_reporting() & ~E_DEPRECATED); + require __DIR__ . '/../../../bootstrap.php'; /** @var ?string $globalTopLevelCodeId */ diff --git a/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php b/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php index 4373b7421..a42f996d7 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php +++ b/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php @@ -25,6 +25,9 @@ use Elastic\Apm\ElasticApm; +// Disable deprecation notices +error_reporting(error_reporting() & ~E_DEPRECATED); + require __DIR__ . '/../../../bootstrap.php'; /** @var ?string $globalTopLevelCodeId */ diff --git a/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php b/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php index 525fda0d0..6da3d0f37 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php +++ b/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php @@ -21,6 +21,9 @@ declare(strict_types=1); +// Disable deprecation notices +error_reporting(error_reporting() & ~E_DEPRECATED); + require __DIR__ . '/../../../bootstrap.php'; use ElasticApmTests\ComponentTests\Util\MockApmServer; diff --git a/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php b/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php index 1057620ac..e90234df6 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php +++ b/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php @@ -21,6 +21,9 @@ declare(strict_types=1); +// Disable deprecation notices +error_reporting(error_reporting() & ~E_DEPRECATED); + require __DIR__ . '/../../../bootstrap.php'; use ElasticApmTests\ComponentTests\Util\ResourcesCleaner; From 13d75d1a60ae61c53706680917beb64fc597c0bf Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Tue, 14 Jan 2025 17:16:36 +0200 Subject: [PATCH 18/27] Fixed issue with mysqli::ping being deprecated since PHP 8.4 --- .../MySQLiAutoInstrumentationTest.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/ElasticApmTests/ComponentTests/MySQLiAutoInstrumentationTest.php b/tests/ElasticApmTests/ComponentTests/MySQLiAutoInstrumentationTest.php index 14eb41dab..258ef816f 100644 --- a/tests/ElasticApmTests/ComponentTests/MySQLiAutoInstrumentationTest.php +++ b/tests/ElasticApmTests/ComponentTests/MySQLiAutoInstrumentationTest.php @@ -134,7 +134,10 @@ public function testPrerequisitesSatisfied(): void AmbientContextForTests::testConfig()->mysqlDb ); self::assertNotNull($mySQLi); - self::assertTrue($mySQLi->ping()); + // Method mysqli::ping() is deprecated since PHP 8.4 + if (PHP_VERSION_ID < 80400) { + self::assertTrue($mySQLi->ping()); + } } public function testIsAutoInstrumentationEnabled(): void @@ -351,7 +354,11 @@ public static function appCodeForTestAutoInstrumentation(MixedMap $appCodeArgs): $mySQLiApiFacade = new ApiFacade($isOOPApi); $mySQLi = $mySQLiApiFacade->connect($host, $port, $user, $password, $connectDbName); self::assertNotNull($mySQLi); - self::assertTrue($mySQLi->ping()); + + // Method mysqli::ping() is deprecated since PHP 8.4 + if (PHP_VERSION_ID < 80400) { + self::assertTrue($mySQLi->ping()); + } if ($connectDbName !== $workDbName) { self::assertTrue($mySQLi->query(self::CREATE_DATABASE_IF_NOT_EXISTS_SQL_PREFIX . $workDbName)); @@ -447,7 +454,11 @@ private function implTestAutoInstrumentation(MixedMap $testArgs): void $expectedSpans = []; if ($isInstrumentationEnabled) { $expectedSpans[] = $expectationsBuilder->fromNames('mysqli', '__construct', 'mysqli_connect'); - $expectedSpans[] = $expectationsBuilder->fromNames('mysqli', 'ping'); + + // Method mysqli::ping() is deprecated since PHP 8.4 + if (PHP_VERSION_ID < 80400) { + $expectedSpans[] = $expectationsBuilder->fromNames('mysqli', 'ping'); + } if ($connectDbName !== $workDbName) { $expectedSpans[] = $expectationsBuilder->fromStatement(self::CREATE_DATABASE_IF_NOT_EXISTS_SQL_PREFIX . $workDbName); From aa081302de809274289b373170a28439d500fea4 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Wed, 15 Jan 2025 11:31:20 +0200 Subject: [PATCH 19/27] Disable deprecation notices starting from PHP 8.4 --- .../ElasticApmTests/ComponentTests/ErrorComponentTest.php | 3 +++ .../Util/routeToBuiltinHttpServerAppCodeHost.php | 3 --- .../ComponentTests/Util/runCliScriptAppCodeHost.php | 3 --- .../ComponentTests/Util/runMockApmServer.php | 3 --- .../ComponentTests/Util/runResourcesCleaner.php | 3 --- tests/bootstrap.php | 8 +++++--- tests/polyfills/load.php | 2 -- 7 files changed, 8 insertions(+), 17 deletions(-) diff --git a/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php b/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php index 5db9fd9e0..071611662 100644 --- a/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php +++ b/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php @@ -163,6 +163,7 @@ public static function appCodeForTestPhpErrorUndefinedVariableWrapper(MixedMap $ ] ); + $errorReportingValueToRestore = error_reporting(); if ($includeInErrorReporting) { error_reporting(error_reporting() | self::undefinedVariablePhpErrorCode()); } else { @@ -181,6 +182,8 @@ public static function appCodeForTestPhpErrorUndefinedVariableWrapper(MixedMap $ appCodeForTestPhpErrorUndefinedVariable(); + error_reporting($errorReportingValueToRestore); + if (!$includeInErrorReporting) { ElasticApm::createErrorFromThrowable(self::buildExceptionForSubstituteError()); } diff --git a/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php b/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php index a25a826bb..6710053d8 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php +++ b/tests/ElasticApmTests/ComponentTests/Util/routeToBuiltinHttpServerAppCodeHost.php @@ -25,9 +25,6 @@ use Elastic\Apm\ElasticApm; -// Disable deprecation notices -error_reporting(error_reporting() & ~E_DEPRECATED); - require __DIR__ . '/../../../bootstrap.php'; /** @var ?string $globalTopLevelCodeId */ diff --git a/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php b/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php index a42f996d7..4373b7421 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php +++ b/tests/ElasticApmTests/ComponentTests/Util/runCliScriptAppCodeHost.php @@ -25,9 +25,6 @@ use Elastic\Apm\ElasticApm; -// Disable deprecation notices -error_reporting(error_reporting() & ~E_DEPRECATED); - require __DIR__ . '/../../../bootstrap.php'; /** @var ?string $globalTopLevelCodeId */ diff --git a/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php b/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php index 6da3d0f37..525fda0d0 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php +++ b/tests/ElasticApmTests/ComponentTests/Util/runMockApmServer.php @@ -21,9 +21,6 @@ declare(strict_types=1); -// Disable deprecation notices -error_reporting(error_reporting() & ~E_DEPRECATED); - require __DIR__ . '/../../../bootstrap.php'; use ElasticApmTests\ComponentTests\Util\MockApmServer; diff --git a/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php b/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php index e90234df6..1057620ac 100644 --- a/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php +++ b/tests/ElasticApmTests/ComponentTests/Util/runResourcesCleaner.php @@ -21,9 +21,6 @@ declare(strict_types=1); -// Disable deprecation notices -error_reporting(error_reporting() & ~E_DEPRECATED); - require __DIR__ . '/../../../bootstrap.php'; use ElasticApmTests\ComponentTests\Util\ResourcesCleaner; diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 7ea01209e..ed22184c2 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -21,15 +21,17 @@ declare(strict_types=1); -error_reporting(E_ALL); - use ElasticApmTests\TestsRootDir; // Ensure that composer has installed all dependencies if (!file_exists(dirname(__DIR__) . '/composer.lock')) { - die("Dependencies must be installed using composer\n"); + die('Dependencies must be installed using composer' . PHP_EOL); } +// Disable deprecation notices starting from PHP 8.4 +// Deprecated: funcAbc(): Implicitly marking parameter $xyz as nullable is deprecated, the explicit nullable type must be used instead +error_reporting(PHP_VERSION_ID < 80400 ? E_ALL : (E_ALL & ~E_DEPRECATED)); + require __DIR__ . '/../vendor/autoload.php'; require __DIR__ . '/polyfills/load.php'; diff --git a/tests/polyfills/load.php b/tests/polyfills/load.php index 8b99a2f7e..ef3a9a4dd 100644 --- a/tests/polyfills/load.php +++ b/tests/polyfills/load.php @@ -21,8 +21,6 @@ declare(strict_types=1); -error_reporting(E_ALL); - if (!function_exists('array_key_first')) { require __DIR__ . '/array_key_first.php'; } From 231ebbbdbd09f94f8e43c6cd1ed9af85df6a23f2 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Wed, 15 Jan 2025 11:45:22 +0200 Subject: [PATCH 20/27] Reverted changes to ErrorComponentTest --- tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php b/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php index 071611662..5db9fd9e0 100644 --- a/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php +++ b/tests/ElasticApmTests/ComponentTests/ErrorComponentTest.php @@ -163,7 +163,6 @@ public static function appCodeForTestPhpErrorUndefinedVariableWrapper(MixedMap $ ] ); - $errorReportingValueToRestore = error_reporting(); if ($includeInErrorReporting) { error_reporting(error_reporting() | self::undefinedVariablePhpErrorCode()); } else { @@ -182,8 +181,6 @@ public static function appCodeForTestPhpErrorUndefinedVariableWrapper(MixedMap $ appCodeForTestPhpErrorUndefinedVariable(); - error_reporting($errorReportingValueToRestore); - if (!$includeInErrorReporting) { ElasticApm::createErrorFromThrowable(self::buildExceptionForSubstituteError()); } From 9d505bc63d6737c41601e9d5d0a82f661a4c9881 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Wed, 15 Jan 2025 15:44:53 +0200 Subject: [PATCH 21/27] Fixed WordPressAutoInstrumentationTest --- agent/native/ext/AST_debug.cpp | 7 +++- agent/native/ext/AST_instrumentation.cpp | 42 +++++++++++++++---- .../WordPressAutoInstrumentationTest.php | 26 +++++++++--- .../WordPressAutoInstrumentationUnitTest.php | 2 + 4 files changed, 62 insertions(+), 15 deletions(-) diff --git a/agent/native/ext/AST_debug.cpp b/agent/native/ext/AST_debug.cpp index 4794d91cd..fda0ffc28 100644 --- a/agent/native/ext/AST_debug.cpp +++ b/agent/native/ext/AST_debug.cpp @@ -224,11 +224,16 @@ String zendAstKindToString( zend_ast_kind kind ) ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_TYPE_INTERSECTION ); #endif - #if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 3, 0 ) /* if PHP version from 8.3.0 */ ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_MODIFIER_LIST ); #endif + #if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 4, 0 ) /* if PHP version from 8.4.0 */ + ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PROPERTY_HOOK ); + ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PROPERTY_HOOK_SHORT_BODY ); + ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PARENT_PROPERTY_HOOK_CALL ); + #endif + default: return NULL; } diff --git a/agent/native/ext/AST_instrumentation.cpp b/agent/native/ext/AST_instrumentation.cpp index 45a096269..360f79aa2 100644 --- a/agent/native/ext/AST_instrumentation.cpp +++ b/agent/native/ext/AST_instrumentation.cpp @@ -181,25 +181,47 @@ bool isZendAstListKind( zend_ast_kind kind ) } /** - * zend_ast_create and zend_ast_create_ex allowed up to 4 child* parameters for version before PHP v8 - * and the limit was increased to 5 in PHP v8 + * Max number of children for AST nodes is + * 4 for PHP before 8.0 + * 5 for PHP from 8.0 but before 8.4 + * 6 for PHP from 8.4 * * @see ZEND_AST_SPEC_CALL_EX + * + * When adding support for a new PHP version: + * - Make sure g_astNodeMaxChildCount is correct + * - If g_astNodeMaxChildCount changed then update createAstEx() + * - Make sure zendAstKindToString() in AST_debug.cpp includes all the enum cases from enum _zend_ast_kind in /Zend/zend_ast.h + * - Increment minor part of PHP version in static_assert below */ -static size_t g_maxCreateAstChildCount = +static_assert( + PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 5, 0 ), + "Make sure g_astNodeMaxChildCount is correct. See max number of children in enum _zend_ast_kind in /Zend/zend_ast.h" +); +static constexpr size_t g_astNodeMaxChildCount = + #if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 0, 0 ) + 4 // PHP before 8.0 + #elif PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 4, 0 ) + 5 // PHP from 8.0 but before 8.4 + #else + 6 // PHP from 8.4 + #endif +; +static constexpr size_t g_zendKindWithLargestChildNodesCount = #if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 0, 0 ) - 4 + ZEND_AST_FOR // PHP before 8.0 #else - 5 + ZEND_AST_PARAM // PHP from 8.0 #endif ; +static_assert(g_zendKindWithLargestChildNodesCount == (g_astNodeMaxChildCount << ZEND_AST_NUM_CHILDREN_SHIFT)); zend_ast* createAstEx( zend_ast_kind kind, zend_ast_attr attr, ZendAstPtrArrayView children ) { char txtOutStreamBuf[ELASTIC_APM_TEXT_OUTPUT_STREAM_ON_STACK_BUFFER_SIZE]; TextOutputStream txtOutStream = ELASTIC_APM_TEXT_OUTPUT_STREAM_FROM_STATIC_BUFFER( txtOutStreamBuf ); - ELASTIC_APM_ASSERT_LE_UINT64( children.count, g_maxCreateAstChildCount ); + ELASTIC_APM_ASSERT_LE_UINT64( children.count, g_astNodeMaxChildCount ); ELASTIC_APM_ASSERT( ! isZendAstListKind( kind ), "kind: %s", streamZendAstKind( kind, &txtOutStream ) ); switch( children.count ) @@ -218,6 +240,10 @@ zend_ast* createAstEx( zend_ast_kind kind, zend_ast_attr attr, ZendAstPtrArrayVi case 5: return zend_ast_create_ex( kind, attr, children.values[ 0 ], children.values[ 1 ], children.values[ 2 ], children.values[ 3 ], children.values[ 4 ] ); #endif + #if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 4, 0 ) + case 6: + return zend_ast_create_ex( kind, attr, children.values[ 0 ], children.values[ 1 ], children.values[ 2 ], children.values[ 3 ], children.values[ 4 ], children.values[ 5 ] ); + #endif default: // silence compiler warning return nullptr; } @@ -227,9 +253,9 @@ ResultCode createAstExCheckChildrenCount( zend_ast_kind kind, zend_ast_attr attr { ResultCode resultCode; - if ( children.count > g_maxCreateAstChildCount ) + if ( children.count > g_astNodeMaxChildCount ) { - ELASTIC_APM_LOG_ERROR( "Number of children is larger than max; children.count: %u, g_maxCreateAstChildCount: %u", (unsigned)children.count, (unsigned)g_maxCreateAstChildCount ); + ELASTIC_APM_LOG_ERROR( "Number of children is larger than max; children.count: %u, g_astNodeMaxChildCount: %u", (unsigned)children.count, (unsigned)g_astNodeMaxChildCount ); ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE_EX( resultFailure ); } diff --git a/tests/ElasticApmTests/ComponentTests/WordPressAutoInstrumentationTest.php b/tests/ElasticApmTests/ComponentTests/WordPressAutoInstrumentationTest.php index 716340a53..d41099400 100644 --- a/tests/ElasticApmTests/ComponentTests/WordPressAutoInstrumentationTest.php +++ b/tests/ElasticApmTests/ComponentTests/WordPressAutoInstrumentationTest.php @@ -41,6 +41,7 @@ use ElasticApmTests\ComponentTests\Util\ExpectedEventCounts; use ElasticApmTests\ComponentTests\WordPress\WordPressSpanExpectationsBuilder; use ElasticApmTests\ComponentTests\WordPress\WordPressMockBridge; +use ElasticApmTests\Util\ArrayUtilForTests; use ElasticApmTests\Util\AssertMessageStack; use ElasticApmTests\Util\DataProviderForTestBuilder; use ElasticApmTests\Util\FileUtilForTests; @@ -51,6 +52,7 @@ use ElasticApmTests\Util\SpanExpectations; use ElasticApmTests\Util\SpanSequenceValidator; use ElasticApmTests\Util\StackTraceExpectations; +use ElasticApmTests\Util\TestCaseBase; use ElasticApmTests\Util\TextUtilForTests; use SplFileInfo; @@ -218,6 +220,7 @@ public static function foldTextWithMarkersIntoOneLine(string $fileContents): str $adaptedLines[] = $line . $endOfLine; } + $dbgCtx->pop(); return implode(/* separator */ '', $adaptedLines); } @@ -281,6 +284,8 @@ private static function adaptSourceTree(bool $isExpectedVariant, string $fromDir $loggerProxyDebug && $loggerProxyDebug->log(__LINE__, 'Created file', ['adaptedSrcFileFullPath' => $adaptedSrcFileFullPath]); } $dbgCtx->popSubScope(); + + $dbgCtx->pop(); } /** @@ -343,6 +348,8 @@ private static function adaptManuallyInstrumentedGeneratedFile(/* in,out */ stri self::assertNotFalse(file_put_contents($adaptedFilePath, $adaptedFileContents)); $filePath = $adaptedFilePath; $fileContents = $adaptedFileContents; + + $dbgCtx->pop(); } private static function logFileContentOnMismatch(string $filePath, string $fileContents): void @@ -359,8 +366,7 @@ private static function logFileContentOnMismatch(string $filePath, string $fileC private static function verifyAstProcessGeneratedFiles(string $astProcessDebugDumpOutDir, string $phpFileRelativePath): void { - AssertMessageStack::newScope(/* out */ $dbgCtx); - $dbgCtx->add(['astProcessDebugDumpOutDir' => $astProcessDebugDumpOutDir, 'phpFileRelativePath' => $phpFileRelativePath]); + AssertMessageStack::newScope(/* out */ $dbgCtx, AssertMessageStack::funcArgs()); $logger = self::getLoggerForThisClass()->addAllContext(['astProcessDebugDumpOutDir' => $astProcessDebugDumpOutDir, 'phpFileRelativePath' => $phpFileRelativePath]); @@ -388,6 +394,8 @@ private static function verifyAstProcessGeneratedFiles(string $astProcessDebugDu self::assertFileExists($fileFullPath); $fileContents = file_get_contents($fileFullPath); self::assertNotFalse($fileContents); + + $dbgCtx->pop(); }; ($loggerProxy = $logger->ifDebugLevelEnabled(__LINE__, __FUNCTION__)) && $loggerProxy->log('Starting...'); @@ -414,9 +422,11 @@ private static function verifyAstProcessGeneratedFiles(string $astProcessDebugDu return; } - $logCtx = ['astMatches' => $astMatches]; + $logCtx = compact('astMatches'); + $dbgCtx->add(compact('astMatches', 'actualAstFilePath', 'expectedAstFilePath')); if (AmbientContextForTests::testConfig()->compareAstConvertedBackToSource) { - $logCtx['phpMatches'] = $phpMatches; + ArrayUtilForTests::append(compact('phpMatches'), /* in,out */ $logCtx); + $dbgCtx->add(compact('phpMatches', 'actualPhpFilePath', 'expectedPhpFilePath')); } ($loggerProxy = $logger->ifCriticalLevelEnabled(__LINE__, __FUNCTION__)) @@ -432,9 +442,9 @@ private static function verifyAstProcessGeneratedFiles(string $astProcessDebugDu } if (!$astMatches) { - self::assertSame($expectedAstFilePath, $actualAstFilePath); + TestCaseBase::fail('Dumpted ASTs do not match'); } elseif (AmbientContextForTests::testConfig()->compareAstConvertedBackToSource) { - self::assertSame($expectedPhpFilePath, $actualPhpFileContents); + TestCaseBase::fail('ASTs converted back to source do not match'); } } @@ -523,6 +533,8 @@ public static function appCodeForTestOnMockSource(MixedMap $appCodeArgs): void WordPressMockBridge::loadMockSource($srcVariantBaseDir, /* isExpectedVariant */ false); WordPressMockBridge::runMockSource($appCodeArgs); + + $dbgCtx->pop(); } public static function isWordPressDataToBeExpected(MixedMap $testArgs): bool @@ -737,6 +749,8 @@ function (AppCodeRequestParams $appCodeRequestParams) use ($testArgs): void { self::assertSame($expectedServiceFramework->version, $metadata->service->framework->version); } } + + $dbgCtx->pop(); } /** diff --git a/tests/ElasticApmTests/UnitTests/WordPressAutoInstrumentationUnitTest.php b/tests/ElasticApmTests/UnitTests/WordPressAutoInstrumentationUnitTest.php index 7d3adc9b4..007c044e8 100644 --- a/tests/ElasticApmTests/UnitTests/WordPressAutoInstrumentationUnitTest.php +++ b/tests/ElasticApmTests/UnitTests/WordPressAutoInstrumentationUnitTest.php @@ -45,6 +45,8 @@ public function testFindAddonNameInFilePath(): void $dbgCtx->add(['actualGroupKind' => $actualGroupKind, 'actualGroupName' => $actualGroupName]); self::assertSame($expectedGroupKind, $actualGroupKind); self::assertSame($expectedGroupName, $actualGroupName); + + $dbgCtx->pop(); }; $testImpl = function (string $filePath, string $expectedGroupKind, ?string $expectedGroupName) use ($testImplFilePathAsIs): void { From a8fdf479f87635d6c553d94748e95e497f407f42 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Wed, 15 Jan 2025 16:04:26 +0200 Subject: [PATCH 22/27] Fixed order in zendAstKindToString --- agent/native/ext/AST_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/native/ext/AST_debug.cpp b/agent/native/ext/AST_debug.cpp index fda0ffc28..cbe148df1 100644 --- a/agent/native/ext/AST_debug.cpp +++ b/agent/native/ext/AST_debug.cpp @@ -229,9 +229,9 @@ String zendAstKindToString( zend_ast_kind kind ) #endif #if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 4, 0 ) /* if PHP version from 8.4.0 */ + ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PARENT_PROPERTY_HOOK_CALL ); ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PROPERTY_HOOK ); ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PROPERTY_HOOK_SHORT_BODY ); - ELASTIC_APM_GEN_ENUM_TO_STRING_SWITCH_CASE( ZEND_AST_PARENT_PROPERTY_HOOK_CALL ); #endif default: From 3f1e282ad5c3eed4252b5c9841f8202a72053a15 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Wed, 15 Jan 2025 16:42:11 +0200 Subject: [PATCH 23/27] Remove CentOS/latest PHP from testing agent upgrade because CentOS is end-of-life and it does not support the latest PHP version --- .ci/generate_package_lifecycle_test_matrix.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.ci/generate_package_lifecycle_test_matrix.sh b/.ci/generate_package_lifecycle_test_matrix.sh index d18852b66..6ed00d39a 100755 --- a/.ci/generate_package_lifecycle_test_matrix.sh +++ b/.ci/generate_package_lifecycle_test_matrix.sh @@ -106,8 +106,13 @@ function generateAgentUpgradeRows () { local testingType=agent-upgrade local appHostKindShortName=all local testsGroup=smoke + for phpVersion in 7.4 ; do + for linuxPackageType in rpm ; do + echo "${phpVersion},${linuxPackageType},${testingType},${appHostKindShortName},${testsGroup}" + done + done for phpVersion in 7.4 "$(latestSupportedPhpVersion)" ; do - for linuxPackageType in deb rpm ; do + for linuxPackageType in deb ; do echo "${phpVersion},${linuxPackageType},${testingType},${appHostKindShortName},${testsGroup}" done done From 188bb164c3ebf7074ec04b997803bdae8cdffd93 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Wed, 15 Jan 2025 18:20:13 +0200 Subject: [PATCH 24/27] Fixed GenerateUnpackScriptsTest --- .../ComponentTests/GenerateUnpackScriptsTest.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php b/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php index bad13a6d4..60322db0d 100644 --- a/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php +++ b/tests/ElasticApmTests/ComponentTests/GenerateUnpackScriptsTest.php @@ -393,8 +393,22 @@ private function assertAllTestsAreLeaf(array $whereEnvVars): void private function assertSufficientCoverageAgentUpgrade(): void { + /** @noinspection PhpForeachOverSingleElementArrayLiteralInspection */ + foreach ([self::PHP_VERSION_7_4] as $phpVersion) { + /** @noinspection PhpForeachOverSingleElementArrayLiteralInspection */ + foreach ([self::LINUX_PACKAGE_TYPE_RPM] as $linuxPackageType) { + $this->assertAllTestsAreSmoke( + [ + self::PHP_VERSION_KEY => $phpVersion, + self::LINUX_PACKAGE_TYPE_KEY => $linuxPackageType, + self::TESTING_TYPE_KEY => self::AGENT_UPGRADE_TESTING_TYPE, + ] + ); + } + } foreach ([self::PHP_VERSION_7_4, self::latestSupportedPhpVersion()] as $phpVersion) { - foreach ([self::LINUX_PACKAGE_TYPE_DEB, self::LINUX_PACKAGE_TYPE_RPM] as $linuxPackageType) { + /** @noinspection PhpForeachOverSingleElementArrayLiteralInspection */ + foreach ([self::LINUX_PACKAGE_TYPE_DEB] as $linuxPackageType) { $this->assertAllTestsAreSmoke( [ self::PHP_VERSION_KEY => $phpVersion, From 1b04a28753d36811c0055040075616e408a19a61 Mon Sep 17 00:00:00 2001 From: Sergey Kleyman Date: Wed, 15 Jan 2025 19:42:31 +0200 Subject: [PATCH 25/27] Removed ds extension --- packaging/test/alpine/Dockerfile | 1 - packaging/test/centos/Dockerfile | 1 - packaging/test/ubuntu/Dockerfile | 1 - packaging/test/ubuntu/apache/Dockerfile | 1 - packaging/test/ubuntu/fpm/Dockerfile | 1 - 5 files changed, 5 deletions(-) diff --git a/packaging/test/alpine/Dockerfile b/packaging/test/alpine/Dockerfile index afd2f1d54..c7163048c 100644 --- a/packaging/test/alpine/Dockerfile +++ b/packaging/test/alpine/Dockerfile @@ -15,7 +15,6 @@ RUN apk update \ wget RUN docker-php-ext-install \ - ds \ mysqli \ pcntl \ pdo_mysql \ diff --git a/packaging/test/centos/Dockerfile b/packaging/test/centos/Dockerfile index 779519122..12a203703 100644 --- a/packaging/test/centos/Dockerfile +++ b/packaging/test/centos/Dockerfile @@ -24,7 +24,6 @@ RUN export PHP_VERSION_TRANSFORMED=$(echo "${PHP_VERSION}" | sed 's#\.##g') \ && yum-config-manager --enable remi-php${PHP_VERSION_TRANSFORMED} \ && yum install -y \ php \ - php-ds \ php-mbstring \ php-mysqli \ php-pcntl \ diff --git a/packaging/test/ubuntu/Dockerfile b/packaging/test/ubuntu/Dockerfile index b60ab05ff..f0f09c668 100644 --- a/packaging/test/ubuntu/Dockerfile +++ b/packaging/test/ubuntu/Dockerfile @@ -20,7 +20,6 @@ RUN apt-get -qq update \ && rm -rf /var/lib/apt/lists/* RUN docker-php-ext-install \ - ds \ mysqli \ pcntl \ pdo_mysql \ diff --git a/packaging/test/ubuntu/apache/Dockerfile b/packaging/test/ubuntu/apache/Dockerfile index 239237313..c5db6e792 100644 --- a/packaging/test/ubuntu/apache/Dockerfile +++ b/packaging/test/ubuntu/apache/Dockerfile @@ -31,7 +31,6 @@ RUN apt-get -qq -y --no-install-recommends install software-properties-common \ php${PHP_VERSION} \ libapache2-mod-php \ php${PHP_VERSION}-curl \ - php${PHP_VERSION}-ds \ php${PHP_VERSION}-mbstring \ php${PHP_VERSION}-mysql \ php${PHP_VERSION}-mysqli \ diff --git a/packaging/test/ubuntu/fpm/Dockerfile b/packaging/test/ubuntu/fpm/Dockerfile index fdd2f2ad8..8c16ff31c 100644 --- a/packaging/test/ubuntu/fpm/Dockerfile +++ b/packaging/test/ubuntu/fpm/Dockerfile @@ -31,7 +31,6 @@ RUN apt-get -qq -y --no-install-recommends install software-properties-common \ php${PHP_VERSION} \ libapache2-mod-fcgid \ php${PHP_VERSION}-curl \ - php${PHP_VERSION}-ds \ php${PHP_VERSION}-fpm \ php${PHP_VERSION}-mbstring \ php${PHP_VERSION}-mysql \ From de5c1bf480ff40eba0c399be8a8996edd4067626 Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Thu, 16 Jan 2025 11:41:26 +0100 Subject: [PATCH 26/27] Run PHP 8.4 tests on Fedora --- packaging/Makefile | 18 ++-- packaging/test/docker-compose.yml | 4 +- packaging/test/fedora/Dockerfile | 60 +++++++++++++ packaging/test/fedora/entrypoint.sh | 135 ++++++++++++++++++++++++++++ 4 files changed, 209 insertions(+), 8 deletions(-) create mode 100644 packaging/test/fedora/Dockerfile create mode 100755 packaging/test/fedora/entrypoint.sh diff --git a/packaging/Makefile b/packaging/Makefile index 687b78644..8302a44fc 100644 --- a/packaging/Makefile +++ b/packaging/Makefile @@ -13,6 +13,12 @@ RELEASE_VERSION?= GITHUB_RELEASES_URL=https://github.com/elastic/apm-agent-php/releases/download BUILD_ARCH := $(if $(BUILD_ARCH),$(BUILD_ARCH),"x86-64") +ifeq ($(shell [ $(PHP_VERSION) \< 8.4 ] && echo true), true) + RPM_IMAGE_VERSION = 0.0.3 # PHP < 8.4 - image using centos +else + RPM_IMAGE_VERSION = 0.1.0 # PHP 8.4+ - image using fedora +endif + export FPM_FLAGS= ifneq ($(PHP_VERSION), 7.2) @@ -199,7 +205,7 @@ tar-install: ## Install the tar installer to run some smoke tests .PHONY: rpm-install rpm-install: ## Install the rpm installer to run some smoke tests @echo "::group::$@" # Helping to group logs in GitHub actions - TYPE=rpm $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-0.0.3 + TYPE=rpm $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-$(RPM_IMAGE_VERSION) @echo "::endgroup::" .PHONY: deb-install-in-apache @@ -232,7 +238,7 @@ deb-install-release-github: ## Install the deb installer from a given release to .PHONY: rpm-install-release-github rpm-install-release-github: ## Install the rpm installer from a given release to run some smoke tests @echo "::group::$@" # Helping to group logs in GitHub actions - VERSION=$(RELEASE_VERSION) GITHUB_RELEASES_URL=$(GITHUB_RELEASES_URL) TYPE=release-github $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-0.0.3 + VERSION=$(RELEASE_VERSION) GITHUB_RELEASES_URL=$(GITHUB_RELEASES_URL) TYPE=release-github $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-$(RPM_IMAGE_VERSION) @echo "::endgroup::" .PHONY: tar-install-release-github @@ -274,7 +280,7 @@ deb-lifecycle-testing-in-fpm: ## Lifecycle testing for the deb installer with fp .PHONY: rpm-lifecycle-testing rpm-lifecycle-testing: ## Lifecycle testing for the rpm installer @echo "::group::$@" # Helping to group logs in GitHub actions - TYPE=rpm-uninstall PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-0.0.3 + TYPE=rpm-uninstall PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-$(RPM_IMAGE_VERSION) @echo "::endgroup::" .PHONY: tar-lifecycle-testing @@ -289,13 +295,13 @@ rpm-php-upgrade-testing: PHP_VERSION=7.2 rpm-php-upgrade-testing: ## PHP upgrade, from 7.2 to 7.4, testing for the rpm installer @echo "::group::$@" # Helping to group logs in GitHub actions echo "'$(PHP_VERSION)'" - TYPE=php-upgrade PHP_VERSION=$(PHP_VERSION) PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-0.0.3 + TYPE=php-upgrade PHP_VERSION=$(PHP_VERSION) PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-$(RPM_IMAGE_VERSION) @echo "::endgroup::" .PHONY: rpm-agent-upgrade-testing rpm-agent-upgrade-testing: ## Agent upgrade, from 1.0.0 to the current generated one, testing for the rpm installer @echo "::group::$@" # Helping to group logs in GitHub actions - VERSION=$(RELEASE_VERSION) GITHUB_RELEASES_URL=$(GITHUB_RELEASES_URL) TYPE=agent-upgrade PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-0.0.3 + VERSION=$(RELEASE_VERSION) GITHUB_RELEASES_URL=$(GITHUB_RELEASES_URL) TYPE=agent-upgrade PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-$(RPM_IMAGE_VERSION) @echo "::endgroup::" .PHONY: deb-agent-upgrade-testing @@ -307,7 +313,7 @@ deb-agent-upgrade-testing: ## Agent upgrade, from 1.0.0 to the current generated .PHONY: rpm-agent-upgrade-testing-local rpm-agent-upgrade-testing-local: ## Agent upgrade, from 1.0.0 to the current generated one, testing for the rpm installer @echo "::group::$@" # Helping to group logs in GitHub actions - VERSION=$(RELEASE_VERSION) GITHUB_RELEASES_URL=$(GITHUB_RELEASES_URL) TYPE=agent-upgrade-local PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-0.0.3 + VERSION=$(RELEASE_VERSION) GITHUB_RELEASES_URL=$(GITHUB_RELEASES_URL) TYPE=agent-upgrade-local PACKAGE=$(NAME) $(PWD)/.ci/run_docker_with_component_tests.sh elasticobservability/apm-agent-php-dev:packages-test-rpm-php-$(PHP_VERSION)-$(RPM_IMAGE_VERSION) @echo "::endgroup::" .PHONY: deb-agent-upgrade-testing-local diff --git a/packaging/test/docker-compose.yml b/packaging/test/docker-compose.yml index d1f40dcb4..e461edb55 100644 --- a/packaging/test/docker-compose.yml +++ b/packaging/test/docker-compose.yml @@ -182,9 +182,9 @@ services: - PHP_VERSION=7.2 rpm-php84: - image: elasticobservability/apm-agent-php-dev:packages-test-rpm-php-8.4-0.0.3 + image: elasticobservability/apm-agent-php-dev:packages-test-rpm-php-8.4-0.1.0 build: - context: centos + context: fedora dockerfile: Dockerfile args: - PHP_VERSION=8.4 diff --git a/packaging/test/fedora/Dockerfile b/packaging/test/fedora/Dockerfile new file mode 100644 index 000000000..9635c50a3 --- /dev/null +++ b/packaging/test/fedora/Dockerfile @@ -0,0 +1,60 @@ +FROM fedora:41 +ARG PHP_VERSION=8.4 +ENV PHP_VERSION ${PHP_VERSION} + +RUN echo "PHP_VERSION: $PHP_VERSION" +RUN echo "ls -R -l" && echo `ls -R -l` +RUN ls -1 /etc/*release | xargs -i sh -c 'echo {} && cat {}' + +RUN dnf -y update && dnf install -y \ + git \ + gnupg2 \ + logrotate \ + lsof \ + perl-Digest-SHA \ + rsyslog \ + unzip \ + wget \ + which + + # && yum-config-manager --enable remi-php${PHP_VERSION_TRANSFORMED} \ +RUN export PHP_VERSION_TRANSFORMED=$(echo "${PHP_VERSION}" | sed 's#\.##g') \ + FEDORA_VERSION_ID=$(cat /etc/*release | grep VERSION_ID | cut -d '=' -f 2) && echo "FEDORA_VERSION_ID: $FEDORA_VERSION_ID" \ + && dnf -y install https://rpms.remirepo.net/fedora/remi-release-$FEDORA_VERSION_ID.rpm +RUN dnf -y install dnf-plugins-core + +RUN dnf -y module reset php \ + && dnf -y module enable php:remi-$PHP_VERSION -y + +# composer \ +RUN dnf -y install \ + php \ + php-cli \ + php-curl \ + php-json \ + php-mbstring \ + php-mysqli \ + php-pdo_sqlite \ + php-pcntl \ + php-posix \ + php-xml + + +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# Disable agent for auxiliary PHP processes to reduce noise in logs +ENV ELASTIC_APM_ENABLED=false + +# It seems that even though we install rsyslog and start it (search for ensureSyslogIsRunning in .ci/validate_agent_installation.sh) +# for some reason on CentOS rsyslog does not receive messages from the agent +# so in order to work around this issue we escalate all log levels on CentOS +ENV ELASTIC_APM_PHP_TESTS_ESCALATED_RERUNS_PROD_CODE_LOG_LEVEL_OPTION_NAME=log_level + +# To support tar and rpm packages +ENV TYPE=rpm +ENV VERSION= +ENV GITHUB_RELEASES_URL= +COPY entrypoint.sh /bin +WORKDIR /app + +ENTRYPOINT ["/bin/entrypoint.sh"] diff --git a/packaging/test/fedora/entrypoint.sh b/packaging/test/fedora/entrypoint.sh new file mode 100755 index 000000000..649798cd6 --- /dev/null +++ b/packaging/test/fedora/entrypoint.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +set -xe + +################### +#### VARIABLES #### +################### +BUILD_RELEASES_FOLDER=build/releases +BUILD_PACKAGES=build/packages + +################### +#### FUNCTIONS #### +################### +function download() { + package=$1 + folder=$2 + url=$3 + mkdir -p "${folder}" + wget -q https://artifacts.elastic.co/GPG-KEY-elasticsearch -O "${folder}/GPG-KEY-elasticsearch" + wget -q "${url}/${package}" -O "${folder}/${package}" + wget -q "${url}/${package}.sha512" -O "${folder}/${package}.sha512" + wget -q "${url}/${package}.asc" -O "${folder}/${package}.asc" + cd "${folder}" || exit + gpg --import "GPG-KEY-elasticsearch" + shasum -a 512 -c "${package}.sha512" + gpg --verify "${package}.asc" "${package}" + cd - +} + +function validate_if_agent_is_uninstalled() { + ## Validate if the elastic php agent has been uninstalled + php -m + if php -m | grep -q "Unable to load dynamic library '/opt/elastic/apm-agent-php/extensions" ; then + echo 'Extension has not been uninstalled.' + exit 1 + fi + if php -m | grep -q 'elastic' ; then + echo 'Extension has not been uninstalled.' + exit 1 + fi +} + +function validate_if_agent_is_enabled() { + ## Validate if the elastic php agent is enabled + if ! php -m | grep -q 'elastic' ; then + echo 'Extension has not been installed.' + exit 1 + fi +} + +function validate_agent_installation() { + .ci/validate_agent_installation.sh || exit $? +} + +############## +#### MAIN #### +############## +if [[ "${TYPE}" == "rpm" || "${TYPE}" == "rpm-uninstall" || "${TYPE}" == "php-upgrade" ]] ; then + ls -l $BUILD_PACKAGES + ## Install rpm package and configure the agent accordingly + rpm -ivh $BUILD_PACKAGES/*.rpm +elif [ "${TYPE}" == "release-github" ] ; then + ## fpm replaces - with _ in the version for rpms. + PACKAGE=apm-agent-php-${VERSION/-/_}-1.noarch.rpm + download "${PACKAGE}" "${BUILD_RELEASES_FOLDER}" "${GITHUB_RELEASES_URL}/v${VERSION}" + rpm -ivh "${BUILD_RELEASES_FOLDER}/${PACKAGE}" +elif [ "${TYPE}" == "release-tar-github" ] ; then + PACKAGE=apm-agent-php-linux-x86-64.tar + download "${PACKAGE}" "${BUILD_RELEASES_FOLDER}" "${GITHUB_RELEASES_URL}/v${VERSION}" + ## Install tar package and configure the agent accordingly + tar -xf ${BUILD_RELEASES_FOLDER}/${PACKAGE} -C / + # shellcheck disable=SC1091 + source /opt/elastic/apm-agent-php/bin/post-install.sh +elif [ "${TYPE}" == "agent-upgrade" ] ; then + ## fpm replaces - with _ in the version for rpms. + PACKAGE=apm-agent-php-${VERSION/-/_}-1.noarch.rpm + download "${PACKAGE}" "${BUILD_RELEASES_FOLDER}" "${GITHUB_RELEASES_URL}/v${VERSION}" + rpm -ivh "${BUILD_RELEASES_FOLDER}/${PACKAGE}" +elif [ "${TYPE}" == "agent-upgrade-local" ] ; then + rpm -ivh build/local/*.rpm +else + ## Install tar package and configure the agent accordingly + tar -xf $BUILD_PACKAGES/apm-agent-php-linux-x86-64.tar -C / + # shellcheck disable=SC1091 + source /opt/elastic/apm-agent-php/bin/post-install.sh +fi + +validate_if_agent_is_enabled + +if case $TYPE in agent-upgrade*) ;; *) false;; esac; then + echo 'Validate installation runs after the agent upgrade.' +else + validate_agent_installation +fi + +## Validate the uninstallation works as expected +set -ex +if [ "${TYPE}" == "rpm-uninstall" ] ; then + rpm -e "${PACKAGE}" + validate_if_agent_is_uninstalled +elif [ "${TYPE}" == "tar-uninstall" ] ; then + # shellcheck disable=SC1091 + source /opt/elastic/apm-agent-php/bin/before-uninstall.sh + validate_if_agent_is_uninstalled +elif [ "${TYPE}" == "php-upgrade" ] ; then + ## Copy existing configuration file to compare with + cp /opt/elastic/apm-agent-php/etc/elastic-apm.ini /tmp/elastic-apm-previous.ini + + ## Uninstall existing installation + rpm -e "${PACKAGE}" + + ## Upgrade PHP version + yum-config-manager --enable remi-php74 + yum install -y php php-mbstring php-mysql php-xml + + ## Install rpm package and configure the agent accordingly + rpm -ivh $BUILD_PACKAGES/*.rpm + if ! diff --report-identical-files /opt/elastic/apm-agent-php/etc/elastic-apm.ini /tmp/elastic-apm-previous.ini ; then + echo 'Configuration file has been modified but should be identical.' + exit 1 + fi + ## Validate agent is enabled + validate_if_agent_is_enabled + + ## Run some tests + validate_agent_installation +elif case $TYPE in agent-upgrade*) ;; *) false;; esac; then + ## Upgrade the agent version with the rpm package and configure the agent accordingly + rpm -Uvh build/packages/*.rpm + + ## Validate agent is enabled + validate_if_agent_is_enabled + + ## Run some tests + validate_agent_installation +fi From 0e480874cc1ab895c14474b44ec7899569b2b3a4 Mon Sep 17 00:00:00 2001 From: Pawel Filipczak Date: Thu, 16 Jan 2025 12:44:56 +0100 Subject: [PATCH 27/27] Added missing ps to fedora image --- packaging/Makefile | 2 +- packaging/test/docker-compose.yml | 2 +- packaging/test/fedora/Dockerfile | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packaging/Makefile b/packaging/Makefile index 8302a44fc..88b886324 100644 --- a/packaging/Makefile +++ b/packaging/Makefile @@ -16,7 +16,7 @@ BUILD_ARCH := $(if $(BUILD_ARCH),$(BUILD_ARCH),"x86-64") ifeq ($(shell [ $(PHP_VERSION) \< 8.4 ] && echo true), true) RPM_IMAGE_VERSION = 0.0.3 # PHP < 8.4 - image using centos else - RPM_IMAGE_VERSION = 0.1.0 # PHP 8.4+ - image using fedora + RPM_IMAGE_VERSION = 0.1.1 # PHP 8.4+ - image using fedora endif export FPM_FLAGS= diff --git a/packaging/test/docker-compose.yml b/packaging/test/docker-compose.yml index e461edb55..85e9ff9ab 100644 --- a/packaging/test/docker-compose.yml +++ b/packaging/test/docker-compose.yml @@ -182,7 +182,7 @@ services: - PHP_VERSION=7.2 rpm-php84: - image: elasticobservability/apm-agent-php-dev:packages-test-rpm-php-8.4-0.1.0 + image: elasticobservability/apm-agent-php-dev:packages-test-rpm-php-8.4-0.1.1 build: context: fedora dockerfile: Dockerfile diff --git a/packaging/test/fedora/Dockerfile b/packaging/test/fedora/Dockerfile index 9635c50a3..de2f42b1a 100644 --- a/packaging/test/fedora/Dockerfile +++ b/packaging/test/fedora/Dockerfile @@ -15,7 +15,8 @@ RUN dnf -y update && dnf install -y \ rsyslog \ unzip \ wget \ - which + which \ + procps # && yum-config-manager --enable remi-php${PHP_VERSION_TRANSFORMED} \ RUN export PHP_VERSION_TRANSFORMED=$(echo "${PHP_VERSION}" | sed 's#\.##g') \