Skip to content

Conversation

@itmindbox
Copy link
Contributor

Updates the release version to 2.14.2. Automated PR: merge release/2.14.2 into master

justSmK and others added 15 commits September 9, 2025 09:35
…acks and states. New trim DB size if needed. (#594)

* WMSDK-510: Remove fatal error through loadPersistentStores, add fallbacks and states. New trim DB size if needed.
* Bump SDK version from 2.14.0-rc to 2.14.0

* Bump SDK version from 2.14.0 to 2.14.1

* Squashed commit of the SwiftLint fix:

commit d750caa
Author: Sergei Semko <[email protected]>
Date:   Tue Sep 9 09:35:57 2025 +0300

    Fix SwiftLint: rename deprecated rule, remove fixed TODO (#593)

---------

Co-authored-by: Anka <[email protected]>
Co-authored-by: Andrey Emtsov <[email protected]>
Co-authored-by: Anka <runner@sjc22-bt152_f59a9438-c2d6-4ed9-a6dc-2dc678af9bac-4EBB0FD1AACF.local>
Co-authored-by: Sergei Semko <[email protected]>
* WMSDK-518: Introduce `DataBaseLoading` protocol + in-memory fallback; refactor loader; add contract tests

- Add `DataBaseLoading` protocol (`loadPersistentContainer` / `makeInMemoryContainer` / `destroy`).
- Make `DataBaseLoader` conform to the protocol.
- Startup flow: on-disk load → destroy+retry → in-memory fallback; no fatalError on loader init.
- DI: register `DataBaseLoading`; use `StubLoader` on init failure (assertionFailure in DEBUG).

No Core Data model changes; no public API changes beyond introducing the protocol.

* WMSDK-518: Introduce DatabaseRepository protocol; wire DI; Noop fallback; remove fatalError in injection

- Add DatabaseRepository protocol:
  - Lifecycle/limits: `limit`, `lifeLimitDate`, `deprecatedLimit`, `onObjectsDidChange`.
  - Metadata: `infoUpdateVersion`, `installVersion`, `instanceId`.
  - CRUD: `create(event:)`, `readEvent(by:)`, `update(event:)`, `delete(event:)`.
  - Queries/maintenance: `query(fetchLimit:retryDeadline:)`, `removeDeprecatedEventsIfNeeded()`, `countDeprecatedEvents()`, `erase()`, `countEvents()`.
  - Convenience default: `query(fetchLimit:)` uses `Constants.Database.retryDeadline`.
- Make the existing Core Data repository conform to DatabaseRepository.
- DI/Composition: depend on `DatabaseRepository` instead of a concrete class.
  - On construction failure, inject a safe Noop `StubDatabaseRepository` (logs via MindboxLogger; `assertionFailure` in DEBUG).
- Remove `fatalError` from repository injection paths to avoid startup crashes and allow graceful degradation.
Notes
- No Core Data model changes.
- Public API impact limited to adding the DatabaseRepository protocol and conformances.
- DatabaseLoader changes and tests will follow in separate commits.

* WMSDK-518: Harden `DatabaseLoader`: low-disk guard, read-only metadata salvage, destroy+retry, in-memory fallback

- Add low-disk gate: compute free space via filesystem attributes and bail out to in-memory store if `freeSize < diskSpaceRepairThreshold` (300 MB) without touching on-disk store.
- Implement read-only metadata salvage (`NSReadOnlyPersistentStoreOption: true`) to preserve `install`, `infoUpdate`, `instanceId` before any destructive action; re-apply metadata to the new/retried store.
- Define clear startup flow:
  1. try loadPersistentStores() → return on success;
  2. on failure → salvage metadata;
  3. if low disk → in-memory fallback (no destroy);
  4. else destroy on-disk store and retry loading;
  5. if retry fails → in-memory fallback.
- Centralize Core Data store options in `applyStandardOptions`: synchronous add, `NSFileProtectionNone`, automatic/inferred migration.
- `destroy()` uses `destroyPersistentStore` (iOS 15+ / legacy path for older OSes) and logs before/after states.
- Keep `StubLoader` for DI fallback; no `fatalError` paths in loader code.

* WMSDK-518[Test]: Refactor unit tests to `DatabaseRepository` protocol; add `NoopDatabaseRepository` & retry semantics coverage

- Migrate tests from concrete `MBDatabaseRepository` to the `DatabaseRepository` protocol
  - Update test fixtures/factories to accept `DatabaseRepository` instead of `MBDatabaseRepository`

- Add a dedicated test suite for `NoopDatabaseRepository`
  - Verify CRUD methods are no-ops and never throw
  - Assert `countEvents()` and `countDeprecatedEvents()` return `0`
  - Assert metadata getters return `nil` and setters are safe (no crash, no side effects)
  - Ensure `erase()` is a no-op and safe to call repeatedly

- Update `Event` contract in tests to cover retry support
  - Extend fixtures with `retryTimestamp: TimeInterval`
  - Add computed `isRetry` and pin its behavior:
    - `isRetry == false` when `retryTimestamp == 0` (new/default events)
    - `isRetry == true` when `retryTimestamp != 0` (after update)
  - Use a fixed clock/deterministic timestamps to avoid flakiness

- Notes
  - Test-only changes; no production code or Core Data model changes
  - Prepares the suite for the new loader/fallback flow by decoupling tests from the concrete repository

* WMSDK-518: Replace `fatalError` with `assertionFailure`; fall back to `UserDefaults.standard` when `UserDefaults(suiteName:)` returns `nil`

- Avoids a hard crash in production while still surfacing the problem in debug.
- Keeps the app functional if the App Group identifier is missing/misconfigured.
- Adds a guard around UserDefaults(suiteName:) and returns `.standard` on failure.

* WMSDK-518: Add DatabaseLoader flow tests; keep integration suite

- Add `DatabaseLoaderFlowTests` with Spy subclass to cover all branches:
  - straight success (no salvage/destroy),
  - load failure + low disk → in-memory + metadata applied,
  - load failure + enough disk → destroy+retry + metadata applied,
  - repair failure → in-memory fallback.

* WMSDK-518: Prune in-memory Core Data store on memory warnings; safe observer lifecycle and refactor `DatabaseRepository` injection

- Add memory-warning handling to `MBDatabaseRepository` that’s enabled **only** for the
  `NSInMemoryStoreType` store.
- Subscribe to `UIApplication.didReceiveMemoryWarningNotification` (`queue: .main`) in `init`
  and remove the observer in `deinit`.
- On warning:
  - Create a background context and aggressively prune all `CDEvent` rows
    (`includesPropertyValues = false`), then `save()` and `reset()` the context.
  - Fire `onObjectsDidChange` on the **main** queue after pruning completes.
- Guard against re-entrancy with `isPruningOnWarning`; reset the flag on the main queue
  once the prune finishes.
- No-op for SQLite-backed stores (warning is ignored there).
- Keep the main thread lightweight: the heavy work is performed on a background context;
  main is used only to enqueue the job and deliver the callback.

Tests:
- Add `MBDatabaseRepositoryMemoryWarningTests` covering:
  - `test_InMemory_PrunesAll_OnMemoryWarning` — in-memory store is fully pruned on warning.
  - `test_SQLite_IgnoresMemoryWarning` — SQLite store ignores warning.
  - `test_InMemory_PruneIsIdempotent_WhenWarningsBurst` — multiple warnings don’t double-prune.

Notes:
- No public API changes. Behavior is active only when the SDK runs with the in-memory fallback,
  reducing OOM risk by shedding data under pressure.

* WMSDK-518: Correcting code review comments

* WMSDK-518: Add groups for database files
…amp` (#599)

Previously we saved the current time (`Date().timeIntervalSince1970`).
Now we persist the timestamp from `Event.enqueueTimeStamp` so the record
reflects the actual enqueue time. Event model was not changed.
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
… (UserDefaults) (#603)

* WMSDK-543: feat(migration): migrate CoreData metadata to PersistenceStorage

- Move metadata handling out of `DatabaseRepositoryProtocol` and into a dedicated `DatabaseMetadataMigration`.
- Read/write metadata directly via `store.metadata` (through `MBDatabaseRepository persistentContainer`) inside the migration—no public getters/setters on the protocol.
- Make the migration idempotent:
  - isNeeded checks that target PersistenceStorage fields are empty and source metadata keys exist.
  - Safely clears keys via metadata update (no-op if store is unavailable).
- Document the repair & preservation flow with SwiftDoc:
  - `salvageMetadataFromOnDiskStore()`, `applyMetadata(_:to:)`. `loadPersistentContainer()`. `destroy()`. and `makeInMemoryContainer()`.
- Naming: prefer suffix style for migrations; e.g. ShownInAppIDsMigration.

* WMSDK-543: Refactor and adding unit tests

* WMSDK-543: feat(migration): support cleanup-only run and refine `isNeeded` for CoreData → UserDefaults metadata

- Add “cleanup-only” path to DatabaseMetadataMigration:
  - If destination (PersistenceStorage) already has values but Core Data metadata
    still contains keys, migration runs only to clear metadata on the store.
- Refine `isNeeded`:
  - true if copy is needed (destination is nil and metadata exists), OR
  - true if cleanup is needed (destination is set and metadata still exists).
- Make `run()` idempotent and safe:
  - Write to PersistenceStorage only when destination fields are nil.
  - Always clear both metadata keys to avoid future re-triggers.
- Keep version = 3 (no change in migration ordering).
- Tests:
  - Added coverage for cleanup-only, copy-only, partial-copy, idempotence,
    and no-op when nothing to migrate.
- Minor: avoid accidentally storing Optional<T> into metadata dictionary.

Why:
- On first launch the app may fall back to InMemory and migrate there; a later
  on-disk launch could still carry stale metadata. Cleanup-only ensures the store
  is sanitized without overwriting destination values.

* WMSDK-543: Fix comments

Change `eraseApplicationInfoUpdateVersionAndInstanceId` to `eraseMetadata`, fix comments and add docs

* WMSDK-543: MetadataMigration without `MBDatabaseRepository`
@justSmK justSmK merged commit ebe7e91 into master Oct 9, 2025
10 checks passed
@justSmK justSmK deleted the release/2.14.2 branch October 9, 2025 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants