Skip to content

Commit d958011

Browse files
committed
adding Presence message support
1 parent 49bc57c commit d958011

File tree

3 files changed

+262
-0
lines changed

3 files changed

+262
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package realtime.pubsub;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
import java.util.Objects;
6+
7+
/**
8+
* A message representing a presence event.
9+
*/
10+
public class PresenceMessage {
11+
12+
private final String connectionId;
13+
private final String subject;
14+
private final List<String> permissions;
15+
private final PresenceStatus status;
16+
17+
private PresenceMessage(IncomingMessage message) {
18+
// Validate that the message is not null
19+
Objects.requireNonNull(message, "IncomingMessage cannot be null");
20+
21+
// Extract and validate the 'data' map
22+
Object dataObj = message.getData();
23+
if (!(dataObj instanceof Map<?, ?>)) {
24+
throw new IllegalArgumentException("message.data must be a Map");
25+
}
26+
@SuppressWarnings("unchecked")
27+
Map<String, Object> data = (Map<String, Object>) dataObj;
28+
29+
// Extract and validate the 'client' map
30+
Object clientObj = data.get("client");
31+
if (!(clientObj instanceof Map<?, ?>)) {
32+
throw new IllegalArgumentException("data.client must be a Map");
33+
}
34+
@SuppressWarnings("unchecked")
35+
Map<String, Object> client = (Map<String, Object>) clientObj;
36+
37+
// Extract and validate 'connectionId'
38+
Object connectionIdObj = client.get("connectionId");
39+
if (!(connectionIdObj instanceof String)) {
40+
throw new IllegalArgumentException("client.connectionId must be a String");
41+
}
42+
this.connectionId = (String) connectionIdObj;
43+
44+
// Extract and validate 'subject'
45+
Object subjectObj = client.get("subject");
46+
if (!(subjectObj instanceof String)) {
47+
throw new IllegalArgumentException("client.subject must be a String");
48+
}
49+
this.subject = (String) subjectObj;
50+
51+
// Extract and validate 'permissions'
52+
Object permissionsObj = client.get("permissions");
53+
if (permissionsObj != null && !(permissionsObj instanceof List<?>)) {
54+
throw new IllegalArgumentException("client.permissions must be a List");
55+
}
56+
@SuppressWarnings("unchecked")
57+
List<String> permissionsList = (List<String>) permissionsObj;
58+
this.permissions = permissionsList;
59+
60+
// Extract and validate the 'payload' map
61+
Object payloadObj = data.get("payload");
62+
if (!(payloadObj instanceof Map<?, ?>)) {
63+
throw new IllegalArgumentException("data.payload must be a Map");
64+
}
65+
@SuppressWarnings("unchecked")
66+
Map<String, Object> payload = (Map<String, Object>) payloadObj;
67+
68+
// Extract and validate 'status'
69+
Object statusObj = payload.get("status");
70+
if (!(statusObj instanceof String statusStr)) {
71+
throw new IllegalArgumentException("payload.status must be a String");
72+
}
73+
74+
// Map 'status' string to PresenceStatus enum
75+
this.status = switch (statusStr.toLowerCase()) {
76+
case "connected" -> PresenceStatus.CONNECTED;
77+
case "disconnected" -> PresenceStatus.DISCONNECTED;
78+
default -> throw new IllegalArgumentException("Unknown status: " + statusStr);
79+
};
80+
}
81+
82+
public String getConnectionId() {
83+
return connectionId;
84+
}
85+
86+
public String getSubject() {
87+
return subject;
88+
}
89+
90+
public List<String> getPermissions() {
91+
return permissions;
92+
}
93+
94+
public PresenceStatus getStatus() {
95+
return status;
96+
}
97+
98+
public static PresenceMessage from(IncomingMessage message) {
99+
return new PresenceMessage(message);
100+
}
101+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package realtime.pubsub;
2+
3+
public enum PresenceStatus {
4+
CONNECTED("connected"),
5+
DISCONNECTED("disconnected");
6+
7+
private final String status;
8+
9+
PresenceStatus(String status) {
10+
this.status = status;
11+
}
12+
13+
public String getStatus() {
14+
return status;
15+
}
16+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package realtime.pubsub;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.util.*;
6+
7+
import static org.junit.jupiter.api.Assertions.*;
8+
9+
/**
10+
* Unit tests for the PresenceMessage class.
11+
*/
12+
public class PresenceMessageTest {
13+
14+
@Test
15+
public void testGetConnectionId_ValidData() {
16+
// Arrange
17+
PresenceMessage presenceMessage = createPresenceMessage("conn123", "[email protected]", Arrays.asList("read", "write"), "connected");
18+
19+
// Act
20+
String connectionId = presenceMessage.getConnectionId();
21+
22+
// Assert
23+
assertEquals("conn123", connectionId);
24+
}
25+
26+
@Test
27+
public void testGetConnectionId_MissingData() {
28+
// Act & Assert
29+
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
30+
createPresenceMessage(null, "[email protected]", Arrays.asList("read", "write"), "connected");
31+
});
32+
assertEquals("client.connectionId must be a String", exception.getMessage());
33+
}
34+
35+
@Test
36+
public void testGetSubject_ValidData() {
37+
// Arrange
38+
PresenceMessage presenceMessage = createPresenceMessage("conn123", "[email protected]", Arrays.asList("read", "write"), "connected");
39+
40+
// Act
41+
String subject = presenceMessage.getSubject();
42+
43+
// Assert
44+
assertEquals("[email protected]", subject);
45+
}
46+
47+
@Test
48+
public void testGetSubject_MissingData() {
49+
// Act & Assert
50+
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
51+
createPresenceMessage("conn123", null, Arrays.asList("read", "write"), "connected");
52+
});
53+
assertEquals("client.subject must be a String", exception.getMessage());
54+
}
55+
56+
@Test
57+
public void testGetPermissions_ValidData() {
58+
// Arrange
59+
PresenceMessage presenceMessage = createPresenceMessage("conn123", "[email protected]", Arrays.asList("read", "write"), "connected");
60+
61+
// Act
62+
List<String> permissions = presenceMessage.getPermissions();
63+
64+
// Assert
65+
assertEquals(Arrays.asList("read", "write"), permissions);
66+
}
67+
68+
@Test
69+
public void testGetPermissions_MissingData() {
70+
// Arrange
71+
PresenceMessage presenceMessage = createPresenceMessage("conn123", "[email protected]", null, "connected");
72+
73+
// Act
74+
List<String> permissions = presenceMessage.getPermissions();
75+
76+
// Assert
77+
assertNull(permissions);
78+
}
79+
80+
@Test
81+
public void testGetStatus_ValidData() {
82+
// Arrange
83+
PresenceMessage presenceMessage = createPresenceMessage("conn123", "[email protected]", Arrays.asList("read", "write"), "connected");
84+
85+
// Act
86+
PresenceStatus status = presenceMessage.getStatus();
87+
88+
// Assert
89+
assertEquals(PresenceStatus.CONNECTED, status);
90+
}
91+
92+
@Test
93+
public void testGetStatus_InvalidStatus() {
94+
// Act & Assert
95+
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
96+
createPresenceMessage("conn123", "[email protected]", Arrays.asList("read", "write"), "UNKNOWN_STATUS");
97+
});
98+
assertEquals("Unknown status: UNKNOWN_STATUS", exception.getMessage());
99+
}
100+
101+
@Test
102+
public void testFrom_NullIncomingMessage() {
103+
// Act & Assert
104+
assertThrows(NullPointerException.class, () -> PresenceMessage.from(null));
105+
}
106+
107+
// Helper method to create a PresenceMessage instance with provided data
108+
private PresenceMessage createPresenceMessage(String connectionId, String subject, List<String> permissions, String status) {
109+
// Build client map
110+
Map<String, Object> clientMap = new HashMap<>();
111+
if (connectionId != null) {
112+
clientMap.put("connectionId", connectionId);
113+
}
114+
if (subject != null) {
115+
clientMap.put("subject", subject);
116+
}
117+
if (permissions != null) {
118+
clientMap.put("permissions", permissions);
119+
}
120+
121+
// Build payload map
122+
Map<String, Object> payloadMap = new HashMap<>();
123+
if (status != null) {
124+
payloadMap.put("status", status);
125+
}
126+
127+
// Build data map
128+
Map<String, Object> dataMap = new HashMap<>();
129+
dataMap.put("client", clientMap);
130+
dataMap.put("payload", payloadMap);
131+
132+
// Build message map
133+
Map<String, Object> messageMap = new HashMap<>();
134+
messageMap.put("topic", "presence");
135+
messageMap.put("messageType", "presence.status");
136+
messageMap.put("compression", false);
137+
messageMap.put("data", dataMap);
138+
139+
// Create IncomingMessage
140+
IncomingMessage incomingMessage = IncomingMessage.from(messageMap);
141+
142+
// Create and return PresenceMessage
143+
return PresenceMessage.from(incomingMessage);
144+
}
145+
}

0 commit comments

Comments
 (0)