com.foundationdb.server.test.mt.util.TimeMarkerComparison.java Source code

Java tutorial

Introduction

Here is the source code for com.foundationdb.server.test.mt.util.TimeMarkerComparison.java

Source

/**
 * Copyright (C) 2009-2013 FoundationDB, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.foundationdb.server.test.mt.util;

import com.google.common.base.Supplier;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import org.junit.ComparisonFailure;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;

import static org.junit.Assert.assertEquals;

public final class TimeMarkerComparison {
    private final List<List<String>> combinedMarks;

    public TimeMarkerComparison(Collection<? extends HasTimeMarker> hasTimeMarkers) {
        List<TimeMarker> timeMarkers = new ArrayList<>();
        for (HasTimeMarker htm : hasTimeMarkers) {
            timeMarkers.add(htm.getTimeMarker());
        }
        combinedMarks = combineTimeMarkers(timeMarkers);
    }

    /**
     * Combine multiple TimeMarkers into a single, ordered list of marks.
     *
     * <p>
     * Final output is a list of messages in the order they occurred. If the
     * order is unknown (i.e. overlapping timestamps from multiple markers)
     * then multiple messages will be in a single position and sorted by name.
     * </p>
     *
     * <pre>
     * Input:
     *     A: 1 -> [baz,hop], 2 -> [cap], 3 -> [dig]
     *     B: 1 -> [gap,foo],             3 -> [jog]  4 -> [zap]
     * Output:
     *     [ [baz,gap], [foo,hop], [cap], [dig,jog], [zap] ]
     * </pre>
     */
    static List<List<String>> combineTimeMarkers(TimeMarker... timeMarkers) {
        return combineTimeMarkers(Arrays.asList(timeMarkers));
    }

    /** See {@link #combineTimeMarkers(TimeMarker...)}. */
    static List<List<String>> combineTimeMarkers(Collection<TimeMarker> timeMarkers) {
        // Sort by time, list of lists of messages from all markers
        ListMultimap<Long, List<String>> timeToMarks = Multimaps
                .newListMultimap(new TreeMap<Long, Collection<List<String>>>(), new Supplier<List<List<String>>>() {
                    @Override
                    public List<List<String>> get() {
                        return new ArrayList<>();
                    }
                });
        for (TimeMarker tm : timeMarkers) {
            for (Entry<Long, List<String>> entry : Multimaps.asMap(tm.getMarks()).entrySet()) {
                timeToMarks.put(entry.getKey(), entry.getValue());
            }
        }
        // Concatenate into final ordering
        List<List<String>> output = new ArrayList<>();
        for (List<List<String>> singleTimeMarks : Multimaps.asMap(timeToMarks).values()) {
            // Split a given Marker's messages apart, coalesce overlapping timestamps from multiple Marker's
            ListMultimap<Integer, String> split = ArrayListMultimap.create();
            for (List<String> marks : singleTimeMarks) {
                for (int i = 0; i < marks.size(); ++i) {
                    split.put(i, marks.get(i));
                }
            }
            // Sort any coalesced and output
            for (List<String> marks : Multimaps.asMap(split).values()) {
                Collections.sort(marks);
                output.add(marks);
            }
        }
        return output;
    }

    public void verify(String... expectedMessages) {
        List<Collection<String>> expected = new ArrayList<>();
        for (String expectedMessage : expectedMessages) {
            if (expectedMessage != null) {
                expected.add(Collections.singletonList(expectedMessage));
            }
        }
        // For pretty print
        if (!expected.equals(combinedMarks)) {
            throw new ComparisonFailure("TimePoint messages (in order)", expected.toString(),
                    combinedMarks.toString());
        }
    }

    public List<String> getMarkNames() {
        List<String> markNames = new ArrayList<>();
        for (Collection<String> marksList : combinedMarks) {
            assertEquals("individual marks lists must be singletons; size ", 1, marksList.size());
            markNames.addAll(marksList);
        }
        return markNames;
    }

    public boolean startsWith(String... expectedMessages) {
        List<String> expected = Arrays.asList(expectedMessages);
        List<String> actual = getMarkNames();
        if (actual.size() < expected.size()) {
            return false;
        }
        actual = actual.subList(0, expected.size());
        return expected.equals(actual);
    }

    public boolean matches(String... expectedMessages) {
        List<String> expected = Arrays.asList(expectedMessages);
        List<String> actual = getMarkNames();
        return expected.equals(actual);
    }

    @Override
    public String toString() {
        return combinedMarks.toString();
    }
}