/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2009 Sun Microsystems, Inc. * Portions Copyright 2013 ForgeRock AS */ package org.opends.server.replication.common; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.opends.server.replication.ReplicationTestCase; import org.opends.server.util.TimeThread; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; /** * Test ChangeNumber and ChangeNumberGenerator */ @SuppressWarnings("javadoc") public class ChangeNumberTest extends ReplicationTestCase { /** * Create ChangeNumber Data */ @DataProvider(name = "changeNumberData") public Object[][] createConstructorData() { long time = 0x12ABC; return new Object[][] { {1, 0, 1, "0000000000000001000100000000"}, {time, 123, 45, "0000000000012abc002d0000007b"}, {time, 123456789, 32767, "0000000000012abc7fff075bcd15"}, {time, 123456789, 32768, "0000000000012abc8000075bcd15"}, {time, 123456789, 65000, "0000000000012abcfde8075bcd15"}, {time, 123, 45678, "0000000000012abcb26e0000007b"} }; } /** * Test ChangeNumber constructor */ @Test(dataProvider = "changeNumberData") public void CreateChangeNumber(long time, int seq, int id, String str) throws Exception { ChangeNumber cn = new ChangeNumber(time,seq,id); assertEquals(cn.toString(), str); new ChangeNumber(time, seq, id); new ChangeNumber(time+1, seq, id); new ChangeNumber(time, seq+1, id); new ChangeNumber(time, seq, id+1); } /** * Test toString and constructor from String */ @Test(dataProvider = "changeNumberData") public void ChangeNumberEncodeDecode(long time, int seq, int id, String str) throws Exception { // Create 2 ChangeNumber with the same data and check equality ChangeNumber cn = new ChangeNumber(time,seq,id); ChangeNumber cn2 = new ChangeNumber(cn.toString()); assertEquals(cn, cn2, "The encoding/decoding of ChangeNumber is not reversible"); assertEquals(cn2.toString(), str, "The encoding/decoding of ChangeNumber is not reversible for toString()"); } /** * Create ChangeNumber */ @DataProvider(name = "createChangeNumber") public Object[][] createChangeNumberData() { long time[] = {1, TimeThread.getTime()}; int seq[] = {0, 123}; int id [] = {1, 45}; Object[][] obj = new Object[time.length][5]; for (int i=0; i 0); assertTrue(ChangeNumber.compare(cn1, cn2) == 0); assertTrue(ChangeNumber.compare(cn1, cn3) < 0); assertTrue(ChangeNumber.compare(cn3, cn1) > 0); assertTrue(ChangeNumber.compare(cn1, cn4) < 0); assertTrue(ChangeNumber.compare(cn4, cn1) > 0); assertTrue(ChangeNumber.compare(cn1, cn5) < 0); assertTrue(ChangeNumber.compare(cn5, cn1) > 0); } /** * Test ChangeNumber older method */ @Test(dataProvider = "createChangeNumber") public void ChangeNumberOlder( ChangeNumber cn1, ChangeNumber cn2, ChangeNumber cn3, ChangeNumber cn4, ChangeNumber cn5) throws Exception { assertFalse(cn1.older(null)); assertFalse(cn1.older(cn1)); assertTrue(cn1.older(cn3)); assertTrue(cn1.older(cn4)); assertTrue(cn1.older(cn5)); } /** * Test ChangeNumber olderOrEqual method */ @Test(dataProvider = "createChangeNumber") public void ChangeNumberOlderOrEqual( ChangeNumber cn1, ChangeNumber cn2, ChangeNumber cn3, ChangeNumber cn4, ChangeNumber cn5) throws Exception { assertFalse(cn1.olderOrEqual(null)); assertTrue(cn1.olderOrEqual(cn1)); assertTrue(cn1.olderOrEqual(cn3)); assertTrue(cn1.olderOrEqual(cn4)); assertTrue(cn1.olderOrEqual(cn5)); } /** * Test ChangeNumber newer method */ @Test(dataProvider = "createChangeNumber") public void ChangeNumberNewer( ChangeNumber cn1, ChangeNumber cn2, ChangeNumber cn3, ChangeNumber cn4, ChangeNumber cn5) throws Exception { assertTrue(cn1.newer(null)); assertFalse(cn1.newer(cn1)); assertFalse(cn1.newer(cn3)); assertFalse(cn1.newer(cn4)); assertFalse(cn1.newer(cn5)); } /** * Test ChangeNumber newerOrEquals method */ @Test(dataProvider = "createChangeNumber") public void ChangeNumberNewerOrEquals( ChangeNumber cn1, ChangeNumber cn2, ChangeNumber cn3, ChangeNumber cn4, ChangeNumber cn5) throws Exception { assertTrue(cn1.newerOrEquals(null)); assertTrue(cn1.newerOrEquals(cn1)); assertFalse(cn1.newerOrEquals(cn3)); assertFalse(cn1.newerOrEquals(cn4)); assertFalse(cn1.newerOrEquals(cn5)); } /** * Create a ChangeNumberGenerator The call NewChangeNumber() and adjust() *

* FIXME these tests are calling Thread.sleep() which makes them slow. We * should really have a way to control time (make it go slower or faster) for * the unit tests to avoid such waits. */ @Test public void changeNumberGenerator() throws Exception { ChangeNumber CN1; ChangeNumber CN2; // Generated the ChangeNumberGenerator object ChangeNumberGenerator cng = new ChangeNumberGenerator( 0, TimeThread.getTime()); // Generate 2 changeNumbers and check that they are different CN1 = cng.newChangeNumber(); CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0); // Generate a changeNumber separated by 10 milliseconds // and check that they are different Thread.sleep(10); CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0); // Generate a changeNumber separated by 300 milliseconds // and check that they are different Thread.sleep(300); CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0); // Adjust with the oldest CN cng.adjust(CN1); CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0 ); // Adjust with the newest generated cng.adjust(CN2); CN1 = CN2; CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0 ); // Adjust with the newest generated (time + 300) CN1 = new ChangeNumber(CN2.getTime() +300 ,CN2.getSeqnum(), CN2.getServerId()); cng.adjust(CN1); CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0 ); // Adjust with the newest generated (seqmun + 10) CN1 = new ChangeNumber(CN2.getTime() ,CN2.getSeqnum() +10, CN2.getServerId()); cng.adjust(CN1); CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0 ); // Adjust with the newest generated (seqmun = 0XFFFF) CN1 = new ChangeNumber(CN2.getTime() ,0XFFFF +10,CN2.getServerId()); cng.adjust(CN1); CN2 = cng.newChangeNumber(); assertTrue(CN1.compareTo(CN2) != 0 ); } /** * Test the difference in seq num between 2 change numbers. */ @Test public void changeNumberDiffSeqNum() throws Exception { ChangeNumber CN1; ChangeNumber CN2; CN1 = new ChangeNumber(0, 3, 0); // 3-0 = 3 CN2 = new ChangeNumber(0, 0, 0); assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 3); // 3-1 = 2 CN2 = new ChangeNumber(0, 1, 0); assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 2); // 3-3 = 0 CN2 = new ChangeNumber(0, 3, 0); assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 0); // 3-4 = 0 (CN1 must be newer otherwise 0 should be returned) CN2 = new ChangeNumber(0, 4, 0); assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 0); CN1 = new ChangeNumber(0, 0, 0); // 0-0 = 0 CN2 = new ChangeNumber(0, 0, 0); assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 0); // 0-1 = 0 (CN1 must be newer otherwise 0 should be returned) CN2 = new ChangeNumber(0, 1, 0); assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 0); CN1 = new ChangeNumber(0, 5, 0); CN2 = new ChangeNumber(0, 2, 0); // 5-null = 5 assertEquals(ChangeNumber.diffSeqNum(CN1, null), 5); // null-2 = 0 assertEquals(ChangeNumber.diffSeqNum(null, CN2), 0); // null-null = 0 assertEquals(ChangeNumber.diffSeqNum(null, null), 0); CN1 = new ChangeNumber(1111111, 2, 0); CN2 = new ChangeNumber(3333333, 4, 0); // CN1 older than CN2 -> 0 assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 0); CN1 = new ChangeNumber(3333333, 1, 0); CN2 = new ChangeNumber(1111111, Integer.MAX_VALUE-1, 0); // CN1 seqnum looped assertEquals(ChangeNumber.diffSeqNum(CN1, CN2), 3); } @DataProvider public Iterator createCNPairsToCompare() { final List allCNs = new ArrayList(); for (Object[] cnData : createChangeNumberData()) { allCNs.addAll(Arrays.asList(cnData)); } final List results = new ArrayList(); for (Object cn1 : allCNs) { for (Object cn2 : allCNs) { /* * it is ok to compare to the exact same CN to ensure operations are * reflexive, and it is also ok to compare cn1 to cn2, and cn2 to cn1 to * ensure operations are symmetric */ results.add(new Object[] { cn1, cn2 }); } } return results.iterator(); } @Test(dataProvider = "createCNPairsToCompare") public void compareToEquivalentToEquals(ChangeNumber cn1, ChangeNumber cn2) throws Exception { assertEquals(cn1.compareTo(cn2) == 0, cn1.equals(cn2)); } @Test(dataProvider = "createCNPairsToCompare") public void hashCodesEqualWhenChangeNumbersEqual(ChangeNumber cn1, ChangeNumber cn2) throws Exception { if (cn1.equals(cn2)) { assertEquals(cn1.hashCode(), cn2.hashCode()); } } @Test(dataProvider = "createCNPairsToCompare") public void hashCodesEqualWhenCompareToEqual(ChangeNumber cn1, ChangeNumber cn2) throws Exception { if (cn1.compareTo(cn2) == 0) { assertEquals(cn1.hashCode(), cn2.hashCode()); } } }