Skip to content

Commit 0846c2e

Browse files
committed
Deflake JmsIO tests
* Split unit tests not requiring a broker out of JmsIO * Run messaging xlang Python postcommit on single Python version * Update website about io support status
1 parent 5c58b58 commit 0846c2e

6 files changed

Lines changed: 260 additions & 177 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"comment": "Modify this file in a trivial way to cause this test suite to run",
3-
"modification": 6
3+
"modification": 7
44
}

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
* Upgraded Iceberg dependency to 1.11.0 (Java) ([#38925](https://github.com/apache/beam/issues/38925)).
6868
* Support for X source added (Java/Python) ([#X](https://github.com/apache/beam/issues/X)).
6969
* Add ArrowFlight IO (Java) ([#20116](https://github.com/apache/beam/issues/20116)).
70+
* (Python) JmsIO (IBM MQ, ActiveMQ, and other providers) is now supported in Python via cross-language ([#30716](https://github.com/apache/beam/issues/30716)).
7071

7172
## New Features / Improvements
7273

sdks/java/io/jms/src/test/java/org/apache/beam/sdk/io/jms/JmsIOTest.java

Lines changed: 3 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,20 @@
3232
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
3333
import static org.hamcrest.Matchers.hasProperty;
3434
import static org.hamcrest.Matchers.is;
35-
import static org.hamcrest.Matchers.isA;
3635
import static org.hamcrest.Matchers.lessThan;
3736
import static org.hamcrest.core.StringContains.containsString;
3837
import static org.hamcrest.object.HasToString.hasToString;
3938
import static org.junit.Assert.assertEquals;
40-
import static org.junit.Assert.assertFalse;
4139
import static org.junit.Assert.assertNotNull;
4240
import static org.junit.Assert.assertNull;
4341
import static org.junit.Assert.assertTrue;
4442
import static org.junit.Assert.fail;
45-
import static org.mockito.ArgumentMatchers.any;
46-
import static org.mockito.ArgumentMatchers.anyLong;
47-
import static org.mockito.ArgumentMatchers.eq;
4843
import static org.mockito.Mockito.mock;
4944
import static org.mockito.Mockito.times;
5045
import static org.mockito.Mockito.verify;
51-
import static org.mockito.Mockito.verifyNoMoreInteractions;
5246
import static org.mockito.Mockito.when;
5347

5448
import java.io.IOException;
55-
import java.io.NotSerializableException;
5649
import java.io.Serializable;
5750
import java.lang.reflect.Proxy;
5851
import java.nio.ByteBuffer;
@@ -66,8 +59,6 @@
6659
import java.util.HashSet;
6760
import java.util.List;
6861
import java.util.Set;
69-
import java.util.concurrent.ScheduledExecutorService;
70-
import java.util.concurrent.TimeUnit;
7162
import java.util.concurrent.atomic.AtomicInteger;
7263
import java.util.function.Function;
7364
import javax.jms.BytesMessage;
@@ -84,7 +75,6 @@
8475
import org.apache.activemq.command.ActiveMQMessage;
8576
import org.apache.activemq.util.Callback;
8677
import org.apache.beam.sdk.PipelineResult;
87-
import org.apache.beam.sdk.coders.Coder;
8878
import org.apache.beam.sdk.coders.SerializableCoder;
8979
import org.apache.beam.sdk.coders.StringUtf8Coder;
9080
import org.apache.beam.sdk.io.UnboundedSource;
@@ -94,16 +84,12 @@
9484
import org.apache.beam.sdk.metrics.MetricNameFilter;
9585
import org.apache.beam.sdk.metrics.MetricQueryResults;
9686
import org.apache.beam.sdk.metrics.MetricsFilter;
97-
import org.apache.beam.sdk.options.ExecutorOptions;
98-
import org.apache.beam.sdk.options.PipelineOptions;
9987
import org.apache.beam.sdk.options.PipelineOptionsFactory;
100-
import org.apache.beam.sdk.testing.CoderProperties;
10188
import org.apache.beam.sdk.testing.PAssert;
10289
import org.apache.beam.sdk.testing.TestPipeline;
10390
import org.apache.beam.sdk.transforms.Count;
10491
import org.apache.beam.sdk.transforms.Create;
10592
import org.apache.beam.sdk.transforms.SerializableBiFunction;
106-
import org.apache.beam.sdk.util.SerializableUtils;
10793
import org.apache.beam.sdk.values.PCollection;
10894
import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Throwables;
10995
import org.apache.qpid.jms.JmsAcknowledgeCallback;
@@ -117,7 +103,6 @@
117103
import org.junit.Test;
118104
import org.junit.runner.RunWith;
119105
import org.junit.runners.Parameterized;
120-
import org.mockito.ArgumentCaptor;
121106
import org.mockito.Mockito;
122107
import org.slf4j.Logger;
123108
import org.slf4j.LoggerFactory;
@@ -163,9 +148,9 @@ public static Collection<Object[]> connectionFactories() {
163148
private ConnectionFactory connectionFactory;
164149
private final Class<? extends ConnectionFactory> connectionFactoryClass;
165150
private ConnectionFactory connectionFactoryWithSyncAcksAndWithoutPrefetch;
166-
private final String brokerUrl;
167-
private final Integer brokerPort;
168-
private final String forceAsyncAcksParam;
151+
private String brokerUrl;
152+
private String forceAsyncAcksParam;
153+
private int brokerPort;
169154

170155
public JmsIOTest(
171156
String brokerUrl,
@@ -252,20 +237,6 @@ public void testReadMessages() throws Exception {
252237
assertQueueIsEmpty();
253238
}
254239

255-
@Test
256-
public void testPipelineWithNonSerializableCF() {
257-
SerializableUtils.ensureSerializable(
258-
JmsIO.read()
259-
.withConnectionFactoryProviderFn(__ -> new MockNonSerializableConnectionFactory()));
260-
try {
261-
SerializableUtils.ensureSerializable(
262-
JmsIO.read().withConnectionFactory(new MockNonSerializableConnectionFactory()));
263-
fail();
264-
} catch (Exception e) {
265-
assertThat(Throwables.getRootCause(e), isA(NotSerializableException.class));
266-
}
267-
}
268-
269240
@Test
270241
public void testReadMessagesWithCFProviderFn() throws Exception {
271242
long count = 5;
@@ -522,32 +493,6 @@ public void testWriteDynamicMessage() throws Exception {
522493
assertEquals(100, count);
523494
}
524495

525-
@Test
526-
public void testSplitForQueue() throws Exception {
527-
JmsIO.Read read = JmsIO.read().withQueue(QUEUE);
528-
PipelineOptions pipelineOptions = PipelineOptionsFactory.create();
529-
int desiredNumSplits = 5;
530-
JmsIO.UnboundedJmsSource initialSource = new JmsIO.UnboundedJmsSource(read);
531-
List<JmsIO.UnboundedJmsSource> splits = initialSource.split(desiredNumSplits, pipelineOptions);
532-
// in the case of a queue, we have concurrent consumers by default, so the initial number
533-
// splits is equal to the desired number of splits
534-
assertEquals(desiredNumSplits, splits.size());
535-
}
536-
537-
@Test
538-
public void testSplitForTopic() throws Exception {
539-
JmsIO.Read read = JmsIO.read().withTopic(TOPIC);
540-
PipelineOptions pipelineOptions = PipelineOptionsFactory.create();
541-
int desiredNumSplits = 5;
542-
JmsIO.UnboundedJmsSource initialSource = new JmsIO.UnboundedJmsSource(read);
543-
List<JmsIO.UnboundedJmsSource> splits = initialSource.split(desiredNumSplits, pipelineOptions);
544-
// in the case of a topic, we can have only a unique subscriber on the topic per pipeline
545-
// else it means we can have duplicate messages (all subscribers on the topic receive every
546-
// message).
547-
// So, whatever the desizedNumSplits is, the actual number of splits should be 1.
548-
assertEquals(1, splits.size());
549-
}
550-
551496
private boolean advanceWithRetry(UnboundedSource.UnboundedReader reader) throws IOException {
552497
for (int attempt = 0; attempt < 10; attempt++) {
553498
if (reader.advance()) {
@@ -685,63 +630,6 @@ public void testCheckpointMarkAndFinalizeSeparatelyClientAcknowledgeUnsafe() thr
685630
assertEquals(5, count(QUEUE));
686631
}
687632

688-
@Test
689-
public void testJmsCheckpointMarkIndividualAcknowledgeAllMessages() throws Exception {
690-
Message msg1 = Mockito.mock(Message.class);
691-
Message msg2 = Mockito.mock(Message.class);
692-
Message msg3 = Mockito.mock(Message.class);
693-
694-
JmsCheckpointMark.Preparer preparer =
695-
JmsCheckpointMark.newPreparer(JmsIO.AcknowledgeMode.INDIVIDUAL_ACKNOWLEDGE);
696-
preparer.add(msg1);
697-
preparer.add(msg2);
698-
preparer.add(msg3);
699-
700-
AtomicInteger activeCheckpoints = new AtomicInteger(0);
701-
JmsCheckpointMark mark =
702-
preparer.newCheckpoint(
703-
null, null, JmsIO.AcknowledgeMode.INDIVIDUAL_ACKNOWLEDGE, activeCheckpoints);
704-
assertNotNull(mark.getMessages());
705-
assertEquals(3, mark.getMessages().size());
706-
assertNull(mark.getConsumer());
707-
assertNull(mark.getSession());
708-
assertEquals(1, activeCheckpoints.get());
709-
710-
mark.finalizeCheckpoint();
711-
712-
Mockito.verify(msg1, Mockito.times(1)).acknowledge();
713-
Mockito.verify(msg2, Mockito.times(1)).acknowledge();
714-
Mockito.verify(msg3, Mockito.times(1)).acknowledge();
715-
assertEquals(0, activeCheckpoints.get());
716-
}
717-
718-
@Test
719-
public void testJmsCheckpointMarkClientAcknowledgeUnsafeNoSessionRecreation() throws Exception {
720-
Message msg1 = Mockito.mock(Message.class);
721-
Message msg2 = Mockito.mock(Message.class);
722-
723-
JmsCheckpointMark.Preparer preparer =
724-
JmsCheckpointMark.newPreparer(JmsIO.AcknowledgeMode.CLIENT_ACKNOWLEDGE_UNSAFE);
725-
preparer.add(msg1);
726-
preparer.add(msg2);
727-
728-
AtomicInteger activeCheckpoints = new AtomicInteger(0);
729-
JmsCheckpointMark mark =
730-
preparer.newCheckpoint(
731-
null, null, JmsIO.AcknowledgeMode.CLIENT_ACKNOWLEDGE_UNSAFE, activeCheckpoints);
732-
assertNotNull(mark.getMessages());
733-
assertEquals(1, mark.getMessages().size());
734-
assertNull(mark.getConsumer());
735-
assertNull(mark.getSession());
736-
assertEquals(1, activeCheckpoints.get());
737-
738-
mark.finalizeCheckpoint();
739-
740-
Mockito.verify(msg2, Mockito.times(1)).acknowledge();
741-
Mockito.verify(msg1, Mockito.never()).acknowledge();
742-
assertEquals(0, activeCheckpoints.get());
743-
}
744-
745633
private JmsIO.UnboundedJmsReader setupReaderForTest() throws JMSException {
746634
return setupReaderForTest(null);
747635
}
@@ -890,17 +778,6 @@ public void testCheckpointMarkSafety() throws Exception {
890778
runner.join();
891779
}
892780

893-
/** Test the checkpoint mark default coder, which is actually AvroCoder. */
894-
@Test
895-
public void testCheckpointMarkDefaultCoder() throws Exception {
896-
JmsCheckpointMark jmsCheckpointMark =
897-
JmsCheckpointMark.newPreparer(JmsIO.AcknowledgeMode.CLIENT_ACKNOWLEDGE)
898-
.newCheckpoint(null, null, JmsIO.AcknowledgeMode.CLIENT_ACKNOWLEDGE, null);
899-
Coder coder = new JmsIO.UnboundedJmsSource(null).getCheckpointMarkCoder();
900-
CoderProperties.coderSerializable(coder);
901-
CoderProperties.coderDecodeEncodeEqual(coder, jmsCheckpointMark);
902-
}
903-
904781
@Test
905782
public void testDefaultAutoscaler() throws IOException {
906783
JmsIO.Read spec =
@@ -945,53 +822,6 @@ public void testCustomAutoscaler() throws IOException {
945822
verify(autoScaler, times(1)).stop();
946823
}
947824

948-
@Test
949-
public void testCloseWithTimeout() throws IOException, JMSException {
950-
Duration closeTimeout = Duration.millis(2000L);
951-
JmsIO.Read spec =
952-
JmsIO.read()
953-
.withConnectionFactory(connectionFactory)
954-
.withUsername(USERNAME)
955-
.withPassword(PASSWORD)
956-
.withQueue(QUEUE)
957-
.withCloseTimeout(closeTimeout);
958-
959-
JmsIO.UnboundedJmsSource source = new JmsIO.UnboundedJmsSource(spec);
960-
961-
ScheduledExecutorService mockScheduledExecutorService =
962-
Mockito.mock(ScheduledExecutorService.class);
963-
ExecutorOptions options = PipelineOptionsFactory.as(ExecutorOptions.class);
964-
options.setScheduledExecutorService(mockScheduledExecutorService);
965-
ArgumentCaptor<Runnable> runnableArgumentCaptor = ArgumentCaptor.forClass(Runnable.class);
966-
when(mockScheduledExecutorService.schedule(
967-
runnableArgumentCaptor.capture(), anyLong(), any(TimeUnit.class)))
968-
.thenReturn(null /* unused */);
969-
970-
JmsIO.UnboundedJmsReader reader = source.createReader(options, null);
971-
reader.start();
972-
assertFalse(getDiscardedValue(reader));
973-
reader.checkpointMarkPreparer.add(Mockito.mock(Message.class));
974-
CheckpointMark mark = reader.getCheckpointMark();
975-
reader.close();
976-
assertTrue(getDiscardedValue(reader));
977-
verify(mockScheduledExecutorService)
978-
.schedule(any(Runnable.class), eq(1L), eq(TimeUnit.SECONDS));
979-
mark.finalizeCheckpoint();
980-
runnableArgumentCaptor.getValue().run();
981-
assertTrue(getDiscardedValue(reader));
982-
verifyNoMoreInteractions(mockScheduledExecutorService);
983-
}
984-
985-
private boolean getDiscardedValue(JmsIO.UnboundedJmsReader reader) {
986-
JmsCheckpointMark.Preparer preparer = reader.checkpointMarkPreparer;
987-
preparer.lock.readLock().lock();
988-
try {
989-
return preparer.discarded;
990-
} finally {
991-
preparer.lock.readLock().unlock();
992-
}
993-
}
994-
995825
@Test
996826
public void testDiscardCheckpointMark() throws Exception {
997827
Connection connection =

0 commit comments

Comments
 (0)