From 0dda1ce1be02374851a60dc3a19c282da7d1316c Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Tue, 30 Aug 2022 17:12:34 +0200 Subject: [PATCH 01/10] Update to latest Core --- .../Accessors/ManagedAccessor.cs | 10 +- Realm/Realm/DatabaseTypes/INotifiable.cs | 3 +- .../DatabaseTypes/RealmCollectionBase.cs | 7 +- Realm/Realm/DatabaseTypes/RealmDictionary.cs | 5 +- Realm/Realm/Handles/DictionaryHandle.cs | 6 +- .../Handles/NotifiableObjectHandleBase.cs | 6 +- .../Sync/SynchronizedInstanceTests.cs | 2 - wrappers/realm-core | 2 +- wrappers/src/dictionary_cs.cpp | 388 +++++++++--------- wrappers/src/notifications_cs.hpp | 218 +++++----- 10 files changed, 309 insertions(+), 338 deletions(-) diff --git a/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs b/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs index c43ea5f171..256568304a 100644 --- a/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs +++ b/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs @@ -155,15 +155,9 @@ public void UnsubscribeFromNotifications() } /// - void INotifiable.NotifyCallbacks(NotifiableObjectHandleBase.CollectionChangeSet? changes, NativeException? exception) + void INotifiable.NotifyCallbacks(NotifiableObjectHandleBase.CollectionChangeSet? changes) { - var managedException = exception?.Convert(); - - if (managedException != null) - { - Realm.NotifyError(managedException); - } - else if (changes.HasValue) + if (changes.HasValue) { foreach (int propertyIndex in changes.Value.Properties.AsEnumerable()) { diff --git a/Realm/Realm/DatabaseTypes/INotifiable.cs b/Realm/Realm/DatabaseTypes/INotifiable.cs index 4bb7be0a64..18f02ba45e 100644 --- a/Realm/Realm/DatabaseTypes/INotifiable.cs +++ b/Realm/Realm/DatabaseTypes/INotifiable.cs @@ -33,8 +33,7 @@ internal interface INotifiable /// Method called when there are changes to report for that object. /// /// The changes that occurred. - /// An exception if one occurred. - void NotifyCallbacks(TChangeset? changes, NativeException? exception); + void NotifyCallbacks(TChangeset? changes); } internal class NotificationToken : IDisposable diff --git a/Realm/Realm/DatabaseTypes/RealmCollectionBase.cs b/Realm/Realm/DatabaseTypes/RealmCollectionBase.cs index 5b2008257a..82df3fa922 100644 --- a/Realm/Realm/DatabaseTypes/RealmCollectionBase.cs +++ b/Realm/Realm/DatabaseTypes/RealmCollectionBase.cs @@ -41,7 +41,7 @@ public abstract class RealmCollectionBase IThreadConfined, IMetadataObject { - private readonly List> _callbacks = new List>(); + private readonly List> _callbacks = new(); private NotificationTokenHandle _notificationToken; @@ -395,9 +395,8 @@ private void UpdateCollectionChangedSubscriptionIfNecessary(bool isSubscribed) #endregion INotifyCollectionChanged - void INotifiable.NotifyCallbacks(NotifiableObjectHandleBase.CollectionChangeSet? changes, NativeException? exception) + void INotifiable.NotifyCallbacks(NotifiableObjectHandleBase.CollectionChangeSet? changes) { - var managedException = exception?.Convert(); ChangeSet changeset = null; if (changes != null) { @@ -417,7 +416,7 @@ private void UpdateCollectionChangedSubscriptionIfNecessary(bool isSubscribed) foreach (var callback in _callbacks.ToArray()) { - callback(this, changeset, managedException); + callback(this, changeset, null); } } diff --git a/Realm/Realm/DatabaseTypes/RealmDictionary.cs b/Realm/Realm/DatabaseTypes/RealmDictionary.cs index b9776d7e01..2fd8a78baf 100644 --- a/Realm/Realm/DatabaseTypes/RealmDictionary.cs +++ b/Realm/Realm/DatabaseTypes/RealmDictionary.cs @@ -236,9 +236,8 @@ private static string ValidateKey(string key) protected override KeyValuePair GetValueAtIndex(int index) => _dictionaryHandle.GetValueAtIndex(index, Realm); - void INotifiable.NotifyCallbacks(DictionaryHandle.DictionaryChangeSet? changes, NativeException? exception) + void INotifiable.NotifyCallbacks(DictionaryHandle.DictionaryChangeSet? changes) { - var managedException = exception?.Convert(); DictionaryChangeSet changeset = null; if (changes != null) { @@ -255,7 +254,7 @@ private static string ValidateKey(string key) foreach (var callback in _keyCallbacks.ToArray()) { - callback(this, changeset, managedException); + callback(this, changeset, null); } } } diff --git a/Realm/Realm/Handles/DictionaryHandle.cs b/Realm/Realm/Handles/DictionaryHandle.cs index 20789eb3fe..38e6ea393a 100644 --- a/Realm/Realm/Handles/DictionaryHandle.cs +++ b/Realm/Realm/Handles/DictionaryHandle.cs @@ -34,7 +34,7 @@ internal struct DictionaryChangeSet } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void KeyNotificationCallback(IntPtr managedHandle, IntPtr changes, IntPtr notificationException); + public delegate void KeyNotificationCallback(IntPtr managedHandle, IntPtr changes); private static class NativeMethods { @@ -334,11 +334,11 @@ public ResultsHandle GetKeys() } [MonoPInvokeCallback(typeof(KeyNotificationCallback))] - public static void NotifyDictionaryChanged(IntPtr managedHandle, IntPtr changes, IntPtr exception) + public static void NotifyDictionaryChanged(IntPtr managedHandle, IntPtr changes) { if (GCHandle.FromIntPtr(managedHandle).Target is INotifiable notifiable) { - notifiable.NotifyCallbacks(new PtrTo(changes).Value, new PtrTo(exception).Value); + notifiable.NotifyCallbacks(new PtrTo(changes).Value); } } } diff --git a/Realm/Realm/Handles/NotifiableObjectHandleBase.cs b/Realm/Realm/Handles/NotifiableObjectHandleBase.cs index 14f14d280a..af22218663 100644 --- a/Realm/Realm/Handles/NotifiableObjectHandleBase.cs +++ b/Realm/Realm/Handles/NotifiableObjectHandleBase.cs @@ -45,7 +45,7 @@ public struct Move } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void NotificationCallback(IntPtr managedHandle, IntPtr changes, IntPtr notificationException); + public delegate void NotificationCallback(IntPtr managedHandle, IntPtr changes); protected NotifiableObjectHandleBase(SharedRealmHandle root, IntPtr handle) : base(root, handle) { @@ -56,11 +56,11 @@ protected NotifiableObjectHandleBase(SharedRealmHandle root, IntPtr handle) : ba public abstract ThreadSafeReferenceHandle GetThreadSafeReference(); [MonoPInvokeCallback(typeof(NotificationCallback))] - public static void NotifyObjectChanged(IntPtr managedHandle, IntPtr changes, IntPtr exception) + public static void NotifyObjectChanged(IntPtr managedHandle, IntPtr changes) { if (GCHandle.FromIntPtr(managedHandle).Target is INotifiable notifiable) { - notifiable.NotifyCallbacks(new PtrTo(changes).Value, new PtrTo(exception).Value); + notifiable.NotifyCallbacks(new PtrTo(changes).Value); } } } diff --git a/Tests/Realm.Tests/Sync/SynchronizedInstanceTests.cs b/Tests/Realm.Tests/Sync/SynchronizedInstanceTests.cs index 0f28196f66..eea048e572 100644 --- a/Tests/Realm.Tests/Sync/SynchronizedInstanceTests.cs +++ b/Tests/Realm.Tests/Sync/SynchronizedInstanceTests.cs @@ -351,7 +351,6 @@ public void WriteCopy_CanSynchronizeData([Values(true, false)] bool originalEncr AddDummyData(originalRealm, true); await WaitForUploadAsync(originalRealm); - await WaitForDownloadAsync(originalRealm); originalRealm.WriteCopy(copyConfig); @@ -483,7 +482,6 @@ public void WriteCopy_SyncToLocal([Values(true, false)] bool originalEncrypted, AddDummyData(originalRealm, true); await WaitForUploadAsync(originalRealm); - await WaitForDownloadAsync(originalRealm); originalRealm.WriteCopy(copyConfig); diff --git a/wrappers/realm-core b/wrappers/realm-core index e62f7c94aa..01d4501228 160000 --- a/wrappers/realm-core +++ b/wrappers/realm-core @@ -1 +1 @@ -Subproject commit e62f7c94aa01f855a40a2b89fc2d9d0f63369d13 +Subproject commit 01d45012287055d565f80d1c697b40a988d2befa diff --git a/wrappers/src/dictionary_cs.cpp b/wrappers/src/dictionary_cs.cpp index ce885fc51f..64511bb43b 100644 --- a/wrappers/src/dictionary_cs.cpp +++ b/wrappers/src/dictionary_cs.cpp @@ -31,209 +31,199 @@ using namespace realm::binding; extern "C" { -REALM_EXPORT void realm_dictionary_add(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t value, NativeException::Marshallable& ex) -{ - handle_errors(ex, [&]() { - auto dict_key = from_capi(key.string); - if (dictionary.contains(dict_key)) - { - throw KeyAlreadyExistsException(dict_key); - } - - dictionary.insert(dict_key, from_capi(value)); - }); -} - -REALM_EXPORT Object* realm_dictionary_add_embedded(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - auto dict_key = from_capi(key.string); - if (dictionary.contains(dict_key)) - { - throw KeyAlreadyExistsException(dict_key); - } - - return new Object(dictionary.get_realm(), dictionary.get_object_schema(), dictionary.insert_embedded(dict_key)); - }); -} - -REALM_EXPORT void realm_dictionary_set(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t value, NativeException::Marshallable& ex) -{ - handle_errors(ex, [&]() { - dictionary.insert(from_capi(key.string), from_capi(value)); - }); -} - -REALM_EXPORT Object* realm_dictionary_set_embedded(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return new Object(dictionary.get_realm(), dictionary.get_object_schema(), dictionary.insert_embedded(from_capi(key.string))); - }); -} - -REALM_EXPORT bool realm_dictionary_try_get(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t* value, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - auto mixed_value = dictionary.try_get_any(from_capi(key.string)); - if (mixed_value) - { - *value = to_capi(dictionary, *mixed_value); - return true; - } - - return false; - }); -} - -REALM_EXPORT void realm_dictionary_get_at_index(object_store::Dictionary& dictionary, size_t ndx, realm_value_t* key, realm_value_t* value, NativeException::Marshallable& ex) -{ - handle_errors(ex, [&]() { - const size_t count = dictionary.size(); - if (ndx >= count) - throw IndexOutOfRangeException("Get from RealmDictionary", ndx, count); - - auto pair = dictionary.get_pair(ndx); - *key = to_capi(Mixed(pair.first)); - *value = to_capi(dictionary, pair.second); - }); -} - -REALM_EXPORT bool realm_dictionary_remove(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - auto dict_key = from_capi(key.string); - if (dictionary.contains(dict_key)) - { - dictionary.erase(dict_key); - return true; - } - - return false; - }); -} - -REALM_EXPORT bool realm_dictionary_remove_value(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t value, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - auto dict_key = from_capi(key.string); - auto dict_value = dictionary.try_get_any(dict_key); - - if (dict_value && are_equal(value, *dict_value)) - { - dictionary.erase(dict_key); - return true; - } - - return false; - }); -} - -REALM_EXPORT bool realm_dictionary_contains_key(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return dictionary.contains(from_capi(key.string)); - }); -} - -REALM_EXPORT void realm_dictionary_clear(object_store::Dictionary& dictionary, NativeException::Marshallable& ex) -{ - handle_errors(ex, [&]() { - dictionary.remove_all(); - }); -} - -REALM_EXPORT size_t realm_dictionary_get_size(object_store::Dictionary& dictionary, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return dictionary.size(); - }); -} - -REALM_EXPORT void realm_dictionary_destroy(object_store::Dictionary* dictionary) -{ - delete dictionary; -} - -REALM_EXPORT ManagedNotificationTokenContext* realm_dictionary_add_notification_callback(object_store::Dictionary* dictionary, void* managed_dict, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [=]() { - return subscribe_for_notifications(managed_dict, [dictionary](CollectionChangeCallback callback) { - return dictionary->add_notification_callback(callback); - }); - }); -} - -REALM_EXPORT ManagedNotificationTokenContext* realm_dictionary_add_key_notification_callback(object_store::Dictionary* dictionary, void* managed_dict, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [=]() { - auto context = new ManagedNotificationTokenContext(); - context->managed_object = managed_dict; - context->token = dictionary->add_key_based_notification_callback([context](DictionaryChangeSet changes, std::exception_ptr e) { - if (e) { - try { - std::rethrow_exception(e); - } - catch (...) { - auto exception = convert_exception(); - auto marshallable_exception = exception.for_marshalling(); - s_dictionary_notification_callback(context->managed_object, nullptr, &marshallable_exception); - } + REALM_EXPORT void realm_dictionary_add(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t value, NativeException::Marshallable& ex) + { + handle_errors(ex, [&]() { + auto dict_key = from_capi(key.string); + if (dictionary.contains(dict_key)) + { + throw KeyAlreadyExistsException(dict_key); } - else if (changes.deletions.empty() && changes.insertions.empty() && changes.modifications.empty()) { - s_dictionary_notification_callback(context->managed_object, nullptr, nullptr); + + dictionary.insert(dict_key, from_capi(value)); + }); + } + + REALM_EXPORT Object* realm_dictionary_add_embedded(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + auto dict_key = from_capi(key.string); + if (dictionary.contains(dict_key)) + { + throw KeyAlreadyExistsException(dict_key); } - else { - auto deletions = get_keys_vector(changes.deletions); - auto insertions = get_keys_vector(changes.insertions); - auto modifications = get_keys_vector(changes.modifications); - - MarshallableDictionaryChangeSet marshallable_changes{ - { deletions.data(), deletions.size() }, - { insertions.data(), insertions.size() }, - { modifications.data(), modifications.size() }, - }; - - s_dictionary_notification_callback(context->managed_object, &marshallable_changes, nullptr); + + return new Object(dictionary.get_realm(), dictionary.get_object_schema(), dictionary.insert_embedded(dict_key)); + }); + } + + REALM_EXPORT void realm_dictionary_set(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t value, NativeException::Marshallable& ex) + { + handle_errors(ex, [&]() { + dictionary.insert(from_capi(key.string), from_capi(value)); + }); + } + + REALM_EXPORT Object* realm_dictionary_set_embedded(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return new Object(dictionary.get_realm(), dictionary.get_object_schema(), dictionary.insert_embedded(from_capi(key.string))); + }); + } + + REALM_EXPORT bool realm_dictionary_try_get(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t* value, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + auto mixed_value = dictionary.try_get_any(from_capi(key.string)); + if (mixed_value) + { + *value = to_capi(dictionary, *mixed_value); + return true; } + + return false; + }); + } + + REALM_EXPORT void realm_dictionary_get_at_index(object_store::Dictionary& dictionary, size_t ndx, realm_value_t* key, realm_value_t* value, NativeException::Marshallable& ex) + { + handle_errors(ex, [&]() { + const size_t count = dictionary.size(); + if (ndx >= count) + throw IndexOutOfRangeException("Get from RealmDictionary", ndx, count); + + auto pair = dictionary.get_pair(ndx); + *key = to_capi(Mixed(pair.first)); + *value = to_capi(dictionary, pair.second); + }); + } + + REALM_EXPORT bool realm_dictionary_remove(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + auto dict_key = from_capi(key.string); + if (dictionary.contains(dict_key)) + { + dictionary.erase(dict_key); + return true; + } + + return false; + }); + } + + REALM_EXPORT bool realm_dictionary_remove_value(object_store::Dictionary& dictionary, realm_value_t key, realm_value_t value, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + auto dict_key = from_capi(key.string); + auto dict_value = dictionary.try_get_any(dict_key); + + if (dict_value && are_equal(value, *dict_value)) + { + dictionary.erase(dict_key); + return true; + } + + return false; + }); + } + + REALM_EXPORT bool realm_dictionary_contains_key(object_store::Dictionary& dictionary, realm_value_t key, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return dictionary.contains(from_capi(key.string)); + }); + } + + REALM_EXPORT void realm_dictionary_clear(object_store::Dictionary& dictionary, NativeException::Marshallable& ex) + { + handle_errors(ex, [&]() { + dictionary.remove_all(); + }); + } + + REALM_EXPORT size_t realm_dictionary_get_size(object_store::Dictionary& dictionary, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return dictionary.size(); + }); + } + + REALM_EXPORT void realm_dictionary_destroy(object_store::Dictionary* dictionary) + { + delete dictionary; + } + + REALM_EXPORT ManagedNotificationTokenContext* realm_dictionary_add_notification_callback(object_store::Dictionary* dictionary, void* managed_dict, NativeException::Marshallable& ex) + { + return handle_errors(ex, [=]() { + return subscribe_for_notifications(managed_dict, [dictionary](CollectionChangeCallback callback) { + return dictionary->add_notification_callback(callback); + }); + }); + } + + REALM_EXPORT ManagedNotificationTokenContext* realm_dictionary_add_key_notification_callback(object_store::Dictionary* dictionary, void* managed_dict, NativeException::Marshallable& ex) + { + return handle_errors(ex, [=]() { + auto context = new ManagedNotificationTokenContext(); + context->managed_object = managed_dict; + context->token = dictionary->add_key_based_notification_callback([context](DictionaryChangeSet changes) { + if (changes.deletions.empty() && changes.insertions.empty() && changes.modifications.empty()) { + s_dictionary_notification_callback(context->managed_object, nullptr); + } + else { + auto deletions = get_keys_vector(changes.deletions); + auto insertions = get_keys_vector(changes.insertions); + auto modifications = get_keys_vector(changes.modifications); + + MarshallableDictionaryChangeSet marshallable_changes{ + { deletions.data(), deletions.size() }, + { insertions.data(), insertions.size() }, + { modifications.data(), modifications.size() }, + }; + + s_dictionary_notification_callback(context->managed_object, &marshallable_changes); + } + }); + + return context; }); + } - return context; - }); -} - -REALM_EXPORT bool realm_dictionary_get_is_valid(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return dictionary.is_valid(); - }); -} - -REALM_EXPORT ThreadSafeReference* realm_dictionary_get_thread_safe_reference(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return new ThreadSafeReference(dictionary); - }); -} - -REALM_EXPORT object_store::Dictionary* realm_dictionary_freeze(const object_store::Dictionary& dictionary, const SharedRealm& realm, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return new object_store::Dictionary(dictionary.freeze(realm)); - }); -} - -REALM_EXPORT Results* realm_dictionary_get_values(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return new Results(dictionary.get_values()); - }); -} - -REALM_EXPORT Results* realm_dictionary_get_keys(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) -{ - return handle_errors(ex, [&]() { - return new Results(dictionary.get_keys()); - }); -} + REALM_EXPORT bool realm_dictionary_get_is_valid(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return dictionary.is_valid(); + }); + } + + REALM_EXPORT ThreadSafeReference* realm_dictionary_get_thread_safe_reference(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return new ThreadSafeReference(dictionary); + }); + } + + REALM_EXPORT object_store::Dictionary* realm_dictionary_freeze(const object_store::Dictionary& dictionary, const SharedRealm& realm, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return new object_store::Dictionary(dictionary.freeze(realm)); + }); + } + + REALM_EXPORT Results* realm_dictionary_get_values(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return new Results(dictionary.get_values()); + }); + } + + REALM_EXPORT Results* realm_dictionary_get_keys(const object_store::Dictionary& dictionary, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + return new Results(dictionary.get_keys()); + }); + } } // extern "C" diff --git a/wrappers/src/notifications_cs.hpp b/wrappers/src/notifications_cs.hpp index 078e1cfacb..13c83f9544 100644 --- a/wrappers/src/notifications_cs.hpp +++ b/wrappers/src/notifications_cs.hpp @@ -15,7 +15,7 @@ // limitations under the License. // //////////////////////////////////////////////////////////////////////////// - + #ifndef NOTIFICATIONS_CS_HPP #define NOTIFICATIONS_CS_HPP @@ -27,138 +27,130 @@ using namespace realm::binding; namespace realm { - struct MarshallableCollectionChangeSet { - struct MarshallableIndexSet { - size_t* indices; - size_t count; - }; - - MarshallableIndexSet deletions; - MarshallableIndexSet insertions; - MarshallableIndexSet modifications; - MarshallableIndexSet modifications_new; - - struct { - CollectionChangeSet::Move* moves; - size_t count; - } moves; - - bool cleared; - - MarshallableIndexSet properties; +struct MarshallableCollectionChangeSet { + struct MarshallableIndexSet { + size_t* indices; + size_t count; }; - struct MarshallableDictionaryChangeSet { - struct MarshallableKeySet { - realm_value_t* keys; - size_t count; - }; + MarshallableIndexSet deletions; + MarshallableIndexSet insertions; + MarshallableIndexSet modifications; + MarshallableIndexSet modifications_new; - MarshallableKeySet deletions; - MarshallableKeySet insertions; - MarshallableKeySet modifications; - }; - - struct ManagedNotificationTokenContext { - NotificationToken token; - void* managed_object; - ObjectSchema* schema; + struct { + CollectionChangeSet::Move* moves; + size_t count; + } moves; + + bool cleared; + + MarshallableIndexSet properties; +}; + +struct MarshallableDictionaryChangeSet { + struct MarshallableKeySet { + realm_value_t* keys; + size_t count; }; - using ObjectNotificationCallbackT = void(void* managed_results, MarshallableCollectionChangeSet*, NativeException::Marshallable*); - using DictionaryNotificationCallbackT = void(void* managed_results, MarshallableDictionaryChangeSet*, NativeException::Marshallable*); + MarshallableKeySet deletions; + MarshallableKeySet insertions; + MarshallableKeySet modifications; +}; - extern std::function s_object_notification_callback; - extern std::function s_dictionary_notification_callback; +struct ManagedNotificationTokenContext { + NotificationToken token; + void* managed_object; + ObjectSchema* schema; +}; - inline size_t get_property_index(const ObjectSchema* schema, const ColKey column_key) { - if (!schema) - return 0; - - auto const& props = schema->persisted_properties; - for (size_t i = 0; i < props.size(); ++i) { - if (props[i].column_key == column_key) { - return i; - } +using ObjectNotificationCallbackT = void(void* managed_results, MarshallableCollectionChangeSet*); +using DictionaryNotificationCallbackT = void(void* managed_results, MarshallableDictionaryChangeSet*); + +extern std::function s_object_notification_callback; +extern std::function s_dictionary_notification_callback; + +inline size_t get_property_index(const ObjectSchema* schema, const ColKey column_key) { + if (!schema) + return 0; + + auto const& props = schema->persisted_properties; + for (size_t i = 0; i < props.size(); ++i) { + if (props[i].column_key == column_key) { + return i; } - - return -1; } - - inline std::vector get_indexes_vector(const IndexSet& indexSet) - { - if (indexSet.count() < (size_t)-1) { - return std::vector(indexSet.as_indexes().begin(), indexSet.as_indexes().end()); - } - - return std::vector(); + + return -1; +} + +inline std::vector get_indexes_vector(const IndexSet& indexSet) +{ + if (indexSet.count() < (size_t)-1) { + return std::vector(indexSet.as_indexes().begin(), indexSet.as_indexes().end()); } - static inline std::vector get_keys_vector(const std::vector& keySet) - { - std::vector result; - result.reserve(keySet.size()); + return std::vector(); +} - for (auto &key : keySet) { - result.push_back(to_capi(key)); - } +static inline std::vector get_keys_vector(const std::vector& keySet) +{ + std::vector result; + result.reserve(keySet.size()); - return result; + for (auto& key : keySet) { + result.push_back(to_capi(key)); } - static inline void handle_changes(ManagedNotificationTokenContext* context, CollectionChangeSet changes, std::exception_ptr e) { - if (e) { - try { - std::rethrow_exception(e); - } catch (...) { - auto exception = convert_exception(); - auto marshallable_exception = exception.for_marshalling(); - s_object_notification_callback(context->managed_object, nullptr, &marshallable_exception); - } - } else if (changes.empty()) { - - s_object_notification_callback(context->managed_object, nullptr, nullptr); - } else { - auto deletions = get_indexes_vector(changes.deletions); - auto insertions = get_indexes_vector(changes.insertions); - auto modifications = get_indexes_vector(changes.modifications); - auto modifications_new = get_indexes_vector(changes.modifications_new); - - std::vector properties; - - for (auto& pair : changes.columns) { - if (!pair.second.empty()) { - properties.emplace_back(get_property_index(context->schema, ColKey(pair.first))); - } + return result; +} + +static inline void handle_changes(ManagedNotificationTokenContext* context, CollectionChangeSet changes) { + if (changes.empty()) { + s_object_notification_callback(context->managed_object, nullptr); + } + else { + auto deletions = get_indexes_vector(changes.deletions); + auto insertions = get_indexes_vector(changes.insertions); + auto modifications = get_indexes_vector(changes.modifications); + auto modifications_new = get_indexes_vector(changes.modifications_new); + + std::vector properties; + + for (auto& pair : changes.columns) { + if (!pair.second.empty()) { + properties.emplace_back(get_property_index(context->schema, ColKey(pair.first))); } - - MarshallableCollectionChangeSet marshallable_changes { - { deletions.data(), deletions.size() }, - { insertions.data(), insertions.size() }, - { modifications.data(), modifications.size() }, - { modifications_new.data(), modifications_new.size() }, - { changes.moves.data(), changes.moves.size() }, - { changes.collection_was_cleared }, - { properties.data(), properties.size() } - }; - - s_object_notification_callback(context->managed_object, &marshallable_changes, nullptr); } - } + MarshallableCollectionChangeSet marshallable_changes{ + { deletions.data(), deletions.size() }, + { insertions.data(), insertions.size() }, + { modifications.data(), modifications.size() }, + { modifications_new.data(), modifications_new.size() }, + { changes.moves.data(), changes.moves.size() }, + { changes.collection_was_cleared }, + { properties.data(), properties.size() } + }; - template - inline ManagedNotificationTokenContext* subscribe_for_notifications(void* managed_object, Subscriber subscriber, ObjectSchema* schema = nullptr) - { - auto context = new ManagedNotificationTokenContext(); - context->managed_object = managed_object; - context->schema = schema; - context->token = subscriber([context](CollectionChangeSet changes, std::exception_ptr e) { - handle_changes(context, changes, e); - }); - - return context; + s_object_notification_callback(context->managed_object, &marshallable_changes); } } + +template +inline ManagedNotificationTokenContext* subscribe_for_notifications(void* managed_object, Subscriber subscriber, ObjectSchema* schema = nullptr) +{ + auto context = new ManagedNotificationTokenContext(); + context->managed_object = managed_object; + context->schema = schema; + context->token = subscriber([context](CollectionChangeSet changes) { + handle_changes(context, changes); + }); + + return context; +} +} + #endif // NOTIFICATIONS_CS_HPP From d9494f4a6d27c60f89ab0477244bc4789af8423f Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Tue, 30 Aug 2022 17:34:56 +0200 Subject: [PATCH 02/10] Add vcpkg commit sha to restore keys --- .github/templates/common.lib.yml | 4 ++-- .github/workflows/codeql.yml | 4 ++-- .github/workflows/wrappers.yml | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/templates/common.lib.yml b/.github/templates/common.lib.yml index b7d005eaa7..23c96aed78 100644 --- a/.github/templates/common.lib.yml +++ b/.github/templates/common.lib.yml @@ -110,8 +110,8 @@ with: #@yaml/text-templated-strings with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg-(@= preset @)-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }}-${{ steps.vcpkg_cache_key.outputs.commit }} - cache-restore-keys: vcpkg-(@= preset @)- + cache-key: vcpkg2-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg2-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }} #@ end #@ def downloadAllArtifacts(conclusion = "completed"): diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index eb9773a0fc..81afbdce11 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,8 +41,8 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg-windows-x64-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }}-${{ steps.vcpkg_cache_key.outputs.commit }} - cache-restore-keys: vcpkg-windows-x64- + cache-key: vcpkg2-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg2-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Build wrappers run: powershell ./wrappers/build.ps1 Windows -Platforms x64 -Configuration Release - name: Perform CodeQL Analysis diff --git a/.github/workflows/wrappers.yml b/.github/workflows/wrappers.yml index f028c2d501..62b42b401e 100755 --- a/.github/workflows/wrappers.yml +++ b/.github/workflows/wrappers.yml @@ -471,8 +471,8 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg-windows-${{ matrix.arch }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }}-${{ steps.vcpkg_cache_key.outputs.commit }} - cache-restore-keys: vcpkg-windows-${{ matrix.arch }}- + cache-key: vcpkg2-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg2-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Build wrappers run: pwsh ./wrappers/build.ps1 Windows -Platforms ${{ matrix.arch }} -Configuration Release -EnableLTO if: steps.check-cache.outputs.cache-hit != 'true' @@ -517,8 +517,8 @@ jobs: uses: friendlyanon/setup-vcpkg@v1 with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg-uwp-${{ matrix.arch }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }}-${{ steps.vcpkg_cache_key.outputs.commit }} - cache-restore-keys: vcpkg-uwp-${{ matrix.arch }}- + cache-key: vcpkg2-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg2-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Build wrappers run: pwsh ./wrappers/build.ps1 WindowsStore -Platforms ${{ matrix.arch }} -Configuration Release -EnableLTO if: steps.check-cache.outputs.cache-hit != 'true' From 06e0194258910c88c2b8b578b3494bdbe06acd24 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 00:45:40 +0200 Subject: [PATCH 03/10] trigger native build --- wrappers/src/shared_realm_cs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/src/shared_realm_cs.cpp b/wrappers/src/shared_realm_cs.cpp index 69ab10077c..7d8cbdba6d 100644 --- a/wrappers/src/shared_realm_cs.cpp +++ b/wrappers/src/shared_realm_cs.cpp @@ -775,4 +775,4 @@ REALM_EXPORT int64_t shared_realm_get_subscriptions_version(SharedRealm& realm, }); } -} +} \ No newline at end of file From 10107d3a4697fd4661e49355ce8e5f8c913c7379 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 01:31:04 +0200 Subject: [PATCH 04/10] Try to rebuild vcpkg --- .github/templates/common.lib.yml | 10 +++++-- .github/workflows/build-packages.yml | 6 +++++ .github/workflows/build-unity.yml | 3 +++ .github/workflows/codeql.yml | 9 +++++-- .github/workflows/main.yml | 1 + .github/workflows/wrappers.yml | 40 +++++++++++++++++++++++++--- 6 files changed, 61 insertions(+), 8 deletions(-) diff --git a/.github/templates/common.lib.yml b/.github/templates/common.lib.yml index 23c96aed78..d10467b926 100644 --- a/.github/templates/common.lib.yml +++ b/.github/templates/common.lib.yml @@ -106,12 +106,17 @@ with: shell: bash run: echo "::set-output name=commit::$(git rev-parse HEAD)" - name: Setup Vcpkg + id: setup-vcpkg uses: friendlyanon/setup-vcpkg@v1 #@yaml/text-templated-strings with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg2-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} - cache-restore-keys: vcpkg2-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }} + cache-key: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }} + - name: Refetch vcpkg + if: ${{ setup-vcpkg.outputs.cache-hit == false }} + run: git fetch + working-directory: wrappers/realm-core/tools/vcpkg/ports #@ end #@ def downloadAllArtifacts(conclusion = "completed"): @@ -196,6 +201,7 @@ with: name: #@ artifactName path: #@ "${{ github.workspace }}/" + relPath retention-days: #@ retentionDays + if-no-files-found: error #@ end --- #@ def setupDotnet(version = "6.0.x", ifCondition = ""): diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 320d8a4dd6..e599989918 100755 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -153,30 +153,35 @@ jobs: name: Realm.Fody.${{ steps.get-version.outputs.version }} path: ${{ github.workspace }}/Realm/packages/Realm.Fody.${{ steps.get-version.outputs.version }}.*nupkg retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error - name: Store artifacts for Realm.${{ steps.get-version.outputs.version }} uses: actions/upload-artifact@v2 with: name: Realm.${{ steps.get-version.outputs.version }} path: ${{ github.workspace }}/Realm/packages/Realm.${{ steps.get-version.outputs.version }}.*nupkg retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error - name: Store artifacts for Realm.UnityUtils.${{ steps.get-version.outputs.version }} uses: actions/upload-artifact@v2 with: name: Realm.UnityUtils.${{ steps.get-version.outputs.version }} path: ${{ github.workspace }}/Realm/packages/Realm.UnityUtils.${{ steps.get-version.outputs.version }}.*nupkg retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error - name: Store artifacts for Realm.UnityWeaver.${{ steps.get-version.outputs.version }} uses: actions/upload-artifact@v2 with: name: Realm.UnityWeaver.${{ steps.get-version.outputs.version }} path: ${{ github.workspace }}/Realm/packages/Realm.UnityWeaver.${{ steps.get-version.outputs.version }}.*nupkg retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error - name: Store artifacts for ExtractedChangelog uses: actions/upload-artifact@v2 with: name: ExtractedChangelog path: ${{ github.workspace }}/Realm/Realm/ExtractedChangelog.md retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error - name: Check Docfx cache id: check-docfx-cache if: inputs.build-docs @@ -201,4 +206,5 @@ jobs: name: Docs.zip path: ${{ github.workspace }}/Realm/packages/Docs.zip retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error if: inputs.build-docs diff --git a/.github/workflows/build-unity.yml b/.github/workflows/build-unity.yml index a0367a6b70..7730a2e14c 100755 --- a/.github/workflows/build-unity.yml +++ b/.github/workflows/build-unity.yml @@ -55,12 +55,14 @@ jobs: name: io.realm.unity-${{ inputs.version }}.tgz path: ${{ github.workspace }}/Realm/Realm.Unity/io.realm.unity-${{ inputs.version }}.tgz retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error - name: Store artifacts for AssetStorePublisher-${{ inputs.version }} uses: actions/upload-artifact@v2 with: name: AssetStorePublisher-${{ inputs.version }} path: ${{ github.workspace }}/Tools/AssetStorePublisher retention-days: ${{ (github.event_name != 'pull_request' || contains(github.head_ref, 'release')) && 30 || 1 }} + if-no-files-found: error - name: Build Tests run: dotnet run --project Tools/SetupUnityPackage/ -- tests --realm-package Realm/Realm.Unity/io.realm.unity-${{ inputs.version }}.tgz - name: Store artifacts for UnityTests @@ -69,3 +71,4 @@ jobs: name: UnityTests path: ${{ github.workspace }}/Tests/Tests.Unity retention-days: ${{ github.event_name != 'pull_request' && 30 || 1 }} + if-no-files-found: error diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 81afbdce11..93af8aad34 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,11 +38,16 @@ jobs: shell: bash run: echo "::set-output name=commit::$(git rev-parse HEAD)" - name: Setup Vcpkg + id: setup-vcpkg uses: friendlyanon/setup-vcpkg@v1 with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg2-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} - cache-restore-keys: vcpkg2-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }} + cache-key: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }} + - name: Refetch vcpkg + if: ${{ setup-vcpkg.outputs.cache-hit == false }} + run: git fetch + working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers run: powershell ./wrappers/build.ps1 Windows -Platforms x64 -Configuration Release - name: Perform CodeQL Analysis diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 89359c24c3..6e5742f79b 100755 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -293,6 +293,7 @@ jobs: name: dashboard.charts path: ${{ github.workspace }}/dashboard.charts retention-days: 30 + if-no-files-found: error cleanup-cluster: uses: ./.github/workflows/cleanup-baas.yml if: always() diff --git a/.github/workflows/wrappers.yml b/.github/workflows/wrappers.yml index 62b42b401e..dc86f597a0 100755 --- a/.github/workflows/wrappers.yml +++ b/.github/workflows/wrappers.yml @@ -51,6 +51,7 @@ jobs: name: wrappers-macos path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-macos.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -67,6 +68,7 @@ jobs: name: wrappers-linux path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-linux.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -83,6 +85,7 @@ jobs: name: wrappers-ios-Simulator path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-ios-Simulator.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -99,6 +102,7 @@ jobs: name: wrappers-ios-Device path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-ios-Device.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -115,6 +119,7 @@ jobs: name: wrappers-ios-Catalyst path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-ios-Catalyst.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -131,6 +136,7 @@ jobs: name: wrappers-android-armeabi-v7a path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-android-armeabi-v7a.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -147,6 +153,7 @@ jobs: name: wrappers-android-arm64-v8a path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-android-arm64-v8a.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -163,6 +170,7 @@ jobs: name: wrappers-android-x86 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-android-x86.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -179,6 +187,7 @@ jobs: name: wrappers-android-x86_64 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'ubuntu' && steps.check-cache-android-x86_64.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'ubuntu' @@ -195,6 +204,7 @@ jobs: name: wrappers-windows-Win32 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'windows' && steps.check-cache-windows-Win32.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'windows' @@ -211,6 +221,7 @@ jobs: name: wrappers-windows-x64 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'windows' && steps.check-cache-windows-x64.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'windows' @@ -227,6 +238,7 @@ jobs: name: wrappers-windows-ARM64 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'windows' && steps.check-cache-windows-ARM64.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'windows' @@ -243,6 +255,7 @@ jobs: name: wrappers-windows-uwp-Win32 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'windows' && steps.check-cache-windows-uwp-Win32.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'windows' @@ -259,6 +272,7 @@ jobs: name: wrappers-windows-uwp-x64 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'windows' && steps.check-cache-windows-uwp-x64.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'windows' @@ -275,6 +289,7 @@ jobs: name: wrappers-windows-uwp-ARM path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'windows' && steps.check-cache-windows-uwp-ARM.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'windows' @@ -291,6 +306,7 @@ jobs: name: wrappers-windows-uwp-ARM64 path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: matrix.os == 'windows' && steps.check-cache-windows-uwp-ARM64.outputs.cache-hit == 'true' - run: git clean -fdx if: matrix.os == 'windows' @@ -322,6 +338,7 @@ jobs: name: wrappers-macos path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error ios: runs-on: macos-latest name: iOS @@ -355,6 +372,7 @@ jobs: name: wrappers-ios-${{ matrix.arch }} path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: needs.check-cache.outputs.wrappers-ios-Simulator != 'true' || needs.check-cache.outputs.wrappers-ios-Device != 'true' || needs.check-cache.outputs.wrappers-ios-Catalyst != 'true' linux: runs-on: ubuntu-latest @@ -403,6 +421,7 @@ jobs: name: wrappers-linux path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error android: runs-on: ubuntu-20.04 name: Android @@ -437,6 +456,7 @@ jobs: name: wrappers-android-${{ matrix.arch }} path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: needs.check-cache.outputs.wrappers-android-armeabi-v7a != 'true' || needs.check-cache.outputs.wrappers-android-arm64-v8a != 'true' || needs.check-cache.outputs.wrappers-android-x86 != 'true' || needs.check-cache.outputs.wrappers-android-x86_64 != 'true' windows: runs-on: windows-latest @@ -468,11 +488,16 @@ jobs: shell: bash run: echo "::set-output name=commit::$(git rev-parse HEAD)" - name: Setup Vcpkg + id: setup-vcpkg uses: friendlyanon/setup-vcpkg@v1 with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg2-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} - cache-restore-keys: vcpkg2-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} + cache-key: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} + - name: Refetch vcpkg + if: ${{ setup-vcpkg.outputs.cache-hit == false }} + run: git fetch + working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers run: pwsh ./wrappers/build.ps1 Windows -Platforms ${{ matrix.arch }} -Configuration Release -EnableLTO if: steps.check-cache.outputs.cache-hit != 'true' @@ -482,6 +507,7 @@ jobs: name: wrappers-windows-${{ matrix.arch }} path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: needs.check-cache.outputs.wrappers-windows-Win32 != 'true' || needs.check-cache.outputs.wrappers-windows-x64 != 'true' || needs.check-cache.outputs.wrappers-windows-ARM64 != 'true' uwp: runs-on: windows-latest @@ -514,11 +540,16 @@ jobs: shell: bash run: echo "::set-output name=commit::$(git rev-parse HEAD)" - name: Setup Vcpkg + id: setup-vcpkg uses: friendlyanon/setup-vcpkg@v1 with: path: wrappers/realm-core/tools/vcpkg/ports - cache-key: vcpkg2-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} - cache-restore-keys: vcpkg2-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} + cache-key: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} + cache-restore-keys: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} + - name: Refetch vcpkg + if: ${{ setup-vcpkg.outputs.cache-hit == false }} + run: git fetch + working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers run: pwsh ./wrappers/build.ps1 WindowsStore -Platforms ${{ matrix.arch }} -Configuration Release -EnableLTO if: steps.check-cache.outputs.cache-hit != 'true' @@ -528,4 +559,5 @@ jobs: name: wrappers-windows-uwp-${{ matrix.arch }} path: ${{ github.workspace }}/wrappers/build/** retention-days: 1 + if-no-files-found: error if: needs.check-cache.outputs.wrappers-windows-uwp-Win32 != 'true' || needs.check-cache.outputs.wrappers-windows-uwp-x64 != 'true' || needs.check-cache.outputs.wrappers-windows-uwp-ARM != 'true' || needs.check-cache.outputs.wrappers-windows-uwp-ARM64 != 'true' From 66f5b95690b3a81daad937d6d9062ba0014c15fd Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 01:31:41 +0200 Subject: [PATCH 05/10] trigger wrappers build --- wrappers/src/shared_realm_cs.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrappers/src/shared_realm_cs.cpp b/wrappers/src/shared_realm_cs.cpp index 7d8cbdba6d..3461eece18 100644 --- a/wrappers/src/shared_realm_cs.cpp +++ b/wrappers/src/shared_realm_cs.cpp @@ -775,4 +775,5 @@ REALM_EXPORT int64_t shared_realm_get_subscriptions_version(SharedRealm& realm, }); } -} \ No newline at end of file +} + From 3b9598cb93219d0ab81d6b12a5fc63041769d13e Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 11:52:58 +0200 Subject: [PATCH 06/10] fix workflow --- .github/templates/common.lib.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/wrappers.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/templates/common.lib.yml b/.github/templates/common.lib.yml index d10467b926..afff2a5cd4 100644 --- a/.github/templates/common.lib.yml +++ b/.github/templates/common.lib.yml @@ -114,7 +114,7 @@ with: cache-key: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ setup-vcpkg.outputs.cache-hit == false }} + if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports #@ end diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 93af8aad34..95daf9f44e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,7 +45,7 @@ jobs: cache-key: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ setup-vcpkg.outputs.cache-hit == false }} + if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers diff --git a/.github/workflows/wrappers.yml b/.github/workflows/wrappers.yml index dc86f597a0..63e0adc24e 100755 --- a/.github/workflows/wrappers.yml +++ b/.github/workflows/wrappers.yml @@ -495,7 +495,7 @@ jobs: cache-key: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ setup-vcpkg.outputs.cache-hit == false }} + if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers @@ -547,7 +547,7 @@ jobs: cache-key: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ setup-vcpkg.outputs.cache-hit == false }} + if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers From 9a6de5bfe5f52f461ceca33668057088879541d9 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 12:07:36 +0200 Subject: [PATCH 07/10] Always fetch vcpkg --- .github/templates/common.lib.yml | 1 - .github/workflows/codeql.yml | 1 - .github/workflows/wrappers.yml | 2 -- 3 files changed, 4 deletions(-) diff --git a/.github/templates/common.lib.yml b/.github/templates/common.lib.yml index afff2a5cd4..f5e49a0929 100644 --- a/.github/templates/common.lib.yml +++ b/.github/templates/common.lib.yml @@ -114,7 +114,6 @@ with: cache-key: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports #@ end diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 95daf9f44e..bc49ab05c8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,7 +45,6 @@ jobs: cache-key: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers diff --git a/.github/workflows/wrappers.yml b/.github/workflows/wrappers.yml index 63e0adc24e..8beec69286 100755 --- a/.github/workflows/wrappers.yml +++ b/.github/workflows/wrappers.yml @@ -495,7 +495,6 @@ jobs: cache-key: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers @@ -547,7 +546,6 @@ jobs: cache-key: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - if: ${{ steps.setup-vcpkg.outputs.cache-hit == false }} run: git fetch working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers From ceb62246258a93f6495ef327e2e5fdb77ca00472 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 12:16:13 +0200 Subject: [PATCH 08/10] Use --unshallow --- .github/templates/common.lib.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/wrappers.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/templates/common.lib.yml b/.github/templates/common.lib.yml index f5e49a0929..5ad2184a7f 100644 --- a/.github/templates/common.lib.yml +++ b/.github/templates/common.lib.yml @@ -114,7 +114,7 @@ with: cache-key: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-(@= preset @)-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - run: git fetch + run: git fetch --unshallow working-directory: wrappers/realm-core/tools/vcpkg/ports #@ end diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bc49ab05c8..0a827cce7b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,7 +45,7 @@ jobs: cache-key: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-windows-x64-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - run: git fetch + run: git fetch --unshallow working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers run: powershell ./wrappers/build.ps1 Windows -Platforms x64 -Configuration Release diff --git a/.github/workflows/wrappers.yml b/.github/workflows/wrappers.yml index 8beec69286..28451a38db 100755 --- a/.github/workflows/wrappers.yml +++ b/.github/workflows/wrappers.yml @@ -495,7 +495,7 @@ jobs: cache-key: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-windows-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - run: git fetch + run: git fetch --unshallow working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers run: pwsh ./wrappers/build.ps1 Windows -Platforms ${{ matrix.arch }} -Configuration Release -EnableLTO @@ -546,7 +546,7 @@ jobs: cache-key: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }}-${{ hashFiles('./wrappers/realm-core/tools/vcpkg/vcpkg.json') }} cache-restore-keys: vcpkg3-uwp-${{ matrix.arch }}-${{ steps.vcpkg_cache_key.outputs.commit }} - name: Refetch vcpkg - run: git fetch + run: git fetch --unshallow working-directory: wrappers/realm-core/tools/vcpkg/ports - name: Build wrappers run: pwsh ./wrappers/build.ps1 WindowsStore -Platforms ${{ matrix.arch }} -Configuration Release -EnableLTO From 1193bb654e28865128e872f159042e26a0cc73a9 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 14:15:08 +0200 Subject: [PATCH 09/10] Fix simulate session error --- Realm/Realm/Exceptions/Sync/ClientError.cs | 7 +++++++ Realm/Realm/Extensions/TestingExtensions.cs | 6 +++--- Realm/Realm/Handles/SessionHandle.cs | 6 +++--- Realm/Realm/Sync/Session.cs | 2 +- Tests/Realm.Tests/Sync/SessionTests.cs | 12 ++++++------ wrappers/src/sync_session_cs.cpp | 7 +++++-- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Realm/Realm/Exceptions/Sync/ClientError.cs b/Realm/Realm/Exceptions/Sync/ClientError.cs index 9a343e1c9b..4697cc5710 100644 --- a/Realm/Realm/Exceptions/Sync/ClientError.cs +++ b/Realm/Realm/Exceptions/Sync/ClientError.cs @@ -31,4 +31,11 @@ internal enum SessionErrorCategory : byte ClientError = 0, SessionError = 1 } + + internal enum ServerRequestsAction + { + NoAction = 0, + ApplicationBug = 2, + ClientReset = 6 + } } diff --git a/Realm/Realm/Extensions/TestingExtensions.cs b/Realm/Realm/Extensions/TestingExtensions.cs index 275da6939f..de652fb984 100644 --- a/Realm/Realm/Extensions/TestingExtensions.cs +++ b/Realm/Realm/Extensions/TestingExtensions.cs @@ -44,7 +44,7 @@ public static void SimulateError(this Session session, ErrorCode errorCode, stri Argument.NotNull(session, nameof(session)); Argument.NotNull(message, nameof(message)); - session.ReportErrorForTesting((int)errorCode, SessionErrorCategory.SessionError, message, isFatal); + session.ReportErrorForTesting((int)errorCode, SessionErrorCategory.SessionError, message, isFatal, ServerRequestsAction.ApplicationBug); } /// @@ -60,7 +60,7 @@ public static void SimulateClientReset(this Session session, string message) Argument.NotNull(session, nameof(session)); Argument.NotNull(message, nameof(message)); - session.ReportErrorForTesting((int)ErrorCode.DivergingHistories, SessionErrorCategory.SessionError, message, false); + session.ReportErrorForTesting((int)ErrorCode.DivergingHistories, SessionErrorCategory.SessionError, message, false, ServerRequestsAction.ClientReset); } /// @@ -73,7 +73,7 @@ public static void SimulateAutomaticClientResetFailure(this Session session, str Argument.NotNull(session, nameof(session)); Argument.NotNull(message, nameof(message)); - session.ReportErrorForTesting((int)ClientError.AutoClientResetFailed, SessionErrorCategory.ClientError, message, false); + session.ReportErrorForTesting((int)ClientError.AutoClientResetFailed, SessionErrorCategory.ClientError, message, false, ServerRequestsAction.NoAction); } } } diff --git a/Realm/Realm/Handles/SessionHandle.cs b/Realm/Realm/Handles/SessionHandle.cs index 7a1c04aed4..6ee3ec6181 100644 --- a/Realm/Realm/Handles/SessionHandle.cs +++ b/Realm/Realm/Handles/SessionHandle.cs @@ -104,7 +104,7 @@ public static extern ulong register_progress_notifier(SessionHandle session, public static extern void wait(SessionHandle session, IntPtr task_completion_source, ProgressDirection direction, out NativeException ex); [DllImport(InteropConfig.DLL_NAME, EntryPoint = "realm_syncsession_report_error_for_testing", CallingConvention = CallingConvention.Cdecl)] - public static extern void report_error_for_testing(SessionHandle session, int error_code, SessionErrorCategory error_category, [MarshalAs(UnmanagedType.LPWStr)] string message, IntPtr message_len, [MarshalAs(UnmanagedType.U1)] bool is_fatal); + public static extern void report_error_for_testing(SessionHandle session, int error_code, SessionErrorCategory error_category, [MarshalAs(UnmanagedType.LPWStr)] string message, IntPtr message_len, [MarshalAs(UnmanagedType.U1)] bool is_fatal, int action); [DllImport(InteropConfig.DLL_NAME, EntryPoint = "realm_syncsession_stop", CallingConvention = CallingConvention.Cdecl)] public static extern void stop(SessionHandle session, out NativeException ex); @@ -237,9 +237,9 @@ public IntPtr GetRawPointer() return NativeMethods.get_raw_pointer(this); } - public void ReportErrorForTesting(int errorCode, SessionErrorCategory errorCategory, string errorMessage, bool isFatal) + public void ReportErrorForTesting(int errorCode, SessionErrorCategory errorCategory, string errorMessage, bool isFatal, ServerRequestsAction action) { - NativeMethods.report_error_for_testing(this, errorCode, errorCategory, errorMessage, (IntPtr)errorMessage.Length, isFatal); + NativeMethods.report_error_for_testing(this, errorCode, errorCategory, errorMessage, (IntPtr)errorMessage.Length, isFatal, (int)action); } public void Stop() diff --git a/Realm/Realm/Sync/Session.cs b/Realm/Realm/Sync/Session.cs index 93d74a1fb6..cf5f56fcad 100644 --- a/Realm/Realm/Sync/Session.cs +++ b/Realm/Realm/Sync/Session.cs @@ -217,7 +217,7 @@ internal void CloseHandle(bool waitForShutdown = false) } } - internal void ReportErrorForTesting(int errorCode, SessionErrorCategory sessionErrorCategory, string errorMessage, bool isFatal) => Handle.ReportErrorForTesting(errorCode, sessionErrorCategory, errorMessage, isFatal); + internal void ReportErrorForTesting(int errorCode, SessionErrorCategory sessionErrorCategory, string errorMessage, bool isFatal, ServerRequestsAction action) => Handle.ReportErrorForTesting(errorCode, sessionErrorCategory, errorMessage, isFatal, action); internal static void RaiseError(Session session, Exception error) { diff --git a/Tests/Realm.Tests/Sync/SessionTests.cs b/Tests/Realm.Tests/Sync/SessionTests.cs index 100b3352e5..8f907a42da 100644 --- a/Tests/Realm.Tests/Sync/SessionTests.cs +++ b/Tests/Realm.Tests/Sync/SessionTests.cs @@ -815,7 +815,7 @@ public void Session_OnSessionError() { Assert.That(sender, Is.InstanceOf()); Assert.That(e, Is.InstanceOf()); - Assert.That(e.ErrorCode, Is.EqualTo(ErrorCode.PermissionDenied)); + Assert.That(e.ErrorCode, Is.EqualTo(ErrorCode.NoSuchRealm)); Assert.That(e.Message, Is.EqualTo(errorMsg)); Assert.That(e.InnerException, Is.Null); Assert.That(sessionErrorTriggered, Is.False); @@ -825,7 +825,7 @@ public void Session_OnSessionError() using var realm = await GetRealmAsync(config); var session = GetSession(realm); - session.SimulateError(ErrorCode.PermissionDenied, errorMsg); + session.SimulateError(ErrorCode.NoSuchRealm, errorMsg); await tcs.Task; @@ -1020,7 +1020,7 @@ public void Session_Error_OldSessionError_Coexistence() var handler = GetErrorEventHandler(tcs, (session, error) => { - Assert.That(error.ErrorCode == ErrorCode.PermissionDenied); + Assert.That(error.ErrorCode == ErrorCode.NoSuchRealm); Assert.That(error.Message == errorMsg); Assert.That(error.InnerException == null); Assert.That(obsoleteSessionErrorTriggered, Is.False); @@ -1032,7 +1032,7 @@ public void Session_Error_OldSessionError_Coexistence() using var realm = await GetRealmAsync(config); var session = GetSession(realm); - session.SimulateError(ErrorCode.PermissionDenied, "simulated sync issue"); + session.SimulateError(ErrorCode.NoSuchRealm, "simulated sync issue"); await tcs.Task; Assert.That(obsoleteSessionErrorTriggered, Is.True); @@ -1110,7 +1110,7 @@ public void Session_Error_OnSessionError_Coexistence() // priority is given to the newer appoach in SyncConfigurationBase, so this should never be reached Session.Error += handler; - session.SimulateError(ErrorCode.PermissionDenied, "simulated sync issue"); + session.SimulateError(ErrorCode.NoSuchRealm, "simulated sync issue"); // to avoid a race condition where e.g. both methods are called but because of timing differences `tcs.TrySetResult(true);` is reached // earlier in a call not letting the other finish to run. This would hide an issue. @@ -1500,7 +1500,7 @@ public void Session_WhenDisposed_MethodsThrow() Assert.Throws(() => _ = session.Equals(session)); Assert.Throws(() => _ = session.WaitForDownloadAsync()); Assert.Throws(() => _ = session.WaitForUploadAsync()); - Assert.Throws(() => session.ReportErrorForTesting(1, SessionErrorCategory.SessionError, "test", false)); + Assert.Throws(() => session.ReportErrorForTesting(1, SessionErrorCategory.SessionError, "test", false, ServerRequestsAction.ApplicationBug)); // Calling CloseHandle multiple times should be fine session.CloseHandle(); diff --git a/wrappers/src/sync_session_cs.cpp b/wrappers/src/sync_session_cs.cpp index 6e49e69635..3ddbe067c2 100644 --- a/wrappers/src/sync_session_cs.cpp +++ b/wrappers/src/sync_session_cs.cpp @@ -183,7 +183,7 @@ enum class SessionErrorCategory : uint8_t { SessionError = 1 }; -REALM_EXPORT void realm_syncsession_report_error_for_testing(const SharedSyncSession& session, int err, SessionErrorCategory error_category, const uint16_t* message_buf, size_t message_len, bool is_fatal) +REALM_EXPORT void realm_syncsession_report_error_for_testing(const SharedSyncSession& session, int err, SessionErrorCategory error_category, const uint16_t* message_buf, size_t message_len, bool is_fatal, int server_requests_action) { Utf16StringAccessor message(message_buf, message_len); std::error_code error_code; @@ -200,7 +200,10 @@ REALM_EXPORT void realm_syncsession_report_error_for_testing(const SharedSyncSes return; } - SyncSession::OnlyForTesting::handle_error(*session, SyncError{error_code, std::move(message), is_fatal}); + SyncError error{ error_code, std::move(message), is_fatal }; + error.server_requests_action = static_cast(server_requests_action); + + SyncSession::OnlyForTesting::handle_error(*session, error); } REALM_EXPORT void realm_syncsession_stop(const SharedSyncSession& session, NativeException::Marshallable& ex) From 20718be880d1f21565d218e36ea2dce0e7701d16 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Wed, 31 Aug 2022 17:52:54 +0200 Subject: [PATCH 10/10] Speed up some tests and remove some tests that are no longer relevant --- .../Sync/DataTypeSynchronizationTests.cs | 83 ++++++++--------- Tests/Realm.Tests/Sync/MergeByPKTests.cs | 93 ------------------- Tests/Realm.Tests/Sync/SyncTestBase.cs | 3 - Tests/Realm.Tests/TestHelpers.cs | 9 +- 4 files changed, 45 insertions(+), 143 deletions(-) delete mode 100644 Tests/Realm.Tests/Sync/MergeByPKTests.cs diff --git a/Tests/Realm.Tests/Sync/DataTypeSynchronizationTests.cs b/Tests/Realm.Tests/Sync/DataTypeSynchronizationTests.cs index 241ffe5888..3263405926 100644 --- a/Tests/Realm.Tests/Sync/DataTypeSynchronizationTests.cs +++ b/Tests/Realm.Tests/Sync/DataTypeSynchronizationTests.cs @@ -223,7 +223,7 @@ public class DataTypeSynchronizationTests : SyncTestBase #endregion - #region Byte + #region Binary [Test] public void List_Binary() => TestListCore(o => o.ByteArrayList, TestHelpers.GetBytes(5), TestHelpers.GetBytes(6), (a, b) => a.SequenceEqual(b)); @@ -317,18 +317,14 @@ private void TestListCore(Func> getter, T ite list1.Add(item1); }); - await WaitForCollectionChangeAsync(list2.AsRealmCollection()); - - Assert.That(list1, Is.EquivalentTo(list2).Using(equalsOverride), "Add from list1 should arrive at list2"); + await WaitForCollectionAsync(list2, list1, equalsOverride, "add from 1 shows up in 2"); realm2.Write(() => { list2.Add(item2); }); - await WaitForCollectionChangeAsync(list1.AsRealmCollection()); - - Assert.That(list1, Is.EquivalentTo(list2).Using(equalsOverride), "Add from list2 should arrive at list1"); + await WaitForCollectionAsync(list1, list2, equalsOverride, "add from 2 shows up in 1"); // Assert Remove works realm2.Write(() => @@ -336,9 +332,7 @@ private void TestListCore(Func> getter, T ite list2.Remove(list2.First()); }); - await WaitForCollectionChangeAsync(list1.AsRealmCollection()); - - Assert.That(list1, Is.EquivalentTo(list2).Using(equalsOverride), "Remove from list2 should arrive at list1"); + await WaitForCollectionAsync(list1, list2, equalsOverride, "remove from 2 shows up in 1"); // Assert Clear works realm1.Write(() => @@ -346,7 +340,7 @@ private void TestListCore(Func> getter, T ite list1.Clear(); }); - await TestHelpers.WaitForConditionAsync(() => !list2.Any()); + await TestHelpers.WaitForConditionAsync(() => !list2.Any(), errorMessage: "clear from 1 shows up in 2"); Assert.That(list1, Is.Empty); Assert.That(list2, Is.Empty); @@ -382,18 +376,14 @@ private void TestSetCore(Func> getter, T item1 set1.Add(item1); }); - await WaitForCollectionChangeAsync(set2.AsRealmCollection()); - - Assert.That(set1, Is.EquivalentTo(set2).Using(equalsOverride)); + await WaitForCollectionAsync(set2, set1, equalsOverride, "add from 1 shows up in 2"); realm2.Write(() => { set2.Add(item2); }); - await WaitForCollectionChangeAsync(set1.AsRealmCollection()); - - Assert.That(set1, Is.EquivalentTo(set2).Using(equalsOverride)); + await WaitForCollectionAsync(set1, set2, equalsOverride, "add from 2 shows up in 1"); // Assert Remove works realm2.Write(() => @@ -401,9 +391,7 @@ private void TestSetCore(Func> getter, T item1 set2.Remove(set2.First()); }); - await WaitForCollectionChangeAsync(set1.AsRealmCollection()); - - Assert.That(set1, Is.EquivalentTo(set2).Using(equalsOverride)); + await WaitForCollectionAsync(set1, set2, equalsOverride, "remove from 2 shows up in 1"); // Assert Clear works realm1.Write(() => @@ -411,7 +399,7 @@ private void TestSetCore(Func> getter, T item1 set1.Clear(); }); - await TestHelpers.WaitForConditionAsync(() => !set2.Any()); + await TestHelpers.WaitForConditionAsync(() => !set2.Any(), errorMessage: "clear from 1 shows up in 2"); Assert.That(set1, Is.Empty); Assert.That(set2, Is.Empty); @@ -450,18 +438,14 @@ private void TestDictionaryCore(Func { dict2[key2] = item2; }); - await WaitForCollectionChangeAsync(dict1.AsRealmCollection()); - - Assert.That(dict1, Is.EquivalentTo(dict2).Using(comparer)); + await WaitForCollectionAsync(dict1, dict2, comparer, "add from 2 shows up in 1"); // Assert Update works // item2 might belong to realm2, so let's find the equivalent in realm1 @@ -472,9 +456,7 @@ private void TestDictionaryCore(Func @@ -482,9 +464,7 @@ private void TestDictionaryCore(Func @@ -492,7 +472,7 @@ private void TestDictionaryCore(Func !dict2.Any(), errorMessage: "clear from 1 shows up in 2"); Assert.That(dict1, Is.Empty); Assert.That(dict2, Is.Empty); @@ -643,23 +623,40 @@ void RealmObject_PropertyChanged(object sender, System.ComponentModel.PropertyCh realmObject.PropertyChanged -= RealmObject_PropertyChanged; } - private static async Task WaitForCollectionChangeAsync(IRealmCollection collection, int timeout = 10 * 1000) + private static async Task WaitForCollectionAsync(IEnumerable first, IEnumerable second, Func comparer, string message) { - var tcs = new TaskCompletionSource(); - using var token = collection.SubscribeForNotifications((collection, changes, error) => + comparer ??= EqualityComparer.Default.Equals; + + await TestHelpers.WaitForConditionAsync(() => IsEquivalent(first, second, comparer), errorMessage: message); + Assert.That(first, Is.EquivalentTo(second).Using(comparer)); + } + + private static bool IsEquivalent(IEnumerable first, IEnumerable second, Func comparer) + { + var copy1 = first.ToList(); + var copy2 = second.ToList(); + + while (copy1.Count > 0) { - if (error != null) + var item = copy1[0]; + copy1.RemoveAt(0); + var success = false; + for (var j = 0; j < copy2.Count; j++) { - tcs.TrySetException(error); + if (comparer(copy2[j], item)) + { + success = true; + copy2.RemoveAt(j); + } } - if (changes != null) + if (!success) { - tcs.TrySetResult(null); + return false; } - }); + } - await tcs.Task.Timeout(timeout); + return copy2.Count == 0; } } } diff --git a/Tests/Realm.Tests/Sync/MergeByPKTests.cs b/Tests/Realm.Tests/Sync/MergeByPKTests.cs deleted file mode 100644 index 5c2f8f7254..0000000000 --- a/Tests/Realm.Tests/Sync/MergeByPKTests.cs +++ /dev/null @@ -1,93 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// -// Copyright 2016 Realm Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License 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. -// -//////////////////////////////////////////////////////////////////////////// - -using System; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using NUnit.Framework; -using Realms.Exceptions; -using Realms.Helpers; - -namespace Realms.Tests.Sync -{ - [TestFixture, Preserve(AllMembers = true)] - public class MergeByPKTests : SyncTestBase - { - [TestCaseSource(nameof(MergeTestCases))] - public void WhenObjectHasPK_ShouldNotCreateDuplicates(Type objectType, object pkValue) - { - SyncTestHelpers.RunBaasTestAsync(async () => - { - var pkProperty = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public) - .Single(p => p.GetCustomAttribute() != null); - - var partition = Guid.NewGuid().ToString(); - for (var i = 0; i < 5; i++) - { - var instance = (RealmObject)Activator.CreateInstance(objectType); - - pkProperty.SetValue(instance, pkValue); - - using var realm = await GetSyncedRealm(partition); - try - { - realm.Write(() => realm.Add(instance)); - } - catch (RealmDuplicatePrimaryKeyValueException) - { - // Sync went through too quickly (that's why we do 5 attempts) - } - - await WaitForUploadAsync(realm); - } - - using (var realm = await GetSyncedRealm(partition)) - { - var expectedPK = Operator.Convert(pkValue); - await TestHelpers.WaitForConditionAsync(() => realm.DynamicApi.FindCore(objectType.Name, expectedPK) != null); - - var objectCount = ((IQueryable)realm.DynamicApi.All(objectType.Name)) - .ToArray() - .Count(o => o.DynamicApi.Get("_id") == expectedPK); - - Assert.That(objectCount, Is.EqualTo(1)); - } - }); - } - - public static object[] MergeTestCases = - { - new object[] { typeof(PrimaryKeyInt64Object), 0L }, - new object[] { typeof(PrimaryKeyInt64Object), 1L }, - new object[] { typeof(PrimaryKeyNullableInt64Object), (long?)null }, - new object[] { typeof(PrimaryKeyNullableInt64Object), (long?)0, }, - new object[] { typeof(PrimaryKeyNullableInt64Object), (long?)1, }, - new object[] { typeof(PrimaryKeyStringObject), string.Empty }, - new object[] { typeof(PrimaryKeyStringObject), "key" }, - }; - - private async Task GetSyncedRealm(string partition) - { - var config = await GetIntegrationConfigAsync(partition); - config.Schema = new[] { typeof(PrimaryKeyNullableInt64Object), typeof(PrimaryKeyStringObject), typeof(PrimaryKeyInt64Object) }; - - return GetRealm(config); - } - } -} diff --git a/Tests/Realm.Tests/Sync/SyncTestBase.cs b/Tests/Realm.Tests/Sync/SyncTestBase.cs index 4588b92af0..431e0bd62a 100644 --- a/Tests/Realm.Tests/Sync/SyncTestBase.cs +++ b/Tests/Realm.Tests/Sync/SyncTestBase.cs @@ -114,9 +114,6 @@ protected static async Task WaitForSubscriptionsAsync(Realm realm) protected static async Task WaitForObjectAsync(T obj, Realm realm2) where T : RealmObject { - await WaitForUploadAsync(obj.Realm); - await WaitForDownloadAsync(realm2); - var id = obj.DynamicApi.Get("_id"); return await TestHelpers.WaitForConditionAsync(() => realm2.FindCore(id), o => o != null); diff --git a/Tests/Realm.Tests/TestHelpers.cs b/Tests/Realm.Tests/TestHelpers.cs index 8ab4835a24..71a2823804 100644 --- a/Tests/Realm.Tests/TestHelpers.cs +++ b/Tests/Realm.Tests/TestHelpers.cs @@ -245,12 +245,12 @@ void handler(object sender, TEventArgs args) } } - public static Task WaitForConditionAsync(Func testFunc, int retryDelay = 100, int attempts = 100) + public static Task WaitForConditionAsync(Func testFunc, int retryDelay = 100, int attempts = 100, string errorMessage = null) { - return WaitForConditionAsync(testFunc, b => b, retryDelay, attempts); + return WaitForConditionAsync(testFunc, b => b, retryDelay, attempts, errorMessage); } - public static async Task WaitForConditionAsync(Func producer, Func tester, int retryDelay = 100, int attempts = 100) + public static async Task WaitForConditionAsync(Func producer, Func tester, int retryDelay = 100, int attempts = 100, string errorMessage = null) { var value = producer(); var success = tester(value); @@ -265,7 +265,8 @@ public static async Task WaitForConditionAsync(Func producer, Func