org.apache.cassandra.db.clock.IncrementCounterContextTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cassandra.db.clock.IncrementCounterContextTest.java

Source

/*
 * 
 * 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 org.apache.cassandra.db.clock;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;

import org.apache.commons.lang.ArrayUtils;

import org.junit.Test;

import org.apache.cassandra.Util;
import org.apache.cassandra.db.IClock.ClockRelationship;
import org.apache.cassandra.db.clock.IContext;
import org.apache.cassandra.db.clock.IncrementCounterContext;
import org.apache.cassandra.utils.FBUtilities;

/**
 * Note: these tests assume IPv4 (4 bytes) is used for id.
 *       if IPv6 (16 bytes) is used, tests will fail (but the code will work).
 *       however, it might be pragmatic to modify the code to just use
 *       the IPv4 portion of the IPv6 address-space.
 */
public class IncrementCounterContextTest {
    private static final IncrementCounterContext icc = new IncrementCounterContext();

    private static final int HEADER_LENGTH;

    private static final InetAddress idAddress;
    private static final byte[] id;
    private static final int idLength;
    private static final int countLength;

    private static final int stepLength;
    private static final int defaultEntries;

    static {
        HEADER_LENGTH = IncrementCounterContext.HEADER_LENGTH; // 2x size of long + size of int

        idAddress = FBUtilities.getLocalAddress();
        id = idAddress.getAddress();
        idLength = 4; // size of int
        countLength = 8; // size of long
        stepLength = idLength + countLength;

        defaultEntries = 10;
    }

    @Test
    public void testCreate() {
        long start = System.currentTimeMillis();

        byte[] context = icc.create();
        assert context.length == HEADER_LENGTH;

        long created = FBUtilities.byteArrayToLong(context, 0);
        assert (start <= created);
        assert (created <= System.currentTimeMillis());
    }

    @Test
    public void testUpdatePresentReorder() throws UnknownHostException {
        byte[] context;

        context = new byte[HEADER_LENGTH + (stepLength * defaultEntries)];

        for (int i = 0; i < defaultEntries - 1; i++) {
            icc.writeElementAtStepOffset(context, i, FBUtilities.toByteArray(i), 1L);
        }
        icc.writeElementAtStepOffset(context, (defaultEntries - 1), id, 1L);

        context = icc.update(context, idAddress, 10L);

        assert context.length == (HEADER_LENGTH + (stepLength * defaultEntries));
        assert 11L == FBUtilities.byteArrayToLong(context, HEADER_LENGTH + idLength);
        for (int i = 1; i < defaultEntries; i++) {
            int offset = HEADER_LENGTH + (i * stepLength);
            assert i - 1 == FBUtilities.byteArrayToInt(context, offset);
        }
    }

    @Test
    public void testUpdateNotPresent() {
        byte[] context = new byte[HEADER_LENGTH + (stepLength * 2)];

        for (int i = 0; i < 2; i++) {
            icc.writeElementAtStepOffset(context, i, FBUtilities.toByteArray(i), 1L);
        }

        context = icc.update(context, idAddress, 328L);

        assert context.length == (HEADER_LENGTH + (stepLength * 3));
        assert 328L == FBUtilities.byteArrayToLong(context, HEADER_LENGTH + idLength);
        for (int i = 1; i < 3; i++) {
            int offset = HEADER_LENGTH + (i * stepLength);
            assert i - 1 == FBUtilities.byteArrayToInt(context, offset);
            assert 1L == FBUtilities.byteArrayToLong(context, offset + idLength);
        }
    }

    @Test
    public void testSwapElement() {
        byte[] context = new byte[HEADER_LENGTH + (stepLength * 3)];

        for (int i = 0; i < 3; i++) {
            icc.writeElementAtStepOffset(context, i, FBUtilities.toByteArray(i), 1L);
        }
        icc.swapElement(context, HEADER_LENGTH, HEADER_LENGTH + (2 * stepLength));

        assert 2 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH);
        assert 0 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + (2 * stepLength));

        icc.swapElement(context, HEADER_LENGTH, HEADER_LENGTH + (1 * stepLength));

        assert 1 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH);
        assert 2 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + (1 * stepLength));
    }

    @Test
    public void testPartitionElements() {
        byte[] context = new byte[HEADER_LENGTH + stepLength * 10];

        icc.writeElementAtStepOffset(context, 0, FBUtilities.toByteArray(5), 1L);
        icc.writeElementAtStepOffset(context, 1, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(context, 2, FBUtilities.toByteArray(6), 1L);
        icc.writeElementAtStepOffset(context, 3, FBUtilities.toByteArray(7), 1L);
        icc.writeElementAtStepOffset(context, 4, FBUtilities.toByteArray(8), 1L);
        icc.writeElementAtStepOffset(context, 5, FBUtilities.toByteArray(9), 1L);
        icc.writeElementAtStepOffset(context, 6, FBUtilities.toByteArray(2), 1L);
        icc.writeElementAtStepOffset(context, 7, FBUtilities.toByteArray(4), 1L);
        icc.writeElementAtStepOffset(context, 8, FBUtilities.toByteArray(1), 1L);
        icc.writeElementAtStepOffset(context, 9, FBUtilities.toByteArray(3), 1L);

        icc.partitionElements(context, 0, // left
                9, // right (inclusive)
                2 // pivot
        );

        assert 5 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 0 * stepLength);
        assert 3 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 1 * stepLength);
        assert 3 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 2 * stepLength);
        assert 2 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 3 * stepLength);
        assert 4 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 4 * stepLength);
        assert 1 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 5 * stepLength);
        assert 6 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 6 * stepLength);
        assert 8 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 7 * stepLength);
        assert 9 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 8 * stepLength);
        assert 7 == FBUtilities.byteArrayToInt(context, HEADER_LENGTH + 9 * stepLength);
    }

    @Test
    public void testSortElementsById() {
        byte[] context = new byte[HEADER_LENGTH + (stepLength * 10)];

        icc.writeElementAtStepOffset(context, 0, FBUtilities.toByteArray(5), 1L);
        icc.writeElementAtStepOffset(context, 1, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(context, 2, FBUtilities.toByteArray(6), 1L);
        icc.writeElementAtStepOffset(context, 3, FBUtilities.toByteArray(7), 1L);
        icc.writeElementAtStepOffset(context, 4, FBUtilities.toByteArray(8), 1L);
        icc.writeElementAtStepOffset(context, 5, FBUtilities.toByteArray(9), 1L);
        icc.writeElementAtStepOffset(context, 6, FBUtilities.toByteArray(2), 1L);
        icc.writeElementAtStepOffset(context, 7, FBUtilities.toByteArray(4), 1L);
        icc.writeElementAtStepOffset(context, 8, FBUtilities.toByteArray(1), 1L);
        icc.writeElementAtStepOffset(context, 9, FBUtilities.toByteArray(3), 1L);

        byte[] sorted = icc.sortElementsById(context);

        assert 1 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 0 * stepLength);
        assert 2 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 1 * stepLength);
        assert 3 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 2 * stepLength);
        assert 3 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 3 * stepLength);
        assert 4 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 4 * stepLength);
        assert 5 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 5 * stepLength);
        assert 6 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 6 * stepLength);
        assert 7 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 7 * stepLength);
        assert 8 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 8 * stepLength);
        assert 9 == FBUtilities.byteArrayToInt(sorted, HEADER_LENGTH + 9 * stepLength);
    }

    @Test
    public void testCompare() {
        byte[] left;
        byte[] right;

        // equality:
        //   left:  no local timestamp
        //   right: no local timestamp
        left = Util.concatByteArrays(FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L));
        right = Util.concatByteArrays(FBUtilities.toByteArray(1L), FBUtilities.toByteArray(0L));

        assert ClockRelationship.EQUAL == icc.compare(left, right);

        // equality:
        //   left, right: local timestamps equal
        left = Util.concatByteArrays(FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(32L),
                FBUtilities.toByteArray(1), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(2L));
        right = Util.concatByteArrays(FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(9L), FBUtilities.toByteArray(2), FBUtilities.toByteArray(1L));

        assert ClockRelationship.EQUAL == icc.compare(left, right);

        // greater than:
        //   left:  local timestamp
        //   right: no local timestamp
        left = Util.concatByteArrays(FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(32L),
                FBUtilities.toByteArray(1), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(2L));
        right = Util.concatByteArrays(FBUtilities.toByteArray(4L), FBUtilities.toByteArray(0L),
                FBUtilities.toByteArray(3), FBUtilities.toByteArray(9L), FBUtilities.toByteArray(2),
                FBUtilities.toByteArray(1L));

        assert ClockRelationship.GREATER_THAN == icc.compare(left, right);

        // greater than:
        //   left's local timestamp > right's local timestamp
        left = Util.concatByteArrays(FBUtilities.toByteArray(11L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(32L),
                FBUtilities.toByteArray(1), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(2L));
        right = Util.concatByteArrays(FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(9L), FBUtilities.toByteArray(2), FBUtilities.toByteArray(1L));

        assert ClockRelationship.GREATER_THAN == icc.compare(left, right);

        // less than:
        //   left:  no local timestamp
        //   right: local timestamp
        left = Util.concatByteArrays(FBUtilities.toByteArray(7L), FBUtilities.toByteArray(0L),
                FBUtilities.toByteArray(1), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(2L));
        right = Util.concatByteArrays(FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(9L), FBUtilities.toByteArray(2), FBUtilities.toByteArray(1L));

        assert ClockRelationship.LESS_THAN == icc.compare(left, right);

        // less than:
        //   left's local timestamp < right's local timestamp
        left = Util.concatByteArrays(FBUtilities.toByteArray(9L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(32L),
                FBUtilities.toByteArray(1), FBUtilities.toByteArray(4L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(2L));
        right = Util.concatByteArrays(FBUtilities.toByteArray(122L), FBUtilities.toByteArray(0L),
                FBUtilities.getLocalAddress().getAddress(), FBUtilities.toByteArray(2L), FBUtilities.toByteArray(3),
                FBUtilities.toByteArray(9L), FBUtilities.toByteArray(2), FBUtilities.toByteArray(1L));

        assert ClockRelationship.LESS_THAN == icc.compare(left, right);
    }

    @Test
    public void testDiff() {
        byte[] left = new byte[HEADER_LENGTH + (3 * stepLength)];
        byte[] right;

        // equality: equal nodes, all counts same
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);
        right = ArrayUtils.clone(left);

        assert ClockRelationship.EQUAL == icc.diff(left, right);

        // greater than: left has superset of nodes (counts equal)
        left = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);
        icc.writeElementAtStepOffset(left, 3, FBUtilities.toByteArray(12), 0L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L);

        assert ClockRelationship.GREATER_THAN == icc.diff(left, right);

        // less than: left has subset of nodes (counts equal)
        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);

        right = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L);
        icc.writeElementAtStepOffset(right, 3, FBUtilities.toByteArray(12), 0L);

        assert ClockRelationship.LESS_THAN == icc.diff(left, right);

        // greater than: equal nodes, but left has higher counts
        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 3L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L);

        assert ClockRelationship.GREATER_THAN == icc.diff(left, right);

        // less than: equal nodes, but right has higher counts
        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 3L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 3L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 9L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 3L);

        assert ClockRelationship.LESS_THAN == icc.diff(left, right);

        // disjoint: right and left have disjoint node sets
        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(4), 1L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 1L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 1L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);

        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(4), 1L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(2), 1L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 1L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(12), 1L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);

        // disjoint: equal nodes, but right and left have higher counts in differing nodes
        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 1L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 5L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);

        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 2L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 1L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 9L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 5L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);

        // disjoint: left has more nodes, but lower counts
        left = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 2L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 1L);
        icc.writeElementAtStepOffset(left, 3, FBUtilities.toByteArray(12), 1L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 9L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 5L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);

        // disjoint: left has less nodes, but higher counts
        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 5L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 3L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 2L);

        right = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 3L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 2L);
        icc.writeElementAtStepOffset(right, 3, FBUtilities.toByteArray(12), 1L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);

        // disjoint: mixed nodes and counts
        left = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 5L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(9), 2L);

        right = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 3L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 2L);
        icc.writeElementAtStepOffset(right, 3, FBUtilities.toByteArray(12), 1L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);

        left = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(left, 0, FBUtilities.toByteArray(3), 5L);
        icc.writeElementAtStepOffset(left, 1, FBUtilities.toByteArray(6), 2L);
        icc.writeElementAtStepOffset(left, 2, FBUtilities.toByteArray(7), 2L);
        icc.writeElementAtStepOffset(left, 3, FBUtilities.toByteArray(9), 2L);

        right = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(right, 0, FBUtilities.toByteArray(3), 4L);
        icc.writeElementAtStepOffset(right, 1, FBUtilities.toByteArray(6), 3L);
        icc.writeElementAtStepOffset(right, 2, FBUtilities.toByteArray(9), 2L);

        assert ClockRelationship.DISJOINT == icc.diff(left, right);
    }

    @Test
    public void testMerge() {
        // note: local counts aggregated; remote counts are reconciled (i.e. take max)

        List<byte[]> contexts = new ArrayList<byte[]>();

        byte[] bytes = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(bytes, 0, FBUtilities.toByteArray(1), 1L);
        icc.writeElementAtStepOffset(bytes, 1, FBUtilities.toByteArray(2), 2L);
        icc.writeElementAtStepOffset(bytes, 2, FBUtilities.toByteArray(4), 3L);
        icc.writeElementAtStepOffset(bytes, 3, FBUtilities.getLocalAddress().getAddress(), 3L);
        contexts.add(bytes);

        bytes = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(bytes, 2, FBUtilities.toByteArray(5), 5L);
        icc.writeElementAtStepOffset(bytes, 1, FBUtilities.toByteArray(4), 4L);
        icc.writeElementAtStepOffset(bytes, 0, FBUtilities.getLocalAddress().getAddress(), 9L);
        contexts.add(bytes);

        byte[] merged = icc.merge(contexts);

        // local node id's counts are aggregated
        assert 0 == FBUtilities.compareByteSubArrays(FBUtilities.getLocalAddress().getAddress(), 0, merged,
                HEADER_LENGTH + 0 * stepLength, 4);
        assert 12L == FBUtilities.byteArrayToLong(merged, HEADER_LENGTH + 0 * stepLength + idLength);

        // remote node id counts are reconciled (i.e. take max)
        assert 5 == FBUtilities.byteArrayToInt(merged, HEADER_LENGTH + 1 * stepLength);
        assert 5L == FBUtilities.byteArrayToLong(merged, HEADER_LENGTH + 1 * stepLength + idLength);

        assert 4 == FBUtilities.byteArrayToInt(merged, HEADER_LENGTH + 2 * stepLength);
        assert 4L == FBUtilities.byteArrayToLong(merged, HEADER_LENGTH + 2 * stepLength + idLength);

        assert 2 == FBUtilities.byteArrayToInt(merged, HEADER_LENGTH + 3 * stepLength);
        assert 2L == FBUtilities.byteArrayToLong(merged, HEADER_LENGTH + 3 * stepLength + idLength);

        assert 1 == FBUtilities.byteArrayToInt(merged, HEADER_LENGTH + 4 * stepLength);
        assert 1L == FBUtilities.byteArrayToLong(merged, HEADER_LENGTH + 4 * stepLength + idLength);
    }

    @Test
    public void testTotal() {
        List<byte[]> contexts = new ArrayList<byte[]>();

        byte[] bytes = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(bytes, 0, FBUtilities.toByteArray(1), 1L);
        icc.writeElementAtStepOffset(bytes, 1, FBUtilities.toByteArray(2), 2L);
        icc.writeElementAtStepOffset(bytes, 2, FBUtilities.toByteArray(4), 3L);
        icc.writeElementAtStepOffset(bytes, 3, FBUtilities.getLocalAddress().getAddress(), 3L);
        contexts.add(bytes);

        bytes = new byte[HEADER_LENGTH + (3 * stepLength)];
        icc.writeElementAtStepOffset(bytes, 2, FBUtilities.toByteArray(5), 5L);
        icc.writeElementAtStepOffset(bytes, 1, FBUtilities.toByteArray(4), 4L);
        icc.writeElementAtStepOffset(bytes, 0, FBUtilities.getLocalAddress().getAddress(), 9L);
        contexts.add(bytes);

        byte[] merged = icc.merge(contexts);

        // 127.0.0.1: 12 (3+9)
        // 0.0.0.1:    1
        // 0.0.0.2:    2
        // 0.0.0.4:    4
        // 0.0.0.5:    5

        assert 24L == FBUtilities.byteArrayToLong(icc.total(merged));
    }

    @Test
    public void testCleanNodeCounts() throws UnknownHostException {
        byte[] bytes = new byte[HEADER_LENGTH + (4 * stepLength)];
        icc.writeElementAtStepOffset(bytes, 0, FBUtilities.toByteArray(1), 1L);
        icc.writeElementAtStepOffset(bytes, 1, FBUtilities.toByteArray(2), 2L);
        icc.writeElementAtStepOffset(bytes, 2, FBUtilities.toByteArray(4), 3L);
        icc.writeElementAtStepOffset(bytes, 3, FBUtilities.toByteArray(8), 4L);

        assert 4 == FBUtilities.byteArrayToInt(bytes, HEADER_LENGTH + 2 * stepLength);
        assert 3L == FBUtilities.byteArrayToLong(bytes, HEADER_LENGTH + 2 * stepLength + idLength);

        bytes = icc.cleanNodeCounts(bytes, InetAddress.getByAddress(FBUtilities.toByteArray(4)));

        // node: 0.0.0.4 should be removed
        assert (HEADER_LENGTH + (3 * stepLength)) == bytes.length;

        // other nodes should be unaffected
        assert 1 == FBUtilities.byteArrayToInt(bytes, HEADER_LENGTH + 0 * stepLength);
        assert 1L == FBUtilities.byteArrayToLong(bytes, HEADER_LENGTH + 0 * stepLength + idLength);

        assert 2 == FBUtilities.byteArrayToInt(bytes, HEADER_LENGTH + 1 * stepLength);
        assert 2L == FBUtilities.byteArrayToLong(bytes, HEADER_LENGTH + 1 * stepLength + idLength);

        assert 8 == FBUtilities.byteArrayToInt(bytes, HEADER_LENGTH + 2 * stepLength);
        assert 4L == FBUtilities.byteArrayToLong(bytes, HEADER_LENGTH + 2 * stepLength + idLength);
    }
}