diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..97ce468 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,48 @@ +# AGENTS.md + +## Scope and intent +- `apm_ext` is a PHP extension that caches `solarwinds/apm` sampling data in-process; most work is under `ext/`. +- Runtime boundary has 3 layers: Zend module/API (`ext/apm_ext.c`) -> C bridge (`ext/cache_c_wrapper.h/.cpp`) -> C++ cache (`ext/cache.h/.cpp`). +- Public API is `Solarwinds\\Cache\\{get,put,getBucketState,putBucketState}` from `ext/apm_ext.stub.php` (generated header: `ext/apm_ext_arginfo.h`). + +## Core behavior you must preserve +- Two caches exist in module globals (`ext/php_apm_ext.h`): settings and bucket-state, each with separate INI limits. +- Settings key is intentionally composite in `ext/cache_c_wrapper.cpp`: `collector + hash(token) + serviceName` (token is never stored raw). +- `Solarwinds::Cache` is LRU-by-access/update (`ext/cache.cpp`): both `Get` and `Put` move entries to MRU; overflow evicts oldest. +- Fork handling is explicit in `ext/apm_ext.c`: `pthread_atfork(prefork, postfork, postfork)` frees/rebuilds caches across fork. + +## Project-specific rules (Do/Don't) +- Do add/adjust tunables in `PHP_INI_BEGIN` (`ext/apm_ext.c`) and ensure they appear in `php --ri apm_ext` output. +- Do keep API error contract: invalid/oversize input returns `false`; oversize paths also log to `stderr`. +- Do keep the C/C++ boundary thin: add cache ops in `ext/cache_c_wrapper.h/.cpp`, then bind from Zend functions. +- Don't hand-edit `ext/apm_ext_arginfo.h`; update `ext/apm_ext.stub.php` and regenerate stubs. +- Don't bypass size guards (`COLLECTOR_MAX_LENGTH`, `TOKEN_MAX_LENGTH`, `SERVICE_NAME_MAX_LENGTH`, `PID_MAX_LENGTH`, and INI max lengths). + +## Build/test workflow used in this repo +- Prefer root `Makefile` targets: `make build-image`, `make build`, `make test`, `make all`. +- Docker services mount `./ext` to `/usr/src/myapp` (`docker-compose.yaml`), so extension build/tests run in that directory context. +- `make build` executes `ext/build.sh` (`phpize && ./configure && make`). +- Tests are PHPT (not PHPUnit); canonical suite is `ext/tests/*.phpt`. + +## Common commands (zsh) +```zsh +make all +make build-image +make build +make test +``` + +## Quick task playbook +- If editing Zend API or INI/config, start in `ext/apm_ext.c`; if editing function signatures, update `ext/apm_ext.stub.php` first. +- If editing cache semantics/keying, touch `ext/cache.cpp` and/or `ext/cache_c_wrapper.cpp`, then run targeted PHPTs. +- For API shape changes, do not edit `ext/apm_ext_arginfo.h` directly; regenerate from `ext/apm_ext.stub.php` before running tests. +- Run the smallest relevant tests first (`004` update, `008` LRU, `012` fork), then run broader `make test`. + +## Test files to mirror when changing behavior +- Cache update semantics: `ext/tests/004.phpt`. +- LRU eviction/order semantics: `ext/tests/008.phpt`. +- Fork isolation semantics: `ext/tests/012.phpt`. +- Extension load/config smoke: `ext/tests/001.phpt` and nearby `00x.phpt` files. + +## Existing AI guidance discovery +- One required glob search found only `README.md` as an existing AI-instructions source in this workspace. diff --git a/README.md b/README.md index 92240bd..6c856c5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![GitHub License](https://img.shields.io/github/license/solarwinds/apm-php-ext) ## Overview -solarwinds/apm_ext is an add-on PHP extension to [solarwinds/apm](https://packagist.org/packages/solarwinds/apm), used to cache the sampling settings for the APM library. +solarwinds/apm_ext is an add-on PHP extension to [solarwinds/apm](https://packagist.org/packages/solarwinds/apm), used to cache the sampling settings and the token bucket state for the APM library. ## Requirements - PHP 8+ @@ -25,10 +25,12 @@ pie install solarwinds/apm_ext This extension can be configured via `.ini` by modifying the following entries: -| Configuration | Default | Description | -|-------------------------------|---------|---------------------------------------------------| -| apm_ext.cache_max_entries | 48 | Maximum number of entries in the cache | -| apm_ext.settings_max_length | 2048 | Maximum length of the settings value in the cache | +| Configuration | Default | Description | +|----------------------------------------|---------|--------------------------------------------------------------------| +| apm_ext.cache_max_entries | 48 | Maximum number of entries in the cache | +| apm_ext.settings_max_length | 2048 | Maximum length of the settings value in the cache | +| apm_ext.bucket_state_cache_max_entries | 512 | Maximum number of entries in the bucket state cache | +| apm_ext.bucket_state_max_length | 2048 | Maximum length of the bucket state value in the bucket state cache | ## Verify that the extension is installed and enabled diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index 2d6d3e4..5bad54f 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -1,4 +1,4 @@ -ARG ALPINE_VERSION=alpine:3.20@sha256:765942a4039992336de8dd5db680586e1a206607dd06170ff0a37267a9e01958 +ARG ALPINE_VERSION=alpine:3.23@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 FROM ${ALPINE_VERSION} AS builder WORKDIR /usr/src diff --git a/docker/Dockerfile.debian b/docker/Dockerfile.debian index 1533f9a..bcbfcdd 100644 --- a/docker/Dockerfile.debian +++ b/docker/Dockerfile.debian @@ -1,4 +1,4 @@ -FROM debian:bookworm-slim@sha256:78d2f66e0fec9e5a39fb2c72ea5e052b548df75602b5215ed01a17171529f706 +FROM debian:bookworm-slim@sha256:f06537653ac770703bc45b4b113475bd402f451e85223f0f2837acbf89ab020a WORKDIR /usr/src #clang-format, gdb, valgrind diff --git a/ext/apm_ext.c b/ext/apm_ext.c index dae5771..f193a04 100644 --- a/ext/apm_ext.c +++ b/ext/apm_ext.c @@ -24,6 +24,8 @@ #define COLLECTOR_MAX_LENGTH 100 #define TOKEN_MAX_LENGTH 128 #define SERVICE_NAME_MAX_LENGTH 128 +// Windows process ID range can be [0, 4294967295] +#define PID_MAX_LENGTH 10 ZEND_DECLARE_MODULE_GLOBALS(apm_ext) @@ -34,6 +36,12 @@ STD_PHP_INI_ENTRY("apm_ext.cache_max_entries", "48", PHP_INI_ALL, STD_PHP_INI_ENTRY("apm_ext.settings_max_length", "2048", PHP_INI_ALL, OnUpdateLongGEZero, settings_max_length, zend_apm_ext_globals, apm_ext_globals) +STD_PHP_INI_ENTRY("apm_ext.bucket_state_cache_max_entries", "512", PHP_INI_ALL, + OnUpdateLongGEZero, bucket_state_cache_max_entries, zend_apm_ext_globals, + apm_ext_globals) +STD_PHP_INI_ENTRY("apm_ext.bucket_state_max_length", "2048", PHP_INI_ALL, + OnUpdateLongGEZero, bucket_state_max_length, zend_apm_ext_globals, + apm_ext_globals) PHP_INI_END() /* {{{ void Solarwinds\\Cache\\get() */ @@ -110,14 +118,67 @@ PHP_FUNCTION(Solarwinds_Cache_put) { } /* }}} */ +/* {{{ void Solarwinds\\Cache\\getBucketState() */ +PHP_FUNCTION(Solarwinds_Cache_getBucketState) { + char *pid; + size_t pid_len; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STRING(pid, pid_len) + ZEND_PARSE_PARAMETERS_END(); + + if (!pid_len) { + RETURN_FALSE; + } + + zend_string *state = Cache_GetBucketState(APM_EXT_G(bucket_state_cache), pid); + if (state != NULL) { + RETURN_NEW_STR(state); + } + RETURN_FALSE; +} +/* }}} */ + +/* {{{ void Solarwinds\\Cache\\putBucketState() */ +PHP_FUNCTION(Solarwinds_Cache_putBucketState) { + char *pid; + size_t pid_len; + char *bucket_state; + size_t bucket_state_len; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_STRING(pid, pid_len) + Z_PARAM_STRING(bucket_state, bucket_state_len) + ZEND_PARSE_PARAMETERS_END(); + + if (pid_len && bucket_state_len) { + if (pid_len > PID_MAX_LENGTH) { + fprintf(stderr, "apm_ext: pid length %zu exceeds max length %d\n", pid_len, PID_MAX_LENGTH); + RETURN_FALSE; + } + if (bucket_state_len > (size_t)APM_EXT_G(bucket_state_max_length)) { + fprintf(stderr, "apm_ext: bucket state length %zu exceeds max length %ld\n", + bucket_state_len, (long)APM_EXT_G(bucket_state_max_length)); + RETURN_FALSE; + } + Cache_PutBucketState(APM_EXT_G(bucket_state_cache), pid, bucket_state); + RETURN_TRUE; + } + RETURN_FALSE; +} +/* }}} */ + #ifndef _WIN32 void prefork() { + Cache_Free(APM_EXT_G(bucket_state_cache)); + APM_EXT_G(bucket_state_cache) = NULL; Cache_Free(APM_EXT_G(cache)); APM_EXT_G(cache) = NULL; } void postfork() { APM_EXT_G(cache) = Cache_Allocate(APM_EXT_G(cache_max_entries)); + APM_EXT_G(bucket_state_cache) = Cache_Allocate(APM_EXT_G(bucket_state_cache_max_entries)); } #endif @@ -129,7 +190,7 @@ PHP_MINIT_FUNCTION(apm_ext) { REGISTER_INI_ENTRIES(); APM_EXT_G(cache) = Cache_Allocate(APM_EXT_G(cache_max_entries)); - + APM_EXT_G(bucket_state_cache) = Cache_Allocate(APM_EXT_G(bucket_state_cache_max_entries)); #ifndef _WIN32 pthread_atfork(prefork, postfork, postfork); #endif @@ -140,6 +201,8 @@ PHP_MINIT_FUNCTION(apm_ext) { /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(apm_ext) { + Cache_Free(APM_EXT_G(bucket_state_cache)); + APM_EXT_G(bucket_state_cache) = NULL; Cache_Free(APM_EXT_G(cache)); APM_EXT_G(cache) = NULL; diff --git a/ext/apm_ext.stub.php b/ext/apm_ext.stub.php index e39498c..e860769 100644 --- a/ext/apm_ext.stub.php +++ b/ext/apm_ext.stub.php @@ -7,3 +7,7 @@ function get(string $collector, string $token, string $serviceName): string|false {} function put(string $collector, string $token, string $serviceName, string $settings): bool {} + +function getBucketState(string $pid): string|false {} + +function putBucketState(string $pid, string $bucketState): bool {} diff --git a/ext/apm_ext_arginfo.h b/ext/apm_ext_arginfo.h index 3763f10..7d33fd5 100644 --- a/ext/apm_ext_arginfo.h +++ b/ext/apm_ext_arginfo.h @@ -1,26 +1,39 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 109c874d71ea223fc4aa34c5a131dd8ac8e46c8b */ + * Stub hash: 8b79f936643750559071769b234b5f16f17bcaf1 */ -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_Solarwinds_Cache_get, 0, 3, - MAY_BE_STRING | MAY_BE_FALSE) -ZEND_ARG_TYPE_INFO(0, collector, IS_STRING, 0) -ZEND_ARG_TYPE_INFO(0, token, IS_STRING, 0) -ZEND_ARG_TYPE_INFO(0, serviceName, IS_STRING, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_Solarwinds_Cache_get, 0, 3, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, collector, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, token, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, serviceName, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Solarwinds_Cache_put, 0, 4, - _IS_BOOL, 0) -ZEND_ARG_TYPE_INFO(0, collector, IS_STRING, 0) -ZEND_ARG_TYPE_INFO(0, token, IS_STRING, 0) -ZEND_ARG_TYPE_INFO(0, serviceName, IS_STRING, 0) -ZEND_ARG_TYPE_INFO(0, settings, IS_STRING, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Solarwinds_Cache_put, 0, 4, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, collector, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, token, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, serviceName, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, settings, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_Solarwinds_Cache_getBucketState, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, pid, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_Solarwinds_Cache_putBucketState, 0, 2, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, pid, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, bucketState, IS_STRING, 0) +ZEND_END_ARG_INFO() + + ZEND_FUNCTION(Solarwinds_Cache_get); ZEND_FUNCTION(Solarwinds_Cache_put); +ZEND_FUNCTION(Solarwinds_Cache_getBucketState); +ZEND_FUNCTION(Solarwinds_Cache_putBucketState); + static const zend_function_entry ext_functions[] = { - ZEND_NS_FALIAS("Solarwinds\\Cache", get, Solarwinds_Cache_get, - arginfo_Solarwinds_Cache_get) - ZEND_NS_FALIAS("Solarwinds\\Cache", put, Solarwinds_Cache_put, - arginfo_Solarwinds_Cache_put) ZEND_FE_END}; + ZEND_NS_FALIAS("Solarwinds\\Cache", get, Solarwinds_Cache_get, arginfo_Solarwinds_Cache_get) + ZEND_NS_FALIAS("Solarwinds\\Cache", put, Solarwinds_Cache_put, arginfo_Solarwinds_Cache_put) + ZEND_NS_FALIAS("Solarwinds\\Cache", getBucketState, Solarwinds_Cache_getBucketState, arginfo_Solarwinds_Cache_getBucketState) + ZEND_NS_FALIAS("Solarwinds\\Cache", putBucketState, Solarwinds_Cache_putBucketState, arginfo_Solarwinds_Cache_putBucketState) + ZEND_FE_END +}; diff --git a/ext/cache.cpp b/ext/cache.cpp index 753373c..57867c2 100644 --- a/ext/cache.cpp +++ b/ext/cache.cpp @@ -3,10 +3,7 @@ namespace Solarwinds { Cache::Cache(size_t max_entries) : max_entries_(max_entries) {} -void Cache::Put(const std::string &collector, const std::string &token, - const std::string &serviceName, const std::string &settings) { - auto key = - collector + std::to_string(std::hash{}(token)) + serviceName; +void Cache::Put(const std::string &key, const std::string &value) { std::lock_guard lock(cache_mutex_); if (cache_map_.find(key) == cache_map_.end()) { // new @@ -15,31 +12,27 @@ void Cache::Put(const std::string &collector, const std::string &token, cache_map_.erase(it.first); cache_.pop_front(); } - cache_.push_back(std::make_pair(key, settings)); + cache_.push_back(std::make_pair(key, value)); cache_map_[key] = std::prev(cache_.end()); } else { // update, move cache auto it = cache_map_[key]; cache_.erase(it); - cache_.push_back(std::make_pair(key, settings)); + cache_.push_back(std::make_pair(key, value)); cache_map_[key] = std::prev(cache_.end()); } } -std::pair Cache::Get(const std::string &collector, - const std::string &token, - const std::string &serviceName) { - auto key = - collector + std::to_string(std::hash{}(token)) + serviceName; +std::pair Cache::Get(const std::string &key) { std::lock_guard lock(cache_mutex_); auto it = cache_map_.find(key); if (it == cache_map_.end()) { return std::make_pair(false, ""); } auto cache_iterator = it->second; - auto settings = cache_iterator->second; + auto value = cache_iterator->second; cache_.erase(cache_iterator); - cache_.push_back(std::make_pair(key, settings)); + cache_.push_back(std::make_pair(key, value)); cache_map_[key] = std::prev(cache_.end()); - return std::make_pair(true, settings); + return std::make_pair(true, value); } } // namespace Solarwinds diff --git a/ext/cache.h b/ext/cache.h index 9052b50..5657f31 100644 --- a/ext/cache.h +++ b/ext/cache.h @@ -8,8 +8,7 @@ #include /** - * Simple in-memory cache for storing settings based on collector, token, and - * service name. + * Simple in-memory cache for storing value based on a key. */ namespace Solarwinds { @@ -23,25 +22,18 @@ class Cache { /** * Store settings in the cache. * - * @param collector The collector endpoint. - * @param token The token. - * @param serviceName The name of the service. - * @param settings The settings to be cached. + * @param key The key. + * @param value The value. */ - void Put(const std::string &collector, const std::string &token, - const std::string &serviceName, const std::string &settings); + void Put(const std::string &key, const std::string &value); /** * Retrieve settings from the cache. * - * @param collector The collector endpoint. - * @param token The token. - * @param serviceName The name of the service. - * @return A pair where the first element indicates if the settings were - * found, and the second element is the cached settings (if found). + * @param key The key. + * @return A pair where the first element indicates if the value were + * found, and the second element is the value (if found). */ - std::pair Get(const std::string &collector, - const std::string &token, - const std::string &serviceName); + std::pair Get(const std::string &key); private: /** diff --git a/ext/cache_c_wrapper.cpp b/ext/cache_c_wrapper.cpp index 95b9393..0cc8331 100644 --- a/ext/cache_c_wrapper.cpp +++ b/ext/cache_c_wrapper.cpp @@ -2,8 +2,8 @@ #include "cache.h" #include -void *Cache_Allocate(long cache_max_entries) { - return new (std::nothrow) Solarwinds::Cache(cache_max_entries); +void *Cache_Allocate(long max_entries) { + return new (std::nothrow) Solarwinds::Cache(max_entries); } void Cache_Free(void *cache) { @@ -18,8 +18,8 @@ void Cache_Put(void *cache, char *collector, char *token, char *serviceName, if (cache != nullptr && collector != nullptr && token != nullptr && serviceName != nullptr && settings != nullptr) { auto c = static_cast(cache); - c->Put(std::string(collector), std::string(token), std::string(serviceName), - std::string(settings)); + auto key = std::string(collector) + std::to_string(std::hash{}(std::string(token))) + std::string(serviceName); + c->Put(key, std::string(settings)); } } @@ -28,8 +28,8 @@ zend_string *Cache_Get(void *cache, char *collector, char *token, if (cache != nullptr && collector != nullptr && token != nullptr && serviceName != nullptr) { auto c = static_cast(cache); - auto result = c->Get(std::string(collector), std::string(token), - std::string(serviceName)); + auto key = std::string(collector) + std::to_string(std::hash{}(std::string(token))) + std::string(serviceName); + auto result = c->Get(key); if (result.first) { return zend_string_init(result.second.c_str(), result.second.size(), false); @@ -37,3 +37,21 @@ zend_string *Cache_Get(void *cache, char *collector, char *token, } return nullptr; } + +void Cache_PutBucketState(void *cache, char *pid, char *bucketTokenState) { + if (cache != nullptr && pid != nullptr && bucketTokenState != nullptr) { + auto c = static_cast(cache); + c->Put(std::string(pid), std::string(bucketTokenState)); + } +} + +zend_string *Cache_GetBucketState(void *cache, char *pid) { + if (cache != nullptr && pid != nullptr) { + auto c = static_cast(cache); + auto result = c->Get(std::string(pid)); + if (result.first) { + return zend_string_init(result.second.c_str(), result.second.size(), false); + } + } + return nullptr; +} diff --git a/ext/cache_c_wrapper.h b/ext/cache_c_wrapper.h index 9217154..92ba471 100644 --- a/ext/cache_c_wrapper.h +++ b/ext/cache_c_wrapper.h @@ -10,10 +10,10 @@ extern "C" { /** * Allocate and initialize a new cache instance. * - * @param cache_max_entries The maximum number of entries the cache can hold. + * @param max_entries The maximum number of entries the cache can hold. * @return A pointer to the allocated cache instance. */ -void *Cache_Allocate(long cache_max_entries); +void *Cache_Allocate(long max_entries); /** * Free the allocated cache instance. @@ -45,6 +45,23 @@ void Cache_Put(void *cache, char *collector, char *token, char *serviceName, zend_string *Cache_Get(void *cache, char *collector, char *token, char *serviceName); +/** + * Store bucket token state in the cache. + * + * @param cache A pointer to the cache instance. + * @param pid The process id. + * @param bucketTokenState The bucket token state. + */ +void Cache_PutBucketState(void *cache, char *pid, char *bucketTokenState); + +/** + * Retrieve bucket token state from the cache. + * @param cache A pointer to the cache instance. + * @param pid The process id. + * @return The bucket token state if found, otherwise NULL. + */ +zend_string *Cache_GetBucketState(void *cache, char *pid); + #ifdef __cplusplus } #endif diff --git a/ext/php_apm_ext.h b/ext/php_apm_ext.h index 4ae428b..b215886 100644 --- a/ext/php_apm_ext.h +++ b/ext/php_apm_ext.h @@ -10,13 +10,16 @@ ZEND_BEGIN_MODULE_GLOBALS(apm_ext) void *cache; zend_long cache_max_entries; zend_long settings_max_length; +void *bucket_state_cache; +zend_long bucket_state_cache_max_entries; +zend_long bucket_state_max_length; ZEND_END_MODULE_GLOBALS(apm_ext) ZEND_EXTERN_MODULE_GLOBALS(apm_ext) #define APM_EXT_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(apm_ext, v) -#define PHP_APM_EXT_VERSION "1.0.0" +#define PHP_APM_EXT_VERSION "2.0.0" #if defined(ZTS) && defined(COMPILE_DL_APM_EXT) ZEND_TSRMLS_CACHE_EXTERN() diff --git a/ext/tests/102.phpt b/ext/tests/102.phpt new file mode 100644 index 0000000..24a5b8a --- /dev/null +++ b/ext/tests/102.phpt @@ -0,0 +1,16 @@ +--TEST-- +\Solarwinds\Cache\getBucketState test +--EXTENSIONS-- +apm_ext +--FILE-- + +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/tests/103.phpt b/ext/tests/103.phpt new file mode 100644 index 0000000..b39f868 --- /dev/null +++ b/ext/tests/103.phpt @@ -0,0 +1,31 @@ +--TEST-- +\Solarwinds\Cache\putBucketState test +--EXTENSIONS-- +apm_ext +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(true) +bool(true) +string(1) "0" +string(1) "1" + diff --git a/ext/tests/104.phpt b/ext/tests/104.phpt new file mode 100644 index 0000000..f220574 --- /dev/null +++ b/ext/tests/104.phpt @@ -0,0 +1,37 @@ +--TEST-- +\Solarwinds\Cache update bucket state test +--EXTENSIONS-- +apm_ext +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +string(1) "0" +string(1) "1" +bool(true) +bool(true) +string(4) "new0" +string(4) "new1" diff --git a/ext/tests/105.phpt b/ext/tests/105.phpt new file mode 100644 index 0000000..7319ce0 --- /dev/null +++ b/ext/tests/105.phpt @@ -0,0 +1,28 @@ +--TEST-- +\Solarwinds\Cache put/getBucketState edge test +--EXTENSIONS-- +apm_ext +--FILE-- + +--EXPECTF-- +bool(true) + +Deprecated: Solarwinds\Cache\putBucketState(): Passing null to parameter #1 ($pid) of type string is deprecated in %s on line %d +bool(false) + +Deprecated: Solarwinds\Cache\putBucketState(): Passing null to parameter #2 ($bucketState) of type string is deprecated in %s on line %d +bool(false) +string(1) "s" + +Deprecated: Solarwinds\Cache\getBucketState(): Passing null to parameter #1 ($pid) of type string is deprecated in %s on line %d +bool(false) + diff --git a/ext/tests/106.phpt b/ext/tests/106.phpt new file mode 100644 index 0000000..e1dd587 --- /dev/null +++ b/ext/tests/106.phpt @@ -0,0 +1,39 @@ +--TEST-- +\Solarwinds\Cache bucket state max length test +--EXTENSIONS-- +apm_ext +--INI-- +apm_ext.bucket_state_max_length=5 +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +apm_ext: bucket state length 6 exceeds max length 5 +bool(false) +string(1) "1" +string(2) "12" +string(3) "123" +string(4) "1234" +string(5) "12345" +bool(false) + diff --git a/ext/tests/107.phpt b/ext/tests/107.phpt new file mode 100644 index 0000000..ea68dd3 --- /dev/null +++ b/ext/tests/107.phpt @@ -0,0 +1,68 @@ +--TEST-- +\Solarwinds\Cache bucket state max entries test +--EXTENSIONS-- +apm_ext +--INI-- +apm_ext.bucket_state_cache_max_entries=3 +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +string(1) "1" +string(2) "12" +string(3) "123" +bool(true) +bool(false) +string(2) "12" +string(3) "123" +string(4) "1234" +bool(true) +bool(false) +bool(false) +string(3) "123" +string(4) "1234" +string(5) "12345" +bool(true) +bool(false) +bool(false) +bool(false) +string(4) "1234" +string(5) "12345" +string(6) "123456" + diff --git a/ext/tests/108.phpt b/ext/tests/108.phpt new file mode 100644 index 0000000..3039df0 --- /dev/null +++ b/ext/tests/108.phpt @@ -0,0 +1,35 @@ +--TEST-- +\Solarwinds\Cache bucket state LRU test +--EXTENSIONS-- +apm_ext +--INI-- +apm_ext.bucket_state_cache_max_entries=3 +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +string(1) "1" +bool(true) +bool(false) +string(3) "123" +string(4) "1234" +string(1) "1" + diff --git a/ext/tests/109.phpt b/ext/tests/109.phpt new file mode 100644 index 0000000..ac13972 --- /dev/null +++ b/ext/tests/109.phpt @@ -0,0 +1,31 @@ +--TEST-- +\Solarwinds\Cache pid max length test +--EXTENSIONS-- +apm_ext +--FILE-- + +--EXPECT-- +bool(true) +string(1) "1" +apm_ext: pid length 11 exceeds max length 10 +bool(false) +bool(false) + diff --git a/ext/tests/110.phpt b/ext/tests/110.phpt new file mode 100644 index 0000000..2c14248 --- /dev/null +++ b/ext/tests/110.phpt @@ -0,0 +1,32 @@ +--TEST-- +\Solarwinds\Cache bucket state length boundary test +--EXTENSIONS-- +apm_ext +--INI-- +apm_ext.bucket_state_max_length=128 +--FILE-- + +--EXPECT-- +bool(true) +string(128) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +apm_ext: bucket state length 129 exceeds max length 128 +bool(false) +bool(false) + diff --git a/ext/tests/111.phpt b/ext/tests/111.phpt new file mode 100644 index 0000000..5fd0b20 --- /dev/null +++ b/ext/tests/111.phpt @@ -0,0 +1,24 @@ +--TEST-- +\Solarwinds\Cache bucket state empty input test +--EXTENSIONS-- +apm_ext +--FILE-- + +--EXPECT-- +bool(true) +bool(false) +bool(false) +string(1) "s" +bool(false) +bool(false) + diff --git a/ext/tests/112.phpt b/ext/tests/112.phpt new file mode 100644 index 0000000..2051305 --- /dev/null +++ b/ext/tests/112.phpt @@ -0,0 +1,45 @@ +--TEST-- +\Solarwinds\Cache bucket state forking test +--EXTENSIONS-- +apm_ext +pcntl +--FILE-- + +--EXPECT-- +bool(true) +string(1) "1" +string(5) "child" +bool(false) +bool(true) +string(1) "3" +string(6) "parent" +bool(false) +bool(true) +string(1) "2" +