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.hamcrest.CoreMatchers.instanceOf;
021import static org.hamcrest.MatcherAssert.assertThat;
022import static org.junit.Assert.assertEquals;
023import static org.junit.Assert.assertFalse;
024import static org.junit.Assert.assertNull;
025import static org.junit.Assert.assertTrue;
026import static org.junit.Assert.fail;
027
028import java.io.IOException;
029import java.util.Arrays;
030import java.util.Collections;
031import java.util.List;
032import org.apache.hadoop.hbase.CompareOperator;
033import org.apache.hadoop.hbase.HBaseClassTestRule;
034import org.apache.hadoop.hbase.HBaseTestingUtil;
035import org.apache.hadoop.hbase.TableName;
036import org.apache.hadoop.hbase.filter.BinaryComparator;
037import org.apache.hadoop.hbase.filter.FamilyFilter;
038import org.apache.hadoop.hbase.filter.FilterList;
039import org.apache.hadoop.hbase.filter.QualifierFilter;
040import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
041import org.apache.hadoop.hbase.filter.TimestampsFilter;
042import org.apache.hadoop.hbase.io.TimeRange;
043import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
044import org.apache.hadoop.hbase.testclassification.MediumTests;
045import org.apache.hadoop.hbase.util.Bytes;
046import org.junit.AfterClass;
047import org.junit.BeforeClass;
048import org.junit.ClassRule;
049import org.junit.Rule;
050import org.junit.Test;
051import org.junit.experimental.categories.Category;
052import org.junit.rules.TestName;
053
054@Category(MediumTests.class)
055public class TestCheckAndMutate {
056
057  @ClassRule
058  public static final HBaseClassTestRule CLASS_RULE =
059    HBaseClassTestRule.forClass(TestCheckAndMutate.class);
060
061  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
062  private static final byte[] ROWKEY = Bytes.toBytes("12345");
063  private static final byte[] ROWKEY2 = Bytes.toBytes("67890");
064  private static final byte[] ROWKEY3 = Bytes.toBytes("abcde");
065  private static final byte[] ROWKEY4 = Bytes.toBytes("fghij");
066  private static final byte[] FAMILY = Bytes.toBytes("cf");
067
068  @Rule
069  public TestName name = new TestName();
070
071  @BeforeClass
072  public static void setUpBeforeClass() throws Exception {
073    TEST_UTIL.startMiniCluster();
074  }
075
076  @AfterClass
077  public static void tearDownAfterClass() throws Exception {
078    TEST_UTIL.shutdownMiniCluster();
079  }
080
081  private Table createTable() throws IOException, InterruptedException {
082    final TableName tableName = TableName.valueOf(name.getMethodName());
083    Table table = TEST_UTIL.createTable(tableName, FAMILY);
084    TEST_UTIL.waitTableAvailable(tableName.getName(), 5000);
085    return table;
086  }
087
088  private void putOneRow(Table table) throws IOException {
089    Put put = new Put(ROWKEY);
090    put.addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"));
091    put.addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"));
092    put.addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"));
093    table.put(put);
094  }
095
096  private void getOneRowAndAssertAllExist(final Table table) throws IOException {
097    Get get = new Get(ROWKEY);
098    Result result = table.get(get);
099    assertTrue("Column A value should be a",
100      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))).equals("a"));
101    assertTrue("Column B value should be b",
102      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))).equals("b"));
103    assertTrue("Column C value should be c",
104      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))).equals("c"));
105  }
106
107  private void getOneRowAndAssertAllButCExist(final Table table) throws IOException {
108    Get get = new Get(ROWKEY);
109    Result result = table.get(get);
110    assertTrue("Column A value should be a",
111      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))).equals("a"));
112    assertTrue("Column B value should be b",
113      Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))).equals("b"));
114    assertTrue("Column C should not exist", 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 (NoSuchColumnFamilyException e) {
165        // expected
166      } catch (RetriesExhaustedException e) {
167        assertThat(e.getCause(), instanceOf(NoSuchColumnFamilyException.class));
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 (NoSuchColumnFamilyException e) {
398        // expected
399      } catch (RetriesExhaustedException e) {
400        assertThat(e.getCause(), instanceOf(NoSuchColumnFamilyException.class));
401      }
402    }
403  }
404
405  @Test
406  public void testCheckAndMutateWithSingleFilter() throws Throwable {
407    try (Table table = createTable()) {
408      // put one row
409      putOneRow(table);
410      // get row back and assert the values
411      getOneRowAndAssertAllExist(table);
412
413      // Put with success
414      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
415        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
416          Bytes.toBytes("a")))
417        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
418      assertTrue(result.isSuccess());
419      assertNull(result.getResult());
420
421      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
422      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
423
424      // Put with failure
425      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
426        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
427          Bytes.toBytes("b")))
428        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e"))));
429      assertFalse(result.isSuccess());
430      assertNull(result.getResult());
431
432      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"))));
433
434      // Delete with success
435      result = table.checkAndMutate(CheckAndMutate
436        .newBuilder(ROWKEY).ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"),
437          CompareOperator.EQUAL, Bytes.toBytes("a")))
438        .build(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("D"))));
439      assertTrue(result.isSuccess());
440      assertNull(result.getResult());
441
442      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"))));
443
444      // Mutate with success
445      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
446        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
447          Bytes.toBytes("b")))
448        .build(new RowMutations(ROWKEY)
449          .add((Mutation) new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")))
450          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A")))));
451      assertTrue(result.isSuccess());
452      assertNull(result.getResult());
453
454      r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
455      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
456
457      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
458    }
459  }
460
461  @Test
462  public void testCheckAndMutateWithMultipleFilters() throws Throwable {
463    try (Table table = createTable()) {
464      // put one row
465      putOneRow(table);
466      // get row back and assert the values
467      getOneRowAndAssertAllExist(table);
468
469      // Put with success
470      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
471        .ifMatches(new FilterList(
472          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
473            Bytes.toBytes("a")),
474          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
475            Bytes.toBytes("b"))))
476        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
477      assertTrue(result.isSuccess());
478      assertNull(result.getResult());
479
480      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
481      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
482
483      // Put with failure
484      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
485        .ifMatches(new FilterList(
486          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
487            Bytes.toBytes("a")),
488          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
489            Bytes.toBytes("c"))))
490        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e"))));
491      assertFalse(result.isSuccess());
492      assertNull(result.getResult());
493
494      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("E"))));
495
496      // Delete with success
497      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
498        .ifMatches(new FilterList(
499          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
500            Bytes.toBytes("a")),
501          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
502            Bytes.toBytes("b"))))
503        .build(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("D"))));
504      assertTrue(result.isSuccess());
505      assertNull(result.getResult());
506
507      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"))));
508
509      // Mutate with success
510      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
511        .ifMatches(new FilterList(
512          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
513            Bytes.toBytes("a")),
514          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
515            Bytes.toBytes("b"))))
516        .build(new RowMutations(ROWKEY)
517          .add((Mutation) new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")))
518          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A")))));
519      assertTrue(result.isSuccess());
520      assertNull(result.getResult());
521
522      r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D")));
523      assertEquals("d", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("D"))));
524
525      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
526    }
527  }
528
529  @Test
530  public void testCheckAndMutateWithTimestampFilter() throws Throwable {
531    try (Table table = createTable()) {
532      // Put with specifying the timestamp
533      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a")));
534
535      // Put with success
536      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
537        .ifMatches(
538          new FilterList(new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(FAMILY)),
539            new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("A"))),
540            new TimestampsFilter(Collections.singletonList(100L))))
541        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
542      assertTrue(result.isSuccess());
543      assertNull(result.getResult());
544
545      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
546      assertEquals("b", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("B"))));
547
548      // Put with failure
549      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
550        .ifMatches(
551          new FilterList(new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(FAMILY)),
552            new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("A"))),
553            new TimestampsFilter(Collections.singletonList(101L))))
554        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))));
555      assertFalse(result.isSuccess());
556      assertNull(result.getResult());
557
558      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
559    }
560  }
561
562  @Test
563  public void testCheckAndMutateWithFilterAndTimeRange() throws Throwable {
564    try (Table table = createTable()) {
565      // Put with specifying the timestamp
566      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a")));
567
568      // Put with success
569      CheckAndMutateResult result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
570        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
571          Bytes.toBytes("a")))
572        .timeRange(TimeRange.between(0, 101))
573        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
574      assertTrue(result.isSuccess());
575      assertNull(result.getResult());
576
577      Result r = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
578      assertEquals("b", Bytes.toString(r.getValue(FAMILY, Bytes.toBytes("B"))));
579
580      // Put with failure
581      result = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
582        .ifMatches(new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
583          Bytes.toBytes("a")))
584        .timeRange(TimeRange.between(0, 100))
585        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))));
586      assertFalse(result.isSuccess());
587      assertNull(result.getResult());
588
589      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
590    }
591  }
592
593  @Test(expected = IllegalStateException.class)
594  public void testCheckAndMutateBuilderWithoutCondition() {
595    CheckAndMutate.newBuilder(ROWKEY)
596      .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")));
597  }
598
599  @Test
600  public void testCheckAndIncrement() throws Throwable {
601    try (Table table = createTable()) {
602      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")));
603
604      // CheckAndIncrement with correct value
605      CheckAndMutateResult res = table.checkAndMutate(
606        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
607          .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 1)));
608      assertTrue(res.isSuccess());
609      assertEquals(1, Bytes.toLong(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
610
611      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
612      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
613
614      // CheckAndIncrement with wrong value
615      res = table.checkAndMutate(
616        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("b"))
617          .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 1)));
618      assertFalse(res.isSuccess());
619      assertNull(res.getResult());
620
621      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
622      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
623
624      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")));
625
626      // CheckAndIncrement with a filter and correct value
627      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
628        .ifMatches(new FilterList(
629          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
630            Bytes.toBytes("a")),
631          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
632            Bytes.toBytes("c"))))
633        .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 2)));
634      assertTrue(res.isSuccess());
635      assertEquals(3, Bytes.toLong(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
636
637      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
638      assertEquals(3, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
639
640      // CheckAndIncrement with a filter and correct value
641      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
642        .ifMatches(new FilterList(
643          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
644            Bytes.toBytes("b")),
645          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
646            Bytes.toBytes("d"))))
647        .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 2)));
648      assertFalse(res.isSuccess());
649      assertNull(res.getResult());
650
651      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
652      assertEquals(3, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
653    }
654  }
655
656  @Test
657  public void testCheckAndAppend() throws Throwable {
658    try (Table table = createTable()) {
659      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")));
660
661      // CheckAndAppend with correct value
662      CheckAndMutateResult res = table.checkAndMutate(
663        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
664          .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
665      assertTrue(res.isSuccess());
666      assertEquals("b", Bytes.toString(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
667
668      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
669      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
670
671      // CheckAndAppend with correct value
672      res = table.checkAndMutate(
673        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("b"))
674          .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))));
675      assertFalse(res.isSuccess());
676      assertNull(res.getResult());
677
678      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
679      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
680
681      table.put(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")));
682
683      // CheckAndAppend with a filter and correct value
684      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
685        .ifMatches(new FilterList(
686          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
687            Bytes.toBytes("a")),
688          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
689            Bytes.toBytes("c"))))
690        .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("bb"))));
691      assertTrue(res.isSuccess());
692      assertEquals("bbb", Bytes.toString(res.getResult().getValue(FAMILY, Bytes.toBytes("B"))));
693
694      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
695      assertEquals("bbb", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
696
697      // CheckAndAppend with a filter and wrong value
698      res = table.checkAndMutate(CheckAndMutate.newBuilder(ROWKEY)
699        .ifMatches(new FilterList(
700          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
701            Bytes.toBytes("b")),
702          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("C"), CompareOperator.EQUAL,
703            Bytes.toBytes("d"))))
704        .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("bb"))));
705      assertFalse(res.isSuccess());
706      assertNull(res.getResult());
707
708      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
709      assertEquals("bbb", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
710    }
711  }
712
713  @Test
714  public void testCheckAndRowMutations() throws Throwable {
715    final byte[] q1 = Bytes.toBytes("q1");
716    final byte[] q2 = Bytes.toBytes("q2");
717    final byte[] q3 = Bytes.toBytes("q3");
718    final byte[] q4 = Bytes.toBytes("q4");
719    final String v1 = "v1";
720
721    try (Table table = createTable()) {
722      // Initial values
723      table.put(Arrays.asList(new Put(ROWKEY).addColumn(FAMILY, q2, Bytes.toBytes("toBeDeleted")),
724        new Put(ROWKEY).addColumn(FAMILY, q3, Bytes.toBytes(5L)),
725        new Put(ROWKEY).addColumn(FAMILY, q4, Bytes.toBytes("a"))));
726
727      // Do CheckAndRowMutations
728      CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(ROWKEY).ifNotExists(FAMILY, q1)
729        .build(new RowMutations(ROWKEY).add(Arrays.asList(
730          new Put(ROWKEY).addColumn(FAMILY, q1, Bytes.toBytes(v1)),
731          new Delete(ROWKEY).addColumns(FAMILY, q2), new Increment(ROWKEY).addColumn(FAMILY, q3, 1),
732          new Append(ROWKEY).addColumn(FAMILY, q4, Bytes.toBytes("b")))));
733
734      CheckAndMutateResult result = table.checkAndMutate(checkAndMutate);
735      assertTrue(result.isSuccess());
736      assertEquals(6L, Bytes.toLong(result.getResult().getValue(FAMILY, q3)));
737      assertEquals("ab", Bytes.toString(result.getResult().getValue(FAMILY, q4)));
738
739      // Verify the value
740      Result r = table.get(new Get(ROWKEY));
741      assertEquals(v1, Bytes.toString(r.getValue(FAMILY, q1)));
742      assertNull(r.getValue(FAMILY, q2));
743      assertEquals(6L, Bytes.toLong(r.getValue(FAMILY, q3)));
744      assertEquals("ab", Bytes.toString(r.getValue(FAMILY, q4)));
745
746      // Do CheckAndRowMutations again
747      checkAndMutate = CheckAndMutate.newBuilder(ROWKEY).ifNotExists(FAMILY, q1)
748        .build(new RowMutations(ROWKEY).add(Arrays.asList(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      result = table.checkAndMutate(checkAndMutate);
754      assertFalse(result.isSuccess());
755      assertNull(result.getResult());
756
757      // Verify the value
758      r = table.get(new Get(ROWKEY));
759      assertEquals(v1, Bytes.toString(r.getValue(FAMILY, q1)));
760      assertNull(r.getValue(FAMILY, q2));
761      assertEquals(6L, Bytes.toLong(r.getValue(FAMILY, q3)));
762      assertEquals("ab", Bytes.toString(r.getValue(FAMILY, q4)));
763    }
764  }
765
766  // Tests for batch version of checkAndMutate
767
768  @Test
769  public void testCheckAndMutateBatch() throws Throwable {
770    try (Table table = createTable()) {
771      table.put(
772        Arrays.asList(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")),
773          new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")),
774          new Put(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")),
775          new Put(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
776
777      // Test for Put
778      CheckAndMutate checkAndMutate1 =
779        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
780          .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("e")));
781
782      CheckAndMutate checkAndMutate2 =
783        CheckAndMutate.newBuilder(ROWKEY2).ifEquals(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("a"))
784          .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("f")));
785
786      List<CheckAndMutateResult> results =
787        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
788
789      assertTrue(results.get(0).isSuccess());
790      assertNull(results.get(0).getResult());
791      assertFalse(results.get(1).isSuccess());
792      assertNull(results.get(1).getResult());
793
794      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A")));
795      assertEquals("e", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
796
797      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
798      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
799
800      // Test for Delete
801      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
802        .ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("e")).build(new Delete(ROWKEY));
803
804      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
805        .ifEquals(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("a")).build(new Delete(ROWKEY2));
806
807      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
808
809      assertTrue(results.get(0).isSuccess());
810      assertNull(results.get(0).getResult());
811      assertFalse(results.get(1).isSuccess());
812      assertNull(results.get(1).getResult());
813
814      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"))));
815
816      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
817      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
818
819      // Test for RowMutations
820      checkAndMutate1 =
821        CheckAndMutate.newBuilder(ROWKEY3).ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))
822          .build(new RowMutations(ROWKEY3)
823            .add(
824              (Mutation) new Put(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f")))
825            .add((Mutation) new Delete(ROWKEY3).addColumns(FAMILY, Bytes.toBytes("C"))));
826
827      checkAndMutate2 =
828        CheckAndMutate.newBuilder(ROWKEY4).ifEquals(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("f"))
829          .build(new RowMutations(ROWKEY4)
830            .add(
831              (Mutation) new Put(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f")))
832            .add((Mutation) new Delete(ROWKEY4).addColumns(FAMILY, Bytes.toBytes("D"))));
833
834      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
835
836      assertTrue(results.get(0).isSuccess());
837      assertNull(results.get(0).getResult());
838      assertFalse(results.get(1).isSuccess());
839      assertNull(results.get(1).getResult());
840
841      result = table.get(new Get(ROWKEY3));
842      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
843      assertNull(result.getValue(FAMILY, Bytes.toBytes("D")));
844
845      result = table.get(new Get(ROWKEY4));
846      assertNull(result.getValue(FAMILY, Bytes.toBytes("F")));
847      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
848    }
849  }
850
851  @Test
852  public void testCheckAndMutateBatch2() throws Throwable {
853    try (Table table = createTable()) {
854      table.put(
855        Arrays.asList(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")),
856          new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")),
857          new Put(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C"), 100, Bytes.toBytes("c")),
858          new Put(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D"), 100, Bytes.toBytes("d"))));
859
860      // Test for ifNotExists()
861      CheckAndMutate checkAndMutate1 =
862        CheckAndMutate.newBuilder(ROWKEY).ifNotExists(FAMILY, Bytes.toBytes("B"))
863          .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("e")));
864
865      CheckAndMutate checkAndMutate2 =
866        CheckAndMutate.newBuilder(ROWKEY2).ifNotExists(FAMILY, Bytes.toBytes("B"))
867          .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("f")));
868
869      List<CheckAndMutateResult> results =
870        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
871
872      assertTrue(results.get(0).isSuccess());
873      assertNull(results.get(0).getResult());
874      assertFalse(results.get(1).isSuccess());
875      assertNull(results.get(1).getResult());
876
877      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A")));
878      assertEquals("e", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
879
880      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
881      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
882
883      // Test for ifMatches()
884      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
885        .ifMatches(FAMILY, Bytes.toBytes("A"), CompareOperator.NOT_EQUAL, Bytes.toBytes("a"))
886        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")));
887
888      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
889        .ifMatches(FAMILY, Bytes.toBytes("B"), CompareOperator.GREATER, Bytes.toBytes("b"))
890        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("f")));
891
892      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
893
894      assertTrue(results.get(0).isSuccess());
895      assertNull(results.get(0).getResult());
896      assertFalse(results.get(1).isSuccess());
897      assertNull(results.get(1).getResult());
898
899      result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A")));
900      assertEquals("a", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
901
902      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("B")));
903      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
904
905      // Test for timeRange()
906      checkAndMutate1 =
907        CheckAndMutate.newBuilder(ROWKEY3).ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c"))
908          .timeRange(TimeRange.between(0, 101))
909          .build(new Put(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("e")));
910
911      checkAndMutate2 =
912        CheckAndMutate.newBuilder(ROWKEY4).ifEquals(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))
913          .timeRange(TimeRange.between(0, 100))
914          .build(new Put(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("f")));
915
916      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
917
918      assertTrue(results.get(0).isSuccess());
919      assertNull(results.get(0).getResult());
920      assertFalse(results.get(1).isSuccess());
921      assertNull(results.get(1).getResult());
922
923      result = table.get(new Get(ROWKEY3).addColumn(FAMILY, Bytes.toBytes("C")));
924      assertEquals("e", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
925
926      result = table.get(new Get(ROWKEY4).addColumn(FAMILY, Bytes.toBytes("D")));
927      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
928    }
929  }
930
931  @Test
932  public void testCheckAndMutateBatchWithFilter() throws Throwable {
933    try (Table table = createTable()) {
934      table.put(Arrays.asList(
935        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
936          .addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))
937          .addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")),
938        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))
939          .addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e"))
940          .addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f"))));
941
942      // Test for Put
943      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
944        .ifMatches(new FilterList(
945          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
946            Bytes.toBytes("a")),
947          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
948            Bytes.toBytes("b"))))
949        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("g")));
950
951      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
952        .ifMatches(new FilterList(
953          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
954            Bytes.toBytes("a")),
955          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
956            Bytes.toBytes("b"))))
957        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("h")));
958
959      List<CheckAndMutateResult> results =
960        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
961
962      assertTrue(results.get(0).isSuccess());
963      assertNull(results.get(0).getResult());
964      assertFalse(results.get(1).isSuccess());
965      assertNull(results.get(1).getResult());
966
967      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C")));
968      assertEquals("g", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
969
970      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
971      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
972
973      // Test for Delete
974      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
975        .ifMatches(new FilterList(
976          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
977            Bytes.toBytes("a")),
978          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
979            Bytes.toBytes("b"))))
980        .build(new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("C")));
981
982      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
983        .ifMatches(new FilterList(
984          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
985            Bytes.toBytes("a")),
986          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
987            Bytes.toBytes("b"))))
988        .build(new Delete(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
989
990      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
991
992      assertTrue(results.get(0).isSuccess());
993      assertNull(results.get(0).getResult());
994      assertFalse(results.get(1).isSuccess());
995      assertNull(results.get(1).getResult());
996
997      assertFalse(table.exists(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"))));
998
999      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
1000      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1001
1002      // Test for RowMutations
1003      checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
1004        .ifMatches(new FilterList(
1005          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
1006            Bytes.toBytes("a")),
1007          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
1008            Bytes.toBytes("b"))))
1009        .build(new RowMutations(ROWKEY)
1010          .add((Mutation) new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")))
1011          .add((Mutation) new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("A"))));
1012
1013      checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
1014        .ifMatches(new FilterList(
1015          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
1016            Bytes.toBytes("a")),
1017          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
1018            Bytes.toBytes("b"))))
1019        .build(new RowMutations(ROWKEY2)
1020          .add(
1021            (Mutation) new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("g")))
1022          .add((Mutation) new Delete(ROWKEY2).addColumns(FAMILY, Bytes.toBytes("D"))));
1023
1024      results = table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1025
1026      assertTrue(results.get(0).isSuccess());
1027      assertNull(results.get(0).getResult());
1028      assertFalse(results.get(1).isSuccess());
1029      assertNull(results.get(1).getResult());
1030
1031      result = table.get(new Get(ROWKEY));
1032      assertNull(result.getValue(FAMILY, Bytes.toBytes("A")));
1033      assertEquals("c", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
1034
1035      result = table.get(new Get(ROWKEY2));
1036      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
1037      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1038    }
1039  }
1040
1041  @Test
1042  public void testCheckAndMutateBatchWithFilterAndTimeRange() throws Throwable {
1043    try (Table table = createTable()) {
1044      table.put(Arrays.asList(
1045        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), 100, Bytes.toBytes("a"))
1046          .addColumn(FAMILY, Bytes.toBytes("B"), 100, Bytes.toBytes("b"))
1047          .addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")),
1048        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D"), 100, Bytes.toBytes("d"))
1049          .addColumn(FAMILY, Bytes.toBytes("E"), 100, Bytes.toBytes("e"))
1050          .addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f"))));
1051
1052      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
1053        .ifMatches(new FilterList(
1054          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("A"), CompareOperator.EQUAL,
1055            Bytes.toBytes("a")),
1056          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("B"), CompareOperator.EQUAL,
1057            Bytes.toBytes("b"))))
1058        .timeRange(TimeRange.between(0, 101))
1059        .build(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("g")));
1060
1061      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(ROWKEY2)
1062        .ifMatches(new FilterList(
1063          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("D"), CompareOperator.EQUAL,
1064            Bytes.toBytes("d")),
1065          new SingleColumnValueFilter(FAMILY, Bytes.toBytes("E"), CompareOperator.EQUAL,
1066            Bytes.toBytes("e"))))
1067        .timeRange(TimeRange.between(0, 100))
1068        .build(new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("h")));
1069
1070      List<CheckAndMutateResult> results =
1071        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1072
1073      assertTrue(results.get(0).isSuccess());
1074      assertNull(results.get(0).getResult());
1075      assertFalse(results.get(1).isSuccess());
1076      assertNull(results.get(1).getResult());
1077
1078      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C")));
1079      assertEquals("g", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
1080
1081      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F")));
1082      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1083    }
1084  }
1085
1086  @Test
1087  public void testCheckAndIncrementBatch() throws Throwable {
1088    try (Table table = createTable()) {
1089      table.put(Arrays.asList(
1090        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")).addColumn(FAMILY,
1091          Bytes.toBytes("B"), Bytes.toBytes(0L)),
1092        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")).addColumn(FAMILY,
1093          Bytes.toBytes("D"), Bytes.toBytes(0L))));
1094
1095      // CheckAndIncrement with correct value
1096      CheckAndMutate checkAndMutate1 =
1097        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
1098          .build(new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), 1));
1099
1100      // CheckAndIncrement with wrong value
1101      CheckAndMutate checkAndMutate2 =
1102        CheckAndMutate.newBuilder(ROWKEY2).ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("d"))
1103          .build(new Increment(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D"), 1));
1104
1105      List<CheckAndMutateResult> results =
1106        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1107
1108      assertTrue(results.get(0).isSuccess());
1109      assertEquals(1,
1110        Bytes.toLong(results.get(0).getResult().getValue(FAMILY, Bytes.toBytes("B"))));
1111      assertFalse(results.get(1).isSuccess());
1112      assertNull(results.get(1).getResult());
1113
1114      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
1115      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("B"))));
1116
1117      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D")));
1118      assertEquals(0, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("D"))));
1119    }
1120  }
1121
1122  @Test
1123  public void testCheckAndAppendBatch() throws Throwable {
1124    try (Table table = createTable()) {
1125      table.put(Arrays.asList(
1126        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")).addColumn(FAMILY,
1127          Bytes.toBytes("B"), Bytes.toBytes("b")),
1128        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")).addColumn(FAMILY,
1129          Bytes.toBytes("D"), Bytes.toBytes("d"))));
1130
1131      // CheckAndAppend with correct value
1132      CheckAndMutate checkAndMutate1 =
1133        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
1134          .build(new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")));
1135
1136      // CheckAndAppend with wrong value
1137      CheckAndMutate checkAndMutate2 =
1138        CheckAndMutate.newBuilder(ROWKEY2).ifEquals(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("d"))
1139          .build(new Append(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")));
1140
1141      List<CheckAndMutateResult> results =
1142        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1143
1144      assertTrue(results.get(0).isSuccess());
1145      assertEquals("bb",
1146        Bytes.toString(results.get(0).getResult().getValue(FAMILY, Bytes.toBytes("B"))));
1147      assertFalse(results.get(1).isSuccess());
1148      assertNull(results.get(1).getResult());
1149
1150      Result result = table.get(new Get(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B")));
1151      assertEquals("bb", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
1152
1153      result = table.get(new Get(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("D")));
1154      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
1155    }
1156  }
1157
1158  @Test
1159  public void testCheckAndRowMutationsBatch() throws Throwable {
1160    try (Table table = createTable()) {
1161      table.put(Arrays.asList(
1162        new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))
1163          .addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes(1L))
1164          .addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")),
1165        new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f"))
1166          .addColumn(FAMILY, Bytes.toBytes("G"), Bytes.toBytes(1L))
1167          .addColumn(FAMILY, Bytes.toBytes("H"), Bytes.toBytes("h"))));
1168
1169      // CheckAndIncrement with correct value
1170      CheckAndMutate checkAndMutate1 =
1171        CheckAndMutate.newBuilder(ROWKEY).ifEquals(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b"))
1172          .build(new RowMutations(ROWKEY).add(
1173            Arrays.asList(new Put(ROWKEY).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")),
1174              new Delete(ROWKEY).addColumns(FAMILY, Bytes.toBytes("B")),
1175              new Increment(ROWKEY).addColumn(FAMILY, Bytes.toBytes("C"), 1L),
1176              new Append(ROWKEY).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")))));
1177
1178      // CheckAndIncrement with wrong value
1179      CheckAndMutate checkAndMutate2 =
1180        CheckAndMutate.newBuilder(ROWKEY2).ifEquals(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("a"))
1181          .build(new RowMutations(ROWKEY2).add(Arrays.asList(
1182            new Put(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e")),
1183            new Delete(ROWKEY2).addColumns(FAMILY, Bytes.toBytes("F")),
1184            new Increment(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("G"), 1L),
1185            new Append(ROWKEY2).addColumn(FAMILY, Bytes.toBytes("H"), Bytes.toBytes("h")))));
1186
1187      List<CheckAndMutateResult> results =
1188        table.checkAndMutate(Arrays.asList(checkAndMutate1, checkAndMutate2));
1189
1190      assertTrue(results.get(0).isSuccess());
1191      assertEquals(2,
1192        Bytes.toLong(results.get(0).getResult().getValue(FAMILY, Bytes.toBytes("C"))));
1193      assertEquals("dd",
1194        Bytes.toString(results.get(0).getResult().getValue(FAMILY, Bytes.toBytes("D"))));
1195
1196      assertFalse(results.get(1).isSuccess());
1197      assertNull(results.get(1).getResult());
1198
1199      Result result = table.get(new Get(ROWKEY));
1200      assertEquals("a", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("A"))));
1201      assertNull(result.getValue(FAMILY, Bytes.toBytes("B")));
1202      assertEquals(2, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("C"))));
1203      assertEquals("dd", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
1204
1205      result = table.get(new Get(ROWKEY2));
1206      assertNull(result.getValue(FAMILY, Bytes.toBytes("E")));
1207      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
1208      assertEquals(1, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("G"))));
1209      assertEquals("h", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("H"))));
1210    }
1211  }
1212
1213  @Test
1214  public void testCheckAndMutateForNull() throws Exception {
1215    byte[] qualifier = Bytes.toBytes("Q");
1216    try (Table table = createTable()) {
1217      byte[] row1 = Bytes.toBytes("testRow1");
1218      Put put = new Put(row1);
1219      put.addColumn(FAMILY, qualifier, Bytes.toBytes("v0"));
1220      table.put(put);
1221      assertEquals("v0", Bytes.toString(
1222        table.get(new Get(row1).addColumn(FAMILY, qualifier)).getValue(FAMILY, qualifier)));
1223
1224      CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(row1)
1225        .ifMatches(FAMILY, qualifier, CompareOperator.NOT_EQUAL, new byte[] {})
1226        .build(new Put(row1).addColumn(FAMILY, qualifier, Bytes.toBytes("v1")));
1227      table.checkAndMutate(checkAndMutate1);
1228      assertEquals("v1", Bytes.toString(
1229        table.get(new Get(row1).addColumn(FAMILY, qualifier)).getValue(FAMILY, qualifier)));
1230
1231      byte[] row2 = Bytes.toBytes("testRow2");
1232      put = new Put(row2);
1233      put.addColumn(FAMILY, qualifier, new byte[] {});
1234      table.put(put);
1235      assertEquals(0,
1236        table.get(new Get(row2).addColumn(FAMILY, qualifier)).getValue(FAMILY, qualifier).length);
1237
1238      CheckAndMutate checkAndMutate2 = CheckAndMutate.newBuilder(row2)
1239        .ifMatches(FAMILY, qualifier, CompareOperator.EQUAL, new byte[] {})
1240        .build(new Put(row2).addColumn(FAMILY, qualifier, Bytes.toBytes("v2")));
1241      table.checkAndMutate(checkAndMutate2);
1242      assertEquals("v2", Bytes.toString(
1243        table.get(new Get(row2).addColumn(FAMILY, qualifier)).getValue(FAMILY, qualifier)));
1244
1245      byte[] row3 = Bytes.toBytes("testRow3");
1246      put = new Put(row3).addColumn(FAMILY, qualifier, Bytes.toBytes("v0"));
1247      assertNull(table.get(new Get(row3).addColumn(FAMILY, qualifier)).getValue(FAMILY, qualifier));
1248      CheckAndMutate checkAndMutate3 = CheckAndMutate.newBuilder(row3)
1249        .ifMatches(FAMILY, qualifier, CompareOperator.NOT_EQUAL, new byte[] {}).build(put);
1250      table.checkAndMutate(checkAndMutate3);
1251      assertNull(table.get(new Get(row3).addColumn(FAMILY, qualifier)).getValue(FAMILY, qualifier));
1252
1253      CheckAndMutate checkAndMutate4 = CheckAndMutate.newBuilder(row3)
1254        .ifMatches(FAMILY, qualifier, CompareOperator.EQUAL, new byte[] {}).build(put);
1255      table.checkAndMutate(checkAndMutate4);
1256      assertEquals("v0", Bytes.toString(
1257        table.get(new Get(row3).addColumn(FAMILY, qualifier)).getValue(FAMILY, qualifier)));
1258    }
1259  }
1260}