Skip to content

Commit 7c99d5a

Browse files
author
Travis Sheppard
authored
chore(amplify_storage_s3): add storage integration tests and update example app (#734)
1 parent a2f3725 commit 7c99d5a

File tree

9 files changed

+213
-6
lines changed

9 files changed

+213
-6
lines changed

CONTRIBUTING.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ Finally, run a push to update the resources with the new function resource (lamb
269269
$ amplify push
270270
```
271271

272+
Additionally, the storage category requires some manual configuration as the [headless CLI does not yet support storage](https://github.com/aws-amplify/amplify-cli/issues/7378). Those instructions
273+
are notes in the [storage example app](packages/amplify_storage_s3/example/README.md).
274+
272275
## Code of Conduct
273276

274277
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).

packages/amplify_storage_s3/example/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ node_modules/
5656
aws-exports.js
5757
awsconfiguration.json
5858
amplifyconfiguration.json
59+
amplifyconfiguration.dart
5960
amplify-build-config.json
6061
amplify-gradle-config.json
6162
amplifytools.xcconfig
6263
.secret-*
63-
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,54 @@
11
# amplify_storage_s3_example
22

33
Example app for the Amplify Flutter Storage plugin with AWS S3 provider.
4+
5+
## How to Configure Amplify Backend
6+
7+
This app (as well as integration tests) depend on an Amplify backend with the storage category
8+
configured for guest access.
9+
10+
First, initialize the Amplify backend with:
11+
12+
```
13+
$ cd packages/amplify_storage_s3/example
14+
$ amplify init
15+
```
16+
17+
After completing the prompts, add storage category.
18+
19+
```
20+
$ amplify add storage
21+
? Please select from one of the below mentioned services: Content (Images, audio, video, etc.)
22+
? You need to add auth (Amazon Cognito) to your project in order to add storage for user files. Do you want to add auth now?
23+
Yes
24+
Using service: Cognito, provided by: awscloudformation
25+
26+
The current configured provider is Amazon Cognito.
27+
28+
Do you want to use the default authentication and security configuration? Default configuration
29+
Warning: you will not be able to edit these selections.
30+
How do you want users to be able to sign in?
31+
Username
32+
Do you want to configure advanced settings?
33+
No, I am done.
34+
Successfully added auth resource MYRESOURCENAME locally
35+
36+
Some next steps:
37+
"amplify push" will build all your local backend resources and provision it in the cloud
38+
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
39+
40+
? Please provide a friendly name for your resource that will be used to label this category in the project:
41+
myGreatProjectNameStorage
42+
? Please provide bucket name:
43+
exampleBucketNameUnique12345
44+
? Who should have access:
45+
Auth and guest users
46+
? What kind of access do you want for Authenticated users?
47+
create/update, read, delete
48+
? What kind of access do you want for Guest users?
49+
create/update, read, delete
50+
? Do you want to add a Lambda Trigger for your S3 Bucket?
51+
No
52+
```
53+
54+
Finally, run `$ amplify push` to provision the storage resource in the cloud.

packages/amplify_storage_s3/example/android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
}
77

88
dependencies {
9-
classpath 'com.android.tools.build:gradle:3.5.0'
9+
classpath 'com.android.tools.build:gradle:3.5.4'
1010
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1111
}
1212
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
import 'dart:io';
16+
import 'package:path_provider/path_provider.dart';
17+
import 'package:integration_test/integration_test.dart';
18+
import 'package:flutter_test/flutter_test.dart';
19+
20+
import 'package:amplify_flutter/amplify.dart';
21+
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
22+
import 'package:amplify_storage_s3/amplify_storage_s3.dart';
23+
import 'package:amplify_storage_s3_example/amplifyconfiguration.dart';
24+
25+
const exampleFileName = 'example_file.txt';
26+
27+
void main() async {
28+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
29+
30+
group('amplify_storage_s3', () {
31+
// options used for all tests
32+
S3ListOptions listOptions =
33+
S3ListOptions(accessLevel: StorageAccessLevel.guest);
34+
late String? lastUploadedKey;
35+
36+
// Returns a text file to use for testing, writing if it does not exist.
37+
Future<File> getTemporaryFile() async {
38+
final path = '${(await getTemporaryDirectory()).path}/$exampleFileName';
39+
final file = File(path);
40+
if (!(await file.exists())) {
41+
await file.writeAsString('Upload me to s3 to see if I work.');
42+
}
43+
return file;
44+
}
45+
46+
Future<int> getCountFromListFiles() async {
47+
final result = await Amplify.Storage.list(options: listOptions);
48+
return result.items.length;
49+
}
50+
51+
Future<void> deleteAllGuestFiles() async {
52+
final result = await Amplify.Storage.list(options: listOptions);
53+
for (StorageItem item in result.items) {
54+
await Amplify.Storage.remove(key: item.key);
55+
}
56+
}
57+
58+
setUpAll(() async {
59+
Amplify.addPlugins([AmplifyAuthCognito(), AmplifyStorageS3()]);
60+
await Amplify.configure(amplifyconfig);
61+
62+
await deleteAllGuestFiles();
63+
});
64+
65+
tearDownAll(() async {
66+
await deleteAllGuestFiles();
67+
});
68+
69+
testWidgets('should upload a file', (WidgetTester tester) async {
70+
final file = await getTemporaryFile();
71+
final initialCount = await getCountFromListFiles();
72+
73+
final key = '$exampleFileName${new DateTime.now().toString()}';
74+
Map<String, String> metadata = <String, String>{};
75+
metadata['name'] = exampleFileName;
76+
metadata['desc'] = 'A test file';
77+
S3UploadFileOptions options = S3UploadFileOptions(
78+
accessLevel: StorageAccessLevel.guest, metadata: metadata);
79+
final result = await Amplify.Storage.uploadFile(
80+
key: key, local: file, options: options);
81+
lastUploadedKey = result.key;
82+
expect(lastUploadedKey, key);
83+
84+
final finalCount = await getCountFromListFiles();
85+
expect(initialCount + 1, finalCount);
86+
});
87+
88+
testWidgets('should list files and get expected attributes',
89+
(WidgetTester tester) async {
90+
if (lastUploadedKey == null) {
91+
fail('No uploaded file to verify.');
92+
}
93+
final result = await Amplify.Storage.list(options: listOptions);
94+
expect(result.items.length, greaterThan(0));
95+
final uploadedStorageItem =
96+
result.items.firstWhere((element) => element.key == lastUploadedKey);
97+
expect(uploadedStorageItem.lastModified?.day,
98+
new DateTime.now().day); // was uploaded today
99+
expect(uploadedStorageItem.eTag?.isNotEmpty, true);
100+
expect(uploadedStorageItem.size, greaterThan(0));
101+
});
102+
103+
testWidgets('should get the URL of an uploaded file',
104+
(WidgetTester tester) async {
105+
if (lastUploadedKey == null) {
106+
fail('No uploaded file to verify.');
107+
}
108+
final result = await Amplify.Storage.getUrl(key: lastUploadedKey!);
109+
// assert valid and expected s3 URL
110+
expect(Uri.parse(result.url).isAbsolute, true);
111+
expect(result.url.contains('s3'), true);
112+
});
113+
114+
testWidgets('should delete uploaded files', (WidgetTester tester) async {
115+
final initialCount = await getCountFromListFiles();
116+
expect(initialCount, greaterThan(0));
117+
await deleteAllGuestFiles();
118+
final finalCount = await getCountFromListFiles();
119+
expect(finalCount, 0);
120+
});
121+
});
122+
}

packages/amplify_storage_s3/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/amplify_storage_s3/example/lib/main.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ class _MyAppState extends State<MyApp> {
6464
try {
6565
print('In upload');
6666
// Uploading the file with options
67-
File local = await FilePicker.getFile(type: FileType.image);
67+
FilePickerResult? pickResult =
68+
await FilePicker.platform.pickFiles(type: FileType.image);
69+
if (pickResult == null) {
70+
print('User canceled upload.');
71+
return;
72+
}
73+
File local = File(pickResult.files.single.path!);
6874
final key = new DateTime.now().toString();
6975
Map<String, String> metadata = <String, String>{};
7076
metadata['name'] = 'filename';

packages/amplify_storage_s3/example/pubspec.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ description: Demonstrates how to use the amplify_storage_s3 plugin.
66
publish_to: "none" # Remove this line if you wish to publish to pub.dev
77

88
environment:
9-
sdk: ">=2.7.0 <3.0.0"
9+
sdk: ">=2.12.0 <3.0.0"
10+
flutter: ">=2.2.0"
1011

1112
dependencies:
1213
flutter:
1314
sdk: flutter
14-
file_picker: ^1.8.0+1
15+
file_picker: ^3.0.3
1516
amplify_flutter:
1617
path: ../../amplify_flutter
1718
amplify_auth_cognito:
@@ -32,6 +33,12 @@ dependencies:
3233
dev_dependencies:
3334
flutter_test:
3435
sdk: flutter
36+
flutter_driver:
37+
sdk: flutter
38+
integration_test:
39+
sdk: flutter
40+
path_provider: ^2.0.2
41+
3542

3643
# For information on the generic Dart part of this file, see the
3744
# following page: https://dart.dev/tools/pub/pubspec
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
import 'package:integration_test/integration_test_driver.dart';
17+
18+
Future<void> main() => integrationDriver();

0 commit comments

Comments
 (0)