package com.linkedin.databus.core;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* Licensed 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.
*
*/
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.spec.InvalidParameterSpecException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import org.apache.log4j.Level;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.linkedin.databus.core.data_model.PhysicalPartition;
import com.linkedin.databus2.test.TestUtil;
public class TestCheckpointMult
{
CheckpointMult _cpMult;
int pSrcId1 = 1, pSrcId2 = 2;
Map<Integer, List<Integer>> pSrcIds = new HashMap<Integer, List<Integer>>();
Integer WIN_OFFSET1 = 100;
Integer WIN_SCN1 = 1000;
Integer WIN_OFFSET2 = -1;
Integer WIN_SCN2 = 2000;
@BeforeClass
void setUpClass()
{
TestUtil.setupLogging(true, null, Level.ERROR);
}
@BeforeTest
void setUp() {
_cpMult = makeCpMult();
}
private CheckpointMult makeCpMult() {
// init test data
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(WIN_OFFSET1);
al.add(WIN_SCN1);
pSrcIds.put(pSrcId1, al);
al = new ArrayList<Integer>();
al.add(WIN_OFFSET2);
al.add(WIN_SCN2);
pSrcIds.put(pSrcId2, al);
CheckpointMult cpMult = new CheckpointMult();
for(int id: pSrcIds.keySet()) {
Checkpoint cp = new Checkpoint();
cp.setWindowOffset(pSrcIds.get(id).get(0).longValue());
cp.setWindowScn((long)pSrcIds.get(id).get(1));
PhysicalPartition pPart = new PhysicalPartition(id, "name");
cpMult.addCheckpoint(pPart, cp);
}
return cpMult;
}
@Test
void testCheckpoint() throws JsonGenerationException, JsonMappingException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Checkpoint cp = new Checkpoint();
cp.setWindowOffset(10);
cp.setWindowScn(100L);
assertEquals((long)cp.getWindowOffset(), 10, "window offset mismatch");
assertEquals(cp.getWindowScn(), 100L, "window scn mismatch");
cp.serialize(baos);
//System.out.println("TC: in: " + baos.toString());
Checkpoint cp1 = new Checkpoint(baos.toString());
assertEquals((long)cp1.getWindowOffset(), 10, "after deser window offset mismatch");
assertEquals(cp1.getWindowScn(), 100L, "after deser window scn mismatch");
}
public void validateCheckpoints() {
for(int id : pSrcIds.keySet()) {
PhysicalPartition pPart = new PhysicalPartition(id, "name");
Checkpoint cp = _cpMult.getCheckpoint(pPart);
List<Integer> l = pSrcIds.get(id);
assertEquals(cp.getWindowOffset().longValue(), l.get(0).longValue(),
"window offset in Checkpoint1 doesn't match");
assertEquals(cp.getWindowScn(), (long)l.get(1),
"snapshot offset in Checkpoint1 doesn't match");
}
}
@Test
public void singleCpConstruct() throws JsonGenerationException, JsonMappingException, IOException {
// add one more
Checkpoint cpN = new Checkpoint();
cpN.setFlexible();
cpN.setWindowOffset(150);
cpN.setWindowScn(1500L);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
cpN.serialize(baos);
//System.out.println("SERDE before:" + _cpMult.getCheckpoint(1));
String s = baos.toString();
//System.out.println("singleCpConstruct: ser version of cpMult:" + s);
// de-ser it
//CheckpointMult anotherCpMult = new CheckpointMult();
Checkpoint cp = new Checkpoint(s);
//PhysicalPartition pPart = new PhysicalPartition(5, "name");
//anotherCpMult.addCheckpoint(pPart, cp);
assertEquals(cp.getWindowScn(), cpN.getWindowScn(), "scn offset in new cpMult1 doesn't match");
assertEquals(cp.getWindowOffset(), cpN.getWindowOffset(), "window offset in int the new cpMult1 doesn't match");
}
@Test
public void serdeCheckpointMult() throws Exception {
validateCheckpoints();
assertEquals(_cpMult.getNumCheckponts(), 2, " wrong number of enteries in cpMult");
// serialize checkpoints
ByteArrayOutputStream baos = new ByteArrayOutputStream();
_cpMult.serialize(baos);
//System.out.println("SERDE before:" + _cpMult.getCheckpoint(1));
String s = baos.toString();
//System.out.println("ser version of cpMult:" + s);
// de-ser it
CheckpointMult anotherCpMult = new CheckpointMult(s);
//System.out.println("SERDE after:" + anotherCpMult.getCheckpoint(1));
assertEquals(anotherCpMult.getNumCheckponts(), 2,
" wrong number of enteries in new cpMult");
// verify
for(Integer i : pSrcIds.keySet()) {
PhysicalPartition pPart = new PhysicalPartition(i, "name");
Checkpoint cp = _cpMult.getCheckpoint(pPart);
Checkpoint aCp = anotherCpMult.getCheckpoint(pPart);
//System.out.println("id = " + i + ";scn=" + cp.getWindowScn() + ";awscn=" + aCp.getWindowScn());
assertEquals(cp.getWindowScn(), aCp.getWindowScn(),
"scn offset in new cpMult doesn't match");
assertEquals(cp.getWindowOffset(), aCp.getWindowOffset(),
"window offset in int the new cpMult doesn't match");
}
}
/**
* Test that the cursor position can be set/retrieved from the CheckpointMult object,
* but is never serialized.
* When we change the serialization function to include this in the map, this test will
* change.
*/
@Test
public void testCursorPosition() throws Exception
{
final PhysicalPartition ppart = new PhysicalPartition(26, "January");
CheckpointMult cpMult = makeCpMult();
cpMult.setCursorPartition(ppart);
assertEquals(ppart, cpMult.getCursorPartition());
String serialCpMult = cpMult.toString();
CheckpointMult cpMultCopy = new CheckpointMult(serialCpMult);
assertNull(cpMultCopy.getCursorPartition());
// Make sure we are able to decode it, however.
ObjectMapper mapper = new ObjectMapper();
Map<String, String> map = mapper.readValue(
new ByteArrayInputStream(serialCpMult.getBytes(Charset.defaultCharset())), new TypeReference<Map<String, String>>(){});
map.put("NonJsonKey", "Some value");
map.put("cursorPartition", ppart.toJsonString());
ByteArrayOutputStream bs = new ByteArrayOutputStream();
mapper.writeValue(bs, map);
cpMultCopy = new CheckpointMult(bs.toString());
assertEquals(cpMultCopy.getCursorPartition(), ppart);
}
@Test
public void testAtMostOnePartialWindow() throws Exception
{
CheckpointMult cpMult = new CheckpointMult();
final PhysicalPartition pp1 = new PhysicalPartition(1, "February");
final PhysicalPartition pp2 = new PhysicalPartition(1, "Friday");
Checkpoint cp = new Checkpoint();
cp.setWindowScn(100L);
cp.setWindowOffset(3);
cpMult.addCheckpoint(pp1, cp); // Added one checkpoint with partial window.
assertEquals(pp1, cpMult.getPartialWindowPartition());
cp = new Checkpoint();
cp.setWindowScn(500L);
cp.setWindowOffset(2);
boolean caughtException = false;
try {
cpMult.addCheckpoint(pp2, cp);
} catch (DatabusRuntimeException e) {
caughtException = true;
}
assertTrue(caughtException, "Was able to add two checkpoints with partial windows");
// It should be possible to add the checkpoint and then change it (since we just add it to a map)
cp.setWindowOffset(-1);
cpMult.addCheckpoint(pp2, cp);
cp.setWindowOffset(13);
String serialized = cpMult.toString();
caughtException = false;
try {
CheckpointMult cpMult2 = new CheckpointMult(serialized);
Assert.assertEquals(cpMult, cpMult2);
} catch (InvalidParameterSpecException e) {
caughtException= true;
}
assertTrue(caughtException, "Did not raise exception with two partial windows in serialized checkpoint " + serialized);
}
}