Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/tests-windows.yml
Original file line number Diff line number Diff line change
@@ -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
7 changes: 5 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -41,14 +41,14 @@
"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"
},
"suggest": {
"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": "*",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect syntax. The value is meant to be a reason to the user why the package is needed.

Copy link
Member Author

@stobrien89 stobrien89 Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes- thank you for the reminder. I just copy/pasted into suggest while I was working on the Windows workflows. I had intended to change this, but probably would have forgotten.

"doctrine/cache": "To use the DoctrineCacheAdapter",
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications"
},
Expand Down
6 changes: 5 additions & 1 deletion src/UserAgentMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 0 additions & 2 deletions tests/AbstractConfigurationProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion tests/Api/Parser/EventParsingIteratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 0 additions & 4 deletions tests/Api/ShapeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ 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');
}

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'));
}

Expand All @@ -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());
Expand All @@ -76,7 +73,6 @@ public function testValidatesShapeTypes()
new ShapeMap([])
);
$m = new \ReflectionMethod($s, 'shapeAt');
$m->setAccessible(true);
$m->invoke($s, 'foo');
}

Expand Down
2 changes: 0 additions & 2 deletions tests/Auth/AuthSchemeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']));
}

Expand All @@ -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']));
}

Expand Down
4 changes: 0 additions & 4 deletions tests/AwsClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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']
Expand All @@ -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']
Expand Down
4 changes: 4 additions & 0 deletions tests/Build/Docs/CodeSnippetGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ protected function getMethod($name)
{
$class = new \ReflectionClass(ApiCallAttemptMonitoringMiddleware::class);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}

Expand Down Expand Up @@ -253,7 +252,6 @@ function() {
);
$ref = new \ReflectionClass(ApiCallAttemptMonitoringMiddleware::class);
$method = $ref->getMethod('isEnabled');
$method->setAccessible(true);
$this->assertEquals(false, $method->invoke($middleware));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ protected function getMethod($name)
{
$class = new \ReflectionClass(ApiCallMonitoringMiddleware::class);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}

Expand Down Expand Up @@ -204,7 +203,6 @@ function() {
);
$ref = new \ReflectionClass(ApiCallMonitoringMiddleware::class);
$method = $ref->getMethod('isEnabled');
$method->setAccessible(true);
$this->assertEquals(false, $method->invoke($middleware));
}
}
1 change: 0 additions & 1 deletion tests/ClientSideMonitoring/ConfigurationProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down
1 change: 0 additions & 1 deletion tests/CloudFront/SignerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 8 additions & 4 deletions tests/CloudFront/UrlSignerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
*/
class UrlSignerTest extends TestCase
{

protected $key;
protected $kp;

Expand Down Expand Up @@ -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()
Expand Down
1 change: 0 additions & 1 deletion tests/ConfigurationResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down
Loading
Loading