adds pack of 10 tournaments IAP

newoffer2025
Laurent 2 months ago
parent d3c443d116
commit 9bb39dcf8a
  1. 10
      PadelClubData/Subscriptions/StoreItem.swift
  2. 6
      PadelClubData/Subscriptions/StoreManager.swift
  3. 94
      PadelClubDataTests/PadelClubDataTests.swift
  4. 327
      PadelClubDataTests/SyncDataAccessTests.swift

@ -21,11 +21,19 @@ public enum StoreItem: String, Identifiable, CaseIterable {
public var id: String { return self.rawValue } public var id: String { return self.rawValue }
public var summarySystemImage: String {
switch self {
case .monthlyUnlimited: return "infinity.circle.fill"
case .fivePerMonth: return "star.circle.fill"
case .unit, .unit10Pack: return "tennisball.circle.fill"
}
}
public var systemImage: String { public var systemImage: String {
switch self { switch self {
case .monthlyUnlimited: return "infinity.circle.fill" case .monthlyUnlimited: return "infinity.circle.fill"
case .fivePerMonth: return "star.circle.fill" case .fivePerMonth: return "star.circle.fill"
case .unit: return "tennisball.circle.fill" case .unit: return "1.circle.fill"
case .unit10Pack: return "10.circle.fill" case .unit10Pack: return "10.circle.fill"
} }
} }

@ -53,7 +53,11 @@ public class StoreManager {
var products: [Product] = try await Product.products(for: self._productIdentifiers()) var products: [Product] = try await Product.products(for: self._productIdentifiers())
products = products.sorted { p1, p2 in products = products.sorted { p1, p2 in
return p2.price > p1.price if p1.type == p2.type {
return p2.price > p1.price
} else {
return p2.type.rawValue < p1.type.rawValue
}
} }
Logger.log("products = \(products.count)") Logger.log("products = \(products.count)")

@ -1,94 +0,0 @@
//
// PadelClubDataTests.swift
// PadelClubDataTests
//
// Created by Laurent Morvillier on 15/04/2025.
//
import Testing
@testable import PadelClubData
@testable import LeStorage
enum TestError: Error {
case notAuthenticated
case sameDeviceId
case missingEvent
}
struct PadelClubDataTests {
let username: String = "UserDataTests"
let password: String = "MyPass1234--"
init() async throws {
StoreCenter.main.configureURLs(secureScheme: false, domain: "127.0.0.1:8000")
StoreCenter.main.tokenKeychain = MockKeychainStore(fileName: "token.json")
try await self.login()
}
mutating func login() async throws {
let _: CustomUser = try await StoreCenter.main.service().login(username: self.username, password: self.password)
}
@Test func testAuthentication() {
#expect(StoreCenter.main.isAuthenticated)
}
@Test func createTournament() async throws {
guard let userId = StoreCenter.main.userId else {
throw TestError.notAuthenticated
}
// Cleanup
let events = DataStore.shared.events
try await DataStore.shared.events.deleteAsync(contentOfs: Array(events))
try await DataStore.shared.events.loadDataFromServerIfAllowed(clear: true)
#expect(DataStore.shared.events.count == 0)
try await DataStore.shared.tournaments.loadDataFromServerIfAllowed(clear: true)
#expect(DataStore.shared.tournaments.count == 0)
// Create
let event: Event = Event(creator: userId, club: nil, name: "test")
try await DataStore.shared.events.addOrUpdateAsync(instance: event)
let tournament: Tournament = Tournament.fake()
tournament.event = event.id
try await DataStore.shared.tournaments.addOrUpdateAsync(instance: tournament)
// Test server content
try await DataStore.shared.events.loadDataFromServerIfAllowed(clear: true)
#expect(DataStore.shared.events.count == 1)
try await DataStore.shared.tournaments.loadDataFromServerIfAllowed(clear: true)
#expect(DataStore.shared.tournaments.count == 1)
}
@Test func dualStoreCenter() async throws {
let secondStoreServer = StoreCenter()
secondStoreServer.configureURLs(secureScheme: false, domain: "127.0.0.1:8000")
secondStoreServer.tokenKeychain = MockKeychainStore(fileName: "token.json")
let _: CustomUser = try await secondStoreServer.service().login(username: self.username, password: self.password)
#expect(StoreCenter.main.isAuthenticated)
#expect(secondStoreServer.isAuthenticated)
}
@Test func testWebsocketSynchronization() async throws {
let secondStoreServer = StoreCenter()
secondStoreServer.configureURLs(secureScheme: false, domain: "127.0.0.1:8000")
secondStoreServer.tokenKeychain = MockKeychainStore(fileName: "token.json")
let events = DataStore.shared.events
try await DataStore.shared.events.deleteAsync(contentOfs: Array(events))
}
}

@ -1,327 +0,0 @@
//
// DataAccessSyncTests.swift
// PadelClubDataTests
//
// Created by Laurent Morvillier on 02/05/2025.
//
import Testing
@testable import PadelClubData
@testable import LeStorage
struct SyncDataAccessTests {
let username1: String = "UserDataTests"
let password1: String = "MyPass1234--"
let username2: String = "seconduser"
let password2: String = "MyPass1234--"
var secondStoreCenter: StoreCenter
init() async throws {
FileManager.default.deleteDirectoryInDocuments(directoryName: "storage")
FileManager.default.deleteDirectoryInDocuments(directoryName: "storage-2")
self.secondStoreCenter = StoreCenter(directoryName: "storage-2")
self.secondStoreCenter.configureURLs(secureScheme: false, domain: "127.0.0.1:8000", webSockets: false, useSynchronization: true)
self.secondStoreCenter.tokenKeychain = MockKeychainStore(fileName: "storage-2/token.json")
self.secondStoreCenter.deviceKeychain = MockKeychainStore(fileName: "storage-2/device.json")
try self.secondStoreCenter.deviceKeychain.add(value: UUID().uuidString)
self.secondStoreCenter.classProject = "PadelClubData"
let token2 = try? self.secondStoreCenter.rawTokenShouldNotBeUsed()
if token2 == nil {
try await self.login(storeCenter: self.secondStoreCenter, username: self.username2, password: self.password2)
}
StoreCenter.main.configureURLs(secureScheme: false, domain: "127.0.0.1:8000", webSockets: false, useSynchronization: true)
StoreCenter.main.tokenKeychain = MockKeychainStore(fileName: "storage/token.json")
StoreCenter.main.deviceKeychain = MockKeychainStore(fileName: "storage/device.json")
try StoreCenter.main.deviceKeychain.add(value: UUID().uuidString)
StoreCenter.main.classProject = "PadelClubData"
let token = try? StoreCenter.main.rawTokenShouldNotBeUsed()
if token == nil {
try await self.login(storeCenter: StoreCenter.main, username: self.username1, password: self.password1)
}
}
mutating func login(storeCenter: StoreCenter, username: String, password: String) async throws {
let _: CustomUser = try await storeCenter.service().login(username: username, password: password)
}
@Test func testSetup() async throws {
#expect(StoreCenter.main.isAuthenticated)
#expect(self.secondStoreCenter.isAuthenticated)
guard let userId1 = StoreCenter.main.userId else {
throw TestError.notAuthenticated
}
guard let userId2 = self.secondStoreCenter.userId else {
throw TestError.notAuthenticated
}
#expect(userId1 != userId2)
}
/// In this test, the first user:
/// - creates an event and a tournament
/// - shares the tournament with a second user
/// - remove the sharing with the second user
/// We test that the data is properly received and removed upon the sharing actions
@Test func testTournamentSharing() async throws {
guard let userId1 = StoreCenter.main.userId else {
throw TestError.notAuthenticated
}
guard let userId2 = self.secondStoreCenter.userId else {
throw TestError.notAuthenticated
}
// Setup
let eventColA: SyncedCollection<Event> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let tournamentColA: SyncedCollection<Tournament> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let eventColB: SyncedCollection<Event> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
let tournamentColB: SyncedCollection<Tournament> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
if let dataAccessCollection = StoreCenter.main.dataAccessCollection {
try await dataAccessCollection.deleteAsync(contentOfs: Array(dataAccessCollection))
}
try await eventColA.deleteAsync(contentOfs: Array(eventColA))
try await tournamentColA.deleteAsync(contentOfs: Array(tournamentColA))
let _ = try await self.secondStoreCenter.testSynchronizeOnceAsync()
#expect(eventColB.count == 0)
#expect(tournamentColB.count == 0)
// Create
let eventA = Event(creator: userId1)
try await eventColA.addOrUpdateAsync(instance: eventA)
let tournamentA = Tournament(event: eventA.id, name: "P100")
try await tournamentColA.addOrUpdateAsync(instance: tournamentA)
// Share with user2
try await StoreCenter.main.setAuthorizedUsersAsync(for: tournamentA, users: [userId2])
var dataB = try await self.secondStoreCenter.testSynchronizeOnceAsync()
var syncDataB = try SyncData(data: dataB, storeCenter: self.secondStoreCenter)
#expect(syncDataB.grants.count == 2)
#expect(eventColB.count == 1)
#expect(tournamentColB.count == 1)
// Remove sharing from user2
try await StoreCenter.main.setAuthorizedUsersAsync(for: tournamentA, users: [])
dataB = try await self.secondStoreCenter.testSynchronizeOnceAsync()
syncDataB = try SyncData(data: dataB, storeCenter: self.secondStoreCenter)
#expect(syncDataB.revocations.count == 1)
#expect(syncDataB.revocationParents.count == 1)
#expect(eventColB.count == 0)
#expect(tournamentColB.count == 0)
let dataAccesses: [DataAccess] = try await StoreCenter.main.service().get()
#expect(dataAccesses.count == 0)
}
/// In this test, the first user:
/// - creates a club and 2 events in that club
/// - shares both events with a second user
/// - removes the sharing of 1 event
/// Here we want to test that the Club instance remains even if one event is removed from the second user
@Test func testSharedRelationship() async throws {
guard let userId1 = StoreCenter.main.userId else {
throw TestError.notAuthenticated
}
guard let userId2 = self.secondStoreCenter.userId else {
throw TestError.notAuthenticated
}
// Setup
let eventColA: SyncedCollection<Event> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let clubColA: SyncedCollection<Club> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let eventColB: SyncedCollection<Event> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
let clubColB: SyncedCollection<Club> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
if let dataAccessCollection = StoreCenter.main.dataAccessCollection {
try await dataAccessCollection.deleteAsync(contentOfs: Array(dataAccessCollection))
}
try await eventColA.deleteAsync(contentOfs: Array(eventColA))
try await clubColA.deleteAsync(contentOfs: Array(clubColA))
let _ = try await self.secondStoreCenter.testSynchronizeOnceAsync()
#expect(eventColB.count == 0)
#expect(clubColB.count == 0)
// Create
let clubA = Club(creator: userId1, name: "Club A", acronym: "CA")
try await clubColA.addOrUpdateAsync(instance: clubA)
let event1A = Event(creator: userId1, club: clubA.id, name: "event 1")
let event2A = Event(creator: userId1, club: clubA.id, name: "event 2")
try await eventColA.addOrUpdateAsync(contentOfs: [event1A, event2A])
// Share with user2
try await StoreCenter.main.setAuthorizedUsersAsync(for: event1A, users: [userId2])
try await StoreCenter.main.setAuthorizedUsersAsync(for: event2A, users: [userId2])
var dataB = try await self.secondStoreCenter.testSynchronizeOnceAsync()
var syncDataB = try SyncData(data: dataB, storeCenter: self.secondStoreCenter)
#expect(syncDataB.grants.count == 2)
let clubGrants = syncDataB.grants.first { $0.type == Club.self }
let eventGrants = syncDataB.grants.first { $0.type == Event.self }
#expect(clubGrants?.items.count == 1)
#expect(eventGrants?.items.count == 2)
#expect(eventColB.count == 2)
#expect(clubColB.count == 1)
// Remove sharing from user2
try await StoreCenter.main.setAuthorizedUsersAsync(for: event1A, users: [])
dataB = try await self.secondStoreCenter.testSynchronizeOnceAsync()
syncDataB = try SyncData(data: dataB, storeCenter: self.secondStoreCenter)
#expect(syncDataB.revocations.count == 1)
#expect(syncDataB.revocationParents.count == 1)
#expect(eventColB.count == 1)
#expect(clubColB.count == 1) // club remains because used in event2A
}
/// In this test, the first user:
/// - creates one event and 2 clubs
/// - shares the event with a second user
/// - changes the club on the event
/// Here we want to test that the first Club is removed and the second one is received
@Test func testRelationshipChange() async throws {
guard let userId1 = StoreCenter.main.userId else {
throw TestError.notAuthenticated
}
guard let userId2 = self.secondStoreCenter.userId else {
throw TestError.notAuthenticated
}
// Setup
let eventColA: SyncedCollection<Event> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let clubColA: SyncedCollection<Club> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let eventColB: SyncedCollection<Event> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
let clubColB: SyncedCollection<Club> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
if let dataAccessCollection = StoreCenter.main.dataAccessCollection {
try await dataAccessCollection.deleteAsync(contentOfs: Array(dataAccessCollection))
}
try await eventColA.deleteAsync(contentOfs: Array(eventColA))
try await clubColA.deleteAsync(contentOfs: Array(clubColA))
let _ = try await self.secondStoreCenter.testSynchronizeOnceAsync()
#expect(eventColB.count == 0)
#expect(clubColB.count == 0)
// Create
let club1A = Club(creator: userId1, name: "Club 1", acronym: "C1")
try await clubColA.addOrUpdateAsync(instance: club1A)
let club2A = Club(creator: userId1, name: "Club 2", acronym: "C2")
try await clubColA.addOrUpdateAsync(instance: club2A)
let eventA = Event(creator: userId1, club: club1A.id, name: "event 1")
try await eventColA.addOrUpdateAsync(instance: eventA)
// Share with user2
try await StoreCenter.main.setAuthorizedUsersAsync(for: eventA, users: [userId2])
let _ = try await self.secondStoreCenter.testSynchronizeOnceAsync()
#expect(eventColB.count == 1)
#expect(clubColB.count == 1)
// Change the club
eventA.club = club2A.id
try await eventColA.addOrUpdateAsync(instance: eventA)
let dataB = try await self.secondStoreCenter.testSynchronizeOnceAsync()
let syncDataB = try SyncData(data: dataB, storeCenter: self.secondStoreCenter)
#expect(syncDataB.sharedRelationshipSets.count == 1)
#expect(syncDataB.sharedRelationshipRemovals.count == 1)
#expect(eventColB.first?.club == club2A.id)
}
/// In this test, the first user:
/// - creates one event
/// - shares the event with a second user
/// The second user:
/// - changes the club
/// Here we want to test that the first Club is removed and the second one is received
@Test func testRelationshipChangesByAgent() async throws {
guard let userId1 = StoreCenter.main.userId else {
throw TestError.notAuthenticated
}
guard let userId2 = self.secondStoreCenter.userId else {
throw TestError.notAuthenticated
}
// Setup
let eventColA: SyncedCollection<Event> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let clubColA: SyncedCollection<Club> = await StoreCenter.main.mainStore.asyncLoadingSynchronizedCollection()
let eventColB: SyncedCollection<Event> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
let clubColB: SyncedCollection<Club> = await self.secondStoreCenter.mainStore.asyncLoadingSynchronizedCollection()
if let dataAccessCollection = StoreCenter.main.dataAccessCollection {
try await dataAccessCollection.deleteAsync(contentOfs: Array(dataAccessCollection))
}
try await eventColA.deleteAsync(contentOfs: Array(eventColA))
try await clubColA.deleteAsync(contentOfs: Array(clubColA))
let _ = try await self.secondStoreCenter.testSynchronizeOnceAsync()
#expect(eventColB.count == 0)
#expect(clubColB.count == 0)
// Create
let clubA = Club(creator: userId1, name: "Club 1", acronym: "C1")
try await clubColA.addOrUpdateAsync(instance: clubA)
let eventA = Event(creator: userId1, club: clubA.id, name: "event 1")
try await eventColA.addOrUpdateAsync(instance: eventA)
// Share with user2
try await StoreCenter.main.setAuthorizedUsersAsync(for: eventA, users: [userId2])
let _ = try await self.secondStoreCenter.testSynchronizeOnceAsync()
guard let eventB = eventColB.first else {
throw TestError.missingEvent
}
#expect(eventA.id == eventB.id)
#expect(clubColB.count == 1)
// Second user changes the club
let club2B = Club(creator: userId2, name: "Club 2", acronym: "C2")
try await clubColB.addOrUpdateAsync(instance: club2B)
eventB.club = club2B.id
try await eventColB.addOrUpdateAsync(instance: eventB)
let dataA = try await StoreCenter.main.testSynchronizeOnceAsync()
let syncDataA = try SyncData(data: dataA, storeCenter: StoreCenter.main)
// #expect(syncDataA.sharedRelationshipSets.count == 1)
// #expect(syncDataA.sharedRelationshipRemovals.count == 1)
#expect(eventA.club == club2B.id)
#expect(clubColB.count == 1)
}
}
Loading…
Cancel
Save