Skip to content

Commit 8f8f504

Browse files
committed
fix(SMPP): added test to verify SMPP memory leak
1 parent 336dfaf commit 8f8f504

2 files changed

Lines changed: 72 additions & 7 deletions

File tree

sendium-core/src/main/java/gr/cytech/sendium/core/smpp/server/SmppServerBindHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ public void sessionBindRequested(
4646
sessionConfiguration.getPassword(),
4747
sessionConfiguration.getHost()
4848
);
49-
pendingSessionContexts.put(sessionId, context);
5049
String accountId = context.getAccountId();
5150

5251
checkIfConnectionsFromAccountIdIsOverLimit(accountId, context.getMaxConnections());
@@ -63,6 +62,7 @@ public void sessionBindRequested(
6362
String packageName = SmppServerBindHandler.class.getPackageName();
6463
sessionConfiguration.getLoggingOptions().setLoggerName(packageName);
6564
sessionConfiguration.getLoggingOptions().setLogParamPrefix("accId:" + accountId);
65+
pendingSessionContexts.put(sessionId, context);
6666
}
6767

6868
public void sessionCreated(
Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,36 @@
11
package gr.cytech.sendium.core.smpp.server;
22

33
import com.cloudhopper.smpp.SmppServerSession;
4+
import com.cloudhopper.smpp.SmppBindType;
5+
import com.cloudhopper.smpp.SmppSession;
46
import com.cloudhopper.smpp.SmppSessionConfiguration;
57
import com.cloudhopper.smpp.pdu.BaseBindResp;
8+
import com.cloudhopper.smpp.pdu.BindTransceiver;
9+
import com.cloudhopper.smpp.type.SmppProcessingException;
610
import gr.cytech.sendium.core.message.StandardMessage;
711
import org.junit.jupiter.api.BeforeEach;
812
import org.junit.jupiter.api.Test;
913
import org.junit.jupiter.api.extension.ExtendWith;
1014
import org.mockito.Mock;
1115
import org.mockito.junit.jupiter.MockitoExtension;
1216

17+
import java.lang.reflect.Field;
18+
import java.util.Map;
19+
20+
import static org.assertj.core.api.Assertions.assertThat;
21+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1322
import static org.mockito.ArgumentMatchers.any;
23+
import static org.mockito.ArgumentMatchers.anyString;
24+
import static org.mockito.Mockito.mock;
1425
import static org.mockito.Mockito.timeout;
1526
import static org.mockito.Mockito.verify;
1627
import static org.mockito.Mockito.when;
1728

1829
@ExtendWith(MockitoExtension.class)
1930
class SmppServerBindHandlerTest {
2031

32+
private static final String ACCOUNT_ID = "account-a";
33+
2134
@Mock private SmppServerWorker<StandardMessage> worker;
2235
@Mock private SmppAuthenticationProvider authProvider;
2336
@Mock private SubmitSmProcessor<StandardMessage> submitProcessor;
@@ -31,20 +44,72 @@ class SmppServerBindHandlerTest {
3144
@BeforeEach
3245
void setUp() {
3346
bindHandler = new SmppServerBindHandler<>(worker, authProvider, submitProcessor);
47+
}
48+
49+
@Test
50+
void sessionBindRequested_DoesNotRetainPendingContextsWhenBindIsRejectedBeforeSessionCreated() throws Exception {
3451
when(worker.getMaxConnectionsPerIP()).thenReturn(0);
35-
when(worker.getMessageStore()).thenReturn(messageStore);
36-
when(session.getConfiguration()).thenReturn(sessionConfiguration);
37-
when(sessionConfiguration.getName()).thenReturn("account-a");
38-
when(sessionConfiguration.getHost()).thenReturn("127.0.0.1");
39-
when(sessionConfiguration.getSystemId()).thenReturn("smpp-user");
40-
when(session.isBound()).thenReturn(true);
52+
addExistingConnectionForAccount(ACCOUNT_ID);
53+
54+
SmppSessionContext context = mock(SmppSessionContext.class);
55+
when(context.getAccountId()).thenReturn(ACCOUNT_ID);
56+
when(context.getMaxConnections()).thenReturn(1);
57+
when(authProvider.authenticate(anyString(), anyString(), anyString())).thenReturn(context);
58+
59+
int bindRequests = 100;
60+
for (int i = 0; i < bindRequests; i++) {
61+
Long sessionId = (long) i;
62+
SmppSessionConfiguration bindConfiguration = new SmppSessionConfiguration(
63+
SmppBindType.TRANSCEIVER,
64+
"smpp-user-" + i,
65+
"password"
66+
);
67+
bindConfiguration.setHost("127.0.0.2");
68+
69+
assertThatThrownBy(() -> bindHandler.sessionBindRequested(sessionId, bindConfiguration, new BindTransceiver()))
70+
.isInstanceOf(SmppProcessingException.class);
71+
}
72+
73+
assertThat(pendingSessionContexts()).isEmpty();
4174
}
4275

4376
@Test
4477
void sessionCreated_ReplaysUnpushedDlrsAfterSessionIsBound() throws Exception {
78+
stubSessionCreatedDefaults();
79+
4580
bindHandler.sessionCreated(1L, session, bindResponse);
4681

4782
verify(session).serverReady(any(SmppServerSessionHandler.class));
4883
verify(messageStore, timeout(1_000)).onClientConnected("smpp-user");
4984
}
85+
86+
private void stubSessionCreatedDefaults() {
87+
when(worker.getMaxConnectionsPerIP()).thenReturn(0);
88+
when(worker.getMessageStore()).thenReturn(messageStore);
89+
when(session.getConfiguration()).thenReturn(sessionConfiguration);
90+
when(sessionConfiguration.getName()).thenReturn(ACCOUNT_ID);
91+
when(sessionConfiguration.getHost()).thenReturn("127.0.0.1");
92+
when(sessionConfiguration.getSystemId()).thenReturn("smpp-user");
93+
when(session.isBound()).thenReturn(true);
94+
}
95+
96+
private void addExistingConnectionForAccount(String accountId) {
97+
SmppServerSessionHandler<StandardMessage> existingHandler = mock(SmppServerSessionHandler.class);
98+
when(existingHandler.getSession()).thenReturn(session);
99+
when(existingHandler.isBackupConnection()).thenReturn(false);
100+
when(session.getConfiguration()).thenReturn(sessionConfiguration);
101+
when(session.getBindType()).thenReturn(SmppBindType.TRANSCEIVER);
102+
when(session.getLocalType()).thenReturn(SmppSession.Type.SERVER);
103+
when(sessionConfiguration.getHost()).thenReturn("127.0.0.1");
104+
when(sessionConfiguration.getSystemId()).thenReturn("existing-smpp-user");
105+
106+
bindHandler.connections.addConnection(accountId, existingHandler);
107+
}
108+
109+
@SuppressWarnings("unchecked")
110+
private Map<Long, SmppSessionContext> pendingSessionContexts() throws NoSuchFieldException, IllegalAccessException {
111+
Field field = SmppServerBindHandler.class.getDeclaredField("pendingSessionContexts");
112+
field.setAccessible(true);
113+
return (Map<Long, SmppSessionContext>) field.get(bindHandler);
114+
}
50115
}

0 commit comments

Comments
 (0)