@@ -32,11 +32,25 @@ final class CRDTGossipReplicationClusteredTests: ClusteredActorSystemsXCTestCase
3232
3333 override func configureActorSystem( settings: inout ActorSystemSettings ) {
3434 settings. serialization. register ( CRDT . ORSet< String> . self )
35- settings. serialization. register ( CRDT . LWWMap< String, ValueHolder< String?>> . self )
36- settings. serialization. register ( CRDT . LWWRegister< ValueHolder< String?>> . self )
37- settings. serialization. register ( ValueHolder< String?> . self )
35+ settings. serialization. register ( CRDT . LWWMap< String, String?> . self )
36+ settings. serialization. register ( CRDT . LWWRegister< String?> . self )
37+ settings. serialization. register ( CodableExampleValue . self)
38+ settings. serialization. register ( CRDT . LWWMap< String, CodableExampleValue> . self )
39+ settings. serialization. register ( CRDT . LWWRegister< CodableExampleValue> . self )
40+ settings. serialization. register ( String ? . self)
3841 }
3942
43+ struct CodableExampleValue : Equatable , Codable , ExpressibleByStringLiteral {
44+ let value : String
45+
46+ init ( stringLiteral value: StringLiteralType ) {
47+ self . value = value
48+ }
49+ }
50+
51+ // ==== ----------------------------------------------------------------------------------------------------------------
52+ // MARK: Owns Set
53+
4054 enum OwnsSetMessage : NonTransportableActorMessage {
4155 case insert( String , CRDT . OperationConsistency )
4256 }
@@ -58,6 +72,9 @@ final class CRDTGossipReplicationClusteredTests: ClusteredActorSystemsXCTestCase
5872 }
5973 }
6074
75+ // ==== ----------------------------------------------------------------------------------------------------------------
76+ // MARK: Owns Counter
77+
6178 func ownsCounter( p: ActorTestProbe < CRDT . GCounter > ? ) -> Behavior < Int > {
6279 . setup { context in
6380 let counter : CRDT . ActorOwned < CRDT . GCounter > = CRDT . GCounter. makeOwned ( by: context, id: " counter " )
@@ -72,6 +89,9 @@ final class CRDTGossipReplicationClusteredTests: ClusteredActorSystemsXCTestCase
7289 }
7390 }
7491
92+ // ==== ----------------------------------------------------------------------------------------------------------------
93+ // MARK: Owns Map
94+
7595 enum OwnsMapMessage < Value: Codable > : NonTransportableActorMessage {
7696 case set( key: String , value: Value , CRDT . OperationConsistency )
7797 }
@@ -123,15 +143,36 @@ final class CRDTGossipReplicationClusteredTests: ClusteredActorSystemsXCTestCase
123143 try self . expectSet ( probe: p2, expected: [ " a " , " aa " , " b " ] )
124144 }
125145
126- struct ValueHolder < Value: Codable & Equatable > : Codable , Equatable {
127- let value : Value ?
128-
129- init ( _ value: Value ? = nil ) {
130- self . value = value
146+ func test_gossip_localLWWMapUpdate_toOtherNode( ) throws {
147+ let configure : ( inout ActorSystemSettings ) -> Void = { settings in
148+ settings. crdt. gossipInterval = . seconds( 1 )
149+ settings. crdt. gossipIntervalRandomFactor = 0 // no random factor, exactly 1second intervals
131150 }
151+ let first = self . setUpNode ( " first " , configure)
152+ let second = self . setUpNode ( " second " , configure)
153+ try self . joinNodes ( node: first, with: second, ensureMembers: . up)
154+
155+ let p1 = self . testKit ( first) . spawnTestProbe ( " probe-one " , expecting: CRDT . LWWMap< String, String?> . self )
156+ let p2 = self . testKit ( second) . spawnTestProbe ( " probe-two " , expecting: CRDT . LWWMap< String, String?> . self )
157+
158+ let one = try first. spawn ( " one " , self . ownsLWWMap ( p: p1, defaultValue: nil ) )
159+ let two = try second. spawn ( " two " , self . ownsLWWMap ( p: p2, defaultValue: nil ) )
160+
161+ one. tell ( . set( key: " a " , value: " foo " , . local) )
162+ one. tell ( . set( key: " aa " , value: nil , . local) )
163+
164+ let gossipOneExpectMap : [ String : String ? ] = [ " a " : . init( " foo " ) , " aa " : nil ]
165+ try self . expectMap ( probe: p1, expected: gossipOneExpectMap)
166+ try self . expectMap ( probe: p2, expected: gossipOneExpectMap)
167+
168+ two. tell ( . set( key: " b " , value: " bar " , . local) )
169+
170+ let gossipTwoExpectMap : [ String : String ? ] = [ " a " : " foo " , " aa " : nil , " b " : " bar " ]
171+ try self . expectMap ( probe: p1, expected: gossipTwoExpectMap)
172+ try self . expectMap ( probe: p2, expected: gossipTwoExpectMap)
132173 }
133174
134- func test_gossip_localLWWMapUpdate_toOtherNode ( ) throws {
175+ func test_gossip_localLWWMapUpdate_toOtherNode_codableValue ( ) throws {
135176 let configure : ( inout ActorSystemSettings ) -> Void = { settings in
136177 settings. crdt. gossipInterval = . seconds( 1 )
137178 settings. crdt. gossipIntervalRandomFactor = 0 // no random factor, exactly 1second intervals
@@ -140,24 +181,22 @@ final class CRDTGossipReplicationClusteredTests: ClusteredActorSystemsXCTestCase
140181 let second = self . setUpNode ( " second " , configure)
141182 try self . joinNodes ( node: first, with: second, ensureMembers: . up)
142183
143- let p1 = self . testKit ( first) . spawnTestProbe ( " probe-one " , expecting: CRDT . LWWMap< String, ValueHolder < String ?> >. self )
144- let p2 = self . testKit ( second) . spawnTestProbe ( " probe-two " , expecting: CRDT . LWWMap< String, ValueHolder < String ?> >. self )
184+ let p1 = self . testKit ( first) . spawnTestProbe ( " probe-one " , expecting: CRDT . LWWMap< String, CodableExampleValue > . self )
185+ let p2 = self . testKit ( second) . spawnTestProbe ( " probe-two " , expecting: CRDT . LWWMap< String, CodableExampleValue > . self )
145186
146- // TODO: JSON serialization blows up on Swift 5.2.4 Linux with top-level values so we must wrap (https://bugs.swift.org/browse/SR-13173). Change nilPlaceholder to `:String? = .none` once fixed
147- let nilPlaceholder = ValueHolder < String ? > ( )
148- let one = try first. spawn ( " one " , self . ownsLWWMap ( p: p1, defaultValue: nilPlaceholder) )
149- let two = try second. spawn ( " two " , self . ownsLWWMap ( p: p2, defaultValue: nilPlaceholder) )
187+ let one = try first. spawn ( " one " , self . ownsLWWMap ( p: p1, defaultValue: " <nil> " ) )
188+ let two = try second. spawn ( " two " , self . ownsLWWMap ( p: p2, defaultValue: " <nil> " ) )
150189
151- one. tell ( . set( key: " a " , value: . init ( " foo " ) , . local) )
152- one. tell ( . set( key: " aa " , value: nilPlaceholder , . local) )
190+ one. tell ( . set( key: " a " , value: " foo " , . local) )
191+ one. tell ( . set( key: " aa " , value: " baz " , . local) )
153192
154- let gossipOneExpectMap : [ String : ValueHolder < String ? > ] = [ " a " : . init ( " foo " ) , " aa " : nilPlaceholder ]
193+ let gossipOneExpectMap : [ String : CodableExampleValue ] = [ " a " : " foo " , " aa " : " baz " ]
155194 try self . expectMap ( probe: p1, expected: gossipOneExpectMap)
156195 try self . expectMap ( probe: p2, expected: gossipOneExpectMap)
157196
158- two. tell ( . set( key: " b " , value: . init ( " bar " ) , . local) )
197+ two. tell ( . set( key: " b " , value: " bar " , . local) )
159198
160- let gossipTwoExpectMap : [ String : ValueHolder < String ? > ] = [ " a " : . init ( " foo " ) , " aa " : nilPlaceholder , " b " : . init ( " bar " ) ]
199+ let gossipTwoExpectMap : [ String : CodableExampleValue ] = [ " a " : " foo " , " aa " : " baz " , " b " : " bar " ]
161200 try self . expectMap ( probe: p1, expected: gossipTwoExpectMap)
162201 try self . expectMap ( probe: p2, expected: gossipTwoExpectMap)
163202 }
@@ -294,11 +333,11 @@ final class CRDTGossipReplicationClusteredTests: ClusteredActorSystemsXCTestCase
294333 }
295334 }
296335
297- private func expectMap( probe: ActorTestProbe < CRDT . LWWMap < String , ValueHolder < String ? > > > , expected: [ String : ValueHolder < String ? > ] , file: StaticString = #file, line: UInt = #line) throws {
336+ private func expectMap< Value > ( probe: ActorTestProbe < CRDT . LWWMap < String , Value > > , expected: [ String : Value ] , file: StaticString = #file, line: UInt = #line) throws {
298337 let testKit : ActorTestKit = self . _testKits. first!
299338
300339 try testKit. eventually ( within: . seconds( 10 ) ) {
301- let replicated : CRDT . LWWMap < String , ValueHolder < String ? > > = try probe. expectMessage ( within: . seconds( 10 ) , file: file, line: line)
340+ let replicated : CRDT . LWWMap < String , Value > = try probe. expectMessage ( within: . seconds( 10 ) , file: file, line: line)
302341 pinfo ( " [ \( probe. name) ] received updated crdt: \( replicated) " )
303342
304343 guard expected == replicated. underlying else {
0 commit comments