Skip to content

Commit 1a3b35c

Browse files
committed
[ECO-5386] Added unit tests for Liveobject serialization
1. Created dummy objectmessage fixture for different data types 2. Implemented unit tests with given fixture for various cases
1 parent 53116e8 commit 1a3b35c

3 files changed

Lines changed: 363 additions & 6 deletions

File tree

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package io.ably.lib.objects.unit
2+
3+
import com.google.gson.Gson
4+
import com.google.gson.GsonBuilder
5+
import com.google.gson.JsonElement
6+
import com.google.gson.JsonNull
7+
import io.ably.lib.objects.unit.fixtures.*
8+
import io.ably.lib.types.ProtocolMessage
9+
import io.ably.lib.types.ProtocolMessage.ActionSerializer
10+
import io.ably.lib.types.ProtocolSerializer
11+
import io.ably.lib.util.Serialisation
12+
import kotlinx.coroutines.test.runTest
13+
import org.junit.Assert.assertEquals
14+
import org.junit.Test
15+
import kotlin.test.assertNotNull
16+
import kotlin.test.assertNull
17+
import kotlin.test.assertTrue
18+
19+
class ObjectMessageSerializationTest {
20+
21+
private val objectMessages = arrayOf(
22+
dummyObjectMessageWithStringData(),
23+
dummyObjectMessageWithBinaryData(),
24+
dummyObjectMessageWithNumberData(),
25+
dummyObjectMessageWithBooleanData(),
26+
dummyObjectMessageWithJsonObjectData(),
27+
dummyObjectMessageWithJsonArrayData()
28+
)
29+
30+
@Test
31+
fun testObjectMessageMsgPackSerialization() = runTest {
32+
val protocolMessage = ProtocolMessage()
33+
protocolMessage.action = ProtocolMessage.Action.`object`
34+
protocolMessage.state = objectMessages
35+
36+
// Serialize the ProtocolMessage containing ObjectMessages to MsgPack format
37+
val serializedProtoMsg = ProtocolSerializer.writeMsgpack(protocolMessage)
38+
assertNotNull(serializedProtoMsg)
39+
40+
// Deserialize back to ProtocolMessage
41+
val deserializedProtoMsg = ProtocolSerializer.readMsgpack(serializedProtoMsg)
42+
assertNotNull(deserializedProtoMsg)
43+
44+
deserializedProtoMsg.state.zip(objectMessages).forEach { (actual, expected) ->
45+
assertEquals(expected, actual as? io.ably.lib.objects.ObjectMessage)
46+
}
47+
}
48+
49+
@Test
50+
fun testObjectMessageJsonSerialization() = runTest {
51+
val protocolMessage = ProtocolMessage()
52+
protocolMessage.action = ProtocolMessage.Action.`object`
53+
protocolMessage.state = objectMessages
54+
55+
// Serialize the ProtocolMessage containing ObjectMessages to MsgPack format
56+
val serializedProtoMsg = ProtocolSerializer.writeJSON(protocolMessage).toString(Charsets.UTF_8)
57+
assertNotNull(serializedProtoMsg)
58+
59+
// Deserialize back to ProtocolMessage
60+
val deserializedProtoMsg = ProtocolSerializer.fromJSON(serializedProtoMsg)
61+
assertNotNull(deserializedProtoMsg)
62+
63+
deserializedProtoMsg.state.zip(objectMessages).forEach { (actual, expected) ->
64+
assertEquals(expected, (actual as? io.ably.lib.objects.ObjectMessage))
65+
}
66+
}
67+
68+
@Test
69+
fun testOmitNullsInObjectMessageSerialization() = runTest {
70+
val objectMessage = dummyObjectMessageWithStringData()
71+
val objectMessageWithNullFields = objectMessage.copy(
72+
id = null,
73+
timestamp = null,
74+
clientId = "test-client",
75+
connectionId = "test-connection",
76+
extras = null,
77+
operation = null,
78+
objectState = null,
79+
serial = null,
80+
siteCode = null
81+
)
82+
val protocolMessage = ProtocolMessage()
83+
protocolMessage.action = ProtocolMessage.Action.`object`
84+
protocolMessage.state = arrayOf(objectMessageWithNullFields)
85+
86+
// check if Gson/Msgpack serialization omits null fields
87+
fun assertSerializedObjectMessage(serializedProtoMsg: String) {
88+
val deserializedProtoMsg = Gson().fromJson(serializedProtoMsg, JsonElement::class.java).asJsonObject
89+
val serializedObjectMessage = deserializedProtoMsg.get("state").asJsonArray[0].asJsonObject.toString()
90+
assertEquals("""{"clientId":"test-client","connectionId":"test-connection"}""", serializedObjectMessage)
91+
}
92+
93+
// Serialize using Gson
94+
val serializedProtoMsg = ProtocolSerializer.writeJSON(protocolMessage).toString(Charsets.UTF_8)
95+
assertSerializedObjectMessage(serializedProtoMsg)
96+
97+
// Serialize using MsgPack
98+
val serializedMsgpackBytes = ProtocolSerializer.writeMsgpack(protocolMessage)
99+
val serializedJsonStringFromMsgpackBytes = Serialisation.msgpackToGson(serializedMsgpackBytes).toString()
100+
assertSerializedObjectMessage(serializedJsonStringFromMsgpackBytes)
101+
}
102+
103+
@Test
104+
fun testSerializeEnumsIntoOrdinalValues() = runTest {
105+
val objectMessage = dummyObjectMessageWithStringData()
106+
val protocolMessage = ProtocolMessage()
107+
protocolMessage.action = ProtocolMessage.Action.`object`
108+
protocolMessage.state = arrayOf(objectMessage)
109+
110+
fun assertSerializedObjectMessage(serializedProtoMsg: String) {
111+
val deserializedProtoMsg = Gson().fromJson(serializedProtoMsg, JsonElement::class.java).asJsonObject
112+
val serializedObjectMessage = deserializedProtoMsg.get("state").asJsonArray[0].asJsonObject
113+
val operation = serializedObjectMessage.get("operation").asJsonObject
114+
assertTrue(operation.has("action"))
115+
assertEquals(0, operation.get("action").asInt) // Check if action is serialized as code
116+
}
117+
118+
// Serialize using Gson
119+
val serializedProtoMsg = ProtocolSerializer.writeJSON(protocolMessage).toString(Charsets.UTF_8)
120+
assertSerializedObjectMessage(serializedProtoMsg)
121+
// Serialize using MsgPack
122+
val serializedMsgpackBytes = ProtocolSerializer.writeMsgpack(protocolMessage)
123+
val serializedJsonStringFromMsgpackBytes = Serialisation.msgpackToGson(serializedMsgpackBytes).toString()
124+
assertSerializedObjectMessage(serializedJsonStringFromMsgpackBytes)
125+
}
126+
127+
@Test
128+
fun testHandleNullsInObjectMessageDeserialization() = runTest {
129+
val protocolMessage = ProtocolMessage()
130+
protocolMessage.id = "id"
131+
protocolMessage.action = ProtocolMessage.Action.`object`
132+
protocolMessage.state = null
133+
134+
// Serialize using Gson with serializeNulls enabled
135+
val gsonBuilderCreatingNulls = GsonBuilder()
136+
.registerTypeAdapter(ProtocolMessage.Action::class.java, ActionSerializer())
137+
.serializeNulls().create()
138+
139+
var protoMsgJsonObject = gsonBuilderCreatingNulls.toJsonTree(protocolMessage).asJsonObject
140+
assertTrue(protoMsgJsonObject.has("state"))
141+
assertEquals(JsonNull.INSTANCE, protoMsgJsonObject.get("state"))
142+
143+
var deserializedProtoMsg = ProtocolSerializer.fromJSON(protoMsgJsonObject.toString())
144+
assertNull(deserializedProtoMsg.state)
145+
146+
var serializedMsgpackBytes = Serialisation.gsonToMsgpack(protoMsgJsonObject)
147+
deserializedProtoMsg = ProtocolSerializer.readMsgpack(serializedMsgpackBytes)
148+
assertNull(deserializedProtoMsg.state)
149+
150+
// Create ObjectMessage and serialize in a way that resulting string/bytes include null fields
151+
val objectMessage = dummyObjectMessageWithStringData()
152+
val objectMessageWithNullFields = objectMessage.copy(
153+
id = null,
154+
timestamp = null,
155+
clientId = "test-client",
156+
connectionId = "test-connection",
157+
extras = null,
158+
operation = objectMessage.operation?.copy(
159+
initialValue = null, // initialValue set to null
160+
mapOp = objectMessage.operation.mapOp?.copy(
161+
data = null // objectData set to null
162+
)
163+
),
164+
objectState = null,
165+
serial = null,
166+
siteCode = null
167+
)
168+
protocolMessage.state = arrayOf(objectMessageWithNullFields)
169+
protoMsgJsonObject = gsonBuilderCreatingNulls.toJsonTree(protocolMessage).asJsonObject
170+
171+
// Check if gson deserialization works correctly
172+
deserializedProtoMsg = ProtocolSerializer.fromJSON(protoMsgJsonObject.toString())
173+
assertEquals(objectMessageWithNullFields, deserializedProtoMsg.state[0] as? io.ably.lib.objects.ObjectMessage)
174+
175+
// Check if msgpack deserialization works correctly
176+
serializedMsgpackBytes = Serialisation.gsonToMsgpack(protoMsgJsonObject)
177+
deserializedProtoMsg = ProtocolSerializer.readMsgpack(serializedMsgpackBytes)
178+
assertEquals(objectMessageWithNullFields, deserializedProtoMsg.state[0] as? io.ably.lib.objects.ObjectMessage)
179+
}
180+
}

live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.ably.lib.objects.unit
22

3+
import com.google.gson.JsonObject
34
import io.ably.lib.objects.*
45
import io.ably.lib.objects.ObjectData
56
import io.ably.lib.objects.ObjectMapOp
@@ -17,6 +18,7 @@ import kotlinx.coroutines.test.runTest
1718
import org.junit.Test
1819
import kotlin.test.assertEquals
1920
import kotlin.test.assertFailsWith
21+
import kotlin.text.toByteArray
2022

2123
class ObjectMessageSizeTest {
2224

@@ -32,10 +34,10 @@ class ObjectMessageSizeTest {
3234
timestamp = 1699123456789L, // Not counted in size calculation
3335
clientId = "test-client", // Size: 11 bytes (UTF-8 byte length)
3436
connectionId = "conn_98765", // Not counted in size calculation
35-
extras = mapOf( // Size: JSON serialization byte length
36-
"meta" to "data", // JSON: {"meta":"data","count":42}
37-
"count" to 42
38-
), // Total extras size: 26 bytes (verified by gson.toJson().length)
37+
extras = JsonObject().apply { // Size: JSON serialization byte length
38+
addProperty("meta", "data") // JSON: {"meta":"data","count":42}
39+
addProperty("count", 42)
40+
}, // Total extras size: 26 bytes (verified by gson.toJson().length)
3941
operation = ObjectOperation(
4042
action = ObjectOperationAction.MapCreate,
4143
objectId = "obj_54321", // Not counted in operation size
@@ -45,7 +47,6 @@ class ObjectMessageSizeTest {
4547
key = "mapKey", // Size: 6 bytes (UTF-8 byte length)
4648
data = ObjectData(
4749
objectId = "ref_obj", // Not counted in data size
48-
encoding = "utf-8", // Not counted in data size
4950
value = ObjectValue("sample") // Size: 6 bytes (UTF-8 byte length)
5051
) // Total ObjectData size: 6 bytes
5152
), // Total ObjectMapOp size: 6 + 6 = 12 bytes
@@ -80,7 +81,7 @@ class ObjectMessageSizeTest {
8081
), // Total ObjectCounter size: 8 bytes
8182

8283
nonce = "nonce123", // Not counted in operation size
83-
initialValue = Binary("initial".toByteArray()), // Not counted in operation size
84+
initialValue = Binary("some-value".toByteArray()), // Not counted in operation size
8485
initialValueEncoding = ProtocolMessageFormat.Json // Not counted in operation size
8586
), // Total ObjectOperation size: 12 + 8 + 26 + 8 = 54 bytes
8687

0 commit comments

Comments
 (0)