http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/data/Condition.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/data/Condition.java index bfd4818,0000000..e6e31eb mode 100644,000000..100644 --- a/core/src/main/java/org/apache/accumulo/core/data/Condition.java +++ b/core/src/main/java/org/apache/accumulo/core/data/Condition.java @@@ -1,238 -1,0 +1,239 @@@ +/* + * 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.accumulo.core.data; + ++import static com.google.common.base.Charsets.UTF_8; ++ +import java.util.Arrays; +import java.util.HashSet; + - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.security.ColumnVisibility; +import org.apache.accumulo.core.util.ArgumentChecker; +import org.apache.hadoop.io.Text; + +/** + * Conditions that must be met on a particular column in a row. + * + * @since 1.6.0 + */ +public class Condition { + + private ByteSequence cf; + private ByteSequence cq; + private ByteSequence cv; + private ByteSequence val; + private Long ts; + private IteratorSetting iterators[] = new IteratorSetting[0]; + private static final ByteSequence EMPTY = new ArrayByteSequence(new byte[0]); + + + public Condition(CharSequence cf, CharSequence cq) { + ArgumentChecker.notNull(cf, cq); - this.cf = new ArrayByteSequence(cf.toString().getBytes(Constants.UTF8)); - this.cq = new ArrayByteSequence(cq.toString().getBytes(Constants.UTF8)); ++ this.cf = new ArrayByteSequence(cf.toString().getBytes(UTF_8)); ++ this.cq = new ArrayByteSequence(cq.toString().getBytes(UTF_8)); + this.cv = EMPTY; + } + + public Condition(byte[] cf, byte[] cq) { + ArgumentChecker.notNull(cf, cq); + this.cf = new ArrayByteSequence(cf); + this.cq = new ArrayByteSequence(cq); + this.cv = EMPTY; + } + + public Condition(Text cf, Text cq) { + ArgumentChecker.notNull(cf, cq); + this.cf = new ArrayByteSequence(cf.getBytes(), 0, cf.getLength()); + this.cq = new ArrayByteSequence(cq.getBytes(), 0, cq.getLength()); + this.cv = EMPTY; + } + + public Condition(ByteSequence cf, ByteSequence cq) { + ArgumentChecker.notNull(cf, cq); + this.cf = cf; + this.cq = cq; + this.cv = EMPTY; + } + + public ByteSequence getFamily() { + return cf; + } + + public ByteSequence getQualifier() { + return cq; + } + + /** + * Sets the version for the column to check. If this is not set then the latest column will be checked, unless iterators do something different. + * + * @return returns this + */ + + public Condition setTimestamp(long ts) { + this.ts = ts; + return this; + } + + public Long getTimestamp() { + return ts; + } + + /** + * see {@link #setValue(byte[])} + * + * @return returns this + */ + + public Condition setValue(CharSequence value) { + ArgumentChecker.notNull(value); - this.val = new ArrayByteSequence(value.toString().getBytes(Constants.UTF8)); ++ this.val = new ArrayByteSequence(value.toString().getBytes(UTF_8)); + return this; + } + + /** + * This method sets the expected value of a column. Inorder for the condition to pass the column must exist and have this value. If a value is not set, then + * the column must be absent for the condition to pass. + * + * @return returns this + */ + + public Condition setValue(byte[] value) { + ArgumentChecker.notNull(value); + this.val = new ArrayByteSequence(value); + return this; + } + + /** + * see {@link #setValue(byte[])} + * + * @return returns this + */ + + public Condition setValue(Text value) { + ArgumentChecker.notNull(value); + this.val = new ArrayByteSequence(value.getBytes(), 0, value.getLength()); + return this; + } + + /** + * see {@link #setValue(byte[])} + * + * @return returns this + */ + + public Condition setValue(ByteSequence value) { + ArgumentChecker.notNull(value); + this.val = value; + return this; + } + + public ByteSequence getValue() { + return val; + } + + /** + * Sets the visibility for the column to check. If not set it defaults to empty visibility. + * + * @return returns this + */ + + public Condition setVisibility(ColumnVisibility cv) { + ArgumentChecker.notNull(cv); + this.cv = new ArrayByteSequence(cv.getExpression()); + return this; + } + + public ByteSequence getVisibility() { + return cv; + } + + /** + * Set iterators to use when reading the columns value. These iterators will be applied in addition to the iterators configured for the table. Using iterators + * its possible to test other conditions, besides equality and absence, like less than. On the server side the iterators will be seeked using a range that + * covers only the family, qualifier, and visibility (if the timestamp is set then it will be used to narrow the range). Value equality will be tested using + * the first entry returned by the iterator stack. + * + * @return returns this + */ + + public Condition setIterators(IteratorSetting... iterators) { + ArgumentChecker.notNull(iterators); + + if (iterators.length > 1) { + HashSet<String> names = new HashSet<String>(); + HashSet<Integer> prios = new HashSet<Integer>(); + + for (IteratorSetting iteratorSetting : iterators) { + if (!names.add(iteratorSetting.getName())) + throw new IllegalArgumentException("iterator name used more than once " + iteratorSetting.getName()); + if (!prios.add(iteratorSetting.getPriority())) + throw new IllegalArgumentException("iterator priority used more than once " + iteratorSetting.getPriority()); + } + } + + this.iterators = iterators; + return this; + } + + public IteratorSetting[] getIterators() { + return iterators; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !(o instanceof Condition)) { + return false; + } + Condition c = (Condition) o; + if (!(c.cf.equals(cf))) { + return false; + } + if (!(c.cq.equals(cq))) { + return false; + } + if (!(c.cv.equals(cv))) { + return false; + } + if (!(c.val == null ? val == null : c.val.equals(val))) { + return false; + } + if (!(c.ts == null ? ts == null : c.ts.equals(ts))) { + return false; + } + if (!(Arrays.equals(c.iterators, iterators))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + cf.hashCode(); + result = 31 * result + cq.hashCode(); + result = 31 * result + cv.hashCode(); + result = 31 * result + (val == null ? 0 : val.hashCode()); + result = 31 * result + (ts == null ? 0 : ts.hashCode()); + result = 31 * result + Arrays.hashCode(iterators); + return result; + } + +}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/data/Value.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/data/Value.java index 11e60e1,bc1f71d..d256107 --- a/core/src/main/java/org/apache/accumulo/core/data/Value.java +++ b/core/src/main/java/org/apache/accumulo/core/data/Value.java @@@ -25,9 -26,6 +26,8 @@@ import java.io.IOException import java.nio.ByteBuffer; import java.util.List; +import com.google.common.base.Preconditions; + - import org.apache.accumulo.core.Constants; import org.apache.hadoop.io.BytesWritable; import org.apache.hadoop.io.WritableComparable; import org.apache.hadoop.io.WritableComparator; http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/file/BloomFilterLayer.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/iterators/user/IntersectingIterator.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/iterators/user/TransformingIterator.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/iterators/user/VisibilityFilter.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/security/Authorizations.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/security/Authorizations.java index 8006114,0b220ee..7073d11 --- a/core/src/main/java/org/apache/accumulo/core/security/Authorizations.java +++ b/core/src/main/java/org/apache/accumulo/core/security/Authorizations.java @@@ -24,10 -26,7 +26,9 @@@ import java.util.Collections import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; +import java.util.TreeSet; - import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.data.ArrayByteSequence; import org.apache.accumulo.core.data.ByteSequence; import org.apache.accumulo.core.util.ArgumentChecker; @@@ -195,13 -166,12 +196,13 @@@ public class Authorizations implements } /** - * Retrieve a serialized form of the underlying set of authorizations. + * Returns a serialized form of these authorizations. * - * @see #Authorizations(byte[]) + * @return serialized form of these authorizations, as a string encoded in UTF-8 + * @see #serialize() */ public byte[] getAuthorizationsArray() { - return serialize().getBytes(Constants.UTF8); + return serialize().getBytes(UTF_8); } /** http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java index e76b0ef,66b68ab..e8f4e97 --- a/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java +++ b/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java @@@ -243,9 -223,9 +244,9 @@@ public class ColumnVisibility /* * Walks an expression's AST and appends a string representation to a supplied StringBuilder. This method adds parens where necessary. */ - private static void stringify(Node root, byte[] expression, StringBuilder out) { + public static void stringify(Node root, byte[] expression, StringBuilder out) { if (root.type == NodeType.TERM) { - out.append(new String(expression, root.start, root.end - root.start, Constants.UTF8)); + out.append(new String(expression, root.start, root.end - root.start, UTF_8)); } else { String sep = ""; for (Node c : root.children) { @@@ -314,12 -293,12 +315,12 @@@ while (index < expression.length) { switch (expression[index++]) { case '&': { - expr = processTerm(termStart, index - 1, expr, expression); + expr = processTerm(subtermStart, index - 1, expr, expression); if (result != null) { if (!result.type.equals(NodeType.AND)) - throw new BadArgumentException("cannot mix & and |", new String(expression, Constants.UTF8), index - 1); + throw new BadArgumentException("cannot mix & and |", new String(expression, UTF_8), index - 1); } else { - result = new Node(NodeType.AND); + result = new Node(NodeType.AND, wholeTermStart); } result.add(expr); expr = null; @@@ -328,12 -307,12 +329,12 @@@ break; } case '|': { - expr = processTerm(termStart, index - 1, expr, expression); + expr = processTerm(subtermStart, index - 1, expr, expression); if (result != null) { if (!result.type.equals(NodeType.OR)) - throw new BadArgumentException("cannot mix | and &", new String(expression, Constants.UTF8), index - 1); + throw new BadArgumentException("cannot mix | and &", new String(expression, UTF_8), index - 1); } else { - result = new Node(NodeType.OR); + result = new Node(NodeType.OR, wholeTermStart); } result.add(expr); expr = null; @@@ -343,18 -322,18 +344,18 @@@ } case '(': { parens++; - if (termStart != index - 1 || expr != null) + if (subtermStart != index - 1 || expr != null) - throw new BadArgumentException("expression needs & or |", new String(expression, Constants.UTF8), index - 1); + throw new BadArgumentException("expression needs & or |", new String(expression, UTF_8), index - 1); expr = parse_(expression); - termStart = index; - termComplete = false; + subtermStart = index; + subtermComplete = false; break; } case ')': { parens--; - Node child = processTerm(termStart, index - 1, expr, expression); + Node child = processTerm(subtermStart, index - 1, expr, expression); if (child == null && result == null) - throw new BadArgumentException("empty expression not allowed", new String(expression, Constants.UTF8), index); + throw new BadArgumentException("empty expression not allowed", new String(expression, UTF_8), index); if (result == null) return child; if (result.type == child.type) @@@ -366,8 -345,8 +367,8 @@@ return result; } case '"': { - if (termStart != index - 1) + if (subtermStart != index - 1) - throw new BadArgumentException("expression needs & or |", new String(expression, Constants.UTF8), index - 1); + throw new BadArgumentException("expression needs & or |", new String(expression, UTF_8), index - 1); while (index < expression.length && expression[index] != '"') { if (expression[index] == '\\') { @@@ -379,20 -358,20 +380,20 @@@ } if (index == expression.length) - throw new BadArgumentException("unclosed quote", new String(expression, Constants.UTF8), subtermStart); - throw new BadArgumentException("unclosed quote", new String(expression, UTF_8), termStart); - - if (termStart + 1 == index) - throw new BadArgumentException("empty term", new String(expression, UTF_8), termStart); ++ throw new BadArgumentException("unclosed quote", new String(expression, UTF_8), subtermStart); + if (subtermStart + 1 == index) - throw new BadArgumentException("empty term", new String(expression, Constants.UTF8), subtermStart); ++ throw new BadArgumentException("empty term", new String(expression, UTF_8), subtermStart); + index++; - termComplete = true; + subtermComplete = true; break; } default: { - if (termComplete) + if (subtermComplete) - throw new BadArgumentException("expression needs & or |", new String(expression, Constants.UTF8), index - 1); + throw new BadArgumentException("expression needs & or |", new String(expression, UTF_8), index - 1); byte c = expression[index - 1]; if (!Authorizations.isValidAuthChar(c)) @@@ -514,12 -482,10 +515,12 @@@ * . * ColumnVisibility cv = new ColumnVisibility(quote("A#C") + "&" + quote("FOO")); * </pre> - * + * + * @param term term to quote + * @return quoted term (unquoted if unnecessary) */ public static String quote(String term) { - return new String(quote(term.getBytes(Constants.UTF8)), Constants.UTF8); + return new String(quote(term.getBytes(UTF_8)), UTF_8); } /** http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/security/Credentials.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/security/Credentials.java index 582b4e0,31fe18d..0ecc31d --- a/core/src/main/java/org/apache/accumulo/core/security/Credentials.java +++ b/core/src/main/java/org/apache/accumulo/core/security/Credentials.java @@@ -16,17 -16,10 +16,18 @@@ */ package org.apache.accumulo.core.security; ++import static com.google.common.base.Charsets.UTF_8; ++ +import java.nio.ByteBuffer; + - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.Instance; +import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.AuthenticationTokenSerializer; import org.apache.accumulo.core.security.thrift.TCredentials; +import org.apache.accumulo.core.util.Base64; /** * A wrapper for internal use. This class carries the instance, principal, and authentication token for use in the public API, in a non-serialized form. This is @@@ -53,102 -36,9 +54,102 @@@ public class Credentials this.principal = principal; this.token = token; } - - public TCredentials toThrift() { - return CredentialHelper.createSquelchError(principal, token, instance.getInstanceID()); + + /** + * Gets the principal. + * + * @return unique identifier for the entity (e.g. a user or service) authorized for these credentials + */ + public String getPrincipal() { + return principal; + } + + /** + * Gets the authentication token. + * + * @return authentication token used to prove that the principal for these credentials has been properly verified + */ + public AuthenticationToken getToken() { + return token; + } + + /** + * Converts the current object to the relevant thrift type. The object returned from this contains a non-destroyable version of the + * {@link AuthenticationToken}, so this should be used just before placing on the wire, and references to it should be tightly controlled. + * + * @param instance + * client instance + * @return Thrift credentials + * @throws RuntimeException + * if the authentication token has been destroyed (expired) + */ + public TCredentials toThrift(Instance instance) { + TCredentials tCreds = new TCredentials(getPrincipal(), getToken().getClass().getName(), + ByteBuffer.wrap(AuthenticationTokenSerializer.serialize(getToken())), instance.getInstanceID()); + if (getToken().isDestroyed()) + throw new RuntimeException("Token has been destroyed", new AccumuloSecurityException(getPrincipal(), SecurityErrorCode.TOKEN_EXPIRED)); + return tCreds; + } + + /** + * Converts a given thrift object to our internal Credentials representation. + * @param serialized a Thrift encoded set of credentials + * @return a new Credentials instance; destroy the token when you're done. + */ + public static Credentials fromThrift(TCredentials serialized) { + return new Credentials(serialized.getPrincipal(), AuthenticationTokenSerializer.deserialize(serialized.getTokenClassName(), serialized.getToken())); + } + + /** + * Converts the current object to a serialized form. The object returned from this contains a non-destroyable version of the {@link AuthenticationToken}, so + * references to it should be tightly controlled. + * + * @return serialized form of these credentials + */ + public final String serialize() { - return (getPrincipal() == null ? "-" : Base64.encodeBase64String(getPrincipal().getBytes(Constants.UTF8))) + ":" - + (getToken() == null ? "-" : Base64.encodeBase64String(getToken().getClass().getName().getBytes(Constants.UTF8))) + ":" ++ return (getPrincipal() == null ? "-" : Base64.encodeBase64String(getPrincipal().getBytes(UTF_8))) + ":" ++ + (getToken() == null ? "-" : Base64.encodeBase64String(getToken().getClass().getName().getBytes(UTF_8))) + ":" + + (getToken() == null ? "-" : Base64.encodeBase64String(AuthenticationTokenSerializer.serialize(getToken()))); + } + + /** + * Converts the serialized form to an instance of {@link Credentials}. The original serialized form will not be affected. + * + * @param serializedForm + * serialized form of credentials + * @return deserialized credentials + */ + public static final Credentials deserialize(String serializedForm) { + String[] split = serializedForm.split(":", 3); - String principal = split[0].equals("-") ? null : new String(Base64.decodeBase64(split[0]), Constants.UTF8); - String tokenType = split[1].equals("-") ? null : new String(Base64.decodeBase64(split[1]), Constants.UTF8); ++ String principal = split[0].equals("-") ? null : new String(Base64.decodeBase64(split[0]), UTF_8); ++ String tokenType = split[1].equals("-") ? null : new String(Base64.decodeBase64(split[1]), UTF_8); + AuthenticationToken token = null; + if (!split[2].equals("-")) { + byte[] tokenBytes = Base64.decodeBase64(split[2]); + token = AuthenticationTokenSerializer.deserialize(tokenType, tokenBytes); + } + return new Credentials(principal, token); + } + + @Override + public int hashCode() { + return getPrincipal() == null ? 0 : getPrincipal().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !(obj instanceof Credentials)) + return false; + Credentials other = Credentials.class.cast(obj); + boolean pEq = getPrincipal() == null ? (other.getPrincipal() == null) : (getPrincipal().equals(other.getPrincipal())); + if (!pEq) + return false; + boolean tEq = getToken() == null ? (other.getToken() == null) : (getToken().equals(other.getToken())); + return tEq; + } + + @Override + public String toString() { + return getClass().getName() + ":" + getPrincipal() + ":" + (getToken() == null ? null : getToken().getClass().getName()) + ":<hidden>"; } - } http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/security/VisibilityConstraint.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java index be5f008,9c5782b..178de91 --- a/core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java +++ b/core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java @@@ -16,27 -16,17 +16,27 @@@ */ package org.apache.accumulo.core.security; - import java.text.ParseException; + import static com.google.common.base.Charsets.UTF_8; - import org.apache.accumulo.core.Constants; + import java.text.ParseException; +/** + * An exception thrown when a visibility string cannot be parsed. + */ public class VisibilityParseException extends ParseException { private static final long serialVersionUID = 1L; private String visibility; - + + /** + * Creates a new exception. + * + * @param reason reason string + * @param visibility visibility that could not be parsed + * @param errorOffset offset into visibility where parsing failed + */ public VisibilityParseException(String reason, byte[] visibility, int errorOffset) { super(reason, errorOffset); - this.visibility = new String(visibility, Constants.UTF8); + this.visibility = new String(visibility, UTF_8); } @Override http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/ByteBufferUtil.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/ByteBufferUtil.java index 7a23c37,f6a6a01..8771832 --- a/core/src/main/java/org/apache/accumulo/core/util/ByteBufferUtil.java +++ b/core/src/main/java/org/apache/accumulo/core/util/ByteBufferUtil.java @@@ -22,8 -24,6 +24,7 @@@ import java.util.Arrays import java.util.Collection; import java.util.List; - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.data.ByteSequence; import org.apache.hadoop.io.Text; public class ByteBufferUtil { @@@ -62,18 -62,6 +63,18 @@@ } public static String toString(ByteBuffer bytes) { - return new String(bytes.array(), bytes.position(), bytes.remaining(), Constants.UTF8); + return new String(bytes.array(), bytes.position(), bytes.remaining(), UTF_8); } + + public static ByteBuffer toByteBuffers(ByteSequence bs) { + if (bs == null) + return null; + + if (bs.isBackedByArray()) { + return ByteBuffer.wrap(bs.getBackingArray(), bs.offset(), bs.length()); + } else { + // TODO create more efficient impl + return ByteBuffer.wrap(bs.toArray()); + } + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/CreateToken.java index 9f86db3,0000000..26a8c73 mode 100644,000000..100644 --- a/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java +++ b/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java @@@ -1,117 -1,0 +1,118 @@@ +/* + * 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.accumulo.core.util; + ++import static com.google.common.base.Charsets.UTF_8; ++ +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +import jline.console.ConsoleReader; + - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.cli.ClientOpts.Password; +import org.apache.accumulo.core.cli.ClientOpts.PasswordConverter; +import org.apache.accumulo.core.cli.Help; +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.AuthenticationTokenSerializer; +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.Properties; +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.TokenProperty; +import org.apache.accumulo.core.client.security.tokens.PasswordToken; +import org.apache.accumulo.core.util.Base64; + +import com.beust.jcommander.Parameter; + +public class CreateToken { + + private static ConsoleReader reader = null; + + private static ConsoleReader getConsoleReader() throws IOException { + if (reader == null) + reader = new ConsoleReader(); + return reader; + } + + static class Opts extends Help { + @Parameter(names = {"-u", "--user"}, description = "Connection user") + public String principal = null; + + @Parameter(names = "-p", converter = PasswordConverter.class, description = "Connection password") + public Password password = null; + + @Parameter(names = "--password", converter = PasswordConverter.class, description = "Enter the connection password", password = true) + public Password securePassword = null; + + @Parameter(names = {"-tc", "--tokenClass"}, description = "The class of the authentication token") + public String tokenClassName = PasswordToken.class.getName(); + + @Parameter(names = {"-f", "--file"}, description = "The filename to save the auth token to. Multiple tokens can be stored in the same file," + + " but only the first for each user will be recognized.") + public String tokenFile = null; + } + + public static void main(String[] args) { + Opts opts = new Opts(); + opts.parseArgs(CreateToken.class.getName(), args); + + Password pass = opts.password; + if (pass == null && opts.securePassword != null) { + pass = opts.securePassword; + } + + try { + String principal = opts.principal; + if (principal == null) { + principal = getConsoleReader().readLine("Username (aka principal): "); + } + + AuthenticationToken token = Class.forName(opts.tokenClassName).asSubclass(AuthenticationToken.class).newInstance(); + Properties props = new Properties(); + for (TokenProperty tp : token.getProperties()) { + String input; + if (pass != null && tp.getKey().equals("password")) { + input = pass.toString(); + } else { + if (tp.getMask()) { + input = getConsoleReader().readLine(tp.getDescription() + ": ", '*'); + } else { + input = getConsoleReader().readLine(tp.getDescription() + ": "); + } + } + props.put(tp.getKey(), input); + token.init(props); + } + String tokenBase64 = Base64.encodeBase64String(AuthenticationTokenSerializer.serialize(token)); + + String tokenFile = opts.tokenFile; + if (tokenFile == null) { + tokenFile = getConsoleReader().readLine("File to save auth token to: "); + } + File tf = new File(tokenFile); + if (!tf.exists()) { + tf.createNewFile(); + } - PrintStream out = new PrintStream(new FileOutputStream(tf, true), true, Constants.UTF8.name()); ++ PrintStream out = new PrintStream(new FileOutputStream(tf, true), true, UTF_8.name()); + String outString = principal + ":" + opts.tokenClassName + ":" + tokenBase64; + out.println(outString); + out.close(); + System.out.println("Token written to " + tokenFile + ". Remember to upload it to hdfs."); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/Encoding.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/Encoding.java index aff8f62,9999c3c..b26b363 --- a/core/src/main/java/org/apache/accumulo/core/util/Encoding.java +++ b/core/src/main/java/org/apache/accumulo/core/util/Encoding.java @@@ -16,8 -16,9 +16,9 @@@ */ package org.apache.accumulo.core.util; - import org.apache.accumulo.core.Constants; + import static com.google.common.base.Charsets.UTF_8; + -import org.apache.commons.codec.binary.Base64; +import org.apache.accumulo.core.util.Base64; import org.apache.hadoop.io.Text; public class Encoding { @@@ -36,8 -38,10 +37,8 @@@ public static byte[] decodeBase64FileName(String node) { while (node.length() % 4 != 0) node += "="; - - node = node.replace('_', '/').replace('-', '+'); - + /* decode transparently handles URLSafe encodings */ - return Base64.decodeBase64(node.getBytes(Constants.UTF8)); + return Base64.decodeBase64(node.getBytes(UTF_8)); } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/Merge.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/Merge.java index 02c8be3,3830108..05067b5 --- a/core/src/main/java/org/apache/accumulo/core/util/Merge.java +++ b/core/src/main/java/org/apache/accumulo/core/util/Merge.java @@@ -21,7 -23,7 +23,6 @@@ import java.util.Iterator import java.util.List; import java.util.Map.Entry; --import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.cli.ClientOnRequiredTable; import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.Scanner; @@@ -236,8 -233,8 +237,8 @@@ public class Merge while (iterator.hasNext()) { Entry<Key,Value> entry = iterator.next(); Key key = entry.getKey(); - if (key.getColumnFamily().equals(Constants.METADATA_DATAFILE_COLUMN_FAMILY)) { + if (key.getColumnFamily().equals(DataFileColumnFamily.NAME)) { - String[] sizeEntries = new String(entry.getValue().get(), Constants.UTF8).split(","); + String[] sizeEntries = new String(entry.getValue().get(), UTF_8).split(","); if (sizeEntries.length == 2) { tabletSize += Long.parseLong(sizeEntries[0]); } http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/MonitorUtil.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/MonitorUtil.java index 1ebbf13,0000000..e71a377 mode 100644,000000..100644 --- a/core/src/main/java/org/apache/accumulo/core/util/MonitorUtil.java +++ b/core/src/main/java/org/apache/accumulo/core/util/MonitorUtil.java @@@ -1,31 -1,0 +1,33 @@@ +/* + * 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.accumulo.core.util; + ++import static com.google.common.base.Charsets.UTF_8; ++ +import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.Instance; +import org.apache.accumulo.core.zookeeper.ZooUtil; +import org.apache.accumulo.fate.zookeeper.ZooReader; +import org.apache.zookeeper.KeeperException; + +public class MonitorUtil { + public static String getLocation(Instance instance) throws KeeperException, InterruptedException { + ZooReader zr = new ZooReader(instance.getZooKeepers(), 5000); + byte[] loc = zr.getData(ZooUtil.getRoot(instance) + Constants.ZMONITOR_HTTP_ADDR, null); - return loc==null ? null : new String(loc, Constants.UTF8); ++ return loc==null ? null : new String(loc, UTF_8); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java index da5648c,755bee2..b187a76 --- a/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java @@@ -557,14 -437,11 +559,14 @@@ public class Shell extends ShellOption } catch (IOException e) { log.warn("Unable to load history file at " + historyPath); } - + + // Turn Ctrl+C into Exception instead of JVM exit + reader.setHandleUserInterrupt(true); + ShellCompletor userCompletor = null; - + if (execFile != null) { - java.util.Scanner scanner = new java.util.Scanner(execFile, Constants.UTF8.name()); - java.util.Scanner scanner = new java.util.Scanner(new File(execFile), UTF_8.name()); ++ java.util.Scanner scanner = new java.util.Scanner(execFile, UTF_8.name()); try { while (scanner.hasNextLine() && !hasExited()) { execCommand(scanner.nextLine(), true, isVerbose()); @@@ -974,14 -805,14 +976,14 @@@ @Override public void close() {} }; - + public static class PrintFile implements PrintLine { PrintWriter writer; - + public PrintFile(String filename) throws FileNotFoundException { - writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), Constants.UTF8))); + writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), UTF_8))); } - + @Override public void print(String s) { writer.println(s); http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java index f06a639,c325612..90a3548 --- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AddSplitsCommand.java @@@ -19,9 -21,7 +21,8 @@@ import static com.google.common.base.Ch import java.io.File; import java.util.TreeSet; - import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.util.Base64; import org.apache.accumulo.core.util.shell.Shell; import org.apache.accumulo.core.util.shell.Shell.Command; import org.apache.commons.cli.CommandLine; http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java index bcb6c24,5c86ac9..44dce0f --- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/AuthenticateCommand.java @@@ -35,12 -36,12 +36,12 @@@ public class AuthenticateCommand extend final String user = cl.getArgs()[0]; final String p = shellState.readMaskedLine("Enter current password for '" + user + "': ", '*'); if (p == null) { - shellState.getReader().printNewline(); + shellState.getReader().println(); return 0; } // user canceled - final byte[] password = p.getBytes(Constants.UTF8); + final byte[] password = p.getBytes(UTF_8); final boolean valid = shellState.getConnector().securityOperations().authenticateUser(user, new PasswordToken(password)); - shellState.getReader().printString((valid ? "V" : "Not v") + "alid\n"); + shellState.getReader().println((valid ? "V" : "Not v") + "alid"); return 0; } http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateTableCommand.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateTableCommand.java index d2c73f7,8e39115..fc1af0f --- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateTableCommand.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/CreateTableCommand.java @@@ -16,16 -16,16 +16,17 @@@ */ package org.apache.accumulo.core.util.shell.commands; + import static com.google.common.base.Charsets.UTF_8; + import java.io.File; import java.io.IOException; +import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; --import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.TableExistsException; @@@ -73,12 -70,12 +74,12 @@@ public class CreateTableCommand extend } final SortedSet<Text> partitions = new TreeSet<Text>(); final boolean decode = cl.hasOption(base64Opt.getOpt()); - + if (cl.hasOption(createTableOptSplit.getOpt())) { final String f = cl.getOptionValue(createTableOptSplit.getOpt()); - + String line; - Scanner file = new Scanner(new File(f), Constants.UTF8.name()); + Scanner file = new Scanner(new File(f), UTF_8.name()); try { while (file.hasNextLine()) { line = file.nextLine(); http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/shell/commands/HiddenCommand.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/shell/commands/HiddenCommand.java index 61f60f8,4f1c793..06d36b9 --- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/HiddenCommand.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/HiddenCommand.java @@@ -19,8 -21,6 +21,7 @@@ import static com.google.common.base.Ch import java.security.SecureRandom; import java.util.Random; - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.util.Base64; import org.apache.accumulo.core.util.shell.Shell; import org.apache.accumulo.core.util.shell.Shell.Command; import org.apache.accumulo.core.util.shell.ShellCommandException; @@@ -39,11 -40,12 +40,11 @@@ public class HiddenCommand extends Comm public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception { if (rand.nextInt(10) == 0) { shellState.getReader().beep(); - shellState.getReader().printNewline(); - shellState.getReader().printString( + shellState.getReader().println(); + shellState.getReader().println( new String(Base64.decodeBase64(("ICAgICAgIC4tLS4KICAgICAgLyAvXCBcCiAgICAgKCAvLS1cICkKICAgICAuPl8gIF88LgogICAgLyB8ICd8ICcgXAog" + "ICAvICB8Xy58Xy4gIFwKICAvIC98ICAgICAgfFwgXAogfCB8IHwgfFwvfCB8IHwgfAogfF98IHwgfCAgfCB8IHxffAogICAgIC8gIF9fICBcCiAgICAvICAv" - + "ICBcICBcCiAgIC8gIC8gICAgXCAgXF8KIHwvICAvICAgICAgXCB8IHwKIHxfXy8gICAgICAgIFx8X3wK").getBytes(Constants.UTF8)), Constants.UTF8)); + + "ICBcICBcCiAgIC8gIC8gICAgXCAgXF8KIHwvICAvICAgICAgXCB8IHwKIHxfXy8gICAgICAgIFx8X3wK").getBytes(UTF_8)), UTF_8)); - shellState.getReader().printNewline(); } else { throw new ShellCommandException(ErrorCode.UNRECOGNIZED_COMMAND, getName()); } http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/shell/commands/PasswdCommand.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserCommand.java ---------------------------------------------------------------------- diff --cc core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserCommand.java index a0743f4,01fb92e..b8fc4c4 --- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserCommand.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserCommand.java @@@ -41,10 -42,10 +42,10 @@@ public class UserCommand extends Comman // of these methods fails final String p = shellState.readMaskedLine("Enter password for user " + user + ": ", '*'); if (p == null) { - shellState.getReader().printNewline(); + shellState.getReader().println(); return 0; } // user canceled - pass = p.getBytes(Constants.UTF8); + pass = p.getBytes(UTF_8); shellState.updateUser(user, new PasswordToken(pass)); return 0; } http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/test/java/org/apache/accumulo/core/client/BatchWriterConfigTest.java ---------------------------------------------------------------------- diff --cc core/src/test/java/org/apache/accumulo/core/client/BatchWriterConfigTest.java index 259cb06,3794f29..c276056 --- a/core/src/test/java/org/apache/accumulo/core/client/BatchWriterConfigTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/BatchWriterConfigTest.java @@@ -16,6 -16,8 +16,7 @@@ */ package org.apache.accumulo.core.client; + import static com.google.common.base.Charsets.UTF_8; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/test/java/org/apache/accumulo/core/client/ZooKeeperInstanceTest.java ---------------------------------------------------------------------- diff --cc core/src/test/java/org/apache/accumulo/core/client/ZooKeeperInstanceTest.java index dde5575,0000000..dce742f mode 100644,000000..100644 --- a/core/src/test/java/org/apache/accumulo/core/client/ZooKeeperInstanceTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/ZooKeeperInstanceTest.java @@@ -1,157 -1,0 +1,158 @@@ +/* + * 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.accumulo.core.client; + ++import static com.google.common.base.Charsets.UTF_8; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.UUID; + +import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.ClientConfiguration.ClientProperty; +import org.apache.accumulo.fate.zookeeper.ZooCache; +import org.apache.accumulo.fate.zookeeper.ZooCacheFactory; +import org.junit.Before; +import org.junit.Test; + +public class ZooKeeperInstanceTest { + private static final UUID IID = UUID.randomUUID(); + private static final String IID_STRING = IID.toString(); + private ClientConfiguration config; + private ZooCacheFactory zcf; + private ZooCache zc; + private ZooKeeperInstance zki; + + private void mockIdConstruction(ClientConfiguration config) { + expect(config.get(ClientProperty.INSTANCE_ID)).andReturn(IID_STRING); + expect(config.get(ClientProperty.INSTANCE_NAME)).andReturn(null); + expect(config.get(ClientProperty.INSTANCE_ZK_HOST)).andReturn("zk1"); + expect(config.get(ClientProperty.INSTANCE_ZK_TIMEOUT)).andReturn("30"); + } + + private void mockNameConstruction(ClientConfiguration config) { + expect(config.get(ClientProperty.INSTANCE_ID)).andReturn(null); + expect(config.get(ClientProperty.INSTANCE_NAME)).andReturn("instance"); + expect(config.get(ClientProperty.INSTANCE_ZK_HOST)).andReturn("zk1"); + expect(config.get(ClientProperty.INSTANCE_ZK_TIMEOUT)).andReturn("30"); + } + + @Before + public void setUp() { + config = createMock(ClientConfiguration.class); + mockNameConstruction(config); + replay(config); + zcf = createMock(ZooCacheFactory.class); + zc = createMock(ZooCache.class); + expect(zcf.getZooCache("zk1", 30000)).andReturn(zc).anyTimes(); + replay(zcf); + zki = new ZooKeeperInstance(config, zcf); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidConstruction() { + config = createMock(ClientConfiguration.class); + expect(config.get(ClientProperty.INSTANCE_ID)).andReturn(IID_STRING); + mockNameConstruction(config); + replay(config); + new ZooKeeperInstance(config); + } + + @Test + public void testSimpleGetters() { + assertEquals("instance", zki.getInstanceName()); + assertEquals("zk1", zki.getZooKeepers()); + assertEquals(30000, zki.getZooKeepersSessionTimeOut()); + } + + @Test + public void testGetInstanceID_FromCache() { - expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/instance")).andReturn(IID_STRING.getBytes(Constants.UTF8)); ++ expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/instance")).andReturn(IID_STRING.getBytes(UTF_8)); + expect(zc.get(Constants.ZROOT + "/" + IID_STRING)).andReturn("yup".getBytes()); + replay(zc); + assertEquals(IID_STRING, zki.getInstanceID()); + } + + @Test + public void testGetInstanceID_Direct() { + config = createMock(ClientConfiguration.class); + mockIdConstruction(config); + replay(config); + zki = new ZooKeeperInstance(config, zcf); + expect(zc.get(Constants.ZROOT + "/" + IID_STRING)).andReturn("yup".getBytes()); + replay(zc); + assertEquals(IID_STRING, zki.getInstanceID()); + } + + @Test(expected = RuntimeException.class) + public void testGetInstanceID_NoMapping() { + expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/instance")).andReturn(null); + replay(zc); + zki.getInstanceID(); + } + + @Test(expected = RuntimeException.class) + public void testGetInstanceID_IDMissingForName() { - expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/instance")).andReturn(IID_STRING.getBytes(Constants.UTF8)); ++ expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/instance")).andReturn(IID_STRING.getBytes(UTF_8)); + expect(zc.get(Constants.ZROOT + "/" + IID_STRING)).andReturn(null); + replay(zc); + zki.getInstanceID(); + } + + @Test(expected = RuntimeException.class) + public void testGetInstanceID_IDMissingForID() { + config = createMock(ClientConfiguration.class); + mockIdConstruction(config); + replay(config); + zki = new ZooKeeperInstance(config, zcf); + expect(zc.get(Constants.ZROOT + "/" + IID_STRING)).andReturn(null); + replay(zc); + zki.getInstanceID(); + } + + @Test + public void testGetInstanceName() { + config = createMock(ClientConfiguration.class); + mockIdConstruction(config); + replay(config); + zki = new ZooKeeperInstance(config, zcf); + expect(zc.get(Constants.ZROOT + "/" + IID_STRING)).andReturn("yup".getBytes()); + List<String> children = new java.util.ArrayList<String>(); + children.add("child1"); + children.add("child2"); + expect(zc.getChildren(Constants.ZROOT + Constants.ZINSTANCES)).andReturn(children); - expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/child1")).andReturn(UUID.randomUUID().toString().getBytes(Constants.UTF8)); - expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/child2")).andReturn(IID_STRING.getBytes(Constants.UTF8)); ++ expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/child1")).andReturn(UUID.randomUUID().toString().getBytes(UTF_8)); ++ expect(zc.get(Constants.ZROOT + Constants.ZINSTANCES + "/child2")).andReturn(IID_STRING.getBytes(UTF_8)); + replay(zc); + assertEquals("child2", zki.getInstanceName()); + } + + @Test + public void testAllZooKeepersAreUsed() { + final String zookeepers = "zk1,zk2,zk3", instanceName = "accumulo"; + ZooCacheFactory factory = createMock(ZooCacheFactory.class); + expect(factory.getZooCache(zookeepers, 30000)).andReturn(zc).anyTimes(); + replay(factory); + ClientConfiguration cfg = ClientConfiguration.loadDefault().withInstance(instanceName).withZkHosts(zookeepers); + ZooKeeperInstance zki = new ZooKeeperInstance(cfg, factory); + assertEquals(zookeepers, zki.getZooKeepers()); + assertEquals(instanceName, zki.getInstanceName()); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/test/java/org/apache/accumulo/core/client/mock/MockNamespacesTest.java ---------------------------------------------------------------------- diff --cc core/src/test/java/org/apache/accumulo/core/client/mock/MockNamespacesTest.java index db4a12b,0000000..e2661e2 mode 100644,000000..100644 --- a/core/src/test/java/org/apache/accumulo/core/client/mock/MockNamespacesTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/mock/MockNamespacesTest.java @@@ -1,306 -1,0 +1,306 @@@ +/* + * 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.accumulo.core.client.mock; + ++import static com.google.common.base.Charsets.UTF_8; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Random; + - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.BatchWriter; +import org.apache.accumulo.core.client.BatchWriterConfig; +import org.apache.accumulo.core.client.Connector; +import org.apache.accumulo.core.client.Instance; +import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.client.NamespaceNotEmptyException; +import org.apache.accumulo.core.client.NamespaceNotFoundException; +import org.apache.accumulo.core.client.Scanner; +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.NamespaceOperations; +import org.apache.accumulo.core.client.impl.Namespaces; +import org.apache.accumulo.core.client.security.tokens.PasswordToken; +import org.apache.accumulo.core.conf.Property; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.Mutation; +import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.iterators.Filter; +import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; +import org.apache.accumulo.core.security.Authorizations; +import org.junit.Test; + +public class MockNamespacesTest { + + Random random = new Random(); + + /** + * This test creates a table without specifying a namespace. In this case, it puts the table into the default namespace. + */ + @Test + public void testDefaultNamespace() throws Exception { + String tableName = "test"; + Instance instance = new MockInstance("default"); + Connector c = instance.getConnector("user", new PasswordToken("pass")); + + assertTrue(c.namespaceOperations().exists(Namespaces.DEFAULT_NAMESPACE)); + c.tableOperations().create(tableName); + assertTrue(c.tableOperations().exists(tableName)); + } + + /** + * This test creates a new namespace "testing" and a table "testing.table1" which puts "table1" into the "testing" namespace. Then we create "testing.table2" + * which creates "table2" and puts it into "testing" as well. Then we make sure that you can't delete a namespace with tables in it, and then we delete the + * tables and delete the namespace. + */ + @Test + public void testCreateAndDeleteNamespace() throws Exception { + String namespace = "testing"; + String tableName1 = namespace + ".table1"; + String tableName2 = namespace + ".table2"; + + Instance instance = new MockInstance("createdelete"); + Connector c = instance.getConnector("user", new PasswordToken("pass")); + + c.namespaceOperations().create(namespace); + assertTrue(c.namespaceOperations().exists(namespace)); + + c.tableOperations().create(tableName1); + assertTrue(c.tableOperations().exists(tableName1)); + + c.tableOperations().create(tableName2); + assertTrue(c.tableOperations().exists(tableName2)); + + // deleting + try { + // can't delete a namespace with tables in it + c.namespaceOperations().delete(namespace); + fail(); + } catch (NamespaceNotEmptyException e) { + // ignore, supposed to happen + } + assertTrue(c.namespaceOperations().exists(namespace)); + assertTrue(c.tableOperations().exists(tableName1)); + assertTrue(c.tableOperations().exists(tableName2)); + + c.tableOperations().delete(tableName2); + assertTrue(!c.tableOperations().exists(tableName2)); + assertTrue(c.namespaceOperations().exists(namespace)); + + c.tableOperations().delete(tableName1); + assertTrue(!c.tableOperations().exists(tableName1)); + c.namespaceOperations().delete(namespace); + assertTrue(!c.namespaceOperations().exists(namespace)); + } + + /** + * This test creates a namespace, modifies it's properties, and checks to make sure that those properties are applied to its tables. To do something on a + * namespace-wide level, use {@link NamespaceOperations}. + * + * Checks to make sure namespace-level properties are overridden by table-level properties. + * + * Checks to see if the default namespace's properties work as well. + */ + + @Test + public void testNamespaceProperties() throws Exception { + String namespace = "propchange"; + String tableName1 = namespace + ".table1"; + String tableName2 = namespace + ".table2"; + + String propKey = Property.TABLE_SCAN_MAXMEM.getKey(); + String propVal = "42K"; + + Instance instance = new MockInstance("props"); + Connector c = instance.getConnector("user", new PasswordToken("pass")); + + c.namespaceOperations().create(namespace); + c.tableOperations().create(tableName1); + c.namespaceOperations().setProperty(namespace, propKey, propVal); + + // check the namespace has the property + assertTrue(checkNamespaceHasProp(c, namespace, propKey, propVal)); + + // check that the table gets it from the namespace + assertTrue(checkTableHasProp(c, tableName1, propKey, propVal)); + + // test a second table to be sure the first wasn't magical + // (also, changed the order, the namespace has the property already) + c.tableOperations().create(tableName2); + assertTrue(checkTableHasProp(c, tableName2, propKey, propVal)); + + // test that table properties override namespace properties + String propKey2 = Property.TABLE_FILE_MAX.getKey(); + String propVal2 = "42"; + String tablePropVal = "13"; + + c.tableOperations().setProperty(tableName2, propKey2, tablePropVal); + c.namespaceOperations().setProperty("propchange", propKey2, propVal2); + + assertTrue(checkTableHasProp(c, tableName2, propKey2, tablePropVal)); + + // now check that you can change the default namespace's properties + propVal = "13K"; + String tableName = "some_table"; + c.tableOperations().create(tableName); + c.namespaceOperations().setProperty(Namespaces.DEFAULT_NAMESPACE, propKey, propVal); + + assertTrue(checkTableHasProp(c, tableName, propKey, propVal)); + + // test the properties server-side by configuring an iterator. + // should not show anything with column-family = 'a' + String tableName3 = namespace + ".table3"; + c.tableOperations().create(tableName3); + + IteratorSetting setting = new IteratorSetting(250, "thing", SimpleFilter.class.getName()); + c.namespaceOperations().attachIterator(namespace, setting); + + BatchWriter bw = c.createBatchWriter(tableName3, new BatchWriterConfig()); + Mutation m = new Mutation("r"); + m.put("a", "b", new Value("abcde".getBytes())); + bw.addMutation(m); + bw.flush(); + bw.close(); + + // Scanner s = c.createScanner(tableName3, Authorizations.EMPTY); + // do scanners work correctly in mock? + // assertTrue(!s.iterator().hasNext()); + } + + /** + * This test renames and clones two separate table into different namespaces. different namespace. + */ + @Test + public void testRenameAndCloneTableToNewNamespace() throws Exception { + String namespace1 = "renamed"; + String namespace2 = "cloned"; + String tableName = "table"; + String tableName1 = "renamed.table1"; + // String tableName2 = "cloned.table2"; + + Instance instance = new MockInstance("renameclone"); + Connector c = instance.getConnector("user", new PasswordToken("pass")); + + c.tableOperations().create(tableName); + c.namespaceOperations().create(namespace1); + c.namespaceOperations().create(namespace2); + + c.tableOperations().rename(tableName, tableName1); + + assertTrue(c.tableOperations().exists(tableName1)); + assertTrue(!c.tableOperations().exists(tableName)); + + // TODO implement clone in mock + /* + * c.tableOperations().clone(tableName1, tableName2, false, null, null); + * + * assertTrue(c.tableOperations().exists(tableName1)); assertTrue(c.tableOperations().exists(tableName2)); + */ + return; + } + + /** + * This test renames a namespace and ensures that its tables are still correct + */ + @Test + public void testNamespaceRename() throws Exception { + String namespace1 = "n1"; + String namespace2 = "n2"; + String table = "t"; + + Instance instance = new MockInstance("rename"); + Connector c = instance.getConnector("user", new PasswordToken("pass")); + + c.namespaceOperations().create(namespace1); + c.tableOperations().create(namespace1 + "." + table); + + c.namespaceOperations().rename(namespace1, namespace2); + + assertTrue(!c.namespaceOperations().exists(namespace1)); + assertTrue(c.namespaceOperations().exists(namespace2)); + assertTrue(!c.tableOperations().exists(namespace1 + "." + table)); + assertTrue(c.tableOperations().exists(namespace2 + "." + table)); + } + + /** + * This tests adding iterators to a namespace, listing them, and removing them + */ + @Test + public void testNamespaceIterators() throws Exception { + Instance instance = new MockInstance("Iterators"); + Connector c = instance.getConnector("user", new PasswordToken("pass")); + + String namespace = "iterator"; + String tableName = namespace + ".table"; + String iter = "thing"; + + c.namespaceOperations().create(namespace); + c.tableOperations().create(tableName); + + IteratorSetting setting = new IteratorSetting(250, iter, SimpleFilter.class.getName()); + HashSet<IteratorScope> scope = new HashSet<IteratorScope>(); + scope.add(IteratorScope.scan); + c.namespaceOperations().attachIterator(namespace, setting, EnumSet.copyOf(scope)); + + BatchWriter bw = c.createBatchWriter(tableName, new BatchWriterConfig()); + Mutation m = new Mutation("r"); - m.put("a", "b", new Value("abcde".getBytes(Constants.UTF8))); ++ m.put("a", "b", new Value("abcde".getBytes(UTF_8))); + bw.addMutation(m); + bw.flush(); + + Scanner s = c.createScanner(tableName, Authorizations.EMPTY); + System.out.println(s.iterator().next()); + // do scanners work correctly in mock? + // assertTrue(!s.iterator().hasNext()); + + assertTrue(c.namespaceOperations().listIterators(namespace).containsKey(iter)); + c.namespaceOperations().removeIterator(namespace, iter, EnumSet.copyOf(scope)); + } + + private boolean checkTableHasProp(Connector c, String t, String propKey, String propVal) throws AccumuloException, TableNotFoundException { + for (Entry<String,String> e : c.tableOperations().getProperties(t)) { + if (e.getKey().equals(propKey) && e.getValue().equals(propVal)) { + return true; + } + } + return false; + } + + private boolean checkNamespaceHasProp(Connector c, String n, String propKey, String propVal) throws AccumuloException, NamespaceNotFoundException, + AccumuloSecurityException { + for (Entry<String,String> e : c.namespaceOperations().getProperties(n)) { + if (e.getKey().equals(propKey) && e.getValue().equals(propVal)) { + return true; + } + } + return false; + } + + public static class SimpleFilter extends Filter { + @Override + public boolean accept(Key k, Value v) { + if (k.getColumnFamily().toString().equals("a")) + return false; + return true; + } + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/test/java/org/apache/accumulo/core/client/security/tokens/CredentialProviderTokenTest.java ---------------------------------------------------------------------- diff --cc core/src/test/java/org/apache/accumulo/core/client/security/tokens/CredentialProviderTokenTest.java index 17d2297,0000000..7bb3fa4 mode 100644,000000..100644 --- a/core/src/test/java/org/apache/accumulo/core/client/security/tokens/CredentialProviderTokenTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/security/tokens/CredentialProviderTokenTest.java @@@ -1,129 -1,0 +1,130 @@@ +/* + * 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.accumulo.core.client.security.tokens; + ++import static com.google.common.base.Charsets.UTF_8; ++ +import java.io.File; +import java.io.IOException; +import java.net.URL; + - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.Properties; +import org.apache.accumulo.core.conf.CredentialProviderFactoryShim; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CredentialProviderTokenTest { + + private static boolean isCredentialProviderAvailable = false; + + // Keystore contains: {'root.password':'password', 'bob.password':'bob'} + private static String keystorePath; + + @BeforeClass + public static void setup() { + try { + Class.forName(CredentialProviderFactoryShim.HADOOP_CRED_PROVIDER_CLASS_NAME); + isCredentialProviderAvailable = true; + } catch (Exception e) { + isCredentialProviderAvailable = false; + } + + URL keystoreUrl = CredentialProviderTokenTest.class.getResource("/passwords.jceks"); + Assert.assertNotNull(keystoreUrl); + keystorePath = "jceks://file/" + new File(keystoreUrl.getFile()).getAbsolutePath(); + } + + @Test + public void testPasswordsFromCredentialProvider() throws Exception { + if (!isCredentialProviderAvailable) { + return; + } + + CredentialProviderToken token = new CredentialProviderToken("root.password", keystorePath); - Assert.assertArrayEquals("password".getBytes(Constants.UTF8), token.getPassword()); ++ Assert.assertArrayEquals("password".getBytes(UTF_8), token.getPassword()); + + token = new CredentialProviderToken("bob.password", keystorePath); - Assert.assertArrayEquals("bob".getBytes(Constants.UTF8), token.getPassword()); ++ Assert.assertArrayEquals("bob".getBytes(UTF_8), token.getPassword()); + } + + @Test + public void testEqualityAfterInit() throws Exception { + if (!isCredentialProviderAvailable) { + return; + } + + CredentialProviderToken token = new CredentialProviderToken("root.password", keystorePath); + + CredentialProviderToken uninitializedToken = new CredentialProviderToken(); + Properties props = new Properties(); + props.put(CredentialProviderToken.NAME_PROPERTY, "root.password"); + props.put(CredentialProviderToken.CREDENTIAL_PROVIDERS_PROPERTY, keystorePath); + uninitializedToken.init(props); + + Assert.assertArrayEquals(token.getPassword(), uninitializedToken.getPassword()); + } + + @Test + public void testMissingClassesThrowsException() throws Exception { + if (isCredentialProviderAvailable) { + return; + } + + try { + new CredentialProviderToken("root.password", keystorePath); + Assert.fail("Should fail to create CredentialProviderToken when classes are not available"); + } catch (IOException e) { + // pass + } + } + + @Test + public void cloneReturnsCorrectObject() throws Exception { + if (!isCredentialProviderAvailable) { + return; + } + + CredentialProviderToken token = new CredentialProviderToken("root.password", keystorePath); + CredentialProviderToken clone = token.clone(); + + Assert.assertEquals(token, clone); + Assert.assertArrayEquals(token.getPassword(), clone.getPassword()); + } + + @Test(expected = IllegalArgumentException.class) + public void missingProperties() throws Exception { + CredentialProviderToken token = new CredentialProviderToken(); + token.init(new Properties()); + } + + @Test(expected = IllegalArgumentException.class) + public void missingNameProperty() throws Exception { + CredentialProviderToken token = new CredentialProviderToken(); + Properties props = new Properties(); + props.put(CredentialProviderToken.NAME_PROPERTY, "root.password"); + token.init(props); + } + + @Test(expected = IllegalArgumentException.class) + public void missingProviderProperty() throws Exception { + CredentialProviderToken token = new CredentialProviderToken(); + Properties props = new Properties(); + props.put(CredentialProviderToken.CREDENTIAL_PROVIDERS_PROPERTY, keystorePath); + token.init(props); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/test/java/org/apache/accumulo/core/data/ConditionTest.java ---------------------------------------------------------------------- diff --cc core/src/test/java/org/apache/accumulo/core/data/ConditionTest.java index 3570610,0000000..d9a47d7 mode 100644,000000..100644 --- a/core/src/test/java/org/apache/accumulo/core/data/ConditionTest.java +++ b/core/src/test/java/org/apache/accumulo/core/data/ConditionTest.java @@@ -1,251 -1,0 +1,251 @@@ +/* + * 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.accumulo.core.data; + ++import static com.google.common.base.Charsets.UTF_8; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + - import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.security.ColumnVisibility; +import org.apache.hadoop.io.Text; +import org.junit.Before; +import org.junit.Test; + +public class ConditionTest { + private static final ByteSequence EMPTY = new ArrayByteSequence(new byte[0]); + private static final String FAMILY = "family"; + private static final String QUALIFIER = "qualifier"; + private static final String VISIBILITY = "visibility"; + private static final String VALUE = "value"; + private static final IteratorSetting[] ITERATORS = {new IteratorSetting(1, "first", "someclass"), new IteratorSetting(2, "second", "someotherclass"), + new IteratorSetting(3, "third", "yetanotherclass")}; + + private String toString(ByteSequence bs) { + if (bs == null) { + return null; + } - return new String(bs.toArray(), Constants.UTF8); ++ return new String(bs.toArray(), UTF_8); + } + + private Condition c; + + @Before + public void setUp() throws Exception { + c = new Condition(FAMILY, QUALIFIER); + } + + @Test + public void testConstruction_CharSequence() { + assertEquals(FAMILY, toString(c.getFamily())); + assertEquals(QUALIFIER, toString(c.getQualifier())); + assertEquals(EMPTY, c.getVisibility()); + } + + @Test + public void testConstruction_ByteArray() { - c = new Condition(FAMILY.getBytes(Constants.UTF8), QUALIFIER.getBytes(Constants.UTF8)); ++ c = new Condition(FAMILY.getBytes(UTF_8), QUALIFIER.getBytes(UTF_8)); + assertEquals(FAMILY, toString(c.getFamily())); + assertEquals(QUALIFIER, toString(c.getQualifier())); + assertEquals(EMPTY, c.getVisibility()); + } + + @Test + public void testConstruction_Text() { + c = new Condition(new Text(FAMILY), new Text(QUALIFIER)); + assertEquals(FAMILY, toString(c.getFamily())); + assertEquals(QUALIFIER, toString(c.getQualifier())); + assertEquals(EMPTY, c.getVisibility()); + } + + @Test + public void testConstruction_ByteSequence() { - c = new Condition(new ArrayByteSequence(FAMILY.getBytes(Constants.UTF8)), new ArrayByteSequence(QUALIFIER.getBytes(Constants.UTF8))); ++ c = new Condition(new ArrayByteSequence(FAMILY.getBytes(UTF_8)), new ArrayByteSequence(QUALIFIER.getBytes(UTF_8))); + assertEquals(FAMILY, toString(c.getFamily())); + assertEquals(QUALIFIER, toString(c.getQualifier())); + assertEquals(EMPTY, c.getVisibility()); + } + + @Test + public void testGetSetTimestamp() { + c.setTimestamp(1234L); + assertEquals(Long.valueOf(1234L), c.getTimestamp()); + } + + @Test + public void testSetValue_CharSequence() { + c.setValue(VALUE); + assertEquals(VALUE, toString(c.getValue())); + } + + @Test + public void testSetValue_ByteArray() { - c.setValue(VALUE.getBytes(Constants.UTF8)); ++ c.setValue(VALUE.getBytes(UTF_8)); + assertEquals(VALUE, toString(c.getValue())); + } + + @Test + public void testSetValue_Text() { + c.setValue(new Text(VALUE)); + assertEquals(VALUE, toString(c.getValue())); + } + + @Test + public void testSetValue_ByteSequence() { - c.setValue(new ArrayByteSequence(VALUE.getBytes(Constants.UTF8))); ++ c.setValue(new ArrayByteSequence(VALUE.getBytes(UTF_8))); + assertEquals(VALUE, toString(c.getValue())); + } + + @Test + public void testGetSetVisibility() { + ColumnVisibility vis = new ColumnVisibility(VISIBILITY); + c.setVisibility(vis); + assertEquals(VISIBILITY, toString(c.getVisibility())); + } + + @Test + public void testGetSetIterators() { + c.setIterators(ITERATORS); + assertArrayEquals(ITERATORS, c.getIterators()); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIterators_DuplicateName() { + IteratorSetting[] iterators = {new IteratorSetting(1, "first", "someclass"), new IteratorSetting(2, "second", "someotherclass"), + new IteratorSetting(3, "first", "yetanotherclass")}; + c.setIterators(iterators); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIterators_DuplicatePriority() { + IteratorSetting[] iterators = {new IteratorSetting(1, "first", "someclass"), new IteratorSetting(2, "second", "someotherclass"), + new IteratorSetting(1, "third", "yetanotherclass")}; + c.setIterators(iterators); + } + + @Test + public void testEquals() { + ColumnVisibility cvis = new ColumnVisibility(VISIBILITY); + c.setVisibility(cvis); + c.setValue(VALUE); + c.setTimestamp(1234L); + c.setIterators(ITERATORS); + + // reflexivity + assertTrue(c.equals(c)); + + // non-nullity + assertFalse(c.equals(null)); + + // symmetry + Condition c2 = new Condition(FAMILY, QUALIFIER); + c2.setVisibility(cvis); + c2.setValue(VALUE); + c2.setTimestamp(1234L); + c2.setIterators(ITERATORS); + assertTrue(c.equals(c2)); + assertTrue(c2.equals(c)); + + Condition c3 = new Condition("nope", QUALIFIER); + c3.setVisibility(cvis); + c3.setValue(VALUE); + c3.setTimestamp(1234L); + c3.setIterators(ITERATORS); + assertFalse(c.equals(c3)); + assertFalse(c3.equals(c)); + c3 = new Condition(FAMILY, "nope"); + c3.setVisibility(cvis); + c3.setValue(VALUE); + c3.setTimestamp(1234L); + c3.setIterators(ITERATORS); + assertFalse(c.equals(c3)); + assertFalse(c3.equals(c)); + + c2.setVisibility(new ColumnVisibility("sekrit")); + assertFalse(c.equals(c2)); + assertFalse(c2.equals(c)); + c2.setVisibility(cvis); + c2.setValue(EMPTY); + assertFalse(c.equals(c2)); + assertFalse(c2.equals(c)); + c2.setValue(VALUE); + c2.setTimestamp(2345L); + assertFalse(c.equals(c2)); + assertFalse(c2.equals(c)); + c2.setTimestamp(1234L); + c2.setIterators(new IteratorSetting[0]); + assertFalse(c.equals(c2)); + assertFalse(c2.equals(c)); + c2.setIterators(ITERATORS); + assertTrue(c.equals(c2)); + assertTrue(c2.equals(c)); + + // set everything but vis, so its null + Condition c4 = new Condition(FAMILY, QUALIFIER); + c4.setValue(VALUE); + c4.setTimestamp(1234L); + c4.setIterators(ITERATORS); + + assertFalse(c.equals(c4)); + assertFalse(c4.equals(c)); + + // set everything but timestamp, so its null + Condition c5 = new Condition(FAMILY, QUALIFIER); + c5.setVisibility(cvis); + c5.setValue(VALUE); + c5.setIterators(ITERATORS); + + assertFalse(c.equals(c5)); + assertFalse(c5.equals(c)); + + // set everything but value + Condition c6 = new Condition(FAMILY, QUALIFIER); + c6.setVisibility(cvis); + c6.setTimestamp(1234L); + c6.setIterators(ITERATORS); + + assertFalse(c.equals(c6)); + assertFalse(c6.equals(c)); + + // test w/ no optional fields set + Condition c7 = new Condition(FAMILY, QUALIFIER); + Condition c8 = new Condition(FAMILY, QUALIFIER); + assertTrue(c7.equals(c8)); + assertTrue(c8.equals(c7)); + + } + + @Test + public void testHashCode() { + ColumnVisibility cvis = new ColumnVisibility(VISIBILITY); + c.setVisibility(cvis); + c.setValue(VALUE); + c.setTimestamp(1234L); + c.setIterators(ITERATORS); + int hc1 = c.hashCode(); + + Condition c2 = new Condition(FAMILY, QUALIFIER); + c2.setVisibility(cvis); + c2.setValue(VALUE); + c2.setTimestamp(1234L); + c2.setIterators(ITERATORS); + assertTrue(c.equals(c2)); + assertEquals(hc1, c2.hashCode()); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/9b20a9d4/core/src/test/java/org/apache/accumulo/core/data/ConditionalMutationTest.java ---------------------------------------------------------------------- diff --cc core/src/test/java/org/apache/accumulo/core/data/ConditionalMutationTest.java index 47f44f1,0000000..908c391 mode 100644,000000..100644 --- a/core/src/test/java/org/apache/accumulo/core/data/ConditionalMutationTest.java +++ b/core/src/test/java/org/apache/accumulo/core/data/ConditionalMutationTest.java @@@ -1,149 -1,0 +1,149 @@@ +/* + * 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.accumulo.core.data; + ++import static com.google.common.base.Charsets.UTF_8; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; + - import org.apache.accumulo.core.Constants; +import org.apache.hadoop.io.Text; +import org.junit.Before; +import org.junit.Test; + +public class ConditionalMutationTest { - private static final byte[] ROW = "row".getBytes(Constants.UTF8); ++ private static final byte[] ROW = "row".getBytes(UTF_8); + private static final String FAMILY = "family"; + private static final String QUALIFIER = "qualifier"; + private static final String QUALIFIER2 = "qualifier2"; + private static final String QUALIFIER3 = "qualifier3"; + + private Condition c1, c2; + private ConditionalMutation cm; + + @Before + public void setUp() throws Exception { + c1 = new Condition(FAMILY, QUALIFIER); + c2 = new Condition(FAMILY, QUALIFIER2); + assertFalse(c1.equals(c2)); + cm = new ConditionalMutation(ROW, c1, c2); + } + + @Test + public void testConstruction_ByteArray() { + assertArrayEquals(ROW, cm.getRow()); + List<Condition> cs = cm.getConditions(); + assertEquals(2, cs.size()); + assertEquals(c1, cs.get(0)); + assertEquals(c2, cs.get(1)); + } + + @Test + public void testConstruction_ByteArray_StartAndLength() { + cm = new ConditionalMutation(ROW, 1, 1, c1, c2); - assertArrayEquals("o".getBytes(Constants.UTF8), cm.getRow()); ++ assertArrayEquals("o".getBytes(UTF_8), cm.getRow()); + List<Condition> cs = cm.getConditions(); + assertEquals(2, cs.size()); + assertEquals(c1, cs.get(0)); + assertEquals(c2, cs.get(1)); + } + + @Test + public void testConstruction_Text() { + cm = new ConditionalMutation(new Text(ROW), c1, c2); + assertArrayEquals(ROW, cm.getRow()); + List<Condition> cs = cm.getConditions(); + assertEquals(2, cs.size()); + assertEquals(c1, cs.get(0)); + assertEquals(c2, cs.get(1)); + } + + @Test + public void testConstruction_CharSequence() { - cm = new ConditionalMutation(new String(ROW, Constants.UTF8), c1, c2); ++ cm = new ConditionalMutation(new String(ROW, UTF_8), c1, c2); + assertArrayEquals(ROW, cm.getRow()); + List<Condition> cs = cm.getConditions(); + assertEquals(2, cs.size()); + assertEquals(c1, cs.get(0)); + assertEquals(c2, cs.get(1)); + } + + @Test + public void testConstruction_ByteSequence() { + cm = new ConditionalMutation(new ArrayByteSequence(ROW), c1, c2); + assertArrayEquals(ROW, cm.getRow()); + List<Condition> cs = cm.getConditions(); + assertEquals(2, cs.size()); + assertEquals(c1, cs.get(0)); + assertEquals(c2, cs.get(1)); + } + + @Test + public void testCopyConstructor() { + ConditionalMutation cm2 = new ConditionalMutation(cm); + assertArrayEquals(cm.getRow(), cm2.getRow()); + assertEquals(cm.getConditions(), cm2.getConditions()); + } + + @Test + public void testAddCondition() { + Condition c3 = new Condition(FAMILY, QUALIFIER3); + cm.addCondition(c3); + List<Condition> cs = cm.getConditions(); + assertEquals(3, cs.size()); + assertEquals(c1, cs.get(0)); + assertEquals(c2, cs.get(1)); + assertEquals(c3, cs.get(2)); + } + + @Test + public void testEquals() { + // reflexivity + assertTrue(cm.equals(cm)); + + // non-nullity + assertFalse(cm.equals((Object) null)); + + // symmetry + ConditionalMutation cm2 = new ConditionalMutation(ROW, c1, c2); + assertTrue(cm.equals(cm2)); + assertTrue(cm2.equals(cm)); + - ConditionalMutation cm3 = new ConditionalMutation("row2".getBytes(Constants.UTF8), c1, c2); ++ ConditionalMutation cm3 = new ConditionalMutation("row2".getBytes(UTF_8), c1, c2); + assertFalse(cm.equals(cm3)); + cm3 = new ConditionalMutation(ROW, c2, c1); + assertFalse(cm.getConditions().equals(cm3.getConditions())); + assertFalse(cm.equals(cm3)); + } + + @Test + public void testEquals_Mutation() { + Mutation m = new Mutation(ROW); + assertFalse(m.equals(cm)); + assertFalse(cm.equals(m)); + } + + @Test + public void testHashcode() { + ConditionalMutation cm2 = new ConditionalMutation(ROW, c1, c2); + assertTrue(cm.equals(cm2)); + assertEquals(cm2.hashCode(), cm.hashCode()); + } +}