001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertNull;
023import static org.junit.Assert.assertTrue;
024import static org.junit.Assert.fail;
025
026import java.io.IOException;
027import java.util.Arrays;
028import java.util.Collections;
029import java.util.List;
030import org.apache.hadoop.hbase.CompareOperator;
031import org.apache.hadoop.hbase.HBaseClassTestRule;
032import org.apache.hadoop.hbase.HBaseTestingUtility;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.filter.BinaryComparator;
035import org.apache.hadoop.hbase.filter.FamilyFilter;
036import org.apache.hadoop.hbase.filter.FilterList;
037import org.apache.hadoop.hbase.filter.QualifierFilter;
038import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
039import org.apache.hadoop.hbase.filter.TimestampsFilter;
040import org.apache.hadoop.hbase.io.TimeRange;
041import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
042import org.apache.hadoop.hbase.testclassification.MediumTests;
043import org.apache.hadoop.hbase.util.Bytes;
044import org.junit.AfterClass;
045import org.junit.BeforeClass;
046import org.junit.ClassRule;
047import org.junit.Rule;
048import org.junit.Test;
049import org.junit.experimental.categories.Category;
050import org.junit.rules.TestName;
051
052@Category(MediumTests.class)
053public class TestCheckAndMutate {
054
055  @ClassRule
056  public static final HBaseClassTestRule CLASS_RULE =
057      HBaseClassTestRule.forClass(TestCheckAndMutate.class);
058
059  private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
060  private static final byte[] ROWKEY = Bytes.toBytes("12345");
061  private static final byte[] ROWKEY2 = Bytes.toBytes("67890");
062  private static final byte[] ROWKEY3 = Bytes.toBytes("abcde");
063  private static final byte[] ROWKEY4 = Bytes.toBytes("fghij");
064  private static final byte[] FAMILY = Bytes.toBytes("cf");
065
066  @Rule
067  public TestName name = new TestName();
068
069  @BeforeClass
070  public static void setUpBeforeClass() throws Exception {
071    TEST_UTIL.startMiniCluster();
072  }
073
074  @AfterClass
075  public static void tearDownAfterClass() throws Exception {
076    TEST_UTIL.shutdownMiniCluster();
077  }
078
079  private Table createTable()
080  throws IOException, InterruptedException {
081    final TableName tableName = TableName.valueOf(name.getMethodName());
082    Table table = TEST_UTIL.createTable(tableName, FAMILY);
083    TEST_UTIL.waitTableAvailable(tableName.getName(), 5000);
084    return table;
085  }
086
087  private void putOneRow(Table table) throws IOException {
088    Put put = new Put(ROWKEY);
089    put.addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"));
090    put.addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"));
091    put.addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"));
092    table.put(put);
093  }
094
095  private void getOneRowAndAssertAllExist(final Table table) throws IOException {
096    Get get = new Get(ROWKEY);
097    Result result = table.get(get);
098    assertTrue("Column A value should be a",
099      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))).equals("a"));
100    assertTrue("Column B value should be b",
101      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))).equals("b"));
102    assertTrue("Column C value should be c",
103      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))).equals("c"));
104  }
105
106  private void getOneRowAndAssertAllButCExist(final Table table) throws IOException {
107    Get get = new Get(ROWKEY);
108    Result result = table.get(get);
109    assertTrue("Column A value should be a",
110      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))).equals("a"));
111    assertTrue("Column B value should be b",
112      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))).equals("b"));
113    assertTrue("Column C should not exist",
114    result.getValue(FAMILY, Bytes.toBytes("C")) == null);
115  }
116
117  private RowMutations makeRowMutationsWithColumnCDeleted() throws IOException {
118    RowMutations rm = new RowMutations(ROWKEY, 2);
119    Put put = new Put(ROWKEY);
120    put.addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"));
121    put.addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"));
122    rm.add(put);
123    Delete del = new Delete(ROWKEY);
124    del.addColumn(FAMILY, Bytes.toBytes("C"));
125    rm.add(del);
126    return rm;
127  }
128
129  private RowMutations getBogusRowMutations() throws IOException {
130    Put p = new Put(ROWKEY);
131    byte[] value = new byte[0];
132    p.addColumn(new byte[]{'b', 'o', 'g', 'u', 's'}, new byte[]{'A'}, value);
133    RowMutations rm = new RowMutations(ROWKEY);
134    rm.add(p);
135    return rm;
136  }
137
138  // Tests for old checkAndMutate API
139
140  @Test
141  @Deprecated
142  public void testCheckAndMutateForOldApi() throws Throwable {
143    try (Table table = createTable()) {
144      // put one row
145      putOneRow(table);
146      // get row back and assert the values
147      getOneRowAndAssertAllExist(table);
148
149      // put the same row again with C column deleted
150      RowMutations rm = makeRowMutationsWithColumnCDeleted();
151      boolean res = table.checkAndMutate(ROWKEY, FAMILY).qualifier(Bytes.toBytes("A"))
152          .ifEquals(Bytes.toBytes("a")).thenMutate(rm);
153      assertTrue(res);
154
155      // get row back and assert the values
156      getOneRowAndAssertAllButCExist(table);
157
158      //Test that we get a region level exception
159      try {
160        rm = getBogusRowMutations();
161        table.checkAndMutate(ROWKEY, FAMILY).qualifier(Bytes.toBytes("A"))
162            .ifEquals(Bytes.toBytes("a")).thenMutate(rm);
163        fail("Expected NoSuchColumnFamilyException");
164      } catch (RetriesExhaustedWithDetailsException e) {
165        try {
166          throw e.getCause(0);
167        } catch (NoSuchColumnFamilyException e1) {
168          // expected
169        }
170      }
171    }
172  }
173
174  @Test
175  @Deprecated
176  public void testCheckAndMutateWithSingleFilterForOldApi() throws Throwable {
177    try (Table table = createTable()) {
178      // put one row
179      putOneRow(table);
180      // get row back and assert the values
181      getOneRowAndAssertAllExist(table);
182
183      // Put with success
184      boolean ok = table.checkAndMutate(ROWKEY, new SingleColumnValueFilter(FAMILY,
185          Bytes.toBytes("A"), CompareOperator.EQUAL, Bytes.toBytes("a")))
186        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")));
187      assertTrue(ok);
188
189      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
190      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
191
192      // Put with failure
193      ok = table.checkAndMutate(ROWKEY, new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"),
194          CompareOperator.EQUAL, Bytes.toBytes("b")))
195        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e")));
196      assertFalse(ok);
197
198      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"))));
199
200      // Delete with success
201      ok = table.checkAndMutate(ROWKEY, new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"),
202          CompareOperator.EQUAL, Bytes.toBytes("a")))
203        .thenDelete(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("D")));
204      assertTrue(ok);
205
206      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"))));
207
208      // Mutate with success
209      ok = table.checkAndMutate(ROWKEY, new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"),
210          CompareOperator.EQUAL, Bytes.toBytes("b")))
211        .thenMutate(new RowMutations(ROWKEY)
212          .add((Mutation) new Put(ROWKEY)
213            .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")))
214          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A"))));
215      assertTrue(ok);
216
217      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
218      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
219
220      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
221    }
222  }
223
224  @Test
225  @Deprecated
226  public void testCheckAndMutateWithMultipleFiltersForOldApi() throws Throwable {
227    try (Table table = createTable()) {
228      // put one row
229      putOneRow(table);
230      // get row back and assert the values
231      getOneRowAndAssertAllExist(table);
232
233      // Put with success
234      boolean ok = table.checkAndMutate(ROWKEY, new FilterList(
235          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
236            Bytes.toBytes("a")),
237          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
238            Bytes.toBytes("b"))
239        ))
240        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")));
241      assertTrue(ok);
242
243      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
244      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
245
246      // Put with failure
247      ok = table.checkAndMutate(ROWKEY, new FilterList(
248          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
249            Bytes.toBytes("a")),
250          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
251            Bytes.toBytes("c"))
252        ))
253        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e")));
254      assertFalse(ok);
255
256      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"))));
257
258      // Delete with success
259      ok = table.checkAndMutate(ROWKEY, new FilterList(
260          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
261            Bytes.toBytes("a")),
262          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
263            Bytes.toBytes("b"))
264        ))
265        .thenDelete(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("D")));
266      assertTrue(ok);
267
268      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"))));
269
270      // Mutate with success
271      ok = table.checkAndMutate(ROWKEY, new FilterList(
272          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
273            Bytes.toBytes("a")),
274          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
275            Bytes.toBytes("b"))
276        ))
277        .thenMutate(new RowMutations(ROWKEY)
278          .add((Mutation) new Put(ROWKEY)
279            .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")))
280          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A"))));
281      assertTrue(ok);
282
283      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
284      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
285
286      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
287    }
288  }
289
290  @Test
291  @Deprecated
292  public void testCheckAndMutateWithTimestampFilterForOldApi() throws Throwable {
293    try (Table table = createTable()) {
294      // Put with specifying the timestamp
295      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a")));
296
297      // Put with success
298      boolean ok = table.checkAndMutate(ROWKEY, new FilterList(
299          new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(FAMILY)),
300          new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("A"))),
301          new TimestampsFilter(Collections.singletonList(100L))
302        ))
303        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")));
304      assertTrue(ok);
305
306      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
307      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
308
309      // Put with failure
310      ok = table.checkAndMutate(ROWKEY, new FilterList(
311          new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(FAMILY)),
312          new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("A"))),
313          new TimestampsFilter(Collections.singletonList(101L))
314        ))
315        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")));
316      assertFalse(ok);
317
318      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
319    }
320  }
321
322  @Test
323  @Deprecated
324  public void testCheckAndMutateWithFilterAndTimeRangeForOldApi() throws Throwable {
325    try (Table table = createTable()) {
326      // Put with specifying the timestamp
327      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a")));
328
329      // Put with success
330      boolean ok = table.checkAndMutate(ROWKEY, new SingleColumnValueFilter(FAMILY,
331          Bytes.toBytes("A"), CompareOperator.EQUAL, Bytes.toBytes("a")))
332        .timeRange(TimeRange.between(0, 101))
333        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")));
334      assertTrue(ok);
335
336      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
337      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
338
339      // Put with failure
340      ok = table.checkAndMutate(ROWKEY, new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"),
341          CompareOperator.EQUAL, Bytes.toBytes("a")))
342        .timeRange(TimeRange.between(0, 100))
343        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")));
344      assertFalse(ok);
345
346      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
347    }
348  }
349
350  @Test(expected = NullPointerException.class)
351  @Deprecated
352  public void testCheckAndMutateWithoutConditionForOldApi() throws Throwable {
353    try (Table table = createTable()) {
354      table.checkAndMutate(ROWKEY, FAMILY)
355        .thenPut(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")));
356    }
357  }
358
359  // Tests for new CheckAndMutate API
360
361  @Test
362  public void testCheckAndMutate() throws Throwable {
363    try (Table table = createTable()) {
364      // put one row
365      putOneRow(table);
366      // get row back and assert the values
367      getOneRowAndAssertAllExist(table);
368
369      // put the same row again with C column deleted
370      RowMutations rm = makeRowMutationsWithColumnCDeleted();
371      CheckAndMutateResult res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
372        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
373        .build(rm));
374      assertTrue(res.isSuccess());
375      assertNull(res.getResult());
376
377      // get row back and assert the values
378      getOneRowAndAssertAllButCExist(table);
379
380      // Test that we get a region level exception
381      try {
382        rm = getBogusRowMutations();
383        table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
384          .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
385          .build(rm));
386        fail("Expected NoSuchColumnFamilyException");
387      } catch (RetriesExhaustedWithDetailsException e) {
388        try {
389          throw e.getCause(0);
390        } catch (NoSuchColumnFamilyException e1) {
391          // expected
392        }
393      }
394    }
395  }
396
397  @Test
398  public void testCheckAndMutateWithSingleFilter() throws Throwable {
399    try (Table table = createTable()) {
400      // put one row
401      putOneRow(table);
402      // get row back and assert the values
403      getOneRowAndAssertAllExist(table);
404
405      // Put with success
406      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
407        .ifMatches(new SingleColumnValueFilter(FAMILY,
408          Bytes.toBytes("A"), CompareOperator.EQUAL, Bytes.toBytes("a")))
409        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
410      assertTrue(result.isSuccess());
411      assertNull(result.getResult());
412
413      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
414      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
415
416      // Put with failure
417      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
418        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"),
419        CompareOperator.EQUAL, Bytes.toBytes("b")))
420        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e"))));
421      assertFalse(result.isSuccess());
422      assertNull(result.getResult());
423
424      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"))));
425
426      // Delete with success
427      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
428        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"),
429          CompareOperator.EQUAL, Bytes.toBytes("a")))
430        .build(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("D"))));
431      assertTrue(result.isSuccess());
432      assertNull(result.getResult());
433
434      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"))));
435
436      // Mutate with success
437      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
438        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"),
439          CompareOperator.EQUAL, Bytes.toBytes("b")))
440        .build(new RowMutations(ROWKEY)
441          .add((Mutation) new Put(ROWKEY)
442            .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")))
443          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A")))));
444      assertTrue(result.isSuccess());
445      assertNull(result.getResult());
446
447      r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
448      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
449
450      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
451    }
452  }
453
454  @Test
455  public void testCheckAndMutateWithMultipleFilters() throws Throwable {
456    try (Table table = createTable()) {
457      // put one row
458      putOneRow(table);
459      // get row back and assert the values
460      getOneRowAndAssertAllExist(table);
461
462      // Put with success
463      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
464        .ifMatches(new FilterList(
465          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
466            Bytes.toBytes("a")),
467          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
468            Bytes.toBytes("b"))))
469        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
470      assertTrue(result.isSuccess());
471      assertNull(result.getResult());
472
473      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
474      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
475
476      // Put with failure
477      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
478        .ifMatches(new FilterList(
479          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
480            Bytes.toBytes("a")),
481          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
482            Bytes.toBytes("c"))))
483        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e"))));
484      assertFalse(result.isSuccess());
485      assertNull(result.getResult());
486
487      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"))));
488
489      // Delete with success
490      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
491        .ifMatches(new FilterList(
492            new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
493              Bytes.toBytes("a")),
494            new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
495              Bytes.toBytes("b"))))
496        .build(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("D"))));
497      assertTrue(result.isSuccess());
498      assertNull(result.getResult());
499
500      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"))));
501
502      // Mutate with success
503      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
504        .ifMatches(new FilterList(
505          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
506            Bytes.toBytes("a")),
507          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
508            Bytes.toBytes("b"))))
509        .build(new RowMutations(ROWKEY)
510          .add((Mutation) new Put(ROWKEY)
511            .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")))
512          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A")))));
513      assertTrue(result.isSuccess());
514      assertNull(result.getResult());
515
516      r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
517      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
518
519      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
520    }
521  }
522
523  @Test
524  public void testCheckAndMutateWithTimestampFilter() throws Throwable {
525    try (Table table = createTable()) {
526      // Put with specifying the timestamp
527      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a")));
528
529      // Put with success
530      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
531        .ifMatches(new FilterList(
532          new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(FAMILY)),
533          new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("A"))),
534          new TimestampsFilter(Collections.singletonList(100L))))
535        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
536      assertTrue(result.isSuccess());
537      assertNull(result.getResult());
538
539      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
540      assertEquals("b", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("B"))));
541
542      // Put with failure
543      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
544        .ifMatches(new FilterList(
545          new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(FAMILY)),
546          new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("A"))),
547          new TimestampsFilter(Collections.singletonList(101L))))
548        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))));
549      assertFalse(result.isSuccess());
550      assertNull(result.getResult());
551
552      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
553    }
554  }
555
556  @Test
557  public void testCheckAndMutateWithFilterAndTimeRange() throws Throwable {
558    try (Table table = createTable()) {
559      // Put with specifying the timestamp
560      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a")));
561
562      // Put with success
563      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
564        .ifMatches(new SingleColumnValueFilter(FAMILY,
565          Bytes.toBytes("A"), CompareOperator.EQUAL, Bytes.toBytes("a")))
566        .timeRange(TimeRange.between(0, 101))
567        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
568      assertTrue(result.isSuccess());
569      assertNull(result.getResult());
570
571      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
572      assertEquals("b", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("B"))));
573
574      // Put with failure
575      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
576        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"),
577          CompareOperator.EQUAL, Bytes.toBytes("a")))
578        .timeRange(TimeRange.between(0, 100))
579        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))));
580      assertFalse(result.isSuccess());
581      assertNull(result.getResult());
582
583      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
584    }
585  }
586
587  @Test(expected = IllegalStateException.class)
588  public void testCheckAndMutateBuilderWithoutCondition() {
589    CheckAndMutate.newBuilder(ROWKEY)
590      .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")));
591  }
592
593  @Test
594  public void testCheckAndIncrement() throws Throwable {
595    try (Table table = createTable()) {
596      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")));
597
598      // CheckAndIncrement with correct value
599      CheckAndMutateResult res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
600        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
601        .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 1)));
602      assertTrue(res.isSuccess());
603      assertEquals(1, Bytes.toLong(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
604
605      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
606      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
607
608      // CheckAndIncrement with wrong value
609      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
610        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("b"))
611        .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 1)));
612      assertFalse(res.isSuccess());
613      assertNull(res.getResult());
614
615      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
616      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
617
618      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")));
619
620      // CheckAndIncrement with a filter and correct value
621      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
622        .ifMatches(new FilterList(
623          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
624            Bytes.toBytes("a")),
625          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
626            Bytes.toBytes("c"))))
627        .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 2)));
628      assertTrue(res.isSuccess());
629      assertEquals(3, Bytes.toLong(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
630
631      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
632      assertEquals(3, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
633
634      // CheckAndIncrement with a filter and correct value
635      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
636        .ifMatches(new FilterList(
637          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
638            Bytes.toBytes("b")),
639          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
640            Bytes.toBytes("d"))))
641        .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 2)));
642      assertFalse(res.isSuccess());
643      assertNull(res.getResult());
644
645      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
646      assertEquals(3, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
647    }
648  }
649
650  @Test
651  public void testCheckAndAppend() throws Throwable {
652    try (Table table = createTable()) {
653      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")));
654
655      // CheckAndAppend with correct value
656      CheckAndMutateResult res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
657        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
658        .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
659      assertTrue(res.isSuccess());
660      assertEquals("b", Bytes.toString(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
661
662      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
663      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
664
665      // CheckAndAppend with correct value
666      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
667        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("b"))
668        .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
669      assertFalse(res.isSuccess());
670      assertNull(res.getResult());
671
672      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
673      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
674
675      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")));
676
677      // CheckAndAppend with a filter and correct value
678      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
679        .ifMatches(new FilterList(
680          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
681            Bytes.toBytes("a")),
682          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
683            Bytes.toBytes("c"))))
684        .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("bb"))));
685      assertTrue(res.isSuccess());
686      assertEquals("bbb", Bytes.toString(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
687
688      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
689      assertEquals("bbb", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
690
691      // CheckAndAppend with a filter and wrong value
692      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
693        .ifMatches(new FilterList(
694          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
695            Bytes.toBytes("b")),
696          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
697            Bytes.toBytes("d"))))
698        .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("bb"))));
699      assertFalse(res.isSuccess());
700      assertNull(res.getResult());
701
702      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
703      assertEquals("bbb", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
704    }
705  }
706
707  @Test
708  public void testCheckAndRowMutations() throws Throwable {
709    final byte[] q1 = Bytes.toBytes("q1");
710    final byte[] q2 = Bytes.toBytes("q2");
711    final byte[] q3 = Bytes.toBytes("q3");
712    final byte[] q4 = Bytes.toBytes("q4");
713    final String v1 = "v1";
714
715    try (Table table = createTable()) {
716      // Initial values
717      table.put(Arrays.asList(
718        new Put(ROWKEY).addColumn(FAMILY, q2, Bytes.toBytes("toBeDeleted")),
719        new Put(ROWKEY).addColumn(FAMILY, q3, Bytes.toBytes(5L)),
720        new Put(ROWKEY).addColumn(FAMILY, q4, Bytes.toBytes("a"))));
721
722      // Do CheckAndRowMutations
723      CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(ROWKEY)
724        .ifNotExists(FAMILY, q1)
725        .build(new RowMutations(ROWKEY).add(Arrays.asList(
726          new Put(ROWKEY).addColumn(FAMILY, q1, Bytes.toBytes(v1)),
727          new Delete(ROWKEY).addColumns(FAMILY, q2),
728          new Increment(ROWKEY).addColumn(FAMILY, q3, 1),
729          new Append(ROWKEY).addColumn(FAMILY, q4, Bytes.toBytes("b"))))
730        );
731
732      CheckAndMutateResult result = table.checkAndMutate(checkAndMutate);
733      assertTrue(result.isSuccess());
734      assertEquals(6L, Bytes.toLong(result.getResult().getValue(FAMILY, q3)));
735      assertEquals("ab", Bytes.toString(result.getResult().getValue(FAMILY, q4)));
736
737      // Verify the value
738      Result r = table.get(new Get(ROWKEY));
739      assertEquals(v1, Bytes.toString(r.getValue(FAMILY, q1)));
740      assertNull(r.getValue(FAMILY, q2));
741      assertEquals(6L, Bytes.toLong(r.getValue(FAMILY, q3)));
742      assertEquals("ab", Bytes.toString(r.getValue(FAMILY, q4)));
743
744      // Do CheckAndRowMutations again
745      checkAndMutate = CheckAndMutate.newBuilder(ROWKEY)
746        .ifNotExists(FAMILY, q1)
747        .build(new RowMutations(ROWKEY).add(Arrays.asList(
748          new Delete(ROWKEY).addColumns(FAMILY, q1),
749          new Put(ROWKEY).addColumn(FAMILY, q2, Bytes.toBytes(v1)),
750          new Increment(ROWKEY).addColumn(FAMILY, q3, 1),
751          new Append(ROWKEY).addColumn(FAMILY, q4, Bytes.toBytes("b"))))
752        );
753
754      result = table.checkAndMutate(checkAndMutate);
755      assertFalse(result.isSuccess());
756      assertNull(result.getResult());
757
758      // Verify the value
759      r = table.get(new Get(ROWKEY));
760      assertEquals(v1, Bytes.toString(r.getValue(FAMILY, q1)));
761      assertNull(r.getValue(FAMILY, q2));
762      assertEquals(6L, Bytes.toLong(r.getValue(FAMILY, q3)));
763      assertEquals("ab", Bytes.toString(r.getValue(FAMILY, q4)));
764    }
765  }
766
767  // Tests for batch version of checkAndMutate
768
769  @Test
770  public void testCheckAndMutateBatch() throws Throwable {
771    try (Table table = createTable()) {
772      table.put(Arrays.asList(
773        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")),
774        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")),
775        new Put(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")),
776        new Put(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
777
778      // Test for Put
779      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
780        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
781        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("e")));
782
783      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
784        .ifEquals(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("a"))
785        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("f")));
786
787      List<CheckAndMutateResult> results =
788        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
789
790      assertTrue(results.get(0).isSuccess());
791      assertNull(results.get(0).getResult());
792      assertFalse(results.get(1).isSuccess());
793      assertNull(results.get(1).getResult());
794
795      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A")));
796      assertEquals("e", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
797
798      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
799      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
800
801      // Test for Delete
802      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
803        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("e"))
804        .build(new Delete(ROWKEY));
805
806      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
807        .ifEquals(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("a"))
808        .build(new Delete(ROWKEY2));
809
810      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
811
812      assertTrue(results.get(0).isSuccess());
813      assertNull(results.get(0).getResult());
814      assertFalse(results.get(1).isSuccess());
815      assertNull(results.get(1).getResult());
816
817      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
818
819      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
820      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
821
822      // Test for RowMutations
823      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY3)
824        .ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))
825        .build(new RowMutations(ROWKEY3)
826          .add((Mutation) new Put(ROWKEY3)
827            .addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f")))
828          .add((Mutation) new Delete(ROWKEY3).addColumns(FAMILY, Bytes.toBytes("C"))));
829
830      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY4)
831        .ifEquals(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("f"))
832        .build(new RowMutations(ROWKEY4)
833          .add((Mutation) new Put(ROWKEY4)
834            .addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f")))
835          .add((Mutation) new Delete(ROWKEY4).addColumns(FAMILY, Bytes.toBytes("D"))));
836
837      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
838
839      assertTrue(results.get(0).isSuccess());
840      assertNull(results.get(0).getResult());
841      assertFalse(results.get(1).isSuccess());
842      assertNull(results.get(1).getResult());
843
844      result = table.get(new Get(ROWKEY3));
845      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
846      assertNull(result.getValue(FAMILY, Bytes.toBytes("D")));
847
848      result = table.get(new Get(ROWKEY4));
849      assertNull(result.getValue(FAMILY, Bytes.toBytes("F")));
850      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
851    }
852  }
853
854  @Test
855  public void testCheckAndMutateBatch2() throws Throwable {
856    try (Table table = createTable()) {
857      table.put(Arrays.asList(
858        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")),
859        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")),
860        new Put(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C"), 100, Bytes.toBytes("c")),
861        new Put(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D"), 100, Bytes.toBytes("d"))));
862
863      // Test for ifNotExists()
864      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
865        .ifNotExists(FAMILY, Bytes.toBytes("B"))
866        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("e")));
867
868      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
869        .ifNotExists(FAMILY, Bytes.toBytes("B"))
870        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("f")));
871
872      List<CheckAndMutateResult> results =
873        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
874
875      assertTrue(results.get(0).isSuccess());
876      assertNull(results.get(0).getResult());
877      assertFalse(results.get(1).isSuccess());
878      assertNull(results.get(1).getResult());
879
880      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A")));
881      assertEquals("e", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
882
883      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
884      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
885
886      // Test for ifMatches()
887      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
888        .ifMatches(FAMILY, Bytes.toBytes("A"), CompareOperator.NOT_EQUAL, Bytes.toBytes("a"))
889        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")));
890
891      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
892        .ifMatches(FAMILY, Bytes.toBytes("B"), CompareOperator.GREATER, Bytes.toBytes("b"))
893        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("f")));
894
895      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
896
897      assertTrue(results.get(0).isSuccess());
898      assertNull(results.get(0).getResult());
899      assertFalse(results.get(1).isSuccess());
900      assertNull(results.get(1).getResult());
901
902      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A")));
903      assertEquals("a", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
904
905      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
906      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
907
908      // Test for timeRange()
909      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY3)
910        .ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))
911        .timeRange(TimeRange.between(0, 101))
912        .build(new Put(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("e")));
913
914      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY4)
915        .ifEquals(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))
916        .timeRange(TimeRange.between(0, 100))
917        .build(new Put(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("f")));
918
919      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
920
921      assertTrue(results.get(0).isSuccess());
922      assertNull(results.get(0).getResult());
923      assertFalse(results.get(1).isSuccess());
924      assertNull(results.get(1).getResult());
925
926      result = table.get(new Get(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C")));
927      assertEquals("e", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
928
929      result = table.get(new Get(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D")));
930      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
931    }
932  }
933
934  @Test
935  public void testCheckAndMutateBatchWithFilter() throws Throwable {
936    try (Table table = createTable()) {
937      table.put(Arrays.asList(
938        new Put(ROWKEY)
939          .addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
940          .addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))
941          .addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")),
942        new Put(ROWKEY2)
943          .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))
944          .addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e"))
945          .addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f"))));
946
947      // Test for Put
948      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
949        .ifMatches(new FilterList(
950          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
951            Bytes.toBytes("a")),
952          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
953            Bytes.toBytes("b"))))
954        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("g")));
955
956      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
957        .ifMatches(new FilterList(
958          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
959            Bytes.toBytes("a")),
960          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
961            Bytes.toBytes("b"))))
962        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("h")));
963
964      List<CheckAndMutateResult> results =
965        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
966
967      assertTrue(results.get(0).isSuccess());
968      assertNull(results.get(0).getResult());
969      assertFalse(results.get(1).isSuccess());
970      assertNull(results.get(1).getResult());
971
972      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C")));
973      assertEquals("g", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
974
975      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
976      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
977
978      // Test for Delete
979      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
980        .ifMatches(new FilterList(
981          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
982            Bytes.toBytes("a")),
983          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
984            Bytes.toBytes("b"))))
985        .build(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("C")));
986
987      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
988        .ifMatches(new FilterList(
989          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
990            Bytes.toBytes("a")),
991          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
992            Bytes.toBytes("b"))))
993        .build(new Delete(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
994
995      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
996
997      assertTrue(results.get(0).isSuccess());
998      assertNull(results.get(0).getResult());
999      assertFalse(results.get(1).isSuccess());
1000      assertNull(results.get(1).getResult());
1001
1002      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
1003
1004      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
1005      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1006
1007      // Test for RowMutations
1008      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
1009        .ifMatches(new FilterList(
1010          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
1011            Bytes.toBytes("a")),
1012          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
1013            Bytes.toBytes("b"))))
1014        .build(new RowMutations(ROWKEY)
1015          .add((Mutation) new Put(ROWKEY)
1016            .addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")))
1017          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A"))));
1018
1019      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
1020        .ifMatches(new FilterList(
1021          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
1022            Bytes.toBytes("a")),
1023          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
1024            Bytes.toBytes("b"))))
1025        .build(new RowMutations(ROWKEY2)
1026          .add((Mutation) new Put(ROWKEY2)
1027            .addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("g")))
1028          .add((Mutation) new Delete(ROWKEY2).addColumns(FAMILY, Bytes.toBytes("D"))));
1029
1030      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1031
1032      assertTrue(results.get(0).isSuccess());
1033      assertNull(results.get(0).getResult());
1034      assertFalse(results.get(1).isSuccess());
1035      assertNull(results.get(1).getResult());
1036
1037      result = table.get(new Get(ROWKEY));
1038      assertNull(result.getValue(FAMILY, Bytes.toBytes("A")));
1039      assertEquals("c", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
1040
1041      result = table.get(new Get(ROWKEY2));
1042      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
1043      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1044    }
1045  }
1046
1047  @Test
1048  public void testCheckAndMutateBatchWithFilterAndTimeRange() throws Throwable {
1049    try (Table table = createTable()) {
1050      table.put(Arrays.asList(
1051        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a"))
1052          .addColumn(FAMILY, Bytes.toBytes("B"), 100, Bytes.toBytes("b"))
1053          .addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")),
1054        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D"), 100, Bytes.toBytes("d"))
1055          .addColumn(FAMILY, Bytes.toBytes("E"), 100, Bytes.toBytes("e"))
1056          .addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f"))));
1057
1058      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
1059        .ifMatches(new FilterList(
1060          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
1061            Bytes.toBytes("a")),
1062          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
1063            Bytes.toBytes("b"))))
1064        .timeRange(TimeRange.between(0, 101))
1065        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("g")));
1066
1067      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
1068        .ifMatches(new FilterList(
1069          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
1070            Bytes.toBytes("d")),
1071          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
1072            Bytes.toBytes("e"))))
1073        .timeRange(TimeRange.between(0, 100))
1074        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("h")));
1075
1076      List<CheckAndMutateResult> results =
1077        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1078
1079      assertTrue(results.get(0).isSuccess());
1080      assertNull(results.get(0).getResult());
1081      assertFalse(results.get(1).isSuccess());
1082      assertNull(results.get(1).getResult());
1083
1084      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C")));
1085      assertEquals("g", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
1086
1087      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
1088      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1089    }
1090  }
1091
1092  @Test
1093  public void testCheckAndIncrementBatch() throws Throwable {
1094    try (Table table = createTable()) {
1095      table.put(Arrays.asList(
1096        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
1097          .addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes(0L)),
1098        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))
1099          .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes(0L))));
1100
1101      // CheckAndIncrement with correct value
1102      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
1103          .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
1104          .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 1));
1105
1106      // CheckAndIncrement with wrong value
1107      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
1108          .ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("d"))
1109          .build(new Increment(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D"), 1));
1110
1111      List<CheckAndMutateResult> results =
1112        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1113
1114      assertTrue(results.get(0).isSuccess());
1115      assertEquals(1, Bytes.toLong(results.get(0).getResult()
1116        .getValue(FAMILY, Bytes.toBytes("B"))));
1117      assertFalse(results.get(1).isSuccess());
1118      assertNull(results.get(1).getResult());
1119
1120      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
1121      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
1122
1123      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D")));
1124      assertEquals(0, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("D"))));
1125    }
1126  }
1127
1128  @Test
1129  public void testCheckAndAppendBatch() throws Throwable {
1130    try (Table table = createTable()) {
1131      table.put(Arrays.asList(
1132        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
1133          .addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")),
1134        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))
1135          .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
1136
1137      // CheckAndAppend with correct value
1138      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
1139        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
1140        .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")));
1141
1142      // CheckAndAppend with wrong value
1143      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
1144        .ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("d"))
1145        .build(new Append(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")));
1146
1147      List<CheckAndMutateResult> results =
1148        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1149
1150      assertTrue(results.get(0).isSuccess());
1151      assertEquals("bb", Bytes.toString(results.get(0).getResult()
1152        .getValue(FAMILY, Bytes.toBytes("B"))));
1153      assertFalse(results.get(1).isSuccess());
1154      assertNull(results.get(1).getResult());
1155
1156      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
1157      assertEquals("bb", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
1158
1159      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D")));
1160      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
1161    }
1162  }
1163
1164  @Test
1165  public void testCheckAndRowMutationsBatch() throws Throwable {
1166    try (Table table = createTable()) {
1167      table.put(Arrays.asList(
1168        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))
1169          .addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes(1L))
1170          .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")),
1171        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f"))
1172          .addColumn(FAMILY, Bytes.toBytes("G"), Bytes.toBytes(1L))
1173          .addColumn(FAMILY, Bytes.toBytes("H"), Bytes.toBytes("h")))
1174      );
1175
1176      // CheckAndIncrement with correct value
1177      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
1178        .ifEquals(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))
1179        .build(new RowMutations(ROWKEY).add(Arrays.asList(
1180          new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")),
1181          new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("B")),
1182          new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), 1L),
1183          new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))
1184        )));
1185
1186      // CheckAndIncrement with wrong value
1187      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
1188        .ifEquals(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("a"))
1189        .build(new RowMutations(ROWKEY2).add(Arrays.asList(
1190          new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e")),
1191          new Delete(ROWKEY2).addColumns(FAMILY, Bytes.toBytes("F")),
1192          new Increment(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("G"), 1L),
1193          new Append(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("H"), Bytes.toBytes("h"))
1194        )));
1195
1196      List<CheckAndMutateResult> results =
1197        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1198
1199      assertTrue(results.get(0).isSuccess());
1200      assertEquals(2, Bytes.toLong(results.get(0).getResult()
1201        .getValue(FAMILY, Bytes.toBytes("C"))));
1202      assertEquals("dd", Bytes.toString(results.get(0).getResult()
1203        .getValue(FAMILY, Bytes.toBytes("D"))));
1204
1205      assertFalse(results.get(1).isSuccess());
1206      assertNull(results.get(1).getResult());
1207
1208      Result result = table.get(new Get(ROWKEY));
1209      assertEquals("a", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
1210      assertNull(result.getValue(FAMILY, Bytes.toBytes("B")));
1211      assertEquals(2, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("C"))));
1212      assertEquals("dd", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
1213
1214      result = table.get(new Get(ROWKEY2));
1215      assertNull(result.getValue(FAMILY, Bytes.toBytes("E")));
1216      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1217      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("G"))));
1218      assertEquals("h", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("H"))));
1219    }
1220  }
1221}