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(datastore): Enable cloud sync in integration tests #1351

Merged
merged 3 commits into from
Mar 25, 2022
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
89 changes: 89 additions & 0 deletions build-support/integ_test_android.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/bin/bash

if [ ! -d android ]; then
echo "No Android project to test" >&2
exit
fi

DEFAULT_DEVICE_ID="sdk"
DEFAULT_ENABLE_CLOUD_SYNC="true"

while [ $# -gt 0 ]; do
case "$1" in
-d|--device-id)
deviceId="$2"
;;
-ec|--enable-cloud-sync)
case "$2" in
true|false)
enableCloudSync="$2"
;;
*)
echo "Invalid value for $1"
exit 1
esac
;;
*)
echo "Invalid arguments"
exit 1
esac
shift
shift
done

deviceId=${deviceId:-$DEFAULT_DEVICE_ID}
enableCloudSync=${enableCloudSync:-$DEFAULT_ENABLE_CLOUD_SYNC}

declare -a testsList
declare -a resultsList

TARGET=integration_test/main_test.dart
if [ ! -e $TARGET ]; then
echo "$TARGET file not found" >&2
exit
fi

testsList+=("$TARGET")
if flutter test \
--no-pub \
-d $deviceId \
$TARGET; then
resultsList+=(0)
else
resultsList+=(1)
fi

TEST_ENTRIES="integration_test/separate_integration_tests/*.dart"
for ENTRY in $TEST_ENTRIES; do
if [ ! -f "${ENTRY}" ]; then
continue
fi
testsList+=("$ENTRY")
if [ $enableCloudSync == "true" ]; then
echo "Run $ENTRY WITH API Sync"
else
echo "Run $ENTRY WITHOUT API Sync"
fi

if flutter test \
--no-pub \
--dart-define ENABLE_CLOUD_SYNC=$enableCloudSync \
-d $deviceId \
$ENTRY; then
resultsList+=(0)
else
resultsList+=(1)
fi
done
HuiSF marked this conversation as resolved.
Show resolved Hide resolved

testFailure=0
for i in "${!testsList[@]}"; do
if [ "${resultsList[i]}" == 0 ]; then
echo "✅ ${testsList[i]}"
else
testFailure=1
echo "❌ ${testsList[i]}"
fi
done

exit $testFailure
82 changes: 78 additions & 4 deletions build-support/integ_test_ios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,99 @@ if [ ! -d ios ]; then
exit
fi

DEFAULT_DEVICE_ID="iPhone"
DEFAULT_ENABLE_CLOUD_SYNC="true"

while [ $# -gt 0 ]; do
case "$1" in
-d|--device-id)
deviceId="$2"
;;
-ec|--enable-cloud-sync)
case "$2" in
true|false)
enableCloudSync="$2"
;;
*)
echo "Invalid value for $1"
exit 1
esac
;;
*)
echo "Invalid arguments"
exit 1
esac
shift
shift
done

deviceId=${deviceId:-$DEFAULT_DEVICE_ID}
enableCloudSync=${enableCloudSync:-$DEFAULT_ENABLE_CLOUD_SYNC}

declare -a testsList
declare -a resultsList

TARGET=integration_test/main_test.dart
if [ ! -e $TARGET ]; then
echo "$TARGET file not found" >&2
exit
fi



# Use xcodebuild if 'RunnerTests' scheme exists, else `flutter test`
if xcodebuild -workspace ios/Runner.xcworkspace -list -json | jq -e '.workspace.schemes | index("RunnerTests")' >/dev/null; then
# Build app for testing
flutter build ios --no-pub --config-only --simulator --target=$TARGET

xcodebuild \
-workspace ios/Runner.xcworkspace \
-scheme RunnerTests \
-destination "platform=iOS Simulator,name=iPhone 12 Pro Max" \
test
else
flutter test \
testsList+=("$TARGET")
if flutter test \
--no-pub \
-d iPhone \
$TARGET
-d $deviceId \
$TARGET; then
resultsList+=(0)
else
resultsList+=(1)
fi
fi

TEST_ENTRIES="integration_test/separate_integration_tests/*.dart"
for ENTRY in $TEST_ENTRIES; do
if [ ! -f "${ENTRY}" ]; then
continue
fi
testsList+=("$ENTRY")
if [ $enableCloudSync == "true" ]; then
echo "Run $ENTRY WITH API Sync"
else
echo "Run $ENTRY WITHOUT API Sync"
fi

if flutter test \
--no-pub \
--dart-define ENABLE_CLOUD_SYNC=$enableCloudSync \
-d $deviceId \
$ENTRY; then
resultsList+=(0)
else
resultsList+=(1)
fi
done

testFailure=0
for i in "${!testsList[@]}"; do
if [ "${resultsList[i]}" == 0 ]; then
echo "✅ ${testsList[i]}"
else
testFailure=1
echo "❌ ${testsList[i]}"
fi
done

exit $testFailure
4 changes: 2 additions & 2 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ scripts:
- Requires running Android and iOS simulators.

test:integration:android:
run: melos exec -c 1 "flutter test --no-pub integration_test/main_test.dart -d sdk"
run: melos exec -c 1 -- "$MELOS_ROOT_PATH/build-support/integ_test_android.sh" $@
description:
Run integration tests for a single package on an Android emulator.
- Run with `--no-select` to run for all applicable packages.
Expand All @@ -239,7 +239,7 @@ scripts:
scope: "*example*"

test:integration:ios:
run: melos exec -c 1 -- "$MELOS_ROOT_PATH/build-support/integ_test_ios.sh"
run: melos exec -c 1 -- "$MELOS_ROOT_PATH/build-support/integ_test_ios.sh" $@
description: Run integration tests for a single package on an iOS simulator.
- Run with `--no-select` to run for all applicable packages.
- Requires launching an iOS simulator prior to execution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ inline fun <reified K, reified V> Map<*, *>.cast(): Map<K, V> =
* casts and make them explicit.
*/
@Suppress("UNCHECKED_CAST")
inline fun <reified T> List<*>.cast(): ArrayList<T> =
this as ArrayList<T>
inline fun <reified T> List<*>.cast(): List<T> =
this as List<T>

/**
* Thrown when an argument of the wrong type is passed to a function.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.amazonaws.amplify.amplify_datastore.types.hub.*
import com.amplifyframework.core.Amplify
import com.amplifyframework.core.model.SerializedModel
import com.amplifyframework.datastore.DataStoreChannelEventName
import com.amplifyframework.datastore.appsync.ModelWithMetadata
import com.amplifyframework.datastore.events.ModelSyncedEvent
import com.amplifyframework.datastore.events.NetworkStatusEvent
import com.amplifyframework.datastore.events.OutboxStatusEvent
Expand Down Expand Up @@ -189,6 +190,24 @@ class DataStoreHubEventStreamHandler : EventChannel.StreamHandler {
LOG.error("Failed to parse and send outboxStatus event: ", e)
}
}
DataStoreChannelEventName.SUBSCRIPTION_DATA_PROCESSED.toString() -> {
try {
val eventData = hubEvent.data as ModelWithMetadata<*>
val model = eventData.model
if (model is SerializedModel) {
val message = FlutterSubscriptionDataProcessedEvent(
hubEvent.name,
model,
eventData.syncMetadata,
)
sendEvent(message.toValueMap())
} else {
LOG.error("Element is not an instance of SerializedModel.")
}
} catch (e: Exception) {
LOG.error("Failed to parse and send ${DataStoreChannelEventName.SUBSCRIPTION_DATA_PROCESSED} event: ", e)
}
}
else -> {
LOG.info("Unhandled DataStoreHubEvent: " + hubEvent.name + "\n" + hubEvent.data.toString())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2022 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.
*/

package com.amazonaws.amplify.amplify_datastore.types.hub

import com.amazonaws.amplify.amplify_datastore.types.model.FlutterSerializedModel
import com.amplifyframework.core.model.Model
import com.amplifyframework.core.model.SerializedModel
import com.amplifyframework.datastore.appsync.ModelMetadata
import com.amplifyframework.datastore.appsync.ModelWithMetadata

class FlutterSubscriptionDataProcessedEvent(
override val eventName: String,
private val model: SerializedModel,
private val syncMetadata: ModelMetadata,
) : FlutterHubEvent {
override fun toValueMap(): Map<String, Any> {
return mapOf(
"eventName" to eventName,
"modelName" to model.modelName,
"element" to mapOf(
"syncMetadata" to mapOf(
"id" to syncMetadata.id,
"_deleted" to syncMetadata.isDeleted,
"_version" to syncMetadata.version,
"_lastChangedAt" to syncMetadata.lastChangedAt?.secondsSinceEpoch
),
"model" to FlutterSerializedModel(model).toMap()
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

package com.amazonaws.amplify.amplify_datastore.types.model

import com.amazonaws.amplify.amplify_core.cast
import com.amplifyframework.core.model.Model
import com.amplifyframework.core.model.ModelSchema
import com.amplifyframework.core.model.SerializedCustomType
Expand Down Expand Up @@ -54,34 +55,41 @@ data class FlutterSerializedModel(val serializedModel: SerializedModel) {
)

return serializedData.mapValues {
val field = modelSchema.fields[it.key]!!
HuiSF marked this conversation as resolved.
Show resolved Hide resolved
when (val value: Any = it.value) {
is Temporal.DateTime -> value.format()
is Temporal.Date -> value.format()
is Temporal.Time -> value.format()
is Model -> FlutterSerializedModel(value as SerializedModel).toMap()
is Temporal.Timestamp -> value.secondsSinceEpoch
is SerializedCustomType -> FlutterSerializedCustomType(value).toMap()
is List<*> -> {
if (field.isCustomType) {
// for a list like field if its type is CustomType
// Then the item type must be CustomType
(value as List<SerializedCustomType>).map { item ->
FlutterSerializedCustomType(item).toMap()
val field = modelSchema.fields[it.key]
if (field == null) {
// At some occasions the SerializeData returned from amplify-android contains meta fields
// e.g. _version, _delete which are not a model filed
// for this case we assign a null value to these meta fields as default
null
} else {
when (val value: Any = it.value) {
is Temporal.DateTime -> value.format()
is Temporal.Date -> value.format()
is Temporal.Time -> value.format()
is Model -> FlutterSerializedModel(value as SerializedModel).toMap()
is Temporal.Timestamp -> value.secondsSinceEpoch
is SerializedCustomType -> FlutterSerializedCustomType(value).toMap()
is List<*> -> {
if (field.isCustomType) {
// for a list like field if its type is CustomType
// Then the item type must be CustomType
(value.cast<SerializedCustomType>()).map { item ->
FlutterSerializedCustomType(item).toMap()
}
}
}
// If collection is not a collection of CustomType
// return the collection directly as
// 1. currently hasMany field won't be populated
// 2. collection of primitive types could be returned as is e.g. ["1", "2"]
else {
value.map { item ->
FlutterFieldUtil.convertValueByFieldType(field.targetType, item)
// If collection is not a collection of CustomType
// return the collection directly as
// 1. currently hasMany field won't be populated
// 2. collection of primitive types could be returned as is e.g. ["1", "2"]
else {
value.map { item ->
FlutterFieldUtil.convertValueByFieldType(field.targetType, item)
}
}
}
// TODO add for other complex objects that can be returned or be part of the codegen model
else -> FlutterFieldUtil.convertValueByFieldType(field.targetType, value)
}
// TODO add for other complex objects that can be returned or be part of the codegen model
else -> FlutterFieldUtil.convertValueByFieldType(field.targetType, value)
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions packages/amplify_datastore/example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,24 @@ app.*.map.json

# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

#amplify-do-not-edit-begin
amplify/\#current-cloud-backend
amplify/.config/local-*
amplify/logs
amplify/mock-data
amplify/backend/amplify-meta.json
amplify/backend/.temp
build/
dist/
node_modules/
aws-exports.js
awsconfiguration.json
amplifyconfiguration.json
amplifyconfiguration.dart
amplify-build-config.json
amplify-gradle-config.json
amplifytools.xcconfig
.secret-*
**.sample
#amplify-do-not-edit-end
Loading