You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@accumulo.apache.org by GitBox <gi...@apache.org> on 2018/08/15 15:06:06 UTC

[GitHub] mikewalch closed pull request #590: ACCUMULO-4746 Fluent API for Mutation

mikewalch closed pull request #590: ACCUMULO-4746 Fluent API for Mutation
URL: https://github.com/apache/accumulo/pull/590
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/core/src/main/java/org/apache/accumulo/core/data/Mutation.java b/core/src/main/java/org/apache/accumulo/core/data/Mutation.java
index ae95687bfa..766b212c07 100644
--- a/core/src/main/java/org/apache/accumulo/core/data/Mutation.java
+++ b/core/src/main/java/org/apache/accumulo/core/data/Mutation.java
@@ -289,24 +289,24 @@ public Mutation(Mutation m) {
     return row;
   }
 
-  private void put(byte b[]) {
-    put(b, b.length);
+  private void fill(byte b[]) {
+    fill(b, b.length);
   }
 
-  private void put(byte b[], int length) {
+  private void fill(byte b[], int length) {
     buffer.writeVLong(length);
     buffer.add(b, 0, length);
   }
 
-  private void put(boolean b) {
+  private void fill(boolean b) {
     buffer.add(b);
   }
 
-  private void put(int i) {
+  private void fill(int i) {
     buffer.writeVLong(i);
   }
 
-  private void put(long l) {
+  private void fill(long l) {
     buffer.writeVLong(l);
   }
 
@@ -335,17 +335,17 @@ private void put(byte[] cf, int cfLength, byte[] cq, int cqLength, byte[] cv, bo
     Preconditions.checkArgument(
         estimatedSizeAfterPut < MAX_MUTATION_SIZE && estimatedSizeAfterPut >= 0,
         "Maximum mutation size must be less than 2GB ");
-    put(cf, cfLength);
-    put(cq, cqLength);
-    put(cv);
-    put(hasts);
+    fill(cf, cfLength);
+    fill(cq, cqLength);
+    fill(cv);
+    fill(hasts);
     if (hasts) {
-      put(ts);
+      fill(ts);
     }
-    put(deleted);
+    fill(deleted);
 
     if (valLength < VALUE_SIZE_COPY_CUTOFF) {
-      put(val, valLength);
+      fill(val, valLength);
     } else {
       if (values == null) {
         values = new ArrayList<>();
@@ -353,7 +353,7 @@ private void put(byte[] cf, int cfLength, byte[] cq, int cqLength, byte[] cv, bo
       byte copy[] = new byte[valLength];
       System.arraycopy(val, 0, copy, 0, valLength);
       values.add(copy);
-      put(-1 * values.size());
+      fill(-1 * values.size());
       estRowAndLargeValSize += valLength + SERIALIZATION_OVERHEAD;
     }
 
@@ -853,6 +853,474 @@ public void putDelete(byte[] columnFamily, byte[] columnQualifier,
         EMPTY_BYTES);
   }
 
+  /**
+   * Provides methods for setting the column family of a Mutation. The user can provide the family
+   * name as a byte array, CharSequence, ByteBuffer, or Text object instance and the backend will do
+   * the necessary transformation.
+   *
+   * All FamilyOptions methods return an instance derived from the QualifierOptions interface,
+   * allowing the methods to be semantically chained.
+   *
+   * @since 2.0.0
+   */
+  public interface FamilyOptions extends QualifierOptions {
+    QualifierOptions family(byte[] colFam);
+
+    QualifierOptions family(ByteBuffer colFam);
+
+    QualifierOptions family(CharSequence colFam);
+
+    QualifierOptions family(Text colFam);
+  }
+
+  /**
+   * Provides methods for setting the column qualifier of a Mutation. The user can provide the
+   * qualifier name as a byte array, CharSequence, ByteBuffer, or Text object instance and the
+   * backend will do the necessary transformation.
+   *
+   * All QualifierOptions methods return an instance derived from the VisibilityOptions interface,
+   * allowing the methods to be semantically chained.
+   *
+   * @since 2.0.0
+   */
+  public interface QualifierOptions extends VisibilityOptions {
+    VisibilityOptions qualifier(byte[] colQual);
+
+    VisibilityOptions qualifier(ByteBuffer colQual);
+
+    VisibilityOptions qualifier(CharSequence colQual);
+
+    VisibilityOptions qualifier(Text colQual);
+  }
+
+  /**
+   * Provides methods for setting the column visibility of a Mutation. The user can provide the
+   * visibility as a byte array or {@link org.apache.accumulo.core.security.ColumnVisibility} object
+   * instance and the backend will do the necessary transformation.
+   *
+   * All QualifierOptions methods return an instance derived from the VisibilityOptions interface,
+   * allowing the methods to be semantically chained.
+   *
+   * @since 2.0.0
+   */
+  public interface VisibilityOptions extends TimestampOptions {
+    TimestampOptions visibility(byte[] colVis);
+
+    TimestampOptions visibility(ByteBuffer colVis);
+
+    TimestampOptions visibility(CharSequence colVis);
+
+    TimestampOptions visibility(ColumnVisibility colVis);
+
+    TimestampOptions visibility(Text colVis);
+  }
+
+  /**
+   * Provides methods for setting the timestamp of a Mutation. The user must provide the timestamp
+   * as a long.
+   *
+   * <p>
+   * All TimestampOptions methods return an instance derived from the MutationOptions interface,
+   * allowing the methods to be semantically chained.
+   *
+   * @since 2.0.0
+   */
+  public interface TimestampOptions extends MutationOptions {
+    MutationOptions timestamp(long ts);
+  }
+
+  /**
+   * Provides methods for setting the value of a Mutation. The user can provide the value as a byte
+   * array, Value, or ByteBuffer object instance and the backend will do the necessary
+   * transformation.
+   *
+   * <p>
+   * All MutationOptions methods complete a fluent Mutation API method chain.
+   *
+   * @since 2.0.0
+   */
+  public interface MutationOptions {
+    Mutation put(byte[] val);
+
+    Mutation put(ByteBuffer val);
+
+    Mutation put(CharSequence val);
+
+    Mutation put(Text val);
+
+    Mutation put(Value val);
+
+    Mutation delete();
+  }
+
+  /**
+   * Fluent API for putting or deleting to a Mutation that makes it easy use different types
+   * (i.e byte[], CharSequence, etc) when specifying the family, qualifier, value, etc.
+   *
+   * <p>
+   * Methods are optional but must follow this order: family, qualifier, visibility, timestamp.
+   *
+   * <p>
+   * The put and delete methods end the chain and add the modification to the Mutation.
+   *
+   * @return a new FamilyOptions object, starting the method chain
+   * @since 2.0.0
+   */
+  public FamilyOptions at() {
+    return new Options();
+  }
+
+  // private inner class implementing all Options interfaces
+  private class Options implements FamilyOptions {
+    byte[] columnFamily;
+    int columnFamilyLength;
+
+    byte[] columnQualifier;
+    int columnQualifierLength;
+
+    byte[] columnVisibility = null;
+    int columnVisibilityLength;
+
+    boolean hasTs = false;
+    long timestamp;
+
+    private Options() {}
+
+    // methods for changing the column family of a Mutation
+    /**
+     * Sets the column family of a mutation.
+     *
+     * @param colFam
+     *          column family
+     * @param colFamLength
+     *          column family length
+     * @return a QualifierOptions object, advancing the method chain
+     */
+    private QualifierOptions family(byte[] colFam, int colFamLength) {
+      columnFamily = colFam;
+      columnFamilyLength = colFamLength;
+      return this;
+    }
+
+    /**
+     * Sets the column family of a mutation.
+     *
+     * @param colFam
+     *          column family
+     * @return a QualifierOptions object, advancing the method chain
+     */
+    @Override
+    public QualifierOptions family(byte[] colFam) {
+      return family(colFam, colFam.length);
+    }
+
+    /**
+     * Sets the column family of a mutation.
+     *
+     * @param colFam
+     *          column family
+     * @return a QualifierOptions object, advancing the method chain
+     */
+    @Override
+    public QualifierOptions family(ByteBuffer colFam) {
+      return family(ByteBufferUtil.toBytes(colFam));
+    }
+
+    /**
+     * Sets the column family of a mutation.
+     *
+     * @param colFam
+     *          column family
+     * @return a QualifierOptions object, advancing the method chain
+     */
+    @Override
+    public QualifierOptions family(CharSequence colFam) {
+      return family(new Text(colFam.toString()));
+    }
+
+    /**
+     * Sets the column family of a mutation.
+     *
+     * @param colFam
+     *          column family
+     * @return a QualifierOptions object, advancing the method chain
+     */
+    @Override
+    public QualifierOptions family(Text colFam) {
+      return family(colFam.getBytes(), colFam.getLength());
+    }
+
+    /**
+     * Sets the column qualifier of a mutation.
+     *
+     * @param colQual
+     *          column qualifier
+     * @param colQualLength
+     *          column qualifier
+     * @return a VisibilityOptions object, advancing the method chain
+     */
+    private VisibilityOptions qualifier(byte[] colQual, int colQualLength) {
+      columnQualifier = colQual;
+      columnQualifierLength = colQualLength;
+      return this;
+    }
+
+    /**
+     * Sets the column qualifier of a mutation.
+     *
+     * @param colQual
+     *          column qualifier
+     * @return a VisibilityOptions object, advancing the method chain
+     */
+    @Override
+    public VisibilityOptions qualifier(byte[] colQual) {
+      return qualifier(colQual, colQual.length);
+    }
+
+    /**
+     * Sets the column qualifier of a mutation.
+     *
+     * @param colQual
+     *          column qualifier
+     * @return a VisibilityOptions object, advancing the method chain
+     */
+    @Override
+    public VisibilityOptions qualifier(ByteBuffer colQual) {
+      return qualifier(ByteBufferUtil.toBytes(colQual));
+    }
+
+    /**
+     * Sets the column qualifier of a mutation.
+     *
+     * @param colQual
+     *          column qualifier
+     * @return a VisibilityOptions object, advancing the method chain
+     */
+    @Override
+    public VisibilityOptions qualifier(CharSequence colQual) {
+      return qualifier(new Text(colQual.toString()));
+    }
+
+    /**
+     * Sets the column qualifier of a mutation.
+     *
+     * @param colQual
+     *          column qualifier
+     * @return a VisibilityOptions object, advancing the method chain
+     */
+    @Override
+    public VisibilityOptions qualifier(Text colQual) {
+      return qualifier(colQual.getBytes(), colQual.getLength());
+    }
+
+    /**
+     * Sets the column visibility of a mutation.
+     *
+     * @param colVis
+     *          column visibility
+     * @param colVisLen
+     *          column visibility length
+     * @return a TimestampOptions object, advancing the method chain
+     */
+    private TimestampOptions visibility(byte[] colVis, int colVisLen) {
+      columnVisibility = colVis;
+      columnVisibilityLength = colVisLen;
+      return this;
+    }
+
+    /**
+     * Sets the column visibility of a mutation.
+     *
+     * @param colVis
+     *          column visibility
+     * @return a TimestampOptions object, advancing the method chain
+     */
+    @Override
+    public TimestampOptions visibility(byte[] colVis) {
+      return visibility(colVis, colVis.length);
+    }
+
+    /**
+     * Sets the column visibility of a mutation.
+     *
+     * @param colVis
+     *          column visibility
+     * @return a TimestampOptions object, advancing the method chain
+     */
+    @Override
+    public TimestampOptions visibility(ByteBuffer colVis) {
+      return visibility(ByteBufferUtil.toBytes(colVis));
+    }
+
+    /**
+     * Sets the column visibility of a mutation.
+     *
+     * @param colVis
+     *          column visibility
+     * @return a TimestampOptions object, advancing the method chain
+     */
+    @Override
+    public TimestampOptions visibility(CharSequence colVis) {
+      return visibility(new Text(colVis.toString()));
+    }
+
+    /**
+     * Sets the column visibility of a mutation.
+     *
+     * @param colVis
+     *          column visibility
+     * @return a TimestampOptions object, advancing the method chain
+     */
+    @Override
+    public TimestampOptions visibility(ColumnVisibility colVis) {
+      return visibility(colVis.getExpression());
+    }
+
+    /**
+     * Sets the column visibility of a mutation.
+     *
+     * @param colVis
+     *          column visibility
+     * @return a TimestampOptions object, advancing the method chain
+     */
+    @Override
+    public TimestampOptions visibility(Text colVis) {
+      return visibility(colVis.toString().getBytes());
+    }
+
+    /**
+     * Sets the timestamp of a mutation.
+     *
+     * @param ts
+     *          timestamp
+     * @return a MutationOptions object, advancing the method chain
+     */
+    @Override
+    public MutationOptions timestamp(long ts) {
+      hasTs = true;
+      timestamp = ts;
+      return this;
+    }
+
+    /**
+     * Finalizes the method chain by filling the buffer with the gathered Mutation configuration
+     *
+     * @param val
+     *          value
+     * @param delete
+     *          deletion flag
+     */
+    private Mutation put(byte[] val, boolean delete) {
+      if (buffer == null) {
+        throw new IllegalStateException("Can not add to mutation after serializing it");
+      }
+
+      // fill buffer with column family location
+      fill(columnFamily, columnFamilyLength);
+
+      // fill buffer with qualifier location
+      fill(columnQualifier, columnQualifierLength);
+
+      // fill buffer with visibility location
+      // if none given, fill with EMPTY_BYTES
+      if (columnVisibility == null) {
+        fill(EMPTY_BYTES, EMPTY_BYTES.length);
+      } else {
+        fill(columnVisibility, columnVisibilityLength);
+      }
+
+      // fill buffer with timestamp location
+      // if none given, skip
+      fill(hasTs);
+      if (hasTs) {
+        fill(timestamp);
+      }
+
+      // indicate if this is a deletion
+      fill(delete);
+
+      // fill buffer with value
+      if (val.length < VALUE_SIZE_COPY_CUTOFF) {
+        fill(val, val.length);
+      } else {
+        if (values == null) {
+          values = new ArrayList<>();
+        }
+        byte copy[] = new byte[val.length];
+        System.arraycopy(val, 0, copy, 0, val.length);
+        values.add(copy);
+        fill(-1 * values.size());
+      }
+
+      entries++;
+
+      return Mutation.this;
+    }
+
+    /**
+     * Ends method chain with a put of a byte[] value
+     *
+     * @param val
+     *          value
+     */
+    @Override
+    public Mutation put(byte[] val) {
+      return put(val, false);
+    }
+
+    /**
+     * Ends method chain with a put of a ByteBuffer value
+     *
+     * @param val
+     *          value
+     */
+    @Override
+    public Mutation put(ByteBuffer val) {
+      return put(ByteBufferUtil.toBytes(val), false);
+    }
+
+    /**
+     * Ends method chain with a put of a CharSequence value
+     *
+     * @param val
+     *          value
+     */
+    @Override
+    public Mutation put(CharSequence val) {
+      return put(new Text(val.toString()));
+    }
+
+    /**
+     * Ends method chain with a put of a Text value
+     *
+     * @param val
+     *          value
+     */
+    @Override
+    public Mutation put(Text val) {
+      return put(val.toString().getBytes(), false);
+    }
+
+    /**
+     * Ends method chain with a put of a Value object
+     *
+     * @param val
+     *          value
+     */
+    @Override
+    public Mutation put(Value val) {
+      return put(val.get(), false);
+    }
+
+    /**
+     * Ends method chain with a delete
+     */
+    @Override
+    public Mutation delete() {
+      return put(EMPTY_BYTES, true);
+    }
+  }
+
   private byte[] oldReadBytes(UnsynchronizedBuffer.Reader in) {
     int len = in.readInt();
     if (len == 0)
diff --git a/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java b/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java
index 1d84f3823c..807b31f540 100644
--- a/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java
@@ -28,12 +28,14 @@
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.List;
 
 import org.apache.accumulo.core.data.thrift.TMutation;
 import org.apache.accumulo.core.security.ColumnVisibility;
 import org.apache.hadoop.io.Text;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class MutationTest {
@@ -185,6 +187,220 @@ private Value nv(String s) {
     return new Value(s.getBytes());
   }
 
+  @Test
+  public void testAtFamilyTypes() {
+    final String fam = "f16bc";
+    final String qual = "q1pm2";
+    final String val = "v8672194923750";
+
+    Mutation expected = new Mutation("row5");
+    expected.put(fam, qual, val);
+
+    // Test all family methods, keeping qual and val constant as Strings
+    // fam: byte[]
+    Mutation actual = new Mutation("row5");
+    actual.at().family(fam.getBytes(UTF_8)).qualifier(qual).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // fam: ByteBuffer
+    final ByteBuffer bbFam = ByteBuffer.wrap(fam.getBytes(UTF_8));
+    final int bbFamStartPos = bbFam.position();
+    actual = new Mutation("row5");
+    actual.at().family(bbFam).qualifier(qual).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // make sure the ByteBuffer last byte filled in the buffer (its position) is same as before the
+    // API call
+    Assert.assertEquals(bbFamStartPos, bbFam.position());
+
+    // fam: CharSequence (String implementation)
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // fam: Text
+    actual = new Mutation("row5");
+    actual.at().family(new Text(fam)).qualifier(qual).put(val);
+    Assert.assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testAtQualifierTypes() {
+    final String fam = "f16bc";
+    final String qual = "q1pm2";
+    final String val = "v8672194923750";
+
+    Mutation expected = new Mutation("row5");
+    expected.put(fam, qual, val);
+
+    // Test all qualifier methods, keeping fam and val constant as Strings
+    // qual: byte[]
+    Mutation actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual.getBytes(UTF_8)).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // qual: ByteBuffer
+    final ByteBuffer bbQual = ByteBuffer.wrap(qual.getBytes(UTF_8));
+    final int bbQualStartPos = bbQual.position();
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(bbQual).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // make sure the ByteBuffer last byte filled in the buffer (its position) is same as before the
+    // API call
+    Assert.assertEquals(bbQualStartPos, bbQual.position());
+
+    // qual: CharSequence (String implementation)
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // qual: Text
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(new Text(qual)).put(val);
+    Assert.assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testAtVisiblityTypes() {
+    final byte[] fam = "f16bc".getBytes(UTF_8);
+    final byte[] qual = "q1pm2".getBytes(UTF_8);
+    final ColumnVisibility vis = new ColumnVisibility("v35x2");
+    final byte[] val = "v8672194923750".getBytes(UTF_8);
+
+    Mutation expected = new Mutation("row5");
+    expected.put(fam, qual, vis, val);
+
+    // Test all visibility methods, keeping fam, qual, and val constant as byte arrays
+    // vis: byte[]
+    Mutation actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).visibility(vis.getExpression()).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // vis: ByteBuffer
+    final ByteBuffer bbVis = ByteBuffer.wrap(vis.getExpression());
+    final int bbVisStartPos = bbVis.position();
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).visibility(bbVis).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // make sure the ByteBuffer last byte filled in the buffer (its position) is same as before the
+    // API call
+    Assert.assertEquals(bbVisStartPos, bbVis.position());
+
+    // vis: CharSequence (String implementation)
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).visibility(new String(vis.getExpression())).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // vis: ColumnVisibility
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).visibility(vis).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // vis: Text
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).visibility(new Text(vis.getExpression())).put(val);
+    Assert.assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testAtTimestampTypes() {
+    final String fam = "f16bc";
+    final String qual = "q1pm2";
+    final long ts = 324324L;
+    final String val = "v8672194923750";
+
+    Mutation expected = new Mutation("row5");
+    expected.put(fam, qual, ts, val);
+
+    // Test timestamp method, keeping fam and val constant as Strings
+    Mutation actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).timestamp(ts).put(val);
+    Assert.assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testAtPutTypes() {
+    final String fam = "f16bc";
+    final String qual = "q1pm2";
+    final String val = "v8672194923750";
+
+    Mutation expected = new Mutation("row5");
+    expected.put(fam, qual, val);
+
+    // Test all pull methods, keeping fam and qual,constant as Strings
+    // put: byte[]
+    Mutation actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(val.getBytes(UTF_8));
+    Assert.assertEquals(expected, actual);
+
+    // put: ByteBuffer
+    final ByteBuffer bbVal = ByteBuffer.wrap(val.getBytes(UTF_8));
+    final int bbValStartPos = bbVal.position();
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(bbVal);
+    Assert.assertEquals(expected, actual);
+
+    // make sure the ByteBuffer last byte filled in the buffer (its position) is same as before the
+    // API call
+    Assert.assertEquals(bbValStartPos, bbVal.position());
+
+    // put: CharSequence (String implementation)
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // put: Text
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(val);
+    Assert.assertEquals(expected, actual);
+
+    // put: Value
+    actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(new Value(val));
+    Assert.assertEquals(expected, actual);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void testFluentPutNull() {
+    final String fam = "f16bc";
+    final String qual = "q1pm2";
+    final String val = "v8672194923750";
+
+    Mutation expected = new Mutation("row5");
+    expected.put(fam, qual, val);
+
+    Mutation actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).put(val.getBytes());
+    Assert.assertEquals(expected, actual);
+    Assert.assertEquals(34, actual.numBytes());
+    actual.at().family(fam).qualifier(qual).put("test2");
+  }
+
+  @Test
+  public void testFluentPutLarge() {
+    byte[] largeVal = new byte[Mutation.VALUE_SIZE_COPY_CUTOFF + 13];
+    Arrays.fill(largeVal, (byte) 3);
+
+    Mutation m = new Mutation("row123");
+    m.at().family("fam").qualifier("qual").put(largeVal);
+    Assert.assertEquals(32800, m.numBytes());
+  }
+
+  @Test
+  public void testAtDelete() {
+    final String fam = "f16bc";
+    final String qual = "q1pm2";
+
+    Mutation expected = new Mutation("row5");
+    expected.putDelete(fam, qual);
+
+    Mutation actual = new Mutation("row5");
+    actual.at().family(fam).qualifier(qual).delete();
+    Assert.assertEquals(expected, actual);
+  }
+
   @Test
   public void testPuts() {
     Mutation m = new Mutation(new Text("r1"));


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services