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