Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(amplify_storage_s3): add storage integration tests and update example app #734

Merged
merged 7 commits into from
Jul 22, 2021
Merged
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
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ Finally, run a push to update the resources with the new function resource (lamb
$ amplify push
```

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
are notes in the [storage example app](packages/amplify_storage_s3/example/README.md).

## Code of Conduct

This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
Expand Down
2 changes: 1 addition & 1 deletion packages/amplify_storage_s3/example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ node_modules/
aws-exports.js
awsconfiguration.json
amplifyconfiguration.json
amplifyconfiguration.dart
amplify-build-config.json
amplify-gradle-config.json
amplifytools.xcconfig
.secret-*

51 changes: 51 additions & 0 deletions packages/amplify_storage_s3/example/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
# amplify_storage_s3_example

Example app for the Amplify Flutter Storage plugin with AWS S3 provider.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

## How to Configure Amplify Backend

This app (as well as integration tests) depend on an Amplify backend with the storage category
configured for guest access.

First, initialize the Amplify backend with:

```
$ cd packages/amplify_storage_s3/example
$ amplify init
```

After completing the prompts, add storage category.

```
$ amplify add storage
? Please select from one of the below mentioned services: Content (Images, audio, video, etc.)
? 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?
Yes
Using service: Cognito, provided by: awscloudformation

The current configured provider is Amazon Cognito.

Do you want to use the default authentication and security configuration? Default configuration
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in?
Username
Do you want to configure advanced settings?
No, I am done.
Successfully added auth resource MYRESOURCENAME locally

Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

? Please provide a friendly name for your resource that will be used to label this category in the project:
myGreatProjectNameStorage
? Please provide bucket name:
exampleBucketNameUnique12345
? Who should have access:
Auth and guest users
? What kind of access do you want for Authenticated users?
create/update, read, delete
? What kind of access do you want for Guest users?
create/update, read, delete
? Do you want to add a Lambda Trigger for your S3 Bucket?
No
```

Finally, run `$ amplify push` to provision the storage resource in the cloud.
2 changes: 1 addition & 1 deletion packages/amplify_storage_s3/example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.android.tools.build:gradle:3.5.4'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it ok to just make this change here, or should we try to have the same version in all these files? IMO, ok to have this patch here as it's an example app, after all. This is needed here because of something related to new version of file_picker which has sound nulls safety https://github.com/miguelpruivo/flutter_file_picker/wiki/Troubleshooting#-issue.

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand Down
122 changes: 122 additions & 0 deletions packages/amplify_storage_s3/example/integration_test/main_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:amplify_flutter/amplify.dart';
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_storage_s3/amplify_storage_s3.dart';
import 'package:amplify_storage_s3_example/amplifyconfiguration.dart';

const exampleFileName = 'example_file.txt';

void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

group('amplify_storage_s3', () {
// options used for all tests
S3ListOptions listOptions =
S3ListOptions(accessLevel: StorageAccessLevel.guest);
late String? lastUploadedKey;

// Returns a text file to use for testing, writing if it does not exist.
Future<File> getTemporaryFile() async {
final path = '${(await getTemporaryDirectory()).path}/$exampleFileName';
final file = File(path);
if (!(await file.exists())) {
await file.writeAsString('Upload me to s3 to see if I work.');
}
return file;
}

Future<int> getCountFromListFiles() async {
final result = await Amplify.Storage.list(options: listOptions);
return result.items.length;
}

Future<void> deleteAllGuestFiles() async {
final result = await Amplify.Storage.list(options: listOptions);
for (StorageItem item in result.items) {
await Amplify.Storage.remove(key: item.key);
}
}

setUpAll(() async {
Amplify.addPlugins([AmplifyAuthCognito(), AmplifyStorageS3()]);
await Amplify.configure(amplifyconfig);

await deleteAllGuestFiles();
});

tearDownAll(() async {
await deleteAllGuestFiles();
});

testWidgets('should upload a file', (WidgetTester tester) async {
final file = await getTemporaryFile();
final initialCount = await getCountFromListFiles();

final key = '$exampleFileName${new DateTime.now().toString()}';
Map<String, String> metadata = <String, String>{};
metadata['name'] = exampleFileName;
metadata['desc'] = 'A test file';
S3UploadFileOptions options = S3UploadFileOptions(
accessLevel: StorageAccessLevel.guest, metadata: metadata);
final result = await Amplify.Storage.uploadFile(
key: key, local: file, options: options);
lastUploadedKey = result.key;
expect(lastUploadedKey, key);

final finalCount = await getCountFromListFiles();
expect(initialCount + 1, finalCount);
});

testWidgets('should list files and get expected attributes',
(WidgetTester tester) async {
if (lastUploadedKey == null) {
fail('No uploaded file to verify.');
}
final result = await Amplify.Storage.list(options: listOptions);
expect(result.items.length, greaterThan(0));
final uploadedStorageItem =
result.items.firstWhere((element) => element.key == lastUploadedKey);
expect(uploadedStorageItem.lastModified?.day,
new DateTime.now().day); // was uploaded today
expect(uploadedStorageItem.eTag?.isNotEmpty, true);
expect(uploadedStorageItem.size, greaterThan(0));
ragingsquirrel3 marked this conversation as resolved.
Show resolved Hide resolved
});

testWidgets('should get the URL of an uploaded file',
(WidgetTester tester) async {
if (lastUploadedKey == null) {
fail('No uploaded file to verify.');
}
final result = await Amplify.Storage.getUrl(key: lastUploadedKey!);
// assert valid and expected s3 URL
expect(Uri.parse(result.url).isAbsolute, true);
expect(result.url.contains('s3'), true);
});

testWidgets('should delete uploaded files', (WidgetTester tester) async {
final initialCount = await getCountFromListFiles();
expect(initialCount, greaterThan(0));
await deleteAllGuestFiles();
final finalCount = await getCountFromListFiles();
expect(finalCount, 0);
});
});
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion packages/amplify_storage_s3/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,13 @@ class _MyAppState extends State<MyApp> {
try {
print('In upload');
// Uploading the file with options
File local = await FilePicker.getFile(type: FileType.image);
FilePickerResult? pickResult =
await FilePicker.platform.pickFiles(type: FileType.image);
if (pickResult == null) {
print('User canceled upload.');
return;
}
File local = File(pickResult.files.single.path!);
final key = new DateTime.now().toString();
Map<String, String> metadata = <String, String>{};
metadata['name'] = 'filename';
Expand Down
11 changes: 9 additions & 2 deletions packages/amplify_storage_s3/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ description: Demonstrates how to use the amplify_storage_s3 plugin.
publish_to: "none" # Remove this line if you wish to publish to pub.dev

environment:
sdk: ">=2.7.0 <3.0.0"
sdk: ">=2.12.0 <3.0.0"
flutter: ">=2.2.0"

dependencies:
flutter:
sdk: flutter
file_picker: ^1.8.0+1
file_picker: ^3.0.3
amplify_flutter:
path: ../../amplify_flutter
amplify_auth_cognito:
Expand All @@ -32,6 +33,12 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_driver:
sdk: flutter
integration_test:
sdk: flutter
path_provider: ^2.0.2


# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();