org.apache.fluo.recipes.test.FluoITHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.fluo.recipes.test.FluoITHelper.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.fluo.recipes.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.Scanner;
import org.apache.accumulo.core.client.TableNotFoundException;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.fluo.api.client.FluoClient;
import org.apache.fluo.api.client.FluoFactory;
import org.apache.fluo.api.client.Snapshot;
import org.apache.fluo.api.config.FluoConfiguration;
import org.apache.fluo.api.data.Bytes;
import org.apache.fluo.api.data.Column;
import org.apache.fluo.api.data.RowColumnValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper for creating integration tests that connect to a MiniFluo/MiniAccumuloCluster instance.
 *
 * @since 1.0.0
 */
public class FluoITHelper {

    private static final Logger log = LoggerFactory.getLogger(FluoITHelper.class);

    /**
     * Prints list of RowColumnValue objects
     *
     * @param rcvList RowColumnValue list
     */
    public static void printRowColumnValues(Collection<RowColumnValue> rcvList) {
        System.out.println("== RDD start ==");
        rcvList.forEach(rcv -> System.out.println("rc " + Hex.encNonAscii(rcv, " ")));
        System.out.println("== RDD end ==");
    }

    public static void printFluoTable(FluoConfiguration conf) {
        try (FluoClient client = FluoFactory.newClient(conf)) {
            printFluoTable(client);
        }
    }

    /**
     * Prints Fluo table accessible using provided client
     *
     * @param client Fluo client to table
     */
    public static void printFluoTable(FluoClient client) {
        try (Snapshot s = client.newSnapshot()) {
            System.out.println("== fluo start ==");
            for (RowColumnValue rcv : s.scanner().build()) {
                StringBuilder sb = new StringBuilder();
                Hex.encNonAscii(sb, rcv.getRow());
                sb.append(" ");
                Hex.encNonAscii(sb, rcv.getColumn(), " ");
                sb.append("\t");
                Hex.encNonAscii(sb, rcv.getValue());

                System.out.println(sb.toString());
            }
            System.out.println("=== fluo end ===");
        }
    }

    // @formatter:off
    public static boolean verifyFluoTable(FluoConfiguration conf, Collection<RowColumnValue> expected) {
        // @formatter:on
        try (FluoClient client = FluoFactory.newClient(conf)) {
            return verifyFluoTable(client, expected);
        }
    }

    /**
     * Verifies that the actual data in provided Fluo instance matches expected data
     *
     * @param client Fluo client to instance with actual data
     * @param expected RowColumnValue list containing expected data
     * @return True if actual data matches expected data
     */
    public static boolean verifyFluoTable(FluoClient client, Collection<RowColumnValue> expected) {

        expected = sort(expected);

        try (Snapshot s = client.newSnapshot()) {
            Iterator<RowColumnValue> fluoIter = s.scanner().build().iterator();
            Iterator<RowColumnValue> rcvIter = expected.iterator();

            while (fluoIter.hasNext() && rcvIter.hasNext()) {
                RowColumnValue actualRcv = fluoIter.next();
                RowColumnValue rcv = rcvIter.next();

                boolean retval = diff("fluo row", rcv.getRow(), actualRcv.getRow());
                retval |= diff("fluo fam", rcv.getColumn().getFamily(), actualRcv.getColumn().getFamily());
                retval |= diff("fluo qual", rcv.getColumn().getQualifier(), actualRcv.getColumn().getQualifier());
                retval |= diff("fluo val", rcv.getValue(), actualRcv.getValue());

                if (retval) {
                    log.error("Difference found - row {} cf {} cq {} val {}", rcv.getsRow(),
                            rcv.getColumn().getsFamily(), rcv.getColumn().getsQualifier(), rcv.getsValue());
                    return false;
                }

                log.debug("Verified {}", Hex.encNonAscii(rcv, " "));
            }

            if (fluoIter.hasNext() || rcvIter.hasNext()) {
                log.error("An iterator still has more data");
                return false;
            }
            log.debug("Actual data matched expected data");
            return true;
        }
    }

    /**
     * Prints specified Accumulo table (accessible using Accumulo connector parameter)
     *
     * @param conn Accumulo connector of to instance with table to print
     * @param accumuloTable Accumulo table to print
     */
    public static void printAccumuloTable(Connector conn, String accumuloTable) {
        Scanner scanner = null;
        try {
            scanner = conn.createScanner(accumuloTable, Authorizations.EMPTY);
        } catch (TableNotFoundException e) {
            throw new IllegalStateException(e);
        }
        Iterator<Map.Entry<Key, Value>> iterator = scanner.iterator();

        System.out.println("== accumulo start ==");
        while (iterator.hasNext()) {
            Map.Entry<Key, Value> entry = iterator.next();
            System.out.println(entry.getKey() + " " + entry.getValue());
        }
        System.out.println("== accumulo end ==");
    }

    private static boolean diff(String dataType, String expected, String actual) {
        if (!expected.equals(actual)) {
            log.error("Difference found in {} - expected {} actual {}", dataType, expected, actual);
            return true;
        }
        return false;
    }

    private static boolean diff(String dataType, Bytes expected, Bytes actual) {
        if (!expected.equals(actual)) {
            log.error("Difference found in {} - expected {} actual {}", dataType, Hex.encNonAscii(expected),
                    Hex.encNonAscii(actual));
            return true;
        }
        return false;
    }

    /**
     * Verifies that actual data in Accumulo table matches expected data
     *
     * @param conn Connector to Accumulo instance with actual data
     * @param accumuloTable Accumulo table with actual data
     * @param expected RowColumnValue list containing expected data
     * @return True if actual data matches expected data
     */
    public static boolean verifyAccumuloTable(Connector conn, String accumuloTable,
            Collection<RowColumnValue> expected) {

        expected = sort(expected);

        Scanner scanner;
        try {
            scanner = conn.createScanner(accumuloTable, Authorizations.EMPTY);
        } catch (TableNotFoundException e) {
            throw new IllegalStateException(e);
        }
        Iterator<Map.Entry<Key, Value>> scanIter = scanner.iterator();
        Iterator<RowColumnValue> rcvIter = expected.iterator();

        while (scanIter.hasNext() && rcvIter.hasNext()) {
            RowColumnValue rcv = rcvIter.next();
            Map.Entry<Key, Value> kvEntry = scanIter.next();
            Key key = kvEntry.getKey();
            Column col = rcv.getColumn();

            boolean retval = diff("row", rcv.getRow().toString(), key.getRow().toString());
            retval |= diff("fam", col.getFamily().toString(), key.getColumnFamily().toString());
            retval |= diff("qual", col.getQualifier().toString(), key.getColumnQualifier().toString());
            retval |= diff("val", rcv.getValue().toString(), kvEntry.getValue().toString());

            if (retval) {
                log.error("Difference found - row {} cf {} cq {} val {}", rcv.getRow().toString(),
                        col.getFamily().toString(), col.getQualifier().toString(), rcv.getValue().toString());
                return false;
            }
            log.debug("Verified row {} cf {} cq {} val {}", rcv.getRow().toString(), col.getFamily().toString(),
                    col.getQualifier().toString(), rcv.getValue().toString());
        }

        if (scanIter.hasNext() || rcvIter.hasNext()) {
            log.error("An iterator still has more data");
            return false;
        }

        log.debug("Actual data matched expected data");
        return true;
    }

    /**
     * Verifies that expected list of RowColumnValues matches actual
     *
     * @param expected RowColumnValue list containing expected data
     * @param actual RowColumnValue list containing actual data
     * @return True if actual data matches expected data
     */
    public static boolean verifyRowColumnValues(Collection<RowColumnValue> expected,
            Collection<RowColumnValue> actual) {

        expected = sort(expected);
        actual = sort(actual);

        Iterator<RowColumnValue> expectIter = expected.iterator();
        Iterator<RowColumnValue> actualIter = actual.iterator();

        while (expectIter.hasNext() && actualIter.hasNext()) {
            RowColumnValue expRcv = expectIter.next();
            RowColumnValue actRcv = actualIter.next();

            boolean retval = diff("rcv row", expRcv.getRow(), actRcv.getRow());
            retval |= diff("rcv fam", expRcv.getColumn().getFamily(), actRcv.getColumn().getFamily());
            retval |= diff("rcv qual", expRcv.getColumn().getQualifier(), actRcv.getColumn().getQualifier());
            retval |= diff("rcv val", expRcv.getValue(), actRcv.getValue());

            if (retval) {
                log.error("Difference found in RowColumnValue lists - expected {} actual {}", expRcv, actRcv);
                return false;
            }
            log.debug("Verified row/col/val: {}", expRcv);
        }

        if (expectIter.hasNext() || actualIter.hasNext()) {
            log.error("A RowColumnValue list iterator still has more data");
            return false;
        }

        log.debug("Actual data matched expected data");
        return true;
    }

    private static List<RowColumnValue> sort(Collection<RowColumnValue> input) {
        ArrayList<RowColumnValue> copy = new ArrayList<>(input);
        Collections.sort(copy);
        return copy;
    }

    /**
     * A helper method for parsing test data. Each string passed in is expected to have the following
     * format {@literal <row>|<family>|<qualifier>|<value>}
     */
    public static List<RowColumnValue> parse(String... data) {
        return parse(Splitter.on('|'), data);
    }

    /**
     * A helper method for parsing test data. Each string passed in is split using the specified
     * splitter into four fields for row, family, qualifier, and value.
     */
    public static List<RowColumnValue> parse(Splitter splitter, String... data) {
        ArrayList<RowColumnValue> ret = new ArrayList<>();

        for (String line : data) {
            Iterable<String> cols = splitter.split(line);
            if (Iterables.size(cols) != 4) {
                throw new IllegalArgumentException("Bad input " + line);
            }

            Iterator<String> iter = cols.iterator();
            RowColumnValue rcv = new RowColumnValue(Bytes.of(iter.next()), new Column(iter.next(), iter.next()),
                    Bytes.of(iter.next()));

            ret.add(rcv);
        }

        return ret;
    }
}