/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gobblin.writer;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericRecord;
import org.testng.Assert;
import org.testng.annotations.Test;
import gobblin.configuration.ConfigurationKeys;
import gobblin.configuration.State;
import gobblin.source.extractor.CheckpointableWatermark;
import gobblin.source.extractor.DefaultCheckpointableWatermark;
import gobblin.source.extractor.RecordEnvelope;
import gobblin.source.extractor.extract.LongWatermark;
import gobblin.writer.test.TestPartitionAwareWriterBuilder;
import gobblin.writer.test.TestPartitioner;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test {@link gobblin.writer.PartitionedDataWriter}
*/
public class PartitionedWriterTest {
@Test
public void test() throws IOException {
State state = new State();
state.setProp(ConfigurationKeys.WRITER_PARTITIONER_CLASS, TestPartitioner.class.getCanonicalName());
TestPartitionAwareWriterBuilder builder = new TestPartitionAwareWriterBuilder();
PartitionedDataWriter writer = new PartitionedDataWriter<String, String>(builder, state);
Assert.assertEquals(builder.actions.size(), 0);
String record1 = "abc";
writer.write(record1);
Assert.assertEquals(builder.actions.size(), 2);
TestPartitionAwareWriterBuilder.Action action = builder.actions.poll();
Assert.assertEquals(action.getPartition(), "a");
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.BUILD);
action = builder.actions.poll();
Assert.assertEquals(action.getPartition(), "a");
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.WRITE);
Assert.assertEquals(action.getTarget(), record1);
Assert.assertTrue(writer.isSpeculativeAttemptSafe());
String record2 = "123";
writer.write(record2);
Assert.assertEquals(builder.actions.size(), 2);
action = builder.actions.poll();
Assert.assertEquals(action.getPartition(), "1");
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.BUILD);
Assert.assertFalse(writer.isSpeculativeAttemptSafe());
action = builder.actions.poll();
Assert.assertEquals(action.getPartition(), "1");
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.WRITE);
Assert.assertEquals(action.getTarget(), record2);
writer.write(record1);
Assert.assertEquals(builder.actions.size(), 1);
action = builder.actions.poll();
Assert.assertEquals(action.getPartition(), "a");
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.WRITE);
Assert.assertEquals(action.getTarget(), record1);
Assert.assertEquals(writer.recordsWritten(), 3);
Assert.assertEquals(writer.bytesWritten(), 3);
Assert.assertFalse(writer.isSpeculativeAttemptSafe());
writer.cleanup();
Assert.assertEquals(builder.actions.size(), 2);
action = builder.actions.poll();
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.CLEANUP);
action = builder.actions.poll();
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.CLEANUP);
writer.close();
Assert.assertEquals(builder.actions.size(), 2);
action = builder.actions.poll();
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.CLOSE);
action = builder.actions.poll();
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.CLOSE);
writer.commit();
Assert.assertEquals(builder.actions.size(), 2);
action = builder.actions.poll();
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.COMMIT);
action = builder.actions.poll();
Assert.assertEquals(action.getType(), TestPartitionAwareWriterBuilder.Actions.COMMIT);
}
@Test
public void testWatermarkComputation() throws IOException {
testWatermarkComputation(0L, 1L, 0L);
testWatermarkComputation(1L, 0L, null);
testWatermarkComputation(0L, 0L, null);
testWatermarkComputation(20L, 1L, null);
}
public void testWatermarkComputation(Long committed, Long unacknowledged, Long expected) throws IOException {
State state = new State();
state.setProp(ConfigurationKeys.WRITER_PARTITIONER_CLASS, TestPartitioner.class.getCanonicalName());
String defaultSource = "default";
WatermarkAwareWriter mockDataWriter = mock(WatermarkAwareWriter.class);
when(mockDataWriter.isWatermarkCapable()).thenReturn(true);
when(mockDataWriter.getCommittableWatermark()).thenReturn(Collections.singletonMap(defaultSource,
new DefaultCheckpointableWatermark(defaultSource, new LongWatermark(committed))));
when(mockDataWriter.getUnacknowledgedWatermark()).thenReturn(Collections.singletonMap(defaultSource,
new DefaultCheckpointableWatermark(defaultSource, new LongWatermark(unacknowledged))));
PartitionAwareDataWriterBuilder builder = mock(PartitionAwareDataWriterBuilder.class);
when(builder.validatePartitionSchema(any(Schema.class))).thenReturn(true);
when(builder.forPartition(any(GenericRecord.class))).thenReturn(builder);
when(builder.withWriterId(any(String.class))).thenReturn(builder);
when(builder.build()).thenReturn(mockDataWriter);
PartitionedDataWriter writer = new PartitionedDataWriter<String, String>(builder, state);
AcknowledgableRecordEnvelope<String> recordEnvelope = new AcknowledgableRecordEnvelope<>("0",
new AcknowledgableWatermark(new DefaultCheckpointableWatermark(defaultSource, new LongWatermark(0))));
writer.writeEnvelope(recordEnvelope);
Map<String, CheckpointableWatermark> watermark = writer.getCommittableWatermark();
System.out.println(watermark.toString());
if (expected == null) {
Assert.assertTrue(watermark.isEmpty(), "Expected watermark to be absent");
} else {
Assert.assertTrue(watermark.size() == 1);
Assert.assertEquals((long) expected, ((LongWatermark) watermark.values().iterator().next().getWatermark()).getValue());
}
}
}