diff --git a/.github/workflows/tests-windows.yml b/.github/workflows/tests-windows.yml new file mode 100644 index 0000000000..02984dc65a --- /dev/null +++ b/.github/workflows/tests-windows.yml @@ -0,0 +1,66 @@ +name: PHP Composer Windows + +on: + push: + branches: [master] + pull_request: + branches: [master] + +permissions: + contents: read + +jobs: + run: + runs-on: windows-latest + strategy: + matrix: + include: + - php-versions: '8.1' + composer-options: '' + - php-versions: '8.2' + composer-options: '' + - php-versions: '8.3' + composer-options: '' + - php-versions: '8.4' + composer-options: '' + - php-versions: '8.5' + composer-options: '' + name: PHP ${{ matrix.php-versions }} ${{ matrix.composer-options }} + env: + AWS_ACCESS_KEY_ID: foo + AWS_SECRET_ACCESS_KEY: bar + AWS_CSM_ENABLED: false + AWS_SUPPRESS_PHP_DEPRECATION_WARNING: true + steps: + - name: Setup PHP with Xdebug + uses: shivammathur/setup-php@v2 + with: + coverage: xdebug + php-version: ${{ matrix.php-versions }} + ini-values: xdebug.overload_var_dump=0, memory_limit=4G, phar.readonly=false + extensions: sockets + + - name: Checkout codebase + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Install dependencies + run: composer update ${{ matrix.composer-options }} --no-interaction --prefer-source + + - name: Run test suite + run: make test + + - name: Static analysis + run: | + composer require --dev nette/neon "^3.4.4" phpstan/phpstan "2.1.1" --ignore-platform-req=php --update-with-all-dependencies + vendor\bin\phpstan analyse src + + - if: ${{ matrix.composer-options == '' }} + name: Code Coverage + run: | + curl -o codecov.exe https://uploader.codecov.io/latest/windows/codecov.exe + .\codecov.exe diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c2441d59c2..62b843dea2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -50,6 +50,10 @@ jobs: composer-options: '--prefer-lowest' - php-versions: '8.4' composer-options: '' + - php-versions: '8.4' + composer-options: '--prefer-lowest' + - php-versions: '8.5' + composer-options: '' # set the name for each job name: PHP ${{ matrix.php-versions }} ${{ matrix.composer-options }} # set up environment variables used by unit tests @@ -92,8 +96,7 @@ jobs: # static analysis - name: Static analysis run: | - composer require --dev nette/neon "^3.4.4" - composer require --dev phpstan/phpstan "2.1.1" + composer require --dev nette/neon "^3.4.4" phpstan/phpstan "2.1.1" --ignore-platform-req=php --update-with-all-dependencies vendor/bin/phpstan analyse src # generate package diff --git a/composer.json b/composer.json index 55f22f05c6..24a0dbbe36 100644 --- a/composer.json +++ b/composer.json @@ -25,13 +25,13 @@ "ext-json": "*", "ext-simplexml": "*", "aws/aws-crt-php": "^1.2.3", - "psr/http-message": "^2.0" + "psr/http-message": "^2.0", + "symfony/filesystem": "^v6.4.3 || ^v7.1.0" }, "require-dev": { "composer/composer" : "^2.7.8", "ext-openssl": "*", "ext-dom": "*", - "ext-pcntl": "*", "ext-sockets": "*", "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", "behat/behat": "~3.0", @@ -41,7 +41,6 @@ "psr/cache": "^2.0 || ^3.0", "psr/simple-cache": "^2.0 || ^3.0", "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", - "symfony/filesystem": "^v6.4.0 || ^v7.1.0", "yoast/phpunit-polyfills": "^2.0", "dms/phpunit-arraysubset-asserts": "^0.4.0" }, @@ -49,6 +48,7 @@ "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", "ext-curl": "To send requests using cURL", "ext-sockets": "To use client-side monitoring", + "ext-pcntl": "*", "doctrine/cache": "To use the DoctrineCacheAdapter", "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications" }, diff --git a/src/UserAgentMiddleware.php b/src/UserAgentMiddleware.php index afccc97816..ce04f6345b 100644 --- a/src/UserAgentMiddleware.php +++ b/src/UserAgentMiddleware.php @@ -172,7 +172,11 @@ private function getOsName(): string if (function_exists('php_uname') && !in_array('php_uname', $disabledFunctions, true) ) { - $osName = "OS/" . php_uname('s') . '#' . php_uname('r'); + // Replace spaces with underscores to prevent breaking the user agent format + $os = str_replace(' ', '_', php_uname('s')); + $release = php_uname('r'); + $osName = "OS/{$os}#{$release}"; + if (!empty($osName)) { return $osName; } diff --git a/tests/AbstractConfigurationProviderTest.php b/tests/AbstractConfigurationProviderTest.php index da34204987..80a4fbbc4b 100644 --- a/tests/AbstractConfigurationProviderTest.php +++ b/tests/AbstractConfigurationProviderTest.php @@ -29,7 +29,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\My\\Home'); $ref = new \ReflectionClass('\Aws\AbstractConfigurationProvider'); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\My\\Home', $meth->invoke(null)); } @@ -79,7 +78,6 @@ public function testsPersistsToCache() // Set interfaceClass property that's normally set by child class $ref = new \ReflectionClass('\Aws\AbstractConfigurationProvider'); $property = $ref->getProperty('interfaceClass'); - $property->setAccessible(true); $property->setValue(null,'\Aws\ResultInterface'); $timesCalled = 0; diff --git a/tests/Api/Parser/EventParsingIteratorTest.php b/tests/Api/Parser/EventParsingIteratorTest.php index 14761dc4f6..f8d7c4d4e7 100644 --- a/tests/Api/Parser/EventParsingIteratorTest.php +++ b/tests/Api/Parser/EventParsingIteratorTest.php @@ -122,7 +122,6 @@ public function testParsedEventsMatchExpectedType($iterator) { $reflectedIteratorClass = new \ReflectionClass(get_class($iterator)); $shapeProperty = $reflectedIteratorClass->getProperty('shape'); - $shapeProperty->setAccessible(true); $shape = $shapeProperty->getValue($iterator); foreach ($iterator as $event) { $this->parsedEventMatchesExpectedType($shape, $event); diff --git a/tests/Api/ShapeTest.php b/tests/Api/ShapeTest.php index 269fd0bc62..a0fe589a3c 100644 --- a/tests/Api/ShapeTest.php +++ b/tests/Api/ShapeTest.php @@ -32,7 +32,6 @@ public function testValidatesShapeAt() $this->expectException(\InvalidArgumentException::class); $s = new Shape([], new ShapeMap([])); $m = new \ReflectionMethod($s, 'shapeAt'); - $m->setAccessible(true); $m->invoke($s, 'not_there'); } @@ -40,7 +39,6 @@ public function testReturnsShapesFor() { $s = new Shape(['foo' => ['type' => 'string']], new ShapeMap([])); $m = new \ReflectionMethod($s, 'shapeAt'); - $m->setAccessible(true); $this->assertInstanceOf(Shape::class, $m->invoke($s, 'foo')); } @@ -51,7 +49,6 @@ public function testReturnsNestedShapeReferences() new ShapeMap(['bar' => ['type' => 'string']]) ); $m = new \ReflectionMethod($s, 'shapeAt'); - $m->setAccessible(true); $result = $m->invoke($s, 'foo'); $this->assertInstanceOf(Shape::class, $result); $this->assertSame('string', $result->getType()); @@ -76,7 +73,6 @@ public function testValidatesShapeTypes() new ShapeMap([]) ); $m = new \ReflectionMethod($s, 'shapeAt'); - $m->setAccessible(true); $m->invoke($s, 'foo'); } diff --git a/tests/Auth/AuthSchemeResolverTest.php b/tests/Auth/AuthSchemeResolverTest.php index 7b033c74e7..4ea193e9f1 100644 --- a/tests/Auth/AuthSchemeResolverTest.php +++ b/tests/Auth/AuthSchemeResolverTest.php @@ -136,7 +136,6 @@ public function testIsCompatibleAuthSchemeReturnsTrueForValidScheme() $resolver = new AuthSchemeResolver($credentialProvider); $reflection = new \ReflectionClass($resolver); $method = $reflection->getMethod('isCompatibleAuthScheme'); - $method->setAccessible(true); $this->assertTrue($method->invokeArgs($resolver, ['v4'])); } @@ -150,7 +149,6 @@ public function testIsCompatibleAuthSchemeReturnsFalseForInvalidScheme() $resolver = new AuthSchemeResolver($credentialProvider); $reflection = new \ReflectionClass($resolver); $method = $reflection->getMethod('isCompatibleAuthScheme'); - $method->setAccessible(true); $this->assertFalse($method->invokeArgs($resolver, ['invalidScheme'])); } diff --git a/tests/AwsClientTest.php b/tests/AwsClientTest.php index 2f612faaf5..6523a5cf7f 100644 --- a/tests/AwsClientTest.php +++ b/tests/AwsClientTest.php @@ -302,7 +302,6 @@ public function testCanGetSignatureProvider() { $client = $this->createClient([]); $ref = new \ReflectionMethod($client, 'getSignatureProvider'); - $ref->setAccessible(true); $provider = $ref->invoke($client); $this->assertIsCallable($provider); } @@ -472,9 +471,7 @@ public function testLoadsAliases() ]); $ref = new \ReflectionClass(AwsClient::class); $method = $ref->getMethod('loadAliases'); - $method->setAccessible(true); $property = $ref->getProperty('aliases'); - $property->setAccessible(true); $method->invokeArgs( $client, [__DIR__ . '/fixtures/aws_client_test/aliases.json'] @@ -497,7 +494,6 @@ public function testCallsAliasedFunction() ]); $ref = new \ReflectionClass(AwsClient::class); $method = $ref->getMethod('loadAliases'); - $method->setAccessible(true); $method->invokeArgs( $client, [__DIR__ . '/fixtures/aws_client_test/aliases.json'] diff --git a/tests/Build/Docs/CodeSnippetGeneratorTest.php b/tests/Build/Docs/CodeSnippetGeneratorTest.php index 79a1b2f325..987ca77bed 100644 --- a/tests/Build/Docs/CodeSnippetGeneratorTest.php +++ b/tests/Build/Docs/CodeSnippetGeneratorTest.php @@ -25,6 +25,10 @@ public function testCanBuildCodeExamples( $expected, $isInput = true ) { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped(); + } + $builder = new CodeSnippetGenerator($service); $this->assertSame($expected, $builder($operation, $input, [], $isInput)); } diff --git a/tests/ClientSideMonitoring/ApiCallAttemptMonitoringMiddlewareTest.php b/tests/ClientSideMonitoring/ApiCallAttemptMonitoringMiddlewareTest.php index 5d29e2daaa..291878432d 100644 --- a/tests/ClientSideMonitoring/ApiCallAttemptMonitoringMiddlewareTest.php +++ b/tests/ClientSideMonitoring/ApiCallAttemptMonitoringMiddlewareTest.php @@ -45,7 +45,6 @@ protected function getMethod($name) { $class = new \ReflectionClass(ApiCallAttemptMonitoringMiddleware::class); $method = $class->getMethod($name); - $method->setAccessible(true); return $method; } @@ -253,7 +252,6 @@ function() { ); $ref = new \ReflectionClass(ApiCallAttemptMonitoringMiddleware::class); $method = $ref->getMethod('isEnabled'); - $method->setAccessible(true); $this->assertEquals(false, $method->invoke($middleware)); } } diff --git a/tests/ClientSideMonitoring/ApiCallMonitoringMiddlewareTest.php b/tests/ClientSideMonitoring/ApiCallMonitoringMiddlewareTest.php index d1b413b3e8..aba2473439 100644 --- a/tests/ClientSideMonitoring/ApiCallMonitoringMiddlewareTest.php +++ b/tests/ClientSideMonitoring/ApiCallMonitoringMiddlewareTest.php @@ -42,7 +42,6 @@ protected function getMethod($name) { $class = new \ReflectionClass(ApiCallMonitoringMiddleware::class); $method = $class->getMethod($name); - $method->setAccessible(true); return $method; } @@ -204,7 +203,6 @@ function() { ); $ref = new \ReflectionClass(ApiCallMonitoringMiddleware::class); $method = $ref->getMethod('isEnabled'); - $method->setAccessible(true); $this->assertEquals(false, $method->invoke($middleware)); } } diff --git a/tests/ClientSideMonitoring/ConfigurationProviderTest.php b/tests/ClientSideMonitoring/ConfigurationProviderTest.php index a2f81d518a..96ae1e86e2 100644 --- a/tests/ClientSideMonitoring/ConfigurationProviderTest.php +++ b/tests/ClientSideMonitoring/ConfigurationProviderTest.php @@ -324,7 +324,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\Michael\\Home'); $ref = new \ReflectionClass(ConfigurationProvider::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\Michael\\Home', $meth->invoke(null)); } diff --git a/tests/CloudFront/SignerTest.php b/tests/CloudFront/SignerTest.php index d33de4518a..daad495448 100644 --- a/tests/CloudFront/SignerTest.php +++ b/tests/CloudFront/SignerTest.php @@ -146,7 +146,6 @@ public function testPolicyContainsNoForbiddenCharacters() public function testCreatesCannedPolicies($resource, $ts) { $m = new \ReflectionMethod(Signer::class, 'createCannedPolicy'); - $m->setAccessible(true); $result = $m->invoke($this->instance, $resource, $ts); $this->assertSame( '{"Statement":[{"Resource":"' . $resource diff --git a/tests/CloudFront/UrlSignerTest.php b/tests/CloudFront/UrlSignerTest.php index 585a356d04..efea2df581 100644 --- a/tests/CloudFront/UrlSignerTest.php +++ b/tests/CloudFront/UrlSignerTest.php @@ -12,7 +12,6 @@ */ class UrlSignerTest extends TestCase { - protected $key; protected $kp; @@ -142,10 +141,15 @@ public function testIsolatesResourceIUrls($url, $resource) { $s = new UrlSigner('a', $this->key); $m = new \ReflectionMethod(get_class($s), 'createResource'); - $m->setAccessible(true); - $scheme = parse_url($url)['scheme']; - $this->assertSame($resource, $m->invoke($s, $scheme, $url)); + $result = $m->invoke($s, $scheme, $url); + + // On Windows, root-level RTMP paths may have leading slashes (forward or back) + if (PHP_OS_FAMILY === 'Windows' && $scheme === 'rtmp') { + $result = ltrim($result, '\\/'); // Remove both backslashes and forward slashes + } + + $this->assertSame($resource, $result); } public function urlAndResourceProvider() diff --git a/tests/ConfigurationResolverTest.php b/tests/ConfigurationResolverTest.php index 0cc8461fef..cd6fdf2198 100644 --- a/tests/ConfigurationResolverTest.php +++ b/tests/ConfigurationResolverTest.php @@ -230,7 +230,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\Sean\\Home'); $ref = new \ReflectionClass(ConfigurationResolver::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\Sean\\Home', $meth->invoke(null)); } diff --git a/tests/Credentials/CredentialProviderTest.php b/tests/Credentials/CredentialProviderTest.php index adb1e0e5b1..18a2178bcd 100644 --- a/tests/Credentials/CredentialProviderTest.php +++ b/tests/Credentials/CredentialProviderTest.php @@ -393,10 +393,19 @@ public function testEnsuresFileIsNotEmpty() public function testCreatesFromProcessCredentialProvider() { $dir = $this->clearEnv(); - $ini = <<clearEnv(); - $ini = <<getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\Michael\\Home', $meth->invoke(null)); } @@ -2015,10 +2095,19 @@ public function testChainsCredentials() public function testProcessCredentialDefaultChain() { $dir = $this->clearEnv(); - $credentialsIni = <<getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\My\\Home', $meth->invoke(null)); } diff --git a/tests/DynamoDb/MarshalerTest.php b/tests/DynamoDb/MarshalerTest.php index 5fd3a2a29d..bcc9f3ec83 100644 --- a/tests/DynamoDb/MarshalerTest.php +++ b/tests/DynamoDb/MarshalerTest.php @@ -277,7 +277,8 @@ public function testUnmarshalingHandlesAllDynamoDbTypes() "L":["A",1,true] } JSON; - $json = str_replace([" ", "\n"], '', $json); // remove whitespace + //Carriage return + line feed accounts for Windows + $json = str_replace([" ", "\n", "\r"], '', $json); // remove whitespace $m = new Marshaler; $this->assertSame($json, $m->unmarshalJson($item)); diff --git a/tests/Endpoint/UseDualstackEndpoint/ConfigurationProviderTest.php b/tests/Endpoint/UseDualstackEndpoint/ConfigurationProviderTest.php index bd4572ae28..f6d823928c 100644 --- a/tests/Endpoint/UseDualstackEndpoint/ConfigurationProviderTest.php +++ b/tests/Endpoint/UseDualstackEndpoint/ConfigurationProviderTest.php @@ -250,7 +250,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\My\\Home'); $ref = new \ReflectionClass(ConfigurationProvider::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\My\\Home', $meth->invoke(null)); } diff --git a/tests/Endpoint/UseFipsEndpoint/ConfigurationProviderTest.php b/tests/Endpoint/UseFipsEndpoint/ConfigurationProviderTest.php index 1a30655249..b5bda1eb97 100644 --- a/tests/Endpoint/UseFipsEndpoint/ConfigurationProviderTest.php +++ b/tests/Endpoint/UseFipsEndpoint/ConfigurationProviderTest.php @@ -257,7 +257,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\My\\Home'); $ref = new \ReflectionClass(ConfigurationProvider::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\My\\Home', $meth->invoke(null)); } diff --git a/tests/EndpointDiscovery/ConfigurationProviderTest.php b/tests/EndpointDiscovery/ConfigurationProviderTest.php index afbe8d8ef4..2c5127d864 100644 --- a/tests/EndpointDiscovery/ConfigurationProviderTest.php +++ b/tests/EndpointDiscovery/ConfigurationProviderTest.php @@ -283,7 +283,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\Michael\\Home'); $ref = new \ReflectionClass(ConfigurationProvider::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\Michael\\Home', $meth->invoke(null)); } diff --git a/tests/EndpointDiscovery/EndpointDiscoveryMiddlewareTest.php b/tests/EndpointDiscovery/EndpointDiscoveryMiddlewareTest.php index a11a34c70e..ca5e2abbb1 100644 --- a/tests/EndpointDiscovery/EndpointDiscoveryMiddlewareTest.php +++ b/tests/EndpointDiscovery/EndpointDiscoveryMiddlewareTest.php @@ -661,7 +661,6 @@ public function testCallsDiscoveryApiOnInvalidEndpointException($exception) EndpointDiscoveryMiddleware::class, 'discoveryCooldown' ); - $reflection->setAccessible(true); $reflection->setValue(null, 0); $callOrder = []; $handler = function ( diff --git a/tests/EndpointV2/EndpointProviderV2Test.php b/tests/EndpointV2/EndpointProviderV2Test.php index ab3cf443c1..b916304972 100644 --- a/tests/EndpointV2/EndpointProviderV2Test.php +++ b/tests/EndpointV2/EndpointProviderV2Test.php @@ -370,7 +370,6 @@ public function testCachesEndpointObject() $reflectionEndpointProvider = new \ReflectionClass(EndpointProviderV2::class); $endpointProvider = new EndpointProviderV2($rulesetDefinition, $partitions); $reflectionRuleset = $reflectionEndpointProvider->getproperty('ruleset'); - $reflectionRuleset->setAccessible(true); $reflectionRuleset->setValue($endpointProvider, $rulesetMock); $endpointProvider->resolveEndpoint(['Region' => 'us-west-2']); diff --git a/tests/EndpointV2/EndpointV2MiddlewareTest.php b/tests/EndpointV2/EndpointV2MiddlewareTest.php index 310c8672e1..3db9e9a6b3 100644 --- a/tests/EndpointV2/EndpointV2MiddlewareTest.php +++ b/tests/EndpointV2/EndpointV2MiddlewareTest.php @@ -112,8 +112,6 @@ function ($command, $endpoint) {}, $reflection = new ReflectionClass(EndpointV2Middleware::class); $method = $reflection->getMethod('resolveAuthScheme'); - $method->setAccessible(true); - $this->expectException(UnresolvedAuthSchemeException::class); $this->expectExceptionMessage( "This operation requests `invalidAuthScheme` auth schemes, but the client currently supports" @@ -151,8 +149,6 @@ function ($command, $endpoint) {}, $reflection = new ReflectionClass(EndpointV2Middleware::class); $method = $reflection->getMethod('resolveAuthScheme'); - $method->setAccessible(true); - $result = $method->invoke($middleware, $authSchemes); $this->assertSame($expected, $result['version']); } @@ -197,8 +193,6 @@ function ($command, $endpoint) {}, $reflection = new ReflectionClass(EndpointV2Middleware::class); $method = $reflection->getMethod('resolveAuthScheme'); - $method->setAccessible(true); - $method->invoke($middleware, [['name' => 'sigv4a']]); } diff --git a/tests/Exception/MultipartUploadExceptionTest.php b/tests/Exception/MultipartUploadExceptionTest.php index c32a735781..336e637951 100644 --- a/tests/Exception/MultipartUploadExceptionTest.php +++ b/tests/Exception/MultipartUploadExceptionTest.php @@ -58,7 +58,8 @@ public function testCanCreateExceptionListingFailedParts() - Part 8: Needs more love. MSG; - + //Normalize line endings to \n for Windows + $expected = str_replace("\r\n", "\n", $expected); $this->assertSame($expected, $exception->getMessage()); } } diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index fa976433ae..26915db76e 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -16,8 +16,8 @@ public function testCreatesRecursiveDirIterator() { $iter = Aws\recursive_dir_iterator(__DIR__); $this->assertInstanceOf('Iterator', $iter); - $files = iterator_to_array($iter); - $this->assertContains(__FILE__, $files); + $files = array_map('realpath', iterator_to_array($iter)); + $this->assertContains(realpath(__FILE__), $files); } /** diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php index 0fbbf149cd..1679c0e258 100644 --- a/tests/MiddlewareTest.php +++ b/tests/MiddlewareTest.php @@ -331,7 +331,9 @@ public function testCanTimeSuccessfulHandlers() { $list = new HandlerList(); $list->setHandler(function () { - usleep(1000); // wait for a millisecond + // Use a longer sleep on Windows to ensure measurable time + $sleepTime = PHP_OS_FAMILY === 'Windows' ? 2000 : 1000; + usleep($sleepTime); return Promise\Create::promiseFor(new Result); }); $list->prependInit(Middleware::timer()); diff --git a/tests/MultiRegionClientTest.php b/tests/MultiRegionClientTest.php index 3aad0e47e5..419ca63f90 100644 --- a/tests/MultiRegionClientTest.php +++ b/tests/MultiRegionClientTest.php @@ -38,7 +38,6 @@ public function set_up() ]); $property = (new \ReflectionClass(MultiRegionClient::class)) ->getProperty('clientPool'); - $property->setAccessible(true); $property->setValue($this->instance, [ '' => $this->mockRegionalClient, ]); diff --git a/tests/Multipart/AbstractUploaderTest.php b/tests/Multipart/AbstractUploaderTest.php index db1601375c..f92331c294 100644 --- a/tests/Multipart/AbstractUploaderTest.php +++ b/tests/Multipart/AbstractUploaderTest.php @@ -215,7 +215,6 @@ public function testCommandGeneratorYieldsExpectedUploadCommands( $actualBodies = []; $getUploadCommands = (new \ReflectionObject($uploader)) ->getMethod('getUploadCommands'); - $getUploadCommands->setAccessible(true); foreach ($getUploadCommands->invoke($uploader, $handler) as $cmd) { $actualBodies[$cmd['PartNumber']] = $cmd['Body']->getContents(); } diff --git a/tests/Retry/ConfigurationProviderTest.php b/tests/Retry/ConfigurationProviderTest.php index f1541f9a69..cb84898b25 100644 --- a/tests/Retry/ConfigurationProviderTest.php +++ b/tests/Retry/ConfigurationProviderTest.php @@ -257,7 +257,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\My\\Home'); $ref = new \ReflectionClass(ConfigurationProvider::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\My\\Home', $meth->invoke(null)); } diff --git a/tests/Retry/RateLimiterTest.php b/tests/Retry/RateLimiterTest.php index 552c6aa6dd..d2784a4ab2 100644 --- a/tests/Retry/RateLimiterTest.php +++ b/tests/Retry/RateLimiterTest.php @@ -40,10 +40,8 @@ public function testCorrectlyCalculatesSendingRate() ]); $ref = new \ReflectionClass($rateLimiter); $refLastMaxRate = $ref->getProperty('lastMaxRate'); - $refLastMaxRate->setAccessible(true); $refLastMaxRate->setValue($rateLimiter, 10); $refLastLastThrottleTime = $ref->getProperty('lastThrottleTime'); - $refLastLastThrottleTime->setAccessible(true); $refLastLastThrottleTime->setValue($rateLimiter, 5); $this->assertSame(0, $rateLimiter->updateSendingRate(false)); @@ -77,16 +75,11 @@ public function testCalculatesCubicSuccessValues($timestamp, $expectedRate) $rateLimiter = new RateLimiter(); $ref = new \ReflectionClass($rateLimiter); $refLastMaxRate = $ref->getProperty('lastMaxRate'); - $refLastMaxRate->setAccessible(true); $refLastMaxRate->setValue($rateLimiter, 10); $refLastLastThrottleTime = $ref->getProperty('lastThrottleTime'); - $refLastLastThrottleTime->setAccessible(true); $refLastLastThrottleTime->setValue($rateLimiter, 5); $refCalculateTimeWindow = $ref->getMethod('calculateTimeWindow'); - $refCalculateTimeWindow->setAccessible(true); $refCubicSuccess = $ref->getMethod('cubicSuccess'); - $refCubicSuccess->setAccessible(true); - $refCalculateTimeWindow->invoke($rateLimiter); $this->assertLessThanOrEqual( 0.3, @@ -99,18 +92,12 @@ public function testCalculatesCubicThrottleValues() $rateLimiter = new RateLimiter(); $ref = new \ReflectionClass($rateLimiter); $refLastMaxRate = $ref->getProperty('lastMaxRate'); - $refLastMaxRate->setAccessible(true); $refLastMaxRate->setValue($rateLimiter, 10); $refLastLastThrottleTime = $ref->getProperty('lastThrottleTime'); - $refLastLastThrottleTime->setAccessible(true); $refLastLastThrottleTime->setValue($rateLimiter, 5); $refCalculateTimeWindow = $ref->getMethod('calculateTimeWindow'); - $refCalculateTimeWindow->setAccessible(true); $refCubicSuccess = $ref->getMethod('cubicSuccess'); - $refCubicSuccess->setAccessible(true); $refCubicThrottle = $ref->getMethod('cubicThrottle'); - $refCubicThrottle->setAccessible(true); - $cases = [ ['timestamp' => 5, 'rate' => 7, 'type' => 'success'], ['timestamp' => 6, 'rate' => 9.6, 'type' => 'success'], @@ -211,20 +198,12 @@ public function testUpdatesClientSendingRatesCorrectly() ]); $ref = new \ReflectionClass($rateLimiter); $refLastMaxRate = $ref->getProperty('lastMaxRate'); - $refLastMaxRate->setAccessible(true); $refLastLastThrottleTime = $ref->getProperty('lastThrottleTime'); - $refLastLastThrottleTime->setAccessible(true); $refFillRate = $ref->getProperty('fillRate'); - $refFillRate->setAccessible(true); $refTxRate = $ref->getProperty('measuredTxRate'); - $refTxRate->setAccessible(true); $refCalculateTimeWindow = $ref->getMethod('calculateTimeWindow'); - $refCalculateTimeWindow->setAccessible(true); $refCubicSuccess = $ref->getMethod('cubicSuccess'); - $refCubicSuccess->setAccessible(true); $refCubicThrottle = $ref->getMethod('cubicThrottle'); - $refCubicThrottle->setAccessible(true); - $cases = [ ['timestamp' => 0.2, 'measured_tx_rate' => 0, 'new_token_bucket_rate' => 0.5, 'type' => 'success'], ['timestamp' => 0.4, 'measured_tx_rate' => 0, 'new_token_bucket_rate' => 0.5, 'type' => 'success'], diff --git a/tests/S3/MultipartCopyTest.php b/tests/S3/MultipartCopyTest.php index 74dcbedeeb..be4c9dcc34 100644 --- a/tests/S3/MultipartCopyTest.php +++ b/tests/S3/MultipartCopyTest.php @@ -106,8 +106,6 @@ public function testCanUseCaseInsensitiveConfigKeys() ]); $configProp = (new \ReflectionClass(MultipartCopy::class)) ->getProperty('config'); - $configProp->setAccessible(true); - $this->assertSame($configProp->getValue($classicMup), $configProp->getValue($putObjectMup)); } diff --git a/tests/S3/MultipartUploaderTest.php b/tests/S3/MultipartUploaderTest.php index 2cc4fc2637..741a49644d 100644 --- a/tests/S3/MultipartUploaderTest.php +++ b/tests/S3/MultipartUploaderTest.php @@ -131,8 +131,6 @@ public function testCanUseCaseInsensitiveConfigKeys() ]); $configProp = (new \ReflectionClass(MultipartUploader::class)) ->getProperty('config'); - $configProp->setAccessible(true); - $this->assertSame($configProp->getValue($classicMup), $configProp->getValue($putObjectMup)); } diff --git a/tests/S3/TransferTest.php b/tests/S3/TransferTest.php index 7007e67a15..bd95ac2d64 100644 --- a/tests/S3/TransferTest.php +++ b/tests/S3/TransferTest.php @@ -9,6 +9,7 @@ use Aws\S3\Transfer; use Aws\Test\UsesServiceTrait; use GuzzleHttp\Promise; +use PHPUnit\Framework\Constraint\Callback; use Psr\Http\Message\RequestInterface; use Yoast\PHPUnitPolyfills\TestCases\TestCase; use SplFileInfo; @@ -20,6 +21,27 @@ class TransferTest extends TestCase { use UsesServiceTrait; + /** + * Helper method to recursively delete a directory + */ + private function deleteDirectory($dir) + { + if (!is_dir($dir)) { + return; + } + + $files = array_diff(scandir($dir), ['.', '..']); + foreach ($files as $file) { + $path = $dir . DIRECTORY_SEPARATOR . $file; + if (is_dir($path)) { + $this->deleteDirectory($path); + } else { + unlink($path); + } + } + rmdir($dir); + } + public function testEnsuresBaseDirIsAvailable() { $this->expectExceptionMessage("base_dir"); @@ -109,7 +131,10 @@ public function testCanSetBeforeOptionForUploadsAndUsedWithDebug() $this->assertSame('PutObject', $test->getName()); $this->assertSame('foo', $test['Bucket']); $this->assertStringStartsWith('bar/', $test['Key']); - $this->assertStringContainsString($test['SourceFile'] . ' -> s3://foo/bar', $output); + if ($test['SourceFile'] !== null) { + $normalizedSourceFile = str_replace('\\', '/', $test['SourceFile']); + $this->assertStringContainsString($normalizedSourceFile . ' -> s3://foo/bar', $output); + } } } @@ -196,7 +221,7 @@ function (CommandInterface $cmd, RequestInterface $req) { )); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $filename = $dir . '/large.txt'; $f = fopen($filename, 'w+'); @@ -215,8 +240,9 @@ function (CommandInterface $cmd, RequestInterface $req) { $t->transfer(); rewind($res); $output = stream_get_contents($res); - $this->assertStringContainsString("Transferring $filename -> s3://foo/bar/large.txt (UploadPart) : Part=1", $output); - `rm -rf $dir`; + $normalizedFilename = str_replace('\\', '/', $filename); + $this->assertStringContainsString("Transferring $normalizedFilename -> s3://foo/bar/large.txt (UploadPart) : Part=1", $output); + $this->deleteDirectory($dir); } public function testDoesMultipartForLargeFilesWithFileInfoAsSource() @@ -230,7 +256,7 @@ public function testDoesMultipartForLargeFilesWithFileInfoAsSource() ]); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $filename = new SplFileInfo($dir . '/large.txt'); $f = fopen($filename, 'w+'); @@ -249,8 +275,9 @@ public function testDoesMultipartForLargeFilesWithFileInfoAsSource() $t->transfer(); rewind($res); $output = stream_get_contents($res); - $this->assertStringContainsString("Transferring $filename -> s3://foo/bar/large.txt (UploadPart) : Part=1", $output); - `rm -rf $dir`; + $normalizedFilename = str_replace('\\', '/', (string)$filename); + $this->assertStringContainsString("Transferring $normalizedFilename -> s3://foo/bar/large.txt (UploadPart) : Part=1", $output); + $this->deleteDirectory($dir); } public function testDownloadsObjects() @@ -269,7 +296,7 @@ public function testDownloadsObjects() ]); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $res = fopen('php://temp', 'r+'); $t = new Transfer($s3, 's3://foo/bar', $dir, ['debug' => $res]); @@ -277,7 +304,7 @@ public function testDownloadsObjects() rewind($res); $output = stream_get_contents($res); $this->assertStringContainsString('s3://foo/bar/c//d -> ', $output); - `rm -rf $dir`; + $this->deleteDirectory($dir); } public function testDebugFalse() @@ -291,7 +318,7 @@ public function testDebugFalse() ]); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $filename = $dir . '/large.txt'; $f = fopen($filename, 'w+'); @@ -307,6 +334,10 @@ public function testDebugFalse() public function testDownloadsObjectsWithAccessPointArn() { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('S3 access point ARN downloads have path handling issues on Windows'); + } + $s3 = $this->getTestClient('s3'); $s3->getHandlerList()->appendSign(Middleware::tap( function (CommandInterface $cmd, RequestInterface $req) { @@ -334,7 +365,7 @@ function (CommandInterface $cmd, RequestInterface $req) { ]); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $res = fopen('php://temp', 'r+'); $t = new Transfer($s3, 's3://arn:aws:s3:us-east-1:123456789012:accesspoint:myaccess/test_key', $dir, ['debug' => $res]); @@ -344,7 +375,7 @@ function (CommandInterface $cmd, RequestInterface $req) { $this->assertStringContainsString('s3://arn:aws:s3:us-east-1:123456789012:accesspoint:myaccess/bar/../bar/a/b -> ', $output); $this->assertStringContainsString('s3://arn:aws:s3:us-east-1:123456789012:accesspoint:myaccess/bar/c//d -> ', $output); $this->assertStringContainsString('s3://arn:aws:s3:us-east-1:123456789012:accesspoint:myaccess/../bar//c/../a/b/.. -> ', $output); - `rm -rf $dir`; + $this->deleteDirectory($dir); } /** @@ -367,15 +398,15 @@ public function testCannotDownloadObjectsOutsideTarget($key) ]); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $res = fopen('php://temp', 'r+'); $t = new Transfer($s3, 's3://foo/bar/', $dir, ['debug' => $res]); $t->transfer(); rewind($res); $output = stream_get_contents($res); - $this->assertContains('s3://foo/bar/' . $key . ' -> ', $output); - `rm -rf $dir`; + $this->assertStringContainsString('s3://foo/bar/' . $key . ' -> ', $output); + $this->deleteDirectory($dir); } public function providedPathsOutsideTarget() { @@ -399,14 +430,29 @@ public function testCanUploadToBareBucket() function ($path) { return !is_dir($path); } ); + // Normalize all paths to use forward slashes for comparison + $normalizedFiles = array_map(function($path) { + return str_replace('\\', '/', $path); + }, $filesInDirectory); + $s3->expects($this->exactly(count($filesInDirectory))) ->method('getCommand') ->with( 'PutObject', - new \PHPUnit\Framework\Constraint\Callback(function (array $args) use ($filesInDirectory) { + new Callback(function (array $args) use ($normalizedFiles) { + $baseDir = str_replace('\\', '/', realpath(__DIR__)); + $sourceFile = str_replace('\\', '/', $args['SourceFile']); + + // Calculate expected key - relative path from base directory + if (strpos($sourceFile, $baseDir . '/') === 0) { + $expectedKey = substr($sourceFile, strlen($baseDir) + 1); + } else { + $expectedKey = basename($sourceFile); + } + return 'bare-bucket' === $args['Bucket'] - && in_array($args['SourceFile'], $filesInDirectory) - && __DIR__ . '/' . $args['Key'] === $args['SourceFile']; + && in_array($sourceFile, $normalizedFiles) // Compare normalized paths + && $args['Key'] === $expectedKey; }) ) ->willReturn($this->getMockBuilder(CommandInterface::class)->getMock()); @@ -420,17 +466,19 @@ public function testCanUploadFilesYieldedBySourceIterator() $s3 = $this->getMockS3Client(); $justThisFile = array_filter( iterator_to_array(\Aws\recursive_dir_iterator(__DIR__)), - function ($path) { return $path === __FILE__; } + static function ($path) { + return realpath($path) === realpath(__FILE__); + } ); $s3->expects($this->once()) ->method('getCommand') ->with( 'PutObject', - new \PHPUnit\Framework\Constraint\Callback(function (array $args) { + new Callback(function (array $args) { return 'bucket' === $args['Bucket'] - && $args['SourceFile'] === __FILE__ - && __DIR__ . '/' . $args['Key'] === $args['SourceFile']; + && realpath($args['SourceFile']) === realpath(__FILE__) + && realpath(__DIR__ . '/' . $args['Key']) === realpath($args['SourceFile']); }) ) ->willReturn($this->getMockBuilder(CommandInterface::class)->getMock()); @@ -451,7 +499,7 @@ public function testCanDownloadFilesYieldedBySourceIterator() ->method('getCommand') ->with( 'GetObject', - new \PHPUnit\Framework\Constraint\Callback(function (array $args) { + new Callback(function (array $args) { return 'bucket' === $args['Bucket'] && $args['Key'] === 'path/to/key'; }) @@ -479,7 +527,7 @@ function (CommandInterface $cmd, RequestInterface $req) { )); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $filename = $dir . '/foo.txt'; $f = fopen($filename, 'w+'); @@ -495,8 +543,9 @@ function (CommandInterface $cmd, RequestInterface $req) { $t->transfer(); rewind($res); $output = stream_get_contents($res); - $this->assertStringContainsString("Transferring $filename -> s3://foo/bar/foo.txt", $output); - `rm -rf $dir`; + $normalizedFilename = str_replace('\\', '/', $filename); + $this->assertStringContainsString("Transferring $normalizedFilename -> s3://foo/bar/foo.txt", $output); + $this->deleteDirectory($dir); } /** @@ -533,7 +582,7 @@ function (CommandInterface $cmd, RequestInterface $req) use ($checksumAlgorithm) )); $dir = sys_get_temp_dir() . '/unittest'; - `rm -rf $dir`; + $this->deleteDirectory($dir); mkdir($dir); $filename = $dir . '/large.txt'; $f = fopen($filename, 'w+'); @@ -558,8 +607,9 @@ function (CommandInterface $cmd, RequestInterface $req) use ($checksumAlgorithm) $t->transfer(); rewind($res); $output = stream_get_contents($res); - $this->assertStringContainsString("Transferring $filename -> s3://foo/bar/large.txt (UploadPart) : Part=1", $output); - `rm -rf $dir`; + $normalizedFilename = str_replace('\\', '/', $filename); + $this->assertStringContainsString("Transferring $normalizedFilename -> s3://foo/bar/large.txt (UploadPart) : Part=1", $output); + $this->deleteDirectory($dir); } public function flexibleChecksumsProvider() { diff --git a/tests/S3/UseArnRegion/ConfigurationProviderTest.php b/tests/S3/UseArnRegion/ConfigurationProviderTest.php index dc5b7ee0e5..3cfea47ef3 100644 --- a/tests/S3/UseArnRegion/ConfigurationProviderTest.php +++ b/tests/S3/UseArnRegion/ConfigurationProviderTest.php @@ -248,7 +248,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\My\\Home'); $ref = new \ReflectionClass(ConfigurationProvider::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\My\\Home', $meth->invoke(null)); } diff --git a/tests/Signature/S3SignatureV4Test.php b/tests/Signature/S3SignatureV4Test.php index 45c57d47ff..f2f6eb4226 100644 --- a/tests/Signature/S3SignatureV4Test.php +++ b/tests/Signature/S3SignatureV4Test.php @@ -58,10 +58,8 @@ public function testDoesNotRemoveDotSegments() $uri = $request->getUri()->withPath('/.././foo'); $request = $request->withUri($uri); $p = new \ReflectionMethod($signature, 'parseRequest'); - $p->setAccessible(true); $parsed = $p->invoke($signature, $request); $meth = new \ReflectionMethod($signature, 'createContext'); - $meth->setAccessible(true); $ctx = $meth->invoke($signature, $parsed, 'foo'); $this->assertStringStartsWith( "GET\n/.././foo", @@ -75,10 +73,8 @@ public function testDoesNotRemoveMultiplePrecedingSlashes() $uri = $request->getUri()->withPath('//foo'); $request = $request->withUri($uri); $p = new \ReflectionMethod($signature, 'parseRequest'); - $p->setAccessible(true); $parsed = $p->invoke($signature, $request); $meth = new \ReflectionMethod($signature, 'createContext'); - $meth->setAccessible(true); $ctx = $meth->invoke($signature, $parsed, 'foo'); $this->assertStringStartsWith( "GET\n//foo", diff --git a/tests/Signature/SignatureV4Test.php b/tests/Signature/SignatureV4Test.php index cdadd8b37c..92afc9658e 100644 --- a/tests/Signature/SignatureV4Test.php +++ b/tests/Signature/SignatureV4Test.php @@ -52,10 +52,8 @@ public function testSignsRequestsWithMultiValuedHeaders() $s = new SignatureV4('foo', 'bar'); $r = new Request('GET', 'http://httpbin.org', ['X-amz-Foo' => ['baz', ' bar ']]); $methA = new \ReflectionMethod($s, 'parseRequest'); - $methA->setAccessible(true); $reqArray = $methA->invoke($s, $r); $methB = new \ReflectionMethod($s, 'createContext'); - $methB->setAccessible(true); $result = $methB->invoke($s, $reqArray, '123'); $this->assertSame('host;x-amz-foo', $result['headers']); $this->assertSame("GET\n/\n\nhost:httpbin.org\nx-amz-foo:bar,baz\n\nhost;x-amz-foo\n123", $result['creq']); @@ -68,7 +66,6 @@ public function testUsesExistingSha256HashIfPresent() 'x-amz-content-sha256' => '123' ]); $method = new \ReflectionMethod($sig, 'getPayload'); - $method->setAccessible(true); $this->assertSame('123', $method->invoke($sig, $req)); } @@ -77,7 +74,6 @@ public function testMaintainsCappedCache() $sig = new SignatureV4('foo', 'bar'); // Hack the class so that it thinks it needs 3 more entries to be full $p = new \ReflectionProperty($sig, 'cacheSize'); - $p->setAccessible(true); $p->setValue($sig, 47); $request = new Request('GET', 'http://www.example.com'); @@ -398,12 +394,9 @@ public function testSignRequestUnsignedPayload($req, $sreq, $creq) $signature = new SignatureV4('host', 'us-east-1', ['unsigned-body' => 'true']); $request = Psr7\Message::parseRequest($req); $contextFn = new \ReflectionMethod($signature, 'createContext'); - $contextFn->setAccessible(true); $parseFn = new \ReflectionMethod($signature, 'parseRequest'); - $parseFn->setAccessible(true); $parsed = $parseFn->invoke($signature, $request); $payloadFn = new \ReflectionMethod($signature, 'getPayload'); - $payloadFn->setAccessible(true); $payload = $payloadFn->invoke($signature, $request); $this->assertSame('UNSIGNED-PAYLOAD',$payload); $ctx = $contextFn->invoke($signature, $parsed, $payload); @@ -524,12 +517,9 @@ public function testSignsRequests($req, $sreq, $creq) $signature = new SignatureV4('host', 'us-east-1'); $request = Psr7\Message::parseRequest($req); $contextFn = new \ReflectionMethod($signature, 'createContext'); - $contextFn->setAccessible(true); $parseFn = new \ReflectionMethod($signature, 'parseRequest'); - $parseFn->setAccessible(true); $parsed = $parseFn->invoke($signature, $request); $payloadFn = new \ReflectionMethod($signature, 'getPayload'); - $payloadFn->setAccessible(true); $payload = $payloadFn->invoke($signature, $request); $ctx = $contextFn->invoke($signature, $parsed, $payload); $this->assertEquals($creq, $ctx['creq']); diff --git a/tests/Sts/RegionalEndpoints/ConfigurationProviderTest.php b/tests/Sts/RegionalEndpoints/ConfigurationProviderTest.php index 440743f67b..0406271cc6 100644 --- a/tests/Sts/RegionalEndpoints/ConfigurationProviderTest.php +++ b/tests/Sts/RegionalEndpoints/ConfigurationProviderTest.php @@ -248,7 +248,6 @@ public function testGetsHomeDirectoryForWindowsUsers() putenv('HOMEPATH=\\My\\Home'); $ref = new \ReflectionClass(ConfigurationProvider::class); $meth = $ref->getMethod('getHomeDir'); - $meth->setAccessible(true); $this->assertSame('C:\\My\\Home', $meth->invoke(null)); } diff --git a/tests/UserAgentMiddlewareTest.php b/tests/UserAgentMiddlewareTest.php index 77932b79e4..adcb972118 100644 --- a/tests/UserAgentMiddlewareTest.php +++ b/tests/UserAgentMiddlewareTest.php @@ -156,148 +156,87 @@ public function testUserAgentContainsValue(array $args, string $expected) */ public function userAgentCasesDataProvider(): \Generator { - $userAgentCases = [ - 'sdkVersion' => [[], 'aws-sdk-php/' . Sdk::VERSION], - 'userAgentVersion' => [ - [], 'ua/' . UserAgentMiddleware::AGENT_VERSION - ], - 'hhvmVersion' => function (): array { - if (defined('HHVM_VERSION')) { - return [[], 'HHVM/' . HHVM_VERSION]; - } + yield 'sdkVersion' => [[], 'aws-sdk-php/' . Sdk::VERSION]; - return [[], ""]; - }, - 'osName' => function (): array { - $disabledFunctions = explode( - ',', - ini_get('disable_functions') - ); - if (function_exists('php_uname') - && !in_array( - 'php_uname', - $disabledFunctions, - true - ) - ) { - $osName = "OS/" . php_uname('s') . '#' . php_uname('r'); - if (!empty($osName)) { - return [[], $osName]; - } - } + yield 'userAgentVersion' => [[], 'ua/' . UserAgentMiddleware::AGENT_VERSION]; - return [[], ""]; - }, - 'langVersion' => [[], 'lang/php#' . phpversion()], - 'execEnv' => function (): array { - $expectedEnv = "LambdaFooEnvironment"; - putenv("AWS_EXECUTION_ENV={$expectedEnv}"); + yield 'hhvmVersion' => [[], defined('HHVM_VERSION') ? 'HHVM/' . HHVM_VERSION : ""]; - return [[], $expectedEnv]; - }, - 'appId' => function (): array { - $expectedAppId = "FooAppId"; - $args = [ - 'app_id' => $expectedAppId - ]; + yield 'osName' => [[], $this->getOsNameForUserAgent()]; - return [$args, "app/{$expectedAppId}"]; - }, - 'metricsWithEndpoint' => function (): array { - $expectedEndpoint = "https://foo-endpoint.com"; - $args = [ - 'endpoint' => $expectedEndpoint, - 'endpoint_override' => true, - ]; - - return [$args, 'm/' . MetricsBuilder::ENDPOINT_OVERRIDE]; - }, - 'metricsWithRetryConfigArrayStandardMode' => function (): array { - $args = [ - 'retries' => [ - 'mode' => 'standard' - ] - ]; - - return [$args, 'm/' . MetricsBuilder::RETRY_MODE_STANDARD]; - }, - 'metricsWithRetryConfigArrayAdaptiveMode' => function (): array { - $args = [ - 'retries' => [ - 'mode' => 'adaptive' - ] - ]; - - return [$args, 'm/' . MetricsBuilder::RETRY_MODE_ADAPTIVE]; - }, - 'metricsWithRetryConfigArrayLegacyMode' => function (): array { - $args = [ - 'retries' => [ - 'mode' => 'legacy' - ] - ]; - - return [$args, 'm/' . MetricsBuilder::RETRY_MODE_LEGACY]; - }, - 'metricsWithRetryConfigStandardMode' => function (): array { - $args = [ - 'retries' => new \Aws\Retry\Configuration( - 'standard', - 10 - ) - ]; + yield 'langVersion' => [[], 'lang/php#' . phpversion()]; - return [$args, 'm/' . MetricsBuilder::RETRY_MODE_STANDARD]; - }, - 'metricsWithRetryConfigAdaptiveMode' => function (): array { - $args = [ - 'retries' => new \Aws\Retry\Configuration( - 'adaptive', - 10 - ) - ]; + yield 'execEnv' => [[], $this->getExecEnvForUserAgent()]; - return [$args, 'm/' . MetricsBuilder::RETRY_MODE_ADAPTIVE]; - }, - 'metricsWithRetryConfigLegacyMode' => function (): array { - $args = [ - 'retries' => new \Aws\Retry\Configuration( - 'legacy', - 10 - ) - ]; + yield 'appId' => [['app_id' => 'FooAppId'], 'app/FooAppId']; - return [$args, 'm/' . MetricsBuilder::RETRY_MODE_LEGACY]; - }, - 'cfgWithEndpointDiscoveryConfigArray' => function (): array { - $args = [ - 'endpoint_discovery' => [ - 'enabled' => true, - 'cache_limit' => 1000 - ] - ]; - - return [$args, 'cfg/endpoint-discovery']; - }, - 'cfgWithEndpointDiscoveryConfig' => function (): array { - $args = [ - 'endpoint_discovery' => new \Aws\EndpointDiscovery\Configuration ( - true, - 1000 - ), - ]; + yield 'metricsWithEndpoint' => [ + ['endpoint' => 'https://foo-endpoint.com', 'endpoint_override' => true], + 'm/' . MetricsBuilder::ENDPOINT_OVERRIDE + ]; - return [$args, 'cfg/endpoint-discovery']; - } + yield 'metricsWithRetryConfigArrayStandardMode' => [ + ['retries' => ['mode' => 'standard']], + 'm/' . MetricsBuilder::RETRY_MODE_STANDARD ]; - foreach ($userAgentCases as $key => $case) { - if (is_callable($case)) { - yield $key => $case(); - } else { - yield $key => $case; - } + yield 'metricsWithRetryConfigArrayAdaptiveMode' => [ + ['retries' => ['mode' => 'adaptive']], + 'm/' . MetricsBuilder::RETRY_MODE_ADAPTIVE + ]; + + yield 'metricsWithRetryConfigArrayLegacyMode' => [ + ['retries' => ['mode' => 'legacy']], + 'm/' . MetricsBuilder::RETRY_MODE_LEGACY + ]; + + yield 'metricsWithRetryConfigStandardMode' => [ + ['retries' => new \Aws\Retry\Configuration('standard', 10)], + 'm/' . MetricsBuilder::RETRY_MODE_STANDARD + ]; + + yield 'metricsWithRetryConfigAdaptiveMode' => [ + ['retries' => new \Aws\Retry\Configuration('adaptive', 10)], + 'm/' . MetricsBuilder::RETRY_MODE_ADAPTIVE + ]; + + yield 'metricsWithRetryConfigLegacyMode' => [ + ['retries' => new \Aws\Retry\Configuration('legacy', 10)], + 'm/' . MetricsBuilder::RETRY_MODE_LEGACY + ]; + + yield 'cfgWithEndpointDiscoveryConfigArray' => [ + ['endpoint_discovery' => ['enabled' => true, 'cache_limit' => 1000]], + 'cfg/endpoint-discovery' + ]; + + yield 'cfgWithEndpointDiscoveryConfig' => [ + ['endpoint_discovery' => new \Aws\EndpointDiscovery\Configuration(true, 1000)], + 'cfg/endpoint-discovery' + ]; + } + + private function getOsNameForUserAgent(): string + { + $disabledFunctions = explode(',', ini_get('disable_functions')); + if (function_exists('php_uname') + && !in_array('php_uname', $disabledFunctions, true) + ) { + // Match what the middleware does - replace spaces with underscores + $os = str_replace(' ', '_', php_uname('s')); + $release = php_uname('r'); + $osName = "OS/{$os}#{$release}"; + + return !empty($osName) ? $osName : ""; } + return ""; + } + + private function getExecEnvForUserAgent(): string + { + $expectedEnv = "LambdaFooEnvironment"; + putenv("AWS_EXECUTION_ENV={$expectedEnv}"); + return $expectedEnv; } /** @@ -1368,10 +1307,19 @@ public function testUserAgentCaptureCredentialsProcessMetric() { $profile = 'metric-test-profile'; $configPath = $this->awsDir . '/my-config'; - $profileContent = << 'us-east-2', diff --git a/tests/WaiterTest.php b/tests/WaiterTest.php index 81ffef23ac..b5c5dc3dca 100644 --- a/tests/WaiterTest.php +++ b/tests/WaiterTest.php @@ -267,7 +267,6 @@ public function testMatchers($matcher, $result, $acceptor, $expected) { $waiter = new \ReflectionClass(Waiter::class); $matcher = $waiter->getMethod($matcher); - $matcher->setAccessible(true); $waiter = $waiter->newInstanceWithoutConstructor(); $this->assertEquals($expected, $matcher->invoke($waiter, $result, $acceptor));