Completed
Push — 2.x ( c89931...bb002c )
by Frank
01:11
created

AwsS3V3AdapterTest::failing_to_write_a_file()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
dl 9
loc 9
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Flysystem\AwsS3V3;
6
7
use Aws\Result;
8
use Aws\S3\S3Client;
9
use Aws\S3\S3ClientInterface;
10
use Exception;
11
use Generator;
12
use League\Flysystem\AdapterTestUtilities\FilesystemAdapterTestCase;
13
use League\Flysystem\Config;
14
use League\Flysystem\FileAttributes;
15
use League\Flysystem\FilesystemAdapter;
16
use League\Flysystem\StorageAttributes;
17
use League\Flysystem\UnableToCheckFileExistence;
18
use League\Flysystem\UnableToDeleteFile;
19
use League\Flysystem\UnableToMoveFile;
20
use League\Flysystem\UnableToRetrieveMetadata;
21
use League\Flysystem\UnableToWriteFile;
22
use RuntimeException;
23
24
/**
25
 * @group aws
26
 */
27
class AwsS3V3AdapterTest extends FilesystemAdapterTestCase
28
{
29
    /**
30
     * @var bool
31
     */
32
    private $shouldCleanUp = false;
33
34
    /**
35
     * @var string
36
     */
37
    private static $adapterPrefix = 'test-prefix';
38
39
    /**
40
     * @var S3ClientInterface|null
41
     */
42
    private static $s3Client;
43
44
    /**
45
     * @var S3ClientStub
46
     */
47
    private static $stubS3Client;
48
49
    public static function setUpBeforeClass(): void
50
    {
51
        static::$adapterPrefix = 'ci/' . bin2hex(random_bytes(10));
0 ignored issues
show
Bug introduced by
Since $adapterPrefix is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $adapterPrefix to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
52
    }
53
54
    protected function tearDown(): void
55
    {
56
        if ( ! $this->shouldCleanUp) {
57
            return;
58
        }
59
60
        $adapter = $this->adapter();
61
        $adapter->deleteDirectory('/');
62
        /** @var StorageAttributes[] $listing */
63
        $listing = $adapter->listContents('', false);
64
65
        foreach ($listing as $item) {
66
            if ($item->isFile()) {
67
                $adapter->delete($item->path());
68
            } else {
69
                $adapter->deleteDirectory($item->path());
70
            }
71
        }
72
73
        self::$adapter = null;
74
    }
75
76
    private static function s3Client(): S3ClientInterface
77
    {
78
        if (static::$s3Client instanceof S3ClientInterface) {
0 ignored issues
show
Bug introduced by
Since $s3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $s3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
79
            return static::$s3Client;
0 ignored issues
show
Bug introduced by
Since $s3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $s3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
80
        }
81
82
        $key = getenv('FLYSYSTEM_AWS_S3_KEY');
83
        $secret = getenv('FLYSYSTEM_AWS_S3_SECRET');
84
        $bucket = getenv('FLYSYSTEM_AWS_S3_BUCKET');
85
        $region = getenv('FLYSYSTEM_AWS_S3_REGION') ?: 'eu-central-1';
86
87
        if ( ! $key || ! $secret || ! $bucket) {
88
            self::markTestSkipped('No AWS credentials present for testing.');
89
        }
90
91
        $options = ['version' => 'latest', 'credentials' => compact('key', 'secret'), 'region' => $region];
92
93
        return static::$s3Client = new S3Client($options);
0 ignored issues
show
Bug introduced by
Since $s3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $s3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
94
    }
95
96
    /**
97
     * @test
98
     */
99
    public function writing_with_a_specific_mime_type(): void
100
    {
101
        $adapter = $this->adapter();
102
        $adapter->write('some/path.txt', 'contents', new Config(['ContentType' => 'text/plain+special']));
103
        $mimeType = $adapter->mimeType('some/path.txt')->mimeType();
104
        $this->assertEquals('text/plain+special', $mimeType);
105
    }
106
107
    /**
108
     * @test
109
     */
110
    public function listing_contents_recursive(): void
111
    {
112
        $adapter = $this->adapter();
113
        $adapter->write('something/0/here.txt', 'contents', new Config());
114
        $adapter->write('something/1/also/here.txt', 'contents', new Config());
115
116
        $contents = iterator_to_array($adapter->listContents('', true));
117
118
        $this->assertCount(2, $contents);
119
        $this->assertContainsOnlyInstancesOf(FileAttributes::class, $contents);
120
        /** @var FileAttributes $file */
121
        $file = $contents[0];
122
        $this->assertEquals('something/0/here.txt', $file->path());
123
        /** @var FileAttributes $file */
124
        $file = $contents[1];
125
        $this->assertEquals('something/1/also/here.txt', $file->path());
126
    }
127
128
    /**
129
     * @test
130
     */
131 View Code Duplication
    public function failing_to_delete_while_moving(): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
    {
133
        $adapter = $this->adapter();
134
        $adapter->write('source.txt', 'contents to be copied', new Config());
135
        static::$stubS3Client->failOnNextCopy();
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
136
137
        $this->expectException(UnableToMoveFile::class);
138
139
        $adapter->move('source.txt', 'destination.txt', new Config());
140
    }
141
142
143
144
    /**
145
     * @test
146
     */
147 View Code Duplication
    public function failing_to_write_a_file(): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
    {
149
        $adapter = $this->adapter();
150
        static::$stubS3Client->throwDuringUpload(new RuntimeException('Oh no'));
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
151
152
        $this->expectException(UnableToWriteFile::class);
153
154
        $adapter->write('path.txt', 'contents', new Config());
155
    }
156
157
    /**
158
     * @test
159
     */
160
    public function failing_to_delete_a_file(): void
161
    {
162
        $adapter = $this->adapter();
163
        static::$stubS3Client->throwExceptionWhenExecutingCommand('DeleteObject');
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
164
165
        $this->expectException(UnableToDeleteFile::class);
166
167
        $adapter->delete('path.txt');
168
    }
169
170
    /**
171
     * @test
172
     */
173
    public function fetching_unknown_mime_type_of_a_file(): void
174
    {
175
        $this->adapter();
176
        $result = new Result([
177
            'Key' => static::$adapterPrefix . '/unknown-mime-type.md5',
0 ignored issues
show
Bug introduced by
Since $adapterPrefix is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $adapterPrefix to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
178
        ]);
179
        static::$stubS3Client->stageResultForCommand('HeadObject', $result);
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
180
181
        parent::fetching_unknown_mime_type_of_a_file();
182
    }
183
184
    /**
185
     * @test
186
     * @dataProvider dpFailingMetadataGetters
187
     */
188
    public function failing_to_retrieve_metadata(Exception $exception, string $getterName): void
189
    {
190
        $adapter = $this->adapter();
191
        $result = new Result([
192
             'Key' => static::$adapterPrefix . '/filename.txt',
0 ignored issues
show
Bug introduced by
Since $adapterPrefix is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $adapterPrefix to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
193
        ]);
194
        static::$stubS3Client->stageResultForCommand('HeadObject', $result);
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
195
196
        $this->expectExceptionObject($exception);
197
198
        $adapter->{$getterName}('filename.txt');
199
    }
200
201
    public function dpFailingMetadataGetters(): iterable
202
    {
203
        yield "mimeType" => [UnableToRetrieveMetadata::mimeType('filename.txt'), 'mimeType'];
204
        yield "lastModified" => [UnableToRetrieveMetadata::lastModified('filename.txt'), 'lastModified'];
205
        yield "fileSize" => [UnableToRetrieveMetadata::fileSize('filename.txt'), 'fileSize'];
206
    }
207
208
    /**
209
     * @test
210
     */
211
    public function failing_to_check_for_file_existence(): void
212
    {
213
        $adapter = $this->adapter();
214
215
        static::$stubS3Client->throw500ExceptionWhenExecutingCommand('HeadObject');
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
216
217
        $this->expectException(UnableToCheckFileExistence::class);
218
219
        $adapter->fileExists('something-that-does-exist.txt');
220
    }
221
222
    /**
223
     * @test
224
     * @dataProvider casesWhereHttpStreamingInfluencesSeekability
225
     */
226
    public function streaming_reads_are_not_seekable_and_non_streaming_are(bool $streaming, bool $seekable): void
227
    {
228
        if (getenv('COMPOSER_OPTS') === '--prefer-lowest') {
229
            $this->markTestSkipped('The SDK does not support streaming in low versions.');
230
        }
231
232
        $adapter = $this->useAdapter($this->createFilesystemAdapter($streaming));
233
        $this->givenWeHaveAnExistingFile('path.txt');
234
235
        $resource = $adapter->readStream('path.txt');
236
        $metadata = stream_get_meta_data($resource);
237
        fclose($resource);
238
239
        $this->assertEquals($seekable, $metadata['seekable']);
240
    }
241
242
    public function casesWhereHttpStreamingInfluencesSeekability(): Generator
243
    {
244
        yield "not streaming reads have seekable stream" => [false, true];
245
        yield "streaming reads have non-seekable stream" => [true, false];
246
    }
247
248
    /**
249
     * @test
250
     * @dataProvider casesWhereHttpStreamingInfluencesSeekability
251
     */
252
    public function configuring_http_streaming_via_options(bool $streaming): void
253
    {
254
        $adapter = $this->useAdapter($this->createFilesystemAdapter($streaming, ['@http' => ['stream' => false]]));
255
        $this->givenWeHaveAnExistingFile('path.txt');
256
257
        $resource = $adapter->readStream('path.txt');
258
        $metadata = stream_get_meta_data($resource);
259
        fclose($resource);
260
261
        $this->assertTrue($metadata['seekable']);
262
    }
263
264
    /**
265
     * @test
266
     */
267
    public function moving_with_updated_metadata(): void
268
    {
269
        $adapter = $this->adapter();
270
        $adapter->write('source.txt', 'contents to be moved', new Config(['ContentType' => 'text/plain']));
271
        $mimeTypeSource = $adapter->mimeType('source.txt')->mimeType();
272
        $this->assertSame('text/plain', $mimeTypeSource);
273
274
        $adapter->move('source.txt', 'destination.txt', new Config(
275
            ['ContentType' => 'text/plain+special', 'MetadataDirective' => 'REPLACE']
276
        ));
277
        $mimeTypeDestination = $adapter->mimeType('destination.txt')->mimeType();
278
        $this->assertSame('text/plain+special', $mimeTypeDestination);
279
    }
280
281
    protected static function createFilesystemAdapter(bool $streaming = true, array $options = []): FilesystemAdapter
282
    {
283
        static::$stubS3Client = new S3ClientStub(static::s3Client());
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
Bug introduced by
Since s3Client() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of s3Client() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
284
        /** @var string $bucket */
285
        $bucket = getenv('FLYSYSTEM_AWS_S3_BUCKET');
286
        $prefix = getenv('FLYSYSTEM_AWS_S3_PREFIX') ?: static::$adapterPrefix;
0 ignored issues
show
Bug introduced by
Since $adapterPrefix is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $adapterPrefix to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
287
288
        return new AwsS3V3Adapter(static::$stubS3Client, $bucket, $prefix, null, null, $options, $streaming);
0 ignored issues
show
Bug introduced by
Since $stubS3Client is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $stubS3Client to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
289
    }
290
}
291