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.security.visibility;
019
020import static org.awaitility.Awaitility.await;
021import static org.junit.jupiter.api.Assertions.assertEquals;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.io.InterruptedIOException;
026import java.security.PrivilegedExceptionAction;
027import java.time.Duration;
028import java.util.ArrayList;
029import java.util.Arrays;
030import java.util.List;
031import java.util.Random;
032import org.apache.hadoop.hbase.Cell;
033import org.apache.hadoop.hbase.CellScanner;
034import org.apache.hadoop.hbase.CellUtil;
035import org.apache.hadoop.hbase.HConstants;
036import org.apache.hadoop.hbase.TableName;
037import org.apache.hadoop.hbase.TableNameTestExtension;
038import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
039import org.apache.hadoop.hbase.client.Connection;
040import org.apache.hadoop.hbase.client.ConnectionFactory;
041import org.apache.hadoop.hbase.client.Delete;
042import org.apache.hadoop.hbase.client.Get;
043import org.apache.hadoop.hbase.client.Put;
044import org.apache.hadoop.hbase.client.Result;
045import org.apache.hadoop.hbase.client.ResultScanner;
046import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
047import org.apache.hadoop.hbase.client.Scan;
048import org.apache.hadoop.hbase.client.Table;
049import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
050import org.apache.hadoop.hbase.regionserver.HRegion;
051import org.apache.hadoop.hbase.testclassification.LargeTests;
052import org.apache.hadoop.hbase.testclassification.SecurityTests;
053import org.apache.hadoop.hbase.util.Bytes;
054import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
055import org.junit.jupiter.api.Tag;
056import org.junit.jupiter.api.Test;
057import org.junit.jupiter.api.TestInfo;
058
059import org.apache.hadoop.hbase.shaded.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
060
061@Tag(SecurityTests.TAG)
062@Tag(LargeTests.TAG)
063public class TestVisibilityLabelsWithDeletes extends VisibilityLabelsWithDeletesTestBase {
064
065  @Override
066  protected Table createTable(byte[] fam, TestInfo testInfo) throws IOException {
067    TableName tableName = TableName
068      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
069    TEST_UTIL.getAdmin().createTable(TableDescriptorBuilder.newBuilder(tableName)
070      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(fam)).build());
071    return TEST_UTIL.getConnection().getTable(tableName);
072  }
073
074  private TableName createTable(TestInfo testInfo) throws IOException {
075    return createTable(-1, testInfo);
076  }
077
078  private TableName createTable(int maxVersions, TestInfo testInfo) throws IOException {
079    TableName tableName = TableName
080      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
081    createTable(tableName, maxVersions);
082    return tableName;
083  }
084
085  private void createTable(TableName tableName, int maxVersions) throws IOException {
086    ColumnFamilyDescriptorBuilder builder = ColumnFamilyDescriptorBuilder.newBuilder(fam);
087    if (maxVersions > 0) {
088      builder.setMaxVersions(maxVersions);
089    }
090    TEST_UTIL.getAdmin().createTable(
091      TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(builder.build()).build());
092  }
093
094  @Test
095  public void testVisibilityLabelsWithDeleteColumnsWithMultipleVersions(TestInfo testInfo)
096    throws Exception {
097    setAuths();
098    final TableName tableName = TableName
099      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
100    try (Table table = doPuts(tableName)) {
101      TEST_UTIL.getAdmin().flush(tableName);
102      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
103        @Override
104        public Void run() throws Exception {
105          try (Connection connection = ConnectionFactory.createConnection(conf);
106            Table table = connection.getTable(tableName)) {
107            Delete d = new Delete(row1);
108            d.setCellVisibility(new CellVisibility(
109              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
110            d.addColumns(fam, qual, 125L);
111            table.delete(d);
112          } catch (Throwable t) {
113            throw new IOException(t);
114          }
115          return null;
116        }
117      };
118      SUPERUSER.runAs(actiona);
119
120      TEST_UTIL.getAdmin().flush(tableName);
121      Scan s = new Scan();
122      s.readVersions(5);
123      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
124      ResultScanner scanner = table.getScanner(s);
125      Result[] next = scanner.next(3);
126      assertTrue(next.length == 2);
127      CellScanner cellScanner = next[0].cellScanner();
128      cellScanner.advance();
129      Cell current = cellScanner.current();
130      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
131        row1, 0, row1.length));
132      assertEquals(127L, current.getTimestamp());
133      cellScanner.advance();
134      current = cellScanner.current();
135      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
136        row1, 0, row1.length));
137      assertEquals(126L, current.getTimestamp());
138      cellScanner.advance();
139      current = cellScanner.current();
140      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
141        row1, 0, row1.length));
142      assertEquals(125L, current.getTimestamp());
143      cellScanner = next[1].cellScanner();
144      cellScanner.advance();
145      current = cellScanner.current();
146      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
147        row2, 0, row2.length));
148    }
149  }
150
151  @Test
152  public void testVisibilityLabelsWithDeleteColumnsWithMultipleVersionsNoTimestamp(
153    TestInfo testInfo) throws Exception {
154    setAuths();
155    final TableName tableName = TableName
156      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
157    try (Table table = doPuts(tableName)) {
158      TEST_UTIL.getAdmin().flush(tableName);
159      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
160        @Override
161        public Void run() throws Exception {
162          try (Connection connection = ConnectionFactory.createConnection(conf);
163            Table table = connection.getTable(tableName)) {
164            Delete d1 = new Delete(row1);
165            d1.setCellVisibility(new CellVisibility(CONFIDENTIAL));
166            d1.addColumns(fam, qual);
167
168            table.delete(d1);
169
170            Delete d2 = new Delete(row1);
171            d2.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
172            d2.addColumns(fam, qual);
173            table.delete(d2);
174
175            Delete d3 = new Delete(row1);
176            d3.setCellVisibility(new CellVisibility(
177              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
178            d3.addColumns(fam, qual);
179            table.delete(d3);
180          } catch (Throwable t) {
181            throw new IOException(t);
182          }
183          return null;
184        }
185      };
186      SUPERUSER.runAs(actiona);
187      Scan s = new Scan();
188      s.readVersions(5);
189      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
190      ResultScanner scanner = table.getScanner(s);
191      Result[] next = scanner.next(3);
192      assertEquals(1, next.length);
193      CellScanner cellScanner = next[0].cellScanner();
194      cellScanner.advance();
195      Cell current = cellScanner.current();
196      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
197        row2, 0, row2.length));
198    }
199  }
200
201  @Test
202  public void testVisibilityLabelsWithDeleteColumnsNoMatchVisExpWithMultipleVersionsNoTimestamp(
203    TestInfo testInfo) throws Exception {
204    setAuths();
205    final TableName tableName = TableName
206      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
207    try (Table table = doPuts(tableName)) {
208      TEST_UTIL.getAdmin().flush(tableName);
209      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
210        @Override
211        public Void run() throws Exception {
212          try (Connection connection = ConnectionFactory.createConnection(conf);
213            Table table = connection.getTable(tableName)) {
214            Delete d = new Delete(row1);
215            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
216            d.addColumns(fam, qual);
217            table.delete(d);
218
219            d = new Delete(row1);
220            d.setCellVisibility(new CellVisibility(SECRET));
221            d.addColumns(fam, qual);
222            table.delete(d);
223
224            d = new Delete(row1);
225            d.setCellVisibility(new CellVisibility(
226              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
227            d.addColumns(fam, qual);
228            table.delete(d);
229          } catch (Throwable t) {
230            throw new IOException(t);
231          }
232          return null;
233        }
234      };
235      SUPERUSER.runAs(actiona);
236      Scan s = new Scan();
237      s.readVersions(5);
238      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
239      ResultScanner scanner = table.getScanner(s);
240      Result[] next = scanner.next(3);
241      assertTrue(next.length == 2);
242      CellScanner cellScanner = next[0].cellScanner();
243      cellScanner.advance();
244      Cell current = cellScanner.current();
245      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
246        row1, 0, row1.length));
247      cellScanner = next[1].cellScanner();
248      cellScanner.advance();
249      current = cellScanner.current();
250      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
251        row2, 0, row2.length));
252    }
253  }
254
255  @Test
256  public void testVisibilityLabelsWithDeleteFamilyWithMultipleVersionsNoTimestamp(TestInfo testInfo)
257    throws Exception {
258    setAuths();
259    final TableName tableName = TableName
260      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
261    try (Table table = doPuts(tableName)) {
262      TEST_UTIL.getAdmin().flush(tableName);
263      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
264        @Override
265        public Void run() throws Exception {
266          try (Connection connection = ConnectionFactory.createConnection(conf);
267            Table table = connection.getTable(tableName)) {
268            Delete d1 = new Delete(row1);
269            d1.setCellVisibility(new CellVisibility(CONFIDENTIAL));
270            d1.addFamily(fam);
271            table.delete(d1);
272
273            Delete d2 = new Delete(row1);
274            d2.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
275            d2.addFamily(fam);
276            table.delete(d2);
277
278            Delete d3 = new Delete(row1);
279            d3.setCellVisibility(new CellVisibility(
280              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
281            d3.addFamily(fam);
282            table.delete(d3);
283          } catch (Throwable t) {
284            throw new IOException(t);
285          }
286          return null;
287        }
288      };
289      SUPERUSER.runAs(actiona);
290      Scan s = new Scan();
291      s.readVersions(5);
292      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
293      ResultScanner scanner = table.getScanner(s);
294      Result[] next = scanner.next(3);
295      assertEquals(1, next.length);
296      CellScanner cellScanner = next[0].cellScanner();
297      cellScanner.advance();
298      Cell current = cellScanner.current();
299      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
300        row2, 0, row2.length));
301    }
302  }
303
304  @Test
305  public void testDeleteColumnsWithoutAndWithVisibilityLabels(TestInfo testInfo) throws Exception {
306    TableName tableName = createTable(testInfo);
307    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
308      Put put = new Put(row1);
309      put.addColumn(fam, qual, value);
310      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
311      table.put(put);
312      Delete d = new Delete(row1);
313      // without visibility
314      d.addColumns(fam, qual, HConstants.LATEST_TIMESTAMP);
315      table.delete(d);
316      PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
317        @Override
318        public Void run() throws Exception {
319          try (Connection connection = ConnectionFactory.createConnection(conf);
320            Table table = connection.getTable(tableName)) {
321            Scan s = new Scan();
322            ResultScanner scanner = table.getScanner(s);
323            Result[] next = scanner.next(3);
324            assertEquals(1, next.length);
325          }
326          return null;
327        }
328      };
329      SUPERUSER.runAs(scanAction);
330      d = new Delete(row1);
331      // with visibility
332      d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
333      d.addColumns(fam, qual, HConstants.LATEST_TIMESTAMP);
334      table.delete(d);
335      scanAction = new PrivilegedExceptionAction<Void>() {
336        @Override
337        public Void run() throws Exception {
338          try (Connection connection = ConnectionFactory.createConnection(conf);
339            Table table = connection.getTable(tableName)) {
340            Scan s = new Scan();
341            ResultScanner scanner = table.getScanner(s);
342            Result[] next = scanner.next(3);
343            assertEquals(0, next.length);
344          }
345          return null;
346        }
347      };
348      SUPERUSER.runAs(scanAction);
349    }
350  }
351
352  @Test
353  public void testDeleteColumnsWithAndWithoutVisibilityLabels(TestInfo testInfo) throws Exception {
354    TableName tableName = createTable(testInfo);
355    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
356      Put put = new Put(row1);
357      put.addColumn(fam, qual, value);
358      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
359      table.put(put);
360      Delete d = new Delete(row1);
361      // with visibility
362      d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
363      d.addColumns(fam, qual, HConstants.LATEST_TIMESTAMP);
364      table.delete(d);
365      PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
366        @Override
367        public Void run() throws Exception {
368          try (Connection connection = ConnectionFactory.createConnection(conf);
369            Table table = connection.getTable(tableName)) {
370            Scan s = new Scan();
371            ResultScanner scanner = table.getScanner(s);
372            Result[] next = scanner.next(3);
373            assertEquals(0, next.length);
374          }
375          return null;
376        }
377      };
378      SUPERUSER.runAs(scanAction);
379      d = new Delete(row1);
380      // without visibility
381      d.addColumns(fam, qual, HConstants.LATEST_TIMESTAMP);
382      table.delete(d);
383      scanAction = new PrivilegedExceptionAction<Void>() {
384        @Override
385        public Void run() throws Exception {
386          try (Connection connection = ConnectionFactory.createConnection(conf);
387            Table table = connection.getTable(tableName)) {
388            Scan s = new Scan();
389            ResultScanner scanner = table.getScanner(s);
390            Result[] next = scanner.next(3);
391            assertEquals(0, next.length);
392          }
393          return null;
394        }
395      };
396      SUPERUSER.runAs(scanAction);
397    }
398  }
399
400  @Test
401  public void testDeleteFamiliesWithoutAndWithVisibilityLabels(TestInfo testInfo) throws Exception {
402    TableName tableName = createTable(testInfo);
403    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
404      Put put = new Put(row1);
405      put.addColumn(fam, qual, value);
406      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
407      table.put(put);
408      Delete d = new Delete(row1);
409      // without visibility
410      d.addFamily(fam);
411      table.delete(d);
412      PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
413        @Override
414        public Void run() throws Exception {
415          try (Connection connection = ConnectionFactory.createConnection(conf);
416            Table table = connection.getTable(tableName)) {
417            Scan s = new Scan();
418            ResultScanner scanner = table.getScanner(s);
419            Result[] next = scanner.next(3);
420            assertEquals(1, next.length);
421          }
422          return null;
423        }
424      };
425      SUPERUSER.runAs(scanAction);
426      d = new Delete(row1);
427      // with visibility
428      d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
429      d.addFamily(fam);
430      table.delete(d);
431      scanAction = new PrivilegedExceptionAction<Void>() {
432        @Override
433        public Void run() throws Exception {
434          try (Connection connection = ConnectionFactory.createConnection(conf);
435            Table table = connection.getTable(tableName)) {
436            Scan s = new Scan();
437            ResultScanner scanner = table.getScanner(s);
438            Result[] next = scanner.next(3);
439            assertEquals(0, next.length);
440          }
441          return null;
442        }
443      };
444      SUPERUSER.runAs(scanAction);
445    }
446  }
447
448  @Test
449  public void testDeleteFamiliesWithAndWithoutVisibilityLabels(TestInfo testInfo) throws Exception {
450    TableName tableName = createTable(testInfo);
451    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
452      Put put = new Put(row1);
453      put.addColumn(fam, qual, value);
454      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
455      table.put(put);
456      Delete d = new Delete(row1);
457      d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
458      // with visibility
459      d.addFamily(fam);
460      table.delete(d);
461      PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
462        @Override
463        public Void run() throws Exception {
464          try (Connection connection = ConnectionFactory.createConnection(conf);
465            Table table = connection.getTable(tableName)) {
466            Scan s = new Scan();
467            ResultScanner scanner = table.getScanner(s);
468            Result[] next = scanner.next(3);
469            assertEquals(0, next.length);
470          }
471          return null;
472        }
473      };
474      SUPERUSER.runAs(scanAction);
475      d = new Delete(row1);
476      // without visibility
477      d.addFamily(fam);
478      table.delete(d);
479      scanAction = new PrivilegedExceptionAction<Void>() {
480        @Override
481        public Void run() throws Exception {
482          try (Connection connection = ConnectionFactory.createConnection(conf);
483            Table table = connection.getTable(tableName)) {
484            Scan s = new Scan();
485            ResultScanner scanner = table.getScanner(s);
486            Result[] next = scanner.next(3);
487            assertEquals(0, next.length);
488          }
489          return null;
490        }
491      };
492      SUPERUSER.runAs(scanAction);
493    }
494  }
495
496  @Test
497  public void testDeletesWithoutAndWithVisibilityLabels(TestInfo testInfo) throws Exception {
498    TableName tableName = createTable(testInfo);
499    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
500      Put put = new Put(row1);
501      put.addColumn(fam, qual, value);
502      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
503      table.put(put);
504      Delete d = new Delete(row1);
505      // without visibility
506      d.addColumn(fam, qual);
507      table.delete(d);
508      PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
509        @Override
510        public Void run() throws Exception {
511          try (Connection connection = ConnectionFactory.createConnection(conf);
512            Table table = connection.getTable(tableName)) {
513            Scan s = new Scan();
514            ResultScanner scanner = table.getScanner(s);
515            // The delete would not be able to apply it because of visibility mismatch
516            Result[] next = scanner.next(3);
517            assertEquals(1, next.length);
518          }
519          return null;
520        }
521      };
522      SUPERUSER.runAs(scanAction);
523      d = new Delete(row1);
524      // with visibility
525      d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
526      d.addColumn(fam, qual);
527      table.delete(d);
528      scanAction = new PrivilegedExceptionAction<Void>() {
529        @Override
530        public Void run() throws Exception {
531          try (Connection connection = ConnectionFactory.createConnection(conf);
532            Table table = connection.getTable(tableName)) {
533            Scan s = new Scan();
534            ResultScanner scanner = table.getScanner(s);
535            Result[] next = scanner.next(3);
536            // this will alone match
537            assertEquals(0, next.length);
538          }
539          return null;
540        }
541      };
542      SUPERUSER.runAs(scanAction);
543    }
544  }
545
546  @Test
547  public void testVisibilityLabelsWithDeleteFamilyWithPutsReAppearing(TestInfo testInfo)
548    throws Exception {
549    TableName tableName = createTable(5, testInfo);
550    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
551      Put put = new Put(Bytes.toBytes("row1"));
552      put.addColumn(fam, qual, value);
553      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
554      table.put(put);
555      put = new Put(Bytes.toBytes("row1"));
556      put.addColumn(fam, qual, value);
557      put.setCellVisibility(new CellVisibility(SECRET));
558      table.put(put);
559      TEST_UTIL.getAdmin().flush(tableName);
560      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
561        @Override
562        public Void run() throws Exception {
563          try (Connection connection = ConnectionFactory.createConnection(conf);
564            Table table = connection.getTable(tableName)) {
565            Delete d = new Delete(row1);
566            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
567            d.addFamily(fam);
568            table.delete(d);
569          } catch (Throwable t) {
570            throw new IOException(t);
571          }
572          return null;
573        }
574      };
575      SUPERUSER.runAs(actiona);
576      Scan s = new Scan();
577      s.readVersions(5);
578      s.setAuthorizations(new Authorizations(SECRET));
579      ResultScanner scanner = table.getScanner(s);
580      Result[] next = scanner.next(3);
581      assertEquals(1, next.length);
582      put = new Put(Bytes.toBytes("row1"));
583      put.addColumn(fam, qual, value1);
584      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
585      table.put(put);
586      actiona = new PrivilegedExceptionAction<Void>() {
587        @Override
588        public Void run() throws Exception {
589          try (Connection connection = ConnectionFactory.createConnection(conf);
590            Table table = connection.getTable(tableName)) {
591            Delete d = new Delete(row1);
592            d.setCellVisibility(new CellVisibility(SECRET));
593            d.addFamily(fam);
594            table.delete(d);
595          } catch (Throwable t) {
596            throw new IOException(t);
597          }
598          return null;
599        }
600      };
601      SUPERUSER.runAs(actiona);
602      s = new Scan();
603      s.readVersions(5);
604      s.setAuthorizations(new Authorizations(CONFIDENTIAL));
605      scanner = table.getScanner(s);
606      next = scanner.next(3);
607      assertEquals(1, next.length);
608      s = new Scan();
609      s.readVersions(5);
610      s.setAuthorizations(new Authorizations(SECRET));
611      scanner = table.getScanner(s);
612      Result[] next1 = scanner.next(3);
613      assertEquals(0, next1.length);
614    }
615  }
616
617  @Test
618  public void testVisibilityLabelsWithDeleteColumnsWithPutsReAppearing(TestInfo testInfo)
619    throws Exception {
620    TableName tableName = createTable(5, testInfo);
621    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
622      Put put = new Put(Bytes.toBytes("row1"));
623      put.addColumn(fam, qual, value);
624      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
625      table.put(put);
626      put = new Put(Bytes.toBytes("row1"));
627      put.addColumn(fam, qual, value);
628      put.setCellVisibility(new CellVisibility(SECRET));
629      table.put(put);
630      TEST_UTIL.getAdmin().flush(tableName);
631      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
632        @Override
633        public Void run() throws Exception {
634          try (Connection connection = ConnectionFactory.createConnection(conf);
635            Table table = connection.getTable(tableName)) {
636            Delete d = new Delete(row1);
637            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
638            d.addColumns(fam, qual);
639            table.delete(d);
640          } catch (Throwable t) {
641            throw new IOException(t);
642          }
643          return null;
644        }
645      };
646      SUPERUSER.runAs(actiona);
647      Scan s = new Scan();
648      s.readVersions(5);
649      s.setAuthorizations(new Authorizations(SECRET));
650      ResultScanner scanner = table.getScanner(s);
651      Result[] next = scanner.next(3);
652      assertEquals(1, next.length);
653      put = new Put(Bytes.toBytes("row1"));
654      put.addColumn(fam, qual, value1);
655      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
656      table.put(put);
657      actiona = new PrivilegedExceptionAction<Void>() {
658        @Override
659        public Void run() throws Exception {
660          try (Connection connection = ConnectionFactory.createConnection(conf);
661            Table table = connection.getTable(tableName)) {
662            Delete d = new Delete(row1);
663            d.setCellVisibility(new CellVisibility(SECRET));
664            d.addColumns(fam, qual);
665            table.delete(d);
666          } catch (Throwable t) {
667            throw new IOException(t);
668          }
669          return null;
670        }
671      };
672      SUPERUSER.runAs(actiona);
673      s = new Scan();
674      s.readVersions(5);
675      s.setAuthorizations(new Authorizations(CONFIDENTIAL));
676      scanner = table.getScanner(s);
677      next = scanner.next(3);
678      assertEquals(1, next.length);
679      s = new Scan();
680      s.readVersions(5);
681      s.setAuthorizations(new Authorizations(SECRET));
682      scanner = table.getScanner(s);
683      Result[] next1 = scanner.next(3);
684      assertEquals(0, next1.length);
685    }
686  }
687
688  @Test
689  public void testVisibilityCombinations(TestInfo testInfo) throws Exception {
690    TableName tableName = createTable(5, testInfo);
691    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
692      Put put = new Put(Bytes.toBytes("row1"));
693      put.addColumn(fam, qual, 123L, value);
694      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
695      table.put(put);
696      put = new Put(Bytes.toBytes("row1"));
697      put.addColumn(fam, qual, 124L, value1);
698      put.setCellVisibility(new CellVisibility(SECRET));
699      table.put(put);
700      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
701        @Override
702        public Void run() throws Exception {
703          try (Connection connection = ConnectionFactory.createConnection(conf);
704            Table table = connection.getTable(tableName)) {
705            Delete d = new Delete(row1);
706            d.setCellVisibility(new CellVisibility(SECRET));
707            d.addColumns(fam, qual, 126L);
708            table.delete(d);
709          } catch (Throwable t) {
710            throw new IOException(t);
711          }
712
713          try (Connection connection = ConnectionFactory.createConnection(conf);
714            Table table = connection.getTable(tableName)) {
715            Delete d = new Delete(row1);
716            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
717            d.addColumn(fam, qual, 123L);
718            table.delete(d);
719          } catch (Throwable t) {
720            throw new IOException(t);
721          }
722          return null;
723        }
724      };
725      SUPERUSER.runAs(actiona);
726      Scan s = new Scan();
727      s.readVersions(5);
728      s.setAuthorizations(new Authorizations(CONFIDENTIAL, SECRET));
729      ResultScanner scanner = table.getScanner(s);
730      Result[] next = scanner.next(3);
731      assertEquals(0, next.length);
732    }
733  }
734
735  @Test
736  public void testVisibilityLabelsWithDeleteColumnWithSpecificVersionWithPutsReAppearing(
737    TestInfo testInfo) throws Exception {
738    TableName tableName = createTable(5, testInfo);
739    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
740      Put put1 = new Put(Bytes.toBytes("row1"));
741      put1.addColumn(fam, qual, 123L, value);
742      put1.setCellVisibility(new CellVisibility(CONFIDENTIAL));
743
744      Put put2 = new Put(Bytes.toBytes("row1"));
745      put2.addColumn(fam, qual, 123L, value1);
746      put2.setCellVisibility(new CellVisibility(SECRET));
747      table.put(createList(put1, put2));
748
749      Scan s = new Scan();
750      s.readVersions(5);
751      s.setAuthorizations(new Authorizations(CONFIDENTIAL, SECRET));
752
753      ResultScanner scanner = table.getScanner(s);
754      assertEquals(1, scanner.next(3).length);
755      scanner.close();
756
757      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
758        @Override
759        public Void run() throws Exception {
760          try (Connection connection = ConnectionFactory.createConnection(conf);
761            Table table = connection.getTable(tableName)) {
762            Delete d = new Delete(row1);
763            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
764            d.addColumn(fam, qual, 123L);
765            table.delete(d);
766          }
767
768          try (Connection connection = ConnectionFactory.createConnection(conf);
769            Table table = connection.getTable(tableName)) {
770            Delete d = new Delete(row1);
771            d.setCellVisibility(new CellVisibility(SECRET));
772            d.addColumn(fam, qual, 123L);
773            table.delete(d);
774          } catch (Throwable t) {
775            throw new IOException(t);
776          }
777          return null;
778        }
779      };
780      SUPERUSER.runAs(actiona);
781      s = new Scan();
782      s.readVersions(5);
783      s.setAuthorizations(new Authorizations(CONFIDENTIAL));
784      scanner = table.getScanner(s);
785      assertEquals(0, scanner.next(3).length);
786      scanner.close();
787    }
788  }
789
790  @Test
791  public void testVisibilityLabelsWithDeleteFamilyNoMatchingVisExpWithMultipleVersionsNoTimestamp(
792    TestInfo testInfo) throws Exception {
793    setAuths();
794    final TableName tableName = TableName
795      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
796    try (Table table = doPuts(tableName)) {
797      TEST_UTIL.getAdmin().flush(tableName);
798      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
799        @Override
800        public Void run() throws Exception {
801          Delete d1 = new Delete(row1);
802          d1.setCellVisibility(new CellVisibility(CONFIDENTIAL));
803          d1.addFamily(fam);
804
805          Delete d2 = new Delete(row1);
806          d2.setCellVisibility(new CellVisibility(SECRET));
807          d2.addFamily(fam);
808
809          Delete d3 = new Delete(row1);
810          d3.setCellVisibility(new CellVisibility(
811            "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
812          d3.addFamily(fam);
813
814          try (Connection connection = ConnectionFactory.createConnection(conf);
815            Table table = connection.getTable(tableName)) {
816            table.delete(createList(d1, d2, d3));
817          } catch (Throwable t) {
818            throw new IOException(t);
819          }
820          return null;
821        }
822      };
823      SUPERUSER.runAs(actiona);
824      Scan s = new Scan();
825      s.readVersions(5);
826      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
827      ResultScanner scanner = table.getScanner(s);
828      Result[] next = scanner.next(3);
829      assertTrue(next.length == 2);
830      CellScanner cellScanner = next[0].cellScanner();
831      cellScanner.advance();
832      Cell current = cellScanner.current();
833      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
834        row1, 0, row1.length));
835      cellScanner = next[1].cellScanner();
836      cellScanner.advance();
837      current = cellScanner.current();
838      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
839        row2, 0, row2.length));
840      scanner.close();
841    }
842  }
843
844  @Test
845  public void testDeleteFamilyAndDeleteColumnsWithAndWithoutVisibilityExp(TestInfo testInfo)
846    throws Exception {
847    setAuths();
848    final TableName tableName = TableName
849      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
850    try (Table table = doPuts(tableName)) {
851      TEST_UTIL.getAdmin().flush(tableName);
852      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
853        @Override
854        public Void run() throws Exception {
855          Delete d1 = new Delete(row1);
856          d1.addFamily(fam);
857
858          Delete d2 = new Delete(row1);
859          d2.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
860          d2.addColumns(fam, qual);
861          try (Connection connection = ConnectionFactory.createConnection(conf);
862            Table table = connection.getTable(tableName)) {
863            table.delete(createList(d1, d2));
864          } catch (Throwable t) {
865            throw new IOException(t);
866          }
867          return null;
868        }
869      };
870      SUPERUSER.runAs(actiona);
871      Scan s = new Scan();
872      s.readVersions(5);
873      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
874      ResultScanner scanner = table.getScanner(s);
875      Result[] next = scanner.next(3);
876      assertTrue(next.length == 2);
877      CellScanner cellScanner = next[0].cellScanner();
878      cellScanner.advance();
879      Cell current = cellScanner.current();
880      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
881        row1, 0, row1.length));
882      assertEquals(127L, current.getTimestamp());
883      cellScanner.advance();
884      current = cellScanner.current();
885      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
886        row1, 0, row1.length));
887      assertEquals(126L, current.getTimestamp());
888      cellScanner.advance();
889      current = cellScanner.current();
890      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
891        row1, 0, row1.length));
892      assertEquals(124L, current.getTimestamp());
893      cellScanner.advance();
894      current = cellScanner.current();
895      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
896        row1, 0, row1.length));
897      assertEquals(123L, current.getTimestamp());
898      cellScanner = next[1].cellScanner();
899      cellScanner.advance();
900      current = cellScanner.current();
901      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
902        row2, 0, row2.length));
903      scanner.close();
904    }
905  }
906
907  private Table doPuts(TableName tableName) throws IOException, InterruptedIOException,
908    RetriesExhaustedWithDetailsException, InterruptedException {
909    createTable(tableName, 5);
910
911    List<Put> puts = new ArrayList<>(5);
912    Put put = new Put(Bytes.toBytes("row1"));
913    put.addColumn(fam, qual, 123L, value);
914    put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
915    puts.add(put);
916
917    put = new Put(Bytes.toBytes("row1"));
918    put.addColumn(fam, qual, 124L, value);
919    put.setCellVisibility(new CellVisibility(
920      "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
921    puts.add(put);
922
923    put = new Put(Bytes.toBytes("row1"));
924    put.addColumn(fam, qual, 125L, value);
925    put.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
926    puts.add(put);
927
928    put = new Put(Bytes.toBytes("row1"));
929    put.addColumn(fam, qual, 126L, value);
930    put.setCellVisibility(new CellVisibility(
931      "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
932    puts.add(put);
933
934    put = new Put(Bytes.toBytes("row1"));
935    put.addColumn(fam, qual, 127L, value);
936    put.setCellVisibility(new CellVisibility(
937      "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
938    puts.add(put);
939
940    TEST_UTIL.getAdmin().flush(tableName);
941    put = new Put(Bytes.toBytes("row2"));
942    put.addColumn(fam, qual, 127L, value);
943    put.setCellVisibility(new CellVisibility(
944      "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
945    puts.add(put);
946
947    Table table = TEST_UTIL.getConnection().getTable(tableName);
948    table.put(puts);
949    return table;
950  }
951
952  private Table doPutsWithDiffCols(TableName tableName) throws IOException, InterruptedIOException,
953    RetriesExhaustedWithDetailsException, InterruptedException {
954    createTable(tableName, 5);
955
956    List<Put> puts = new ArrayList<>(5);
957    Put put = new Put(Bytes.toBytes("row1"));
958    put.addColumn(fam, qual, 123L, value);
959    put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
960    puts.add(put);
961
962    put = new Put(Bytes.toBytes("row1"));
963    put.addColumn(fam, qual, 124L, value);
964    put.setCellVisibility(new CellVisibility(
965      "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
966    puts.add(put);
967
968    put = new Put(Bytes.toBytes("row1"));
969    put.addColumn(fam, qual, 125L, value);
970    put.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
971    puts.add(put);
972
973    put = new Put(Bytes.toBytes("row1"));
974    put.addColumn(fam, qual1, 126L, value);
975    put.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
976    puts.add(put);
977
978    put = new Put(Bytes.toBytes("row1"));
979    put.addColumn(fam, qual2, 127L, value);
980    put.setCellVisibility(new CellVisibility(
981      "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
982    puts.add(put);
983
984    Table table = TEST_UTIL.getConnection().getTable(tableName);
985    table.put(puts);
986    return table;
987  }
988
989  private Table doPutsWithoutVisibility(TableName tableName) throws IOException,
990    InterruptedIOException, RetriesExhaustedWithDetailsException, InterruptedException {
991    createTable(tableName, 5);
992    List<Put> puts = new ArrayList<>(5);
993    Put put = new Put(Bytes.toBytes("row1"));
994    put.addColumn(fam, qual, 123L, value);
995    puts.add(put);
996
997    put = new Put(Bytes.toBytes("row1"));
998    put.addColumn(fam, qual, 124L, value);
999    puts.add(put);
1000
1001    put = new Put(Bytes.toBytes("row1"));
1002    put.addColumn(fam, qual, 125L, value);
1003    puts.add(put);
1004
1005    put = new Put(Bytes.toBytes("row1"));
1006    put.addColumn(fam, qual, 126L, value);
1007    puts.add(put);
1008
1009    put = new Put(Bytes.toBytes("row1"));
1010    put.addColumn(fam, qual, 127L, value);
1011    puts.add(put);
1012
1013    Table table = TEST_UTIL.getConnection().getTable(tableName);
1014    table.put(puts);
1015
1016    TEST_UTIL.getAdmin().flush(tableName);
1017
1018    put = new Put(Bytes.toBytes("row2"));
1019    put.addColumn(fam, qual, 127L, value);
1020    table.put(put);
1021
1022    return table;
1023  }
1024
1025  @Test
1026  public void testDeleteColumnWithSpecificTimeStampUsingMultipleVersionsUnMatchingVisExpression(
1027    TestInfo testInfo) throws Exception {
1028    setAuths();
1029    final TableName tableName = TableName
1030      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1031    try (Table table = doPuts(tableName)) {
1032      TEST_UTIL.getAdmin().flush(tableName);
1033      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1034        @Override
1035        public Void run() throws Exception {
1036          try (Connection connection = ConnectionFactory.createConnection(conf);
1037            Table table = connection.getTable(tableName)) {
1038            Delete d = new Delete(row1);
1039            d.setCellVisibility(new CellVisibility(
1040              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
1041            d.addColumn(fam, qual, 125L);
1042            table.delete(d);
1043          } catch (Throwable t) {
1044            throw new IOException(t);
1045          }
1046          return null;
1047        }
1048      };
1049      SUPERUSER.runAs(actiona);
1050
1051      TEST_UTIL.getAdmin().flush(tableName);
1052      Scan s = new Scan();
1053      s.readVersions(5);
1054      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1055      ResultScanner scanner = table.getScanner(s);
1056      Result[] next = scanner.next(3);
1057      assertTrue(next.length == 2);
1058      CellScanner cellScanner = next[0].cellScanner();
1059      cellScanner.advance();
1060      Cell current = cellScanner.current();
1061      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1062        row1, 0, row1.length));
1063      assertEquals(127L, current.getTimestamp());
1064      cellScanner.advance();
1065      current = cellScanner.current();
1066      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1067        row1, 0, row1.length));
1068      assertEquals(126L, current.getTimestamp());
1069      cellScanner.advance();
1070      current = cellScanner.current();
1071      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1072        row1, 0, row1.length));
1073      assertEquals(125L, current.getTimestamp());
1074      cellScanner.advance();
1075      current = cellScanner.current();
1076      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1077        row1, 0, row1.length));
1078      assertEquals(124L, current.getTimestamp());
1079      cellScanner.advance();
1080      current = cellScanner.current();
1081      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1082        row1, 0, row1.length));
1083      assertEquals(123L, current.getTimestamp());
1084      cellScanner = next[1].cellScanner();
1085      cellScanner.advance();
1086      current = cellScanner.current();
1087      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1088        row2, 0, row2.length));
1089    }
1090  }
1091
1092  @Test
1093  public void testDeleteColumnWithLatestTimeStampUsingMultipleVersions(TestInfo testInfo)
1094    throws Exception {
1095    setAuths();
1096    final TableName tableName = TableName
1097      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1098    try (Table table = doPuts(tableName)) {
1099      TEST_UTIL.getAdmin().flush(tableName);
1100      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1101        @Override
1102        public Void run() throws Exception {
1103          try (Connection connection = ConnectionFactory.createConnection(conf);
1104            Table table = connection.getTable(tableName)) {
1105            Delete d = new Delete(row1);
1106            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
1107            d.addColumn(fam, qual);
1108            table.delete(d);
1109          } catch (Throwable t) {
1110            throw new IOException(t);
1111          }
1112          return null;
1113        }
1114      };
1115      SUPERUSER.runAs(actiona);
1116
1117      TEST_UTIL.getAdmin().flush(tableName);
1118      Scan s = new Scan();
1119      s.readVersions(5);
1120      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1121      ResultScanner scanner = table.getScanner(s);
1122      Result[] next = scanner.next(3);
1123      assertTrue(next.length == 2);
1124      CellScanner cellScanner = next[0].cellScanner();
1125      cellScanner.advance();
1126      Cell current = cellScanner.current();
1127      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1128        row1, 0, row1.length));
1129      assertEquals(127L, current.getTimestamp());
1130      cellScanner.advance();
1131      current = cellScanner.current();
1132      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1133        row1, 0, row1.length));
1134      assertEquals(126L, current.getTimestamp());
1135      cellScanner.advance();
1136      current = cellScanner.current();
1137      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1138        row1, 0, row1.length));
1139      assertEquals(124L, current.getTimestamp());
1140      cellScanner.advance();
1141      current = cellScanner.current();
1142      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1143        row1, 0, row1.length));
1144      assertEquals(123L, current.getTimestamp());
1145      cellScanner = next[1].cellScanner();
1146      cellScanner.advance();
1147      current = cellScanner.current();
1148      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1149        row2, 0, row2.length));
1150    }
1151  }
1152
1153  @Test
1154  public void testDeleteColumnWithLatestTimeStampWhenNoVersionMatches(TestInfo testInfo)
1155    throws Exception {
1156    setAuths();
1157    final TableName tableName = TableName
1158      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1159    try (Table table = doPuts(tableName)) {
1160      TEST_UTIL.getAdmin().flush(tableName);
1161      Put put = new Put(Bytes.toBytes("row1"));
1162      put.addColumn(fam, qual, 128L, value);
1163      put.setCellVisibility(new CellVisibility(TOPSECRET));
1164      table.put(put);
1165      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1166        @Override
1167        public Void run() throws Exception {
1168          try (Connection connection = ConnectionFactory.createConnection(conf);
1169            Table table = connection.getTable(tableName)) {
1170            Delete d = new Delete(row1);
1171            d.setCellVisibility(new CellVisibility(SECRET));
1172            d.addColumn(fam, qual);
1173            table.delete(d);
1174          } catch (Throwable t) {
1175            throw new IOException(t);
1176          }
1177          return null;
1178        }
1179      };
1180      SUPERUSER.runAs(actiona);
1181
1182      TEST_UTIL.getAdmin().flush(tableName);
1183      Scan s = new Scan();
1184      s.readVersions(5);
1185      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1186      ResultScanner scanner = table.getScanner(s);
1187      Result[] next = scanner.next(3);
1188      assertTrue(next.length == 2);
1189      CellScanner cellScanner = next[0].cellScanner();
1190      cellScanner.advance();
1191      Cell current = cellScanner.current();
1192      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1193        row1, 0, row1.length));
1194      assertEquals(128L, current.getTimestamp());
1195      cellScanner.advance();
1196      current = cellScanner.current();
1197      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1198        row1, 0, row1.length));
1199      assertEquals(127L, current.getTimestamp());
1200      cellScanner.advance();
1201      current = cellScanner.current();
1202      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1203        row1, 0, row1.length));
1204      assertEquals(126L, current.getTimestamp());
1205      cellScanner.advance();
1206      current = cellScanner.current();
1207      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1208        row1, 0, row1.length));
1209      assertEquals(125L, current.getTimestamp());
1210      cellScanner.advance();
1211      current = cellScanner.current();
1212      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1213        row1, 0, row1.length));
1214      assertEquals(124L, current.getTimestamp());
1215      cellScanner = next[1].cellScanner();
1216      cellScanner.advance();
1217      current = cellScanner.current();
1218      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1219        row2, 0, row2.length));
1220
1221      put = new Put(Bytes.toBytes("row1"));
1222      put.addColumn(fam, qual, 129L, value);
1223      put.setCellVisibility(new CellVisibility(SECRET));
1224      table.put(put);
1225
1226      TEST_UTIL.getAdmin().flush(tableName);
1227      s = new Scan();
1228      s.readVersions(5);
1229      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1230      scanner = table.getScanner(s);
1231      next = scanner.next(3);
1232      assertTrue(next.length == 2);
1233      cellScanner = next[0].cellScanner();
1234      cellScanner.advance();
1235      current = cellScanner.current();
1236      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1237        row1, 0, row1.length));
1238      assertEquals(129L, current.getTimestamp());
1239    }
1240  }
1241
1242  @Test
1243  public void testDeleteColumnWithLatestTimeStampUsingMultipleVersionsAfterCompaction(
1244    TestInfo testInfo) throws Exception {
1245    setAuths();
1246    final TableName tableName = TableName
1247      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1248    try (Table table = doPuts(tableName)) {
1249      TEST_UTIL.getAdmin().flush(tableName);
1250      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1251        @Override
1252        public Void run() throws Exception {
1253          try (Connection connection = ConnectionFactory.createConnection(conf);
1254            Table table = connection.getTable(tableName)) {
1255            Delete d = new Delete(row1);
1256            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
1257            d.addColumn(fam, qual);
1258            table.delete(d);
1259          } catch (Throwable t) {
1260            throw new IOException(t);
1261          }
1262          return null;
1263        }
1264      };
1265      SUPERUSER.runAs(actiona);
1266      TEST_UTIL.getAdmin().flush(tableName);
1267      Put put = new Put(Bytes.toBytes("row3"));
1268      put.addColumn(fam, qual, 127L, value);
1269      put.setCellVisibility(new CellVisibility(CONFIDENTIAL + "&" + PRIVATE));
1270      table.put(put);
1271      TEST_UTIL.getAdmin().flush(tableName);
1272      TEST_UTIL.getAdmin().majorCompact(tableName);
1273      // Sleep to ensure compaction happens. Need to do it in a better way
1274      Thread.sleep(5000);
1275      Scan s = new Scan();
1276      s.readVersions(5);
1277      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1278      ResultScanner scanner = table.getScanner(s);
1279      Result[] next = scanner.next(3);
1280      assertTrue(next.length == 3);
1281      CellScanner cellScanner = next[0].cellScanner();
1282      cellScanner.advance();
1283      Cell current = cellScanner.current();
1284      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1285        row1, 0, row1.length));
1286      assertEquals(127L, current.getTimestamp());
1287      cellScanner.advance();
1288      current = cellScanner.current();
1289      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1290        row1, 0, row1.length));
1291      assertEquals(126L, current.getTimestamp());
1292      cellScanner.advance();
1293      current = cellScanner.current();
1294      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1295        row1, 0, row1.length));
1296      assertEquals(124L, current.getTimestamp());
1297      cellScanner.advance();
1298      current = cellScanner.current();
1299      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1300        row1, 0, row1.length));
1301      assertEquals(123L, current.getTimestamp());
1302      cellScanner = next[1].cellScanner();
1303      cellScanner.advance();
1304      current = cellScanner.current();
1305      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1306        row2, 0, row2.length));
1307    }
1308  }
1309
1310  @Test
1311  public void testDeleteFamilyLatestTimeStampWithMulipleVersions(TestInfo testInfo)
1312    throws Exception {
1313    setAuths();
1314    final TableName tableName = TableName
1315      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1316    try (Table table = doPuts(tableName)) {
1317      TEST_UTIL.getAdmin().flush(tableName);
1318      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1319        @Override
1320        public Void run() throws Exception {
1321          try (Connection connection = ConnectionFactory.createConnection(conf);
1322            Table table = connection.getTable(tableName)) {
1323            Delete d = new Delete(row1);
1324            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
1325            d.addFamily(fam);
1326            table.delete(d);
1327          } catch (Throwable t) {
1328            throw new IOException(t);
1329          }
1330          return null;
1331        }
1332      };
1333      SUPERUSER.runAs(actiona);
1334
1335      TEST_UTIL.getAdmin().flush(tableName);
1336      Scan s = new Scan();
1337      s.readVersions(5);
1338      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1339      ResultScanner scanner = table.getScanner(s);
1340      Result[] next = scanner.next(3);
1341      assertTrue(next.length == 2);
1342      CellScanner cellScanner = next[0].cellScanner();
1343      cellScanner.advance();
1344      Cell current = cellScanner.current();
1345      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1346        row1, 0, row1.length));
1347      assertEquals(127L, current.getTimestamp());
1348      cellScanner.advance();
1349      current = cellScanner.current();
1350      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1351        row1, 0, row1.length));
1352      assertEquals(126L, current.getTimestamp());
1353      cellScanner = next[1].cellScanner();
1354      cellScanner.advance();
1355      current = cellScanner.current();
1356      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1357        row2, 0, row2.length));
1358    }
1359  }
1360
1361  @Test
1362  public void testDeleteColumnswithMultipleColumnsWithMultipleVersions(TestInfo testInfo)
1363    throws Exception {
1364    setAuths();
1365    final TableName tableName = TableName
1366      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1367    try (Table table = doPutsWithDiffCols(tableName)) {
1368      TEST_UTIL.getAdmin().flush(tableName);
1369      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1370        @Override
1371        public Void run() throws Exception {
1372          Delete d = new Delete(row1);
1373          d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
1374          d.addColumns(fam, qual, 125L);
1375          try (Connection connection = ConnectionFactory.createConnection(conf);
1376            Table table = connection.getTable(tableName)) {
1377            table.delete(d);
1378          } catch (Throwable t) {
1379            throw new IOException(t);
1380          }
1381          return null;
1382        }
1383      };
1384      SUPERUSER.runAs(actiona);
1385
1386      TEST_UTIL.getAdmin().flush(tableName);
1387      Scan s = new Scan();
1388      s.readVersions(5);
1389      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1390      ResultScanner scanner = table.getScanner(s);
1391      Result[] next = scanner.next(3);
1392      assertTrue(next.length == 1);
1393      CellScanner cellScanner = next[0].cellScanner();
1394      cellScanner.advance();
1395      Cell current = cellScanner.current();
1396      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1397        row1, 0, row1.length));
1398      assertEquals(124L, current.getTimestamp());
1399      cellScanner.advance();
1400      current = cellScanner.current();
1401      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1402        row1, 0, row1.length));
1403      assertEquals(123L, current.getTimestamp());
1404      cellScanner.advance();
1405      current = cellScanner.current();
1406      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1407        row1, 0, row1.length));
1408      assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(),
1409        current.getQualifierLength(), qual1, 0, qual1.length));
1410      assertEquals(126L, current.getTimestamp());
1411      cellScanner.advance();
1412      current = cellScanner.current();
1413      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1414        row1, 0, row1.length));
1415      assertEquals(127L, current.getTimestamp());
1416      assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(),
1417        current.getQualifierLength(), qual2, 0, qual2.length));
1418    }
1419  }
1420
1421  @Test
1422  public void testDeleteColumnsWithDiffColsAndTags(TestInfo testInfo) throws Exception {
1423    TableName tableName = createTable(5, testInfo);
1424    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
1425      Put put = new Put(Bytes.toBytes("row1"));
1426      put.addColumn(fam, qual1, 125L, value);
1427      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
1428      table.put(put);
1429      put = new Put(Bytes.toBytes("row1"));
1430      put.addColumn(fam, qual1, 126L, value);
1431      put.setCellVisibility(new CellVisibility(SECRET));
1432      table.put(put);
1433      TEST_UTIL.getAdmin().flush(tableName);
1434      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1435        @Override
1436        public Void run() throws Exception {
1437          Delete d1 = new Delete(row1);
1438          d1.setCellVisibility(new CellVisibility(SECRET));
1439          d1.addColumns(fam, qual, 126L);
1440
1441          Delete d2 = new Delete(row1);
1442          d2.setCellVisibility(new CellVisibility(CONFIDENTIAL));
1443          d2.addColumns(fam, qual1, 125L);
1444
1445          try (Connection connection = ConnectionFactory.createConnection(conf);
1446            Table table = connection.getTable(tableName)) {
1447            table.delete(createList(d1, d2));
1448          } catch (Throwable t) {
1449            throw new IOException(t);
1450          }
1451          return null;
1452        }
1453      };
1454      SUPERUSER.runAs(actiona);
1455      Scan s = new Scan();
1456      s.readVersions(5);
1457      s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
1458      ResultScanner scanner = table.getScanner(s);
1459      Result[] next = scanner.next(3);
1460      assertEquals(1, next.length);
1461    }
1462  }
1463
1464  @Test
1465  public void testDeleteColumnsWithDiffColsAndTags1(TestInfo testInfo) throws Exception {
1466    TableName tableName = createTable(5, testInfo);
1467    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
1468      Put put = new Put(Bytes.toBytes("row1"));
1469      put.addColumn(fam, qual1, 125L, value);
1470      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
1471      table.put(put);
1472      put = new Put(Bytes.toBytes("row1"));
1473      put.addColumn(fam, qual1, 126L, value);
1474      put.setCellVisibility(new CellVisibility(SECRET));
1475      table.put(put);
1476      TEST_UTIL.getAdmin().flush(tableName);
1477      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1478        @Override
1479        public Void run() throws Exception {
1480          Delete d1 = new Delete(row1);
1481          d1.setCellVisibility(new CellVisibility(SECRET));
1482          d1.addColumns(fam, qual, 126L);
1483
1484          Delete d2 = new Delete(row1);
1485          d2.setCellVisibility(new CellVisibility(CONFIDENTIAL));
1486          d2.addColumns(fam, qual1, 126L);
1487
1488          try (Connection connection = ConnectionFactory.createConnection(conf);
1489            Table table = connection.getTable(tableName)) {
1490            table.delete(createList(d1, d2));
1491          } catch (Throwable t) {
1492            throw new IOException(t);
1493          }
1494          return null;
1495        }
1496      };
1497      SUPERUSER.runAs(actiona);
1498      Scan s = new Scan();
1499      s.readVersions(5);
1500      s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
1501      ResultScanner scanner = table.getScanner(s);
1502      Result[] next = scanner.next(3);
1503      assertEquals(1, next.length);
1504    }
1505  }
1506
1507  @Test
1508  public void testDeleteFamilyWithoutCellVisibilityWithMulipleVersions(TestInfo testInfo)
1509    throws Exception {
1510    setAuths();
1511    final TableName tableName = TableName
1512      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1513    try (Table table = doPutsWithoutVisibility(tableName)) {
1514      TEST_UTIL.getAdmin().flush(tableName);
1515      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1516        @Override
1517        public Void run() throws Exception {
1518          try (Connection connection = ConnectionFactory.createConnection(conf);
1519            Table table = connection.getTable(tableName)) {
1520            Delete d = new Delete(row1);
1521            d.addFamily(fam);
1522            table.delete(d);
1523          } catch (Throwable t) {
1524            throw new IOException(t);
1525          }
1526          return null;
1527        }
1528      };
1529      SUPERUSER.runAs(actiona);
1530
1531      TEST_UTIL.getAdmin().flush(tableName);
1532      Scan s = new Scan();
1533      s.readVersions(5);
1534      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1535      ResultScanner scanner = table.getScanner(s);
1536      Result[] next = scanner.next(3);
1537      assertTrue(next.length == 1);
1538      // All cells wrt row1 should be deleted as we are not passing the Cell Visibility
1539      CellScanner cellScanner = next[0].cellScanner();
1540      cellScanner.advance();
1541      Cell current = cellScanner.current();
1542      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1543        row2, 0, row2.length));
1544    }
1545  }
1546
1547  @Test
1548  public void testDeleteFamilyLatestTimeStampWithMulipleVersionsWithoutCellVisibilityInPuts(
1549    TestInfo testInfo) throws Exception {
1550    setAuths();
1551    final TableName tableName = TableName
1552      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1553    try (Table table = doPutsWithoutVisibility(tableName)) {
1554      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1555        @Override
1556        public Void run() throws Exception {
1557          try (Connection connection = ConnectionFactory.createConnection(conf);
1558            Table table = connection.getTable(tableName)) {
1559            Delete d = new Delete(row1);
1560            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
1561            d.addFamily(fam);
1562            table.delete(d);
1563          } catch (Throwable t) {
1564            throw new IOException(t);
1565          }
1566          return null;
1567        }
1568      };
1569      SUPERUSER.runAs(actiona);
1570      TEST_UTIL.getAdmin().flush(tableName);
1571      Scan s = new Scan();
1572      s.readVersions(5);
1573      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1574      ResultScanner scanner = table.getScanner(s);
1575      Result[] next = scanner.next(3);
1576      assertTrue(next.length == 2);
1577      CellScanner cellScanner = next[0].cellScanner();
1578      cellScanner.advance();
1579      Cell current = cellScanner.current();
1580      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1581        row1, 0, row1.length));
1582      assertEquals(127L, current.getTimestamp());
1583      cellScanner.advance();
1584      current = cellScanner.current();
1585      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1586        row1, 0, row1.length));
1587      assertEquals(126L, current.getTimestamp());
1588      cellScanner.advance();
1589      current = cellScanner.current();
1590      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1591        row1, 0, row1.length));
1592      assertEquals(125L, current.getTimestamp());
1593      cellScanner.advance();
1594      current = cellScanner.current();
1595      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1596        row1, 0, row1.length));
1597      assertEquals(124L, current.getTimestamp());
1598      cellScanner.advance();
1599      current = cellScanner.current();
1600      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1601        row1, 0, row1.length));
1602      assertEquals(123L, current.getTimestamp());
1603      cellScanner = next[1].cellScanner();
1604      cellScanner.advance();
1605      current = cellScanner.current();
1606      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1607        row2, 0, row2.length));
1608    }
1609  }
1610
1611  @Test
1612  public void testDeleteFamilySpecificTimeStampWithMulipleVersions(TestInfo testInfo)
1613    throws Exception {
1614    setAuths();
1615    final TableName tableName = TableName
1616      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1617    try (Table table = doPuts(tableName)) {
1618      TEST_UTIL.getAdmin().flush(tableName);
1619      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1620        @Override
1621        public Void run() throws Exception {
1622          try (Connection connection = ConnectionFactory.createConnection(conf);
1623            Table table = connection.getTable(tableName)) {
1624            Delete d = new Delete(row1);
1625            d.setCellVisibility(new CellVisibility(
1626              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
1627            d.addFamily(fam, 126L);
1628            table.delete(d);
1629          } catch (Throwable t) {
1630            throw new IOException(t);
1631          }
1632          return null;
1633        }
1634      };
1635      SUPERUSER.runAs(actiona);
1636
1637      TEST_UTIL.getAdmin().flush(tableName);
1638      Scan s = new Scan();
1639      s.readVersions(5);
1640      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1641      ResultScanner scanner = table.getScanner(s);
1642      Result[] next = scanner.next(6);
1643      assertTrue(next.length == 2);
1644      CellScanner cellScanner = next[0].cellScanner();
1645      cellScanner.advance();
1646      Cell current = cellScanner.current();
1647      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1648        row1, 0, row1.length));
1649      assertEquals(127L, current.getTimestamp());
1650      cellScanner.advance();
1651      current = cellScanner.current();
1652      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1653        row1, 0, row1.length));
1654      assertEquals(125L, current.getTimestamp());
1655      cellScanner.advance();
1656      current = cellScanner.current();
1657      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1658        row1, 0, row1.length));
1659      assertEquals(123L, current.getTimestamp());
1660      cellScanner = next[1].cellScanner();
1661      cellScanner.advance();
1662      current = cellScanner.current();
1663      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1664        row2, 0, row2.length));
1665    }
1666  }
1667
1668  @Test
1669  public void testScanAfterCompaction(TestInfo testInfo) throws Exception {
1670    setAuths();
1671    final TableName tableName = TableName
1672      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1673    try (Table table = doPuts(tableName)) {
1674      TEST_UTIL.getAdmin().flush(tableName);
1675      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1676        @Override
1677        public Void run() throws Exception {
1678          try (Connection connection = ConnectionFactory.createConnection(conf);
1679            Table table = connection.getTable(tableName)) {
1680            Delete d = new Delete(row1);
1681            d.setCellVisibility(new CellVisibility(
1682              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + SECRET + "&" + TOPSECRET + ")"));
1683            d.addFamily(fam, 126L);
1684            table.delete(d);
1685          } catch (Throwable t) {
1686            throw new IOException(t);
1687          }
1688          return null;
1689        }
1690      };
1691      SUPERUSER.runAs(actiona);
1692
1693      TEST_UTIL.getAdmin().flush(tableName);
1694      Put put = new Put(Bytes.toBytes("row3"));
1695      put.addColumn(fam, qual, 127L, value);
1696      put.setCellVisibility(new CellVisibility(CONFIDENTIAL + "&" + PRIVATE));
1697      table.put(put);
1698      TEST_UTIL.getAdmin().flush(tableName);
1699      TEST_UTIL.getAdmin().compact(tableName);
1700      Thread.sleep(5000);
1701      // Sleep to ensure compaction happens. Need to do it in a better way
1702      Scan s = new Scan();
1703      s.readVersions(5);
1704      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1705      ResultScanner scanner = table.getScanner(s);
1706      Result[] next = scanner.next(3);
1707      assertTrue(next.length == 3);
1708      CellScanner cellScanner = next[0].cellScanner();
1709      cellScanner.advance();
1710      Cell current = cellScanner.current();
1711      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1712        row1, 0, row1.length));
1713      assertEquals(127L, current.getTimestamp());
1714      cellScanner = next[1].cellScanner();
1715      cellScanner.advance();
1716      current = cellScanner.current();
1717      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1718        row2, 0, row2.length));
1719    }
1720  }
1721
1722  /**
1723   * On a cell-visibility table, two DeleteColumn markers carrying different labels shadow disjoint
1724   * cells, so neither is redundant w.r.t. the other. A minor compaction must not drop the
1725   * lower-timestamp marker just because a higher-timestamp marker of a different label was tracked
1726   * first; doing so would resurrect data that must stay deleted. This is the end-to-end regression
1727   * guard for {@link VisibilityScanDeleteTracker#isRedundantDelete}.
1728   * <p>
1729   * The big put is larger than {@code hbase.hstore.compaction.max.size}, so minor compaction
1730   * excludes its file and merges only the two small delete-marker files (isAllFiles=false, hence
1731   * COMPACT_RETAIN_DELETES and MinorCompactionScanQueryMatcher, the path that calls
1732   * isRedundantDelete). The put's data stays in its own file, so dropping the SECRET marker would
1733   * make it visible again.
1734   */
1735  @Test
1736  public void testDifferentLabelDeleteMarkersSurviveMinorCompaction(TestInfo testInfo)
1737    throws Exception {
1738    setAuths();
1739    final TableName tableName = TableName
1740      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1741    // Minor compaction merges at most two files and skips any file larger than 64KB.
1742    ColumnFamilyDescriptorBuilder cfd = ColumnFamilyDescriptorBuilder.newBuilder(fam)
1743      .setMaxVersions(5).setConfiguration("hbase.hstore.compaction.min", "2")
1744      .setConfiguration("hbase.hstore.compaction.max", "2")
1745      .setConfiguration("hbase.hstore.compaction.max.size", "65536");
1746    // Disable automatic compaction while the three HFiles are laid down, so the minor compaction
1747    // under test is exactly the one triggered explicitly below (no racing background compaction).
1748    TEST_UTIL.getAdmin().createTable(TableDescriptorBuilder.newBuilder(tableName)
1749      .setCompactionEnabled(false).setColumnFamily(cfd.build()).build());
1750
1751    SUPERUSER.runAs((PrivilegedExceptionAction<Void>) () -> {
1752      try (Connection connection = ConnectionFactory.createConnection(conf);
1753        Table table = connection.getTable(tableName)) {
1754        // Big SECRET-visible put at ts=40. Random bytes keep the file above max.size so it is
1755        // excluded from the minor compaction and retains the data the SECRET delete shadows.
1756        byte[] big = new byte[200 * 1024];
1757        new Random(1).nextBytes(big);
1758        Put put = new Put(row1);
1759        put.addColumn(fam, qual, 40L, big);
1760        put.setCellVisibility(new CellVisibility(SECRET));
1761        table.put(put);
1762        TEST_UTIL.getAdmin().flush(tableName);
1763        // SECRET DeleteColumn at ts=50 shadows the SECRET put.
1764        Delete dSecret = new Delete(row1);
1765        dSecret.setCellVisibility(new CellVisibility(SECRET));
1766        dSecret.addColumns(fam, qual, 50L);
1767        table.delete(dSecret);
1768        TEST_UTIL.getAdmin().flush(tableName);
1769        // Newer CONFIDENTIAL DeleteColumn at ts=100 shadows disjoint (CONFIDENTIAL) cells.
1770        Delete dConf = new Delete(row1);
1771        dConf.setCellVisibility(new CellVisibility(CONFIDENTIAL));
1772        dConf.addColumns(fam, qual, 100L);
1773        table.delete(dConf);
1774        TEST_UTIL.getAdmin().flush(tableName);
1775      }
1776      return null;
1777    });
1778
1779    // Before compaction the SECRET put is correctly hidden by the SECRET delete.
1780    assertEquals(0, countCells(tableName, SECRET));
1781
1782    // Synchronously minor-compact the two small delete files (the big put file is excluded).
1783    HRegion region = TEST_UTIL.getHBaseCluster().getRegions(tableName).get(0);
1784    region.compact(false);
1785    // Two files remain: the untouched big put file plus the single merged delete file. This both
1786    // confirms a minor compaction happened and that the big file was not swept into a major one.
1787    await().atMost(Duration.ofSeconds(60))
1788      .untilAsserted(() -> assertEquals(2, region.getStore(fam).getStorefilesCount()));
1789
1790    // The SECRET delete must still shadow the SECRET put: no resurrection.
1791    assertEquals(0, countCells(tableName, SECRET));
1792  }
1793
1794  private int countCells(TableName tableName, String... auths) throws Exception {
1795    return SUPERUSER.runAs((PrivilegedExceptionAction<Integer>) () -> {
1796      try (Connection connection = ConnectionFactory.createConnection(conf);
1797        Table table = connection.getTable(tableName)) {
1798        Scan s = new Scan();
1799        s.readVersions(5);
1800        s.setAuthorizations(new Authorizations(auths));
1801        try (ResultScanner scanner = table.getScanner(s)) {
1802          int count = 0;
1803          for (Result r : scanner) {
1804            count += r.size();
1805          }
1806          return count;
1807        }
1808      }
1809    });
1810  }
1811
1812  @Test
1813  public void testDeleteFamilySpecificTimeStampWithMulipleVersionsDoneTwice(TestInfo testInfo)
1814    throws Exception {
1815    setAuths();
1816    final TableName tableName = TableName
1817      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1818    // Do not flush here.
1819    try (Table table = doPuts(tableName)) {
1820      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1821        @Override
1822        public Void run() throws Exception {
1823          try (Connection connection = ConnectionFactory.createConnection(conf);
1824            Table table = connection.getTable(tableName)) {
1825            Delete d = new Delete(row1);
1826            d.setCellVisibility(new CellVisibility(
1827              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + TOPSECRET + "&" + SECRET + ")"));
1828            d.addFamily(fam, 125L);
1829            table.delete(d);
1830          } catch (Throwable t) {
1831            throw new IOException(t);
1832          }
1833          return null;
1834        }
1835      };
1836      SUPERUSER.runAs(actiona);
1837
1838      Scan s = new Scan();
1839      s.readVersions(5);
1840      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1841      ResultScanner scanner = table.getScanner(s);
1842      Result[] next = scanner.next(3);
1843      assertTrue(next.length == 2);
1844      CellScanner cellScanner = next[0].cellScanner();
1845      cellScanner.advance();
1846      Cell current = cellScanner.current();
1847      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1848        row1, 0, row1.length));
1849      assertEquals(127L, current.getTimestamp());
1850      cellScanner.advance();
1851      current = cellScanner.current();
1852      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1853        row1, 0, row1.length));
1854      assertEquals(126L, current.getTimestamp());
1855      cellScanner.advance();
1856      current = cellScanner.current();
1857      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1858        row1, 0, row1.length));
1859      assertEquals(125L, current.getTimestamp());
1860      cellScanner.advance();
1861      current = cellScanner.current();
1862      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1863        row1, 0, row1.length));
1864      assertEquals(123L, current.getTimestamp());
1865      cellScanner = next[1].cellScanner();
1866      cellScanner.advance();
1867      current = cellScanner.current();
1868      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1869        row2, 0, row2.length));
1870
1871      // Issue 2nd delete
1872      actiona = new PrivilegedExceptionAction<Void>() {
1873        @Override
1874        public Void run() throws Exception {
1875          try (Connection connection = ConnectionFactory.createConnection(conf);
1876            Table table = connection.getTable(tableName)) {
1877            Delete d = new Delete(row1);
1878            d.setCellVisibility(new CellVisibility(
1879              "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
1880            d.addFamily(fam, 127L);
1881            table.delete(d);
1882          } catch (Throwable t) {
1883            throw new IOException(t);
1884          }
1885          return null;
1886        }
1887      };
1888      SUPERUSER.runAs(actiona);
1889      s = new Scan();
1890      s.readVersions(5);
1891      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1892      scanner = table.getScanner(s);
1893      next = scanner.next(3);
1894      assertTrue(next.length == 2);
1895      cellScanner = next[0].cellScanner();
1896      cellScanner.advance();
1897      current = cellScanner.current();
1898      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1899        row1, 0, row1.length));
1900      assertEquals(125L, current.getTimestamp());
1901      cellScanner.advance();
1902      current = cellScanner.current();
1903      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1904        row1, 0, row1.length));
1905      assertEquals(123L, current.getTimestamp());
1906      cellScanner = next[1].cellScanner();
1907      cellScanner.advance();
1908      current = cellScanner.current();
1909      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1910        row2, 0, row2.length));
1911      assertEquals(127L, current.getTimestamp());
1912    }
1913  }
1914
1915  @Test
1916  public void testMultipleDeleteFamilyVersionWithDiffLabels(TestInfo testInfo) throws Exception {
1917    PrivilegedExceptionAction<VisibilityLabelsResponse> action =
1918      new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
1919        @Override
1920        public VisibilityLabelsResponse run() throws Exception {
1921          try (Connection conn = ConnectionFactory.createConnection(conf)) {
1922            return VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL, PRIVATE, SECRET },
1923              SUPERUSER.getShortName());
1924          } catch (Throwable e) {
1925          }
1926          return null;
1927        }
1928      };
1929    SUPERUSER.runAs(action);
1930    final TableName tableName = TableName
1931      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1932    try (Table table = doPuts(tableName)) {
1933      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1934        @Override
1935        public Void run() throws Exception {
1936          try (Connection connection = ConnectionFactory.createConnection(conf);
1937            Table table = connection.getTable(tableName)) {
1938            Delete d = new Delete(row1);
1939            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
1940            d.addFamilyVersion(fam, 123L);
1941            table.delete(d);
1942            d = new Delete(row1);
1943            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
1944            d.addFamilyVersion(fam, 125L);
1945            table.delete(d);
1946          } catch (Throwable t) {
1947            throw new IOException(t);
1948          }
1949          return null;
1950        }
1951      };
1952      SUPERUSER.runAs(actiona);
1953
1954      TEST_UTIL.getAdmin().flush(tableName);
1955      Scan s = new Scan();
1956      s.readVersions(5);
1957      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
1958      ResultScanner scanner = table.getScanner(s);
1959      Result[] next = scanner.next(5);
1960      assertTrue(next.length == 2);
1961      CellScanner cellScanner = next[0].cellScanner();
1962      cellScanner.advance();
1963      Cell current = cellScanner.current();
1964      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1965        row1, 0, row1.length));
1966      assertEquals(127L, current.getTimestamp());
1967      cellScanner.advance();
1968      current = cellScanner.current();
1969      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1970        row1, 0, row1.length));
1971      assertEquals(126L, current.getTimestamp());
1972      cellScanner.advance();
1973      current = cellScanner.current();
1974      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
1975        row1, 0, row1.length));
1976      assertEquals(124L, current.getTimestamp());
1977    }
1978  }
1979
1980  @Test
1981  public void testSpecificDeletesFollowedByDeleteFamily(TestInfo testInfo) throws Exception {
1982    setAuths();
1983    final TableName tableName = TableName
1984      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
1985    try (Table table = doPuts(tableName)) {
1986      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
1987        @Override
1988        public Void run() throws Exception {
1989          try (Connection connection = ConnectionFactory.createConnection(conf);
1990            Table table = connection.getTable(tableName)) {
1991            Delete d = new Delete(row1);
1992            d.setCellVisibility(new CellVisibility(
1993              "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
1994            d.addColumn(fam, qual, 126L);
1995            table.delete(d);
1996            d = new Delete(row1);
1997            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
1998            d.addFamilyVersion(fam, 125L);
1999            table.delete(d);
2000          } catch (Throwable t) {
2001            throw new IOException(t);
2002          }
2003          return null;
2004        }
2005      };
2006      SUPERUSER.runAs(actiona);
2007
2008      TEST_UTIL.getAdmin().flush(tableName);
2009      Scan s = new Scan();
2010      s.readVersions(5);
2011      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2012      ResultScanner scanner = table.getScanner(s);
2013      Result[] next = scanner.next(5);
2014      assertTrue(next.length == 2);
2015      CellScanner cellScanner = next[0].cellScanner();
2016      cellScanner.advance();
2017      Cell current = cellScanner.current();
2018      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2019        row1, 0, row1.length));
2020      assertEquals(127L, current.getTimestamp());
2021      cellScanner.advance();
2022      current = cellScanner.current();
2023      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2024        row1, 0, row1.length));
2025      assertEquals(124L, current.getTimestamp());
2026      cellScanner.advance();
2027      current = cellScanner.current();
2028      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2029        row1, 0, row1.length));
2030      assertEquals(123L, current.getTimestamp());
2031      // Issue 2nd delete
2032      actiona = new PrivilegedExceptionAction<Void>() {
2033        @Override
2034        public Void run() throws Exception {
2035          try (Connection connection = ConnectionFactory.createConnection(conf);
2036            Table table = connection.getTable(tableName)) {
2037            Delete d = new Delete(row1);
2038            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
2039            d.addFamily(fam);
2040            table.delete(d);
2041          } catch (Throwable t) {
2042            throw new IOException(t);
2043          }
2044          return null;
2045        }
2046      };
2047      SUPERUSER.runAs(actiona);
2048      s = new Scan();
2049      s.readVersions(5);
2050      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2051      scanner = table.getScanner(s);
2052      next = scanner.next(5);
2053      assertTrue(next.length == 2);
2054      cellScanner = next[0].cellScanner();
2055      cellScanner.advance();
2056      current = cellScanner.current();
2057      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2058        row1, 0, row1.length));
2059      assertEquals(127L, current.getTimestamp());
2060      cellScanner.advance();
2061      current = cellScanner.current();
2062      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2063        row1, 0, row1.length));
2064      assertEquals(124L, current.getTimestamp());
2065    }
2066  }
2067
2068  @Test
2069  public void testSpecificDeletesFollowedByDeleteFamily1(TestInfo testInfo) throws Exception {
2070    PrivilegedExceptionAction<VisibilityLabelsResponse> action =
2071      new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
2072        @Override
2073        public VisibilityLabelsResponse run() throws Exception {
2074          try (Connection conn = ConnectionFactory.createConnection(conf)) {
2075            return VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL, PRIVATE, SECRET },
2076              SUPERUSER.getShortName());
2077          } catch (Throwable e) {
2078          }
2079          return null;
2080        }
2081      };
2082    SUPERUSER.runAs(action);
2083    final TableName tableName = TableName
2084      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
2085    try (Table table = doPuts(tableName)) {
2086      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2087        @Override
2088        public Void run() throws Exception {
2089          try (Connection connection = ConnectionFactory.createConnection(conf);
2090            Table table = connection.getTable(tableName)) {
2091            Delete d = new Delete(row1);
2092            d.setCellVisibility(new CellVisibility(
2093              "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
2094            d.addColumn(fam, qual);
2095            table.delete(d);
2096
2097            d = new Delete(row1);
2098            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
2099            d.addFamilyVersion(fam, 125L);
2100            table.delete(d);
2101          } catch (Throwable t) {
2102            throw new IOException(t);
2103          }
2104          return null;
2105        }
2106      };
2107      SUPERUSER.runAs(actiona);
2108
2109      TEST_UTIL.getAdmin().flush(tableName);
2110      Scan s = new Scan();
2111      s.readVersions(5);
2112      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2113      ResultScanner scanner = table.getScanner(s);
2114      Result[] next = scanner.next(5);
2115      assertTrue(next.length == 2);
2116      CellScanner cellScanner = next[0].cellScanner();
2117      cellScanner.advance();
2118      Cell current = cellScanner.current();
2119      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2120        row1, 0, row1.length));
2121      assertEquals(126L, current.getTimestamp());
2122      cellScanner.advance();
2123      current = cellScanner.current();
2124      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2125        row1, 0, row1.length));
2126      assertEquals(124L, current.getTimestamp());
2127      cellScanner.advance();
2128      current = cellScanner.current();
2129      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2130        row1, 0, row1.length));
2131      assertEquals(123L, current.getTimestamp());
2132      // Issue 2nd delete
2133      actiona = new PrivilegedExceptionAction<Void>() {
2134        @Override
2135        public Void run() throws Exception {
2136          try (Connection connection = ConnectionFactory.createConnection(conf);
2137            Table table = connection.getTable(tableName)) {
2138            Delete d = new Delete(row1);
2139            d.setCellVisibility(new CellVisibility(CONFIDENTIAL));
2140            d.addFamily(fam);
2141            table.delete(d);
2142          } catch (Throwable t) {
2143            throw new IOException(t);
2144          }
2145          return null;
2146        }
2147      };
2148      SUPERUSER.runAs(actiona);
2149      s = new Scan();
2150      s.readVersions(5);
2151      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2152      scanner = table.getScanner(s);
2153      next = scanner.next(5);
2154      assertTrue(next.length == 2);
2155      cellScanner = next[0].cellScanner();
2156      cellScanner.advance();
2157      current = cellScanner.current();
2158      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2159        row1, 0, row1.length));
2160      assertEquals(126L, current.getTimestamp());
2161      cellScanner.advance();
2162      current = cellScanner.current();
2163      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2164        row1, 0, row1.length));
2165      assertEquals(124L, current.getTimestamp());
2166    }
2167  }
2168
2169  @Test
2170  public void testDeleteColumnSpecificTimeStampWithMulipleVersionsDoneTwice(TestInfo testInfo)
2171    throws Exception {
2172    setAuths();
2173    final TableName tableName = TableName
2174      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
2175    try (Table table = doPuts(tableName)) {
2176      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2177        @Override
2178        public Void run() throws Exception {
2179          try (Connection connection = ConnectionFactory.createConnection(conf);
2180            Table table = connection.getTable(tableName)) {
2181            Delete d = new Delete(row1);
2182            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
2183            d.addColumn(fam, qual, 125L);
2184            table.delete(d);
2185          } catch (Throwable t) {
2186            throw new IOException(t);
2187          }
2188          return null;
2189        }
2190      };
2191      SUPERUSER.runAs(actiona);
2192
2193      Scan s = new Scan();
2194      s.readVersions(5);
2195      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2196      ResultScanner scanner = table.getScanner(s);
2197      Result[] next = scanner.next(3);
2198      assertTrue(next.length == 2);
2199      CellScanner cellScanner = next[0].cellScanner();
2200      cellScanner.advance();
2201      Cell current = cellScanner.current();
2202      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2203        row1, 0, row1.length));
2204      assertEquals(127L, current.getTimestamp());
2205      cellScanner.advance();
2206      current = cellScanner.current();
2207      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2208        row1, 0, row1.length));
2209      assertEquals(126L, current.getTimestamp());
2210      cellScanner.advance();
2211      current = cellScanner.current();
2212      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2213        row1, 0, row1.length));
2214      assertEquals(124L, current.getTimestamp());
2215      cellScanner.advance();
2216      current = cellScanner.current();
2217      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2218        row1, 0, row1.length));
2219      assertEquals(123L, current.getTimestamp());
2220      cellScanner = next[1].cellScanner();
2221      cellScanner.advance();
2222      current = cellScanner.current();
2223      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2224        row2, 0, row2.length));
2225
2226      // Issue 2nd delete
2227      actiona = new PrivilegedExceptionAction<Void>() {
2228        @Override
2229        public Void run() throws Exception {
2230          try (Connection connection = ConnectionFactory.createConnection(conf);
2231            Table table = connection.getTable(tableName)) {
2232            Delete d = new Delete(row1);
2233            d.setCellVisibility(new CellVisibility(
2234              "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
2235            d.addColumn(fam, qual, 127L);
2236            table.delete(d);
2237          } catch (Throwable t) {
2238            throw new IOException(t);
2239          }
2240          return null;
2241        }
2242      };
2243      SUPERUSER.runAs(actiona);
2244      s = new Scan();
2245      s.readVersions(5);
2246      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2247      scanner = table.getScanner(s);
2248      next = scanner.next(3);
2249      assertTrue(next.length == 2);
2250      cellScanner = next[0].cellScanner();
2251      cellScanner.advance();
2252      current = cellScanner.current();
2253      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2254        row1, 0, row1.length));
2255      assertEquals(126L, current.getTimestamp());
2256      cellScanner.advance();
2257      current = cellScanner.current();
2258      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2259        row1, 0, row1.length));
2260      assertEquals(124L, current.getTimestamp());
2261      cellScanner.advance();
2262      current = cellScanner.current();
2263      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2264        row1, 0, row1.length));
2265      assertEquals(123L, current.getTimestamp());
2266      cellScanner = next[1].cellScanner();
2267      cellScanner.advance();
2268      current = cellScanner.current();
2269      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2270        row2, 0, row2.length));
2271      assertEquals(127L, current.getTimestamp());
2272    }
2273  }
2274
2275  @Test
2276  public void testDeleteColumnSpecificTimeStampWithMulipleVersionsDoneTwice1(TestInfo testInfo)
2277    throws Exception {
2278    setAuths();
2279    final TableName tableName = TableName
2280      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
2281    // Do not flush here.
2282    try (Table table = doPuts(tableName)) {
2283      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2284        @Override
2285        public Void run() throws Exception {
2286          try (Connection connection = ConnectionFactory.createConnection(conf);
2287            Table table = connection.getTable(tableName)) {
2288            Delete d = new Delete(row1);
2289            d.setCellVisibility(new CellVisibility(
2290              "(" + CONFIDENTIAL + "&" + PRIVATE + ")" + "|(" + TOPSECRET + "&" + SECRET + ")"));
2291            d.addColumn(fam, qual, 127L);
2292            table.delete(d);
2293          } catch (Throwable t) {
2294            throw new IOException(t);
2295          }
2296          return null;
2297        }
2298      };
2299      SUPERUSER.runAs(actiona);
2300
2301      Scan s = new Scan();
2302      s.readVersions(5);
2303      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2304      ResultScanner scanner = table.getScanner(s);
2305      Result[] next = scanner.next(3);
2306      assertTrue(next.length == 2);
2307      CellScanner cellScanner = next[0].cellScanner();
2308      cellScanner.advance();
2309      Cell current = cellScanner.current();
2310      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2311        row1, 0, row1.length));
2312      assertEquals(126L, current.getTimestamp());
2313      cellScanner.advance();
2314      current = cellScanner.current();
2315      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2316        row1, 0, row1.length));
2317      assertEquals(125L, current.getTimestamp());
2318      cellScanner.advance();
2319      current = cellScanner.current();
2320      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2321        row1, 0, row1.length));
2322      assertEquals(124L, current.getTimestamp());
2323      cellScanner.advance();
2324      current = cellScanner.current();
2325      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2326        row1, 0, row1.length));
2327      assertEquals(123L, current.getTimestamp());
2328      cellScanner = next[1].cellScanner();
2329      cellScanner.advance();
2330      current = cellScanner.current();
2331      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2332        row2, 0, row2.length));
2333
2334      // Issue 2nd delete
2335      actiona = new PrivilegedExceptionAction<Void>() {
2336        @Override
2337        public Void run() throws Exception {
2338          try (Connection connection = ConnectionFactory.createConnection(conf);
2339            Table table = connection.getTable(tableName)) {
2340            Delete d = new Delete(row1);
2341            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
2342            d.addColumn(fam, qual, 127L);
2343            table.delete(d);
2344          } catch (Throwable t) {
2345            throw new IOException(t);
2346          }
2347          return null;
2348        }
2349      };
2350      SUPERUSER.runAs(actiona);
2351      s = new Scan();
2352      s.readVersions(5);
2353      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2354      scanner = table.getScanner(s);
2355      next = scanner.next(3);
2356      assertTrue(next.length == 2);
2357      cellScanner = next[0].cellScanner();
2358      cellScanner.advance();
2359      current = cellScanner.current();
2360      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2361        row1, 0, row1.length));
2362      assertEquals(126L, current.getTimestamp());
2363      cellScanner.advance();
2364      current = cellScanner.current();
2365      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2366        row1, 0, row1.length));
2367      assertEquals(125L, current.getTimestamp());
2368      cellScanner.advance();
2369      current = cellScanner.current();
2370      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2371        row1, 0, row1.length));
2372      assertEquals(124L, current.getTimestamp());
2373      cellScanner.advance();
2374      current = cellScanner.current();
2375      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2376        row1, 0, row1.length));
2377      assertEquals(123L, current.getTimestamp());
2378      cellScanner = next[1].cellScanner();
2379      cellScanner.advance();
2380      current = cellScanner.current();
2381      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2382        row2, 0, row2.length));
2383      assertEquals(127L, current.getTimestamp());
2384    }
2385  }
2386
2387  @Test
2388  public void testDeleteColumnSpecificTimeStampWithMulipleVersionsDoneTwice2(TestInfo testInfo)
2389    throws Exception {
2390    setAuths();
2391    final TableName tableName = TableName
2392      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
2393
2394    // Do not flush here.
2395    try (Table table = doPuts(tableName)) {
2396      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2397        @Override
2398        public Void run() throws Exception {
2399          try (Connection connection = ConnectionFactory.createConnection(conf);
2400            Table table = connection.getTable(tableName)) {
2401            Delete d = new Delete(row1);
2402            d.setCellVisibility(new CellVisibility(
2403              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + TOPSECRET + "&" + SECRET + ")"));
2404            d.addColumn(fam, qual, 125L);
2405            table.delete(d);
2406          } catch (Throwable t) {
2407            throw new IOException(t);
2408          }
2409          return null;
2410        }
2411      };
2412      SUPERUSER.runAs(actiona);
2413
2414      Scan s = new Scan();
2415      s.readVersions(5);
2416      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2417      ResultScanner scanner = table.getScanner(s);
2418      Result[] next = scanner.next(3);
2419      assertTrue(next.length == 2);
2420      CellScanner cellScanner = next[0].cellScanner();
2421      cellScanner.advance();
2422      Cell current = cellScanner.current();
2423      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2424        row1, 0, row1.length));
2425      assertEquals(127L, current.getTimestamp());
2426      cellScanner.advance();
2427      current = cellScanner.current();
2428      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2429        row1, 0, row1.length));
2430      assertEquals(126L, current.getTimestamp());
2431      cellScanner.advance();
2432      current = cellScanner.current();
2433      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2434        row1, 0, row1.length));
2435      assertEquals(125L, current.getTimestamp());
2436      cellScanner.advance();
2437      current = cellScanner.current();
2438      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2439        row1, 0, row1.length));
2440      assertEquals(124L, current.getTimestamp());
2441      cellScanner.advance();
2442      current = cellScanner.current();
2443      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2444        row1, 0, row1.length));
2445      assertEquals(123L, current.getTimestamp());
2446      cellScanner = next[1].cellScanner();
2447      cellScanner.advance();
2448      current = cellScanner.current();
2449      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2450        row2, 0, row2.length));
2451
2452      // Issue 2nd delete
2453      actiona = new PrivilegedExceptionAction<Void>() {
2454        @Override
2455        public Void run() throws Exception {
2456          try (Connection connection = ConnectionFactory.createConnection(conf);
2457            Table table = connection.getTable(tableName)) {
2458            Delete d = new Delete(row1);
2459            d.setCellVisibility(new CellVisibility(
2460              "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
2461            d.addColumn(fam, qual, 127L);
2462            table.delete(d);
2463          } catch (Throwable t) {
2464            throw new IOException(t);
2465          }
2466          return null;
2467        }
2468      };
2469      SUPERUSER.runAs(actiona);
2470      s = new Scan();
2471      s.readVersions(5);
2472      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2473      scanner = table.getScanner(s);
2474      next = scanner.next(3);
2475      assertTrue(next.length == 2);
2476      cellScanner = next[0].cellScanner();
2477      cellScanner.advance();
2478      current = cellScanner.current();
2479      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2480        row1, 0, row1.length));
2481      assertEquals(126L, current.getTimestamp());
2482      cellScanner.advance();
2483      current = cellScanner.current();
2484      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2485        row1, 0, row1.length));
2486      assertEquals(125L, current.getTimestamp());
2487      cellScanner.advance();
2488      current = cellScanner.current();
2489      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2490        row1, 0, row1.length));
2491      assertEquals(124L, current.getTimestamp());
2492      cellScanner.advance();
2493      current = cellScanner.current();
2494      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2495        row1, 0, row1.length));
2496      assertEquals(123L, current.getTimestamp());
2497      cellScanner = next[1].cellScanner();
2498      cellScanner.advance();
2499      current = cellScanner.current();
2500      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2501        row2, 0, row2.length));
2502      assertEquals(127L, current.getTimestamp());
2503    }
2504  }
2505
2506  @Test
2507  public void testDeleteColumnAndDeleteFamilylSpecificTimeStampWithMulipleVersion(TestInfo testInfo)
2508    throws Exception {
2509    setAuths();
2510    final TableName tableName = TableName
2511      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
2512    // Do not flush here.
2513    try (Table table = doPuts(tableName)) {
2514      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2515        @Override
2516        public Void run() throws Exception {
2517          try (Connection connection = ConnectionFactory.createConnection(conf);
2518            Table table = connection.getTable(tableName)) {
2519            Delete d = new Delete(row1);
2520            d.setCellVisibility(new CellVisibility(SECRET + "&" + TOPSECRET));
2521            d.addColumn(fam, qual, 125L);
2522            table.delete(d);
2523          } catch (Throwable t) {
2524            throw new IOException(t);
2525          }
2526          return null;
2527        }
2528      };
2529      SUPERUSER.runAs(actiona);
2530
2531      Scan s = new Scan();
2532      s.readVersions(5);
2533      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2534      ResultScanner scanner = table.getScanner(s);
2535      Result[] next = scanner.next(3);
2536      assertTrue(next.length == 2);
2537      CellScanner cellScanner = next[0].cellScanner();
2538      cellScanner.advance();
2539      Cell current = cellScanner.current();
2540      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2541        row1, 0, row1.length));
2542      assertEquals(127L, current.getTimestamp());
2543      cellScanner.advance();
2544      current = cellScanner.current();
2545      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2546        row1, 0, row1.length));
2547      assertEquals(126L, current.getTimestamp());
2548      cellScanner.advance();
2549      current = cellScanner.current();
2550      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2551        row1, 0, row1.length));
2552      assertEquals(124L, current.getTimestamp());
2553      cellScanner.advance();
2554      current = cellScanner.current();
2555      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2556        row1, 0, row1.length));
2557      assertEquals(123L, current.getTimestamp());
2558      cellScanner = next[1].cellScanner();
2559      cellScanner.advance();
2560      current = cellScanner.current();
2561      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2562        row2, 0, row2.length));
2563
2564      // Issue 2nd delete
2565      actiona = new PrivilegedExceptionAction<Void>() {
2566        @Override
2567        public Void run() throws Exception {
2568          try (Connection connection = ConnectionFactory.createConnection(conf);
2569            Table table = connection.getTable(tableName)) {
2570            Delete d = new Delete(row1);
2571            d.setCellVisibility(new CellVisibility(
2572              "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
2573            d.addFamily(fam, 124L);
2574            table.delete(d);
2575          } catch (Throwable t) {
2576            throw new IOException(t);
2577          }
2578          return null;
2579        }
2580      };
2581      SUPERUSER.runAs(actiona);
2582      s = new Scan();
2583      s.readVersions(5);
2584      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2585      scanner = table.getScanner(s);
2586      next = scanner.next(3);
2587      assertTrue(next.length == 2);
2588      cellScanner = next[0].cellScanner();
2589      cellScanner.advance();
2590      current = cellScanner.current();
2591      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2592        row1, 0, row1.length));
2593      assertEquals(127L, current.getTimestamp());
2594      cellScanner.advance();
2595      current = cellScanner.current();
2596      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2597        row1, 0, row1.length));
2598      assertEquals(126L, current.getTimestamp());
2599      cellScanner = next[1].cellScanner();
2600      cellScanner.advance();
2601      current = cellScanner.current();
2602      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2603        row2, 0, row2.length));
2604      assertEquals(127L, current.getTimestamp());
2605    }
2606  }
2607
2608  @Test
2609  public void testDiffDeleteTypesForTheSameCellUsingMultipleVersions(TestInfo testInfo)
2610    throws Exception {
2611    setAuths();
2612    final TableName tableName = TableName
2613      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
2614    try (Table table = doPuts(tableName)) {
2615      // Do not flush here.
2616      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2617        @Override
2618        public Void run() throws Exception {
2619          try (Connection connection = ConnectionFactory.createConnection(conf);
2620            Table table = connection.getTable(tableName)) {
2621            Delete d = new Delete(row1);
2622            d.setCellVisibility(new CellVisibility(
2623              "(" + PRIVATE + "&" + CONFIDENTIAL + ")|(" + TOPSECRET + "&" + SECRET + ")"));
2624            d.addColumns(fam, qual, 125L);
2625            table.delete(d);
2626          } catch (Throwable t) {
2627            throw new IOException(t);
2628          }
2629          return null;
2630        }
2631      };
2632      SUPERUSER.runAs(actiona);
2633
2634      Scan s = new Scan();
2635      s.readVersions(5);
2636      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2637      ResultScanner scanner = table.getScanner(s);
2638      Result[] next = scanner.next(3);
2639      assertTrue(next.length == 2);
2640      CellScanner cellScanner = next[0].cellScanner();
2641      cellScanner.advance();
2642      Cell current = cellScanner.current();
2643      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2644        row1, 0, row1.length));
2645      assertEquals(127L, current.getTimestamp());
2646      cellScanner.advance();
2647      current = cellScanner.current();
2648      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2649        row1, 0, row1.length));
2650      assertEquals(126L, current.getTimestamp());
2651      cellScanner.advance();
2652      current = cellScanner.current();
2653      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2654        row1, 0, row1.length));
2655      assertEquals(125L, current.getTimestamp());
2656      cellScanner.advance();
2657      current = cellScanner.current();
2658      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2659        row1, 0, row1.length));
2660      assertEquals(123L, current.getTimestamp());
2661      cellScanner = next[1].cellScanner();
2662      cellScanner.advance();
2663      current = cellScanner.current();
2664      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2665        row2, 0, row2.length));
2666
2667      // Issue 2nd delete
2668      actiona = new PrivilegedExceptionAction<Void>() {
2669        @Override
2670        public Void run() throws Exception {
2671          try (Connection connection = ConnectionFactory.createConnection(conf);
2672            Table table = connection.getTable(tableName)) {
2673            Delete d = new Delete(row1);
2674            d.setCellVisibility(new CellVisibility(
2675              "(" + CONFIDENTIAL + "&" + PRIVATE + ")|(" + TOPSECRET + "&" + SECRET + ")"));
2676            d.addColumn(fam, qual, 127L);
2677            table.delete(d);
2678          } catch (Throwable t) {
2679            throw new IOException(t);
2680          }
2681          return null;
2682        }
2683      };
2684      SUPERUSER.runAs(actiona);
2685      s = new Scan();
2686      s.readVersions(5);
2687      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2688      scanner = table.getScanner(s);
2689      next = scanner.next(3);
2690      assertTrue(next.length == 2);
2691      cellScanner = next[0].cellScanner();
2692      cellScanner.advance();
2693      current = cellScanner.current();
2694      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2695        row1, 0, row1.length));
2696      assertEquals(126L, current.getTimestamp());
2697      cellScanner.advance();
2698      current = cellScanner.current();
2699      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2700        row1, 0, row1.length));
2701      assertEquals(125L, current.getTimestamp());
2702      cellScanner.advance();
2703      current = cellScanner.current();
2704      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2705        row1, 0, row1.length));
2706      assertEquals(123L, current.getTimestamp());
2707      cellScanner = next[1].cellScanner();
2708      cellScanner.advance();
2709      current = cellScanner.current();
2710      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2711        row2, 0, row2.length));
2712    }
2713  }
2714
2715  @Test
2716  public void testDeleteColumnLatestWithNoCellVisibility(TestInfo testInfo) throws Exception {
2717    setAuths();
2718    final TableName tableName = TableName
2719      .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName()));
2720    try (Table table = doPuts(tableName)) {
2721      TEST_UTIL.getAdmin().flush(tableName);
2722      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2723        @Override
2724        public Void run() throws Exception {
2725          try (Connection connection = ConnectionFactory.createConnection(conf);
2726            Table table = connection.getTable(tableName)) {
2727            Delete d = new Delete(row1);
2728            d.addColumn(fam, qual, 125L);
2729            table.delete(d);
2730          } catch (Throwable t) {
2731            throw new IOException(t);
2732          }
2733          return null;
2734        }
2735      };
2736      SUPERUSER.runAs(actiona);
2737
2738      TEST_UTIL.getAdmin().flush(tableName);
2739      Scan s = new Scan();
2740      s.readVersions(5);
2741      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2742      ResultScanner scanner = table.getScanner(s);
2743      Result[] next = scanner.next(3);
2744      assertTrue(next.length == 2);
2745      scanAll(next);
2746      actiona = new PrivilegedExceptionAction<Void>() {
2747        @Override
2748        public Void run() throws Exception {
2749          try (Connection connection = ConnectionFactory.createConnection(conf);
2750            Table table = connection.getTable(tableName)) {
2751            Delete d = new Delete(row1);
2752            d.addColumns(fam, qual, 125L);
2753            table.delete(d);
2754          } catch (Throwable t) {
2755            throw new IOException(t);
2756          }
2757          return null;
2758        }
2759      };
2760      SUPERUSER.runAs(actiona);
2761
2762      TEST_UTIL.getAdmin().flush(tableName);
2763      s = new Scan();
2764      s.readVersions(5);
2765      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2766      scanner = table.getScanner(s);
2767      next = scanner.next(3);
2768      assertTrue(next.length == 2);
2769      scanAll(next);
2770
2771      actiona = new PrivilegedExceptionAction<Void>() {
2772        @Override
2773        public Void run() throws Exception {
2774          try (Connection connection = ConnectionFactory.createConnection(conf);
2775            Table table = connection.getTable(tableName)) {
2776            Delete d = new Delete(row1);
2777            d.addFamily(fam, 125L);
2778            table.delete(d);
2779          } catch (Throwable t) {
2780            throw new IOException(t);
2781          }
2782          return null;
2783        }
2784      };
2785      SUPERUSER.runAs(actiona);
2786
2787      TEST_UTIL.getAdmin().flush(tableName);
2788      s = new Scan();
2789      s.readVersions(5);
2790      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2791      scanner = table.getScanner(s);
2792      next = scanner.next(3);
2793      assertTrue(next.length == 2);
2794      scanAll(next);
2795
2796      actiona = new PrivilegedExceptionAction<Void>() {
2797        @Override
2798        public Void run() throws Exception {
2799          try (Connection connection = ConnectionFactory.createConnection(conf);
2800            Table table = connection.getTable(tableName)) {
2801            Delete d = new Delete(row1);
2802            d.addFamily(fam);
2803            table.delete(d);
2804          } catch (Throwable t) {
2805            throw new IOException(t);
2806          }
2807          return null;
2808        }
2809      };
2810      SUPERUSER.runAs(actiona);
2811
2812      TEST_UTIL.getAdmin().flush(tableName);
2813      s = new Scan();
2814      s.readVersions(5);
2815      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2816      scanner = table.getScanner(s);
2817      next = scanner.next(3);
2818      assertTrue(next.length == 2);
2819      scanAll(next);
2820
2821      actiona = new PrivilegedExceptionAction<Void>() {
2822        @Override
2823        public Void run() throws Exception {
2824          try (Connection connection = ConnectionFactory.createConnection(conf);
2825            Table table = connection.getTable(tableName)) {
2826            Delete d = new Delete(row1);
2827            d.addColumns(fam, qual);
2828            table.delete(d);
2829          } catch (Throwable t) {
2830            throw new IOException(t);
2831          }
2832          return null;
2833        }
2834      };
2835      SUPERUSER.runAs(actiona);
2836
2837      TEST_UTIL.getAdmin().flush(tableName);
2838      s = new Scan();
2839      s.readVersions(5);
2840      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2841      scanner = table.getScanner(s);
2842      next = scanner.next(3);
2843      assertTrue(next.length == 2);
2844      scanAll(next);
2845
2846      actiona = new PrivilegedExceptionAction<Void>() {
2847        @Override
2848        public Void run() throws Exception {
2849          try (Connection connection = ConnectionFactory.createConnection(conf);
2850            Table table = connection.getTable(tableName)) {
2851            Delete d = new Delete(row1);
2852            d.addFamilyVersion(fam, 126L);
2853            table.delete(d);
2854          } catch (Throwable t) {
2855            throw new IOException(t);
2856          }
2857          return null;
2858        }
2859      };
2860      SUPERUSER.runAs(actiona);
2861
2862      TEST_UTIL.getAdmin().flush(tableName);
2863      s = new Scan();
2864      s.readVersions(5);
2865      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2866      scanner = table.getScanner(s);
2867      next = scanner.next(3);
2868      assertTrue(next.length == 2);
2869      scanAll(next);
2870    }
2871  }
2872
2873  private void scanAll(Result[] next) throws IOException {
2874    CellScanner cellScanner = next[0].cellScanner();
2875    cellScanner.advance();
2876    Cell current = cellScanner.current();
2877    assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2878      row1, 0, row1.length));
2879    assertEquals(127L, current.getTimestamp());
2880    cellScanner.advance();
2881    current = cellScanner.current();
2882    assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2883      row1, 0, row1.length));
2884    assertEquals(126L, current.getTimestamp());
2885    cellScanner.advance();
2886    current = cellScanner.current();
2887    assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2888      row1, 0, row1.length));
2889    assertEquals(125L, current.getTimestamp());
2890    cellScanner.advance();
2891    current = cellScanner.current();
2892    assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2893      row1, 0, row1.length));
2894    assertEquals(124L, current.getTimestamp());
2895    cellScanner.advance();
2896    current = cellScanner.current();
2897    assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2898      row1, 0, row1.length));
2899    assertEquals(123L, current.getTimestamp());
2900    cellScanner = next[1].cellScanner();
2901    cellScanner.advance();
2902    current = cellScanner.current();
2903    assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2904      row2, 0, row2.length));
2905  }
2906
2907  @Test
2908  public void testVisibilityExpressionWithNotEqualORCondition(TestInfo testInfo) throws Exception {
2909    setAuths();
2910    TableName tableName = createTable(5, testInfo);
2911    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
2912      Put put = new Put(Bytes.toBytes("row1"));
2913      put.addColumn(fam, qual, 123L, value);
2914      put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
2915      table.put(put);
2916      put = new Put(Bytes.toBytes("row1"));
2917      put.addColumn(fam, qual, 124L, value);
2918      put.setCellVisibility(new CellVisibility(CONFIDENTIAL + "|" + PRIVATE));
2919      table.put(put);
2920      TEST_UTIL.getAdmin().flush(tableName);
2921      PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() {
2922        @Override
2923        public Void run() throws Exception {
2924          try (Connection connection = ConnectionFactory.createConnection(conf);
2925            Table table = connection.getTable(tableName)) {
2926            Delete d = new Delete(row1);
2927            d.addColumn(fam, qual, 124L);
2928            d.setCellVisibility(new CellVisibility(PRIVATE));
2929            table.delete(d);
2930          } catch (Throwable t) {
2931            throw new IOException(t);
2932          }
2933          return null;
2934        }
2935      };
2936      SUPERUSER.runAs(actiona);
2937
2938      TEST_UTIL.getAdmin().flush(tableName);
2939      Scan s = new Scan();
2940      s.readVersions(5);
2941      s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL, TOPSECRET));
2942      ResultScanner scanner = table.getScanner(s);
2943      Result[] next = scanner.next(3);
2944      assertTrue(next.length == 1);
2945      CellScanner cellScanner = next[0].cellScanner();
2946      cellScanner.advance();
2947      Cell current = cellScanner.current();
2948      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2949        row1, 0, row1.length));
2950      assertEquals(124L, current.getTimestamp());
2951      cellScanner.advance();
2952      current = cellScanner.current();
2953      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(),
2954        row1, 0, row1.length));
2955      assertEquals(123L, current.getTimestamp());
2956    }
2957  }
2958
2959  @Test
2960  public void testDeleteWithNoVisibilitiesForPutsAndDeletes(TestInfo testInfo) throws Exception {
2961    TableName tableName = createTable(5, testInfo);
2962    Put p = new Put(Bytes.toBytes("row1"));
2963    p.addColumn(fam, qual, value);
2964    Table table = TEST_UTIL.getConnection().getTable(tableName);
2965    table.put(p);
2966    p = new Put(Bytes.toBytes("row1"));
2967    p.addColumn(fam, qual1, value);
2968    table.put(p);
2969    p = new Put(Bytes.toBytes("row2"));
2970    p.addColumn(fam, qual, value);
2971    table.put(p);
2972    p = new Put(Bytes.toBytes("row2"));
2973    p.addColumn(fam, qual1, value);
2974    table.put(p);
2975    Delete d = new Delete(Bytes.toBytes("row1"));
2976    table.delete(d);
2977    Get g = new Get(Bytes.toBytes("row1"));
2978    g.readAllVersions();
2979    g.setAuthorizations(new Authorizations(SECRET, PRIVATE));
2980    Result result = table.get(g);
2981    assertEquals(0, result.rawCells().length);
2982
2983    p = new Put(Bytes.toBytes("row1"));
2984    p.addColumn(fam, qual, value);
2985    table.put(p);
2986    result = table.get(g);
2987    assertEquals(1, result.rawCells().length);
2988  }
2989
2990  @Test
2991  public void testDeleteWithFamilyDeletesOfSameTsButDifferentVisibilities(TestInfo testInfo)
2992    throws Exception {
2993    TableName tableName = createTable(5, testInfo);
2994    Table table = TEST_UTIL.getConnection().getTable(tableName);
2995    long t1 = 1234L;
2996    CellVisibility cellVisibility1 = new CellVisibility(SECRET);
2997    CellVisibility cellVisibility2 = new CellVisibility(PRIVATE);
2998    // Cell row1:info:qual:1234 with visibility SECRET
2999    Put p = new Put(row1);
3000    p.addColumn(fam, qual, t1, value);
3001    p.setCellVisibility(cellVisibility1);
3002    table.put(p);
3003
3004    // Cell row1:info:qual1:1234 with visibility PRIVATE
3005    p = new Put(row1);
3006    p.addColumn(fam, qual1, t1, value);
3007    p.setCellVisibility(cellVisibility2);
3008    table.put(p);
3009
3010    Delete d = new Delete(row1);
3011    d.addFamily(fam, t1);
3012    d.setCellVisibility(cellVisibility2);
3013    table.delete(d);
3014    d = new Delete(row1);
3015    d.addFamily(fam, t1);
3016    d.setCellVisibility(cellVisibility1);
3017    table.delete(d);
3018
3019    Get g = new Get(row1);
3020    g.readAllVersions();
3021    g.setAuthorizations(new Authorizations(SECRET, PRIVATE));
3022    Result result = table.get(g);
3023    assertEquals(0, result.rawCells().length);
3024
3025    // Cell row2:info:qual:1234 with visibility SECRET
3026    p = new Put(row2);
3027    p.addColumn(fam, qual, t1, value);
3028    p.setCellVisibility(cellVisibility1);
3029    table.put(p);
3030
3031    // Cell row2:info:qual1:1234 with visibility PRIVATE
3032    p = new Put(row2);
3033    p.addColumn(fam, qual1, t1, value);
3034    p.setCellVisibility(cellVisibility2);
3035    table.put(p);
3036
3037    d = new Delete(row2);
3038    d.addFamilyVersion(fam, t1);
3039    d.setCellVisibility(cellVisibility2);
3040    table.delete(d);
3041    d = new Delete(row2);
3042    d.addFamilyVersion(fam, t1);
3043    d.setCellVisibility(cellVisibility1);
3044    table.delete(d);
3045
3046    g = new Get(row2);
3047    g.readAllVersions();
3048    g.setAuthorizations(new Authorizations(SECRET, PRIVATE));
3049    result = table.get(g);
3050    assertEquals(0, result.rawCells().length);
3051  }
3052
3053  @SafeVarargs
3054  public static <T> List<T> createList(T... ts) {
3055    return new ArrayList<>(Arrays.asList(ts));
3056  }
3057
3058  private enum DeleteMark {
3059    ROW,
3060    FAMILY,
3061    FAMILY_VERSION,
3062    COLUMN,
3063    CELL
3064  }
3065
3066  private static Delete addDeleteMark(Delete d, DeleteMark mark, long now) {
3067    switch (mark) {
3068      case ROW:
3069        break;
3070      case FAMILY:
3071        d.addFamily(fam);
3072        break;
3073      case FAMILY_VERSION:
3074        d.addFamilyVersion(fam, now);
3075        break;
3076      case COLUMN:
3077        d.addColumns(fam, qual);
3078        break;
3079      case CELL:
3080        d.addColumn(fam, qual);
3081        break;
3082      default:
3083        break;
3084    }
3085    return d;
3086  }
3087
3088  @Test
3089  public void testDeleteCellWithoutVisibility(TestInfo testInfo)
3090    throws IOException, InterruptedException {
3091    for (DeleteMark mark : DeleteMark.values()) {
3092      testDeleteCellWithoutVisibility(mark);
3093    }
3094  }
3095
3096  private void testDeleteCellWithoutVisibility(DeleteMark mark)
3097    throws IOException, InterruptedException {
3098    setAuths();
3099    TableName tableName = TableName.valueOf("testDeleteCellWithoutVisibility-" + mark.name());
3100    createTable(tableName, 5);
3101    long now = EnvironmentEdgeManager.currentTime();
3102    List<Put> puts = new ArrayList<>(1);
3103    Put put = new Put(row1);
3104    if (mark == DeleteMark.FAMILY_VERSION) {
3105      put.addColumn(fam, qual, now, value);
3106    } else {
3107      put.addColumn(fam, qual, value);
3108    }
3109
3110    puts.add(put);
3111    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
3112      table.put(puts);
3113      Result r = table.get(new Get(row1));
3114      assertEquals(1, r.size());
3115      assertEquals(Bytes.toString(value), Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
3116
3117      Delete d = addDeleteMark(new Delete(row1), mark, now);
3118      table.delete(d);
3119      r = table.get(new Get(row1));
3120      assertEquals(0, r.size());
3121    }
3122  }
3123
3124  @Test
3125  public void testDeleteCellWithVisibility(TestInfo testInfo)
3126    throws IOException, InterruptedException {
3127    for (DeleteMark mark : DeleteMark.values()) {
3128      testDeleteCellWithVisibility(mark);
3129      testDeleteCellWithVisibilityV2(mark);
3130    }
3131  }
3132
3133  private void testDeleteCellWithVisibility(DeleteMark mark)
3134    throws IOException, InterruptedException {
3135    setAuths();
3136    TableName tableName = TableName.valueOf("testDeleteCellWithVisibility-" + mark.name());
3137    createTable(tableName, 5);
3138    long now = EnvironmentEdgeManager.currentTime();
3139    List<Put> puts = new ArrayList<>(2);
3140    Put put = new Put(row1);
3141    if (mark == DeleteMark.FAMILY_VERSION) {
3142      put.addColumn(fam, qual, now, value);
3143    } else {
3144      put.addColumn(fam, qual, value);
3145    }
3146    puts.add(put);
3147    put = new Put(row1);
3148    if (mark == DeleteMark.FAMILY_VERSION) {
3149      put.addColumn(fam, qual, now, value1);
3150    } else {
3151      put.addColumn(fam, qual, value1);
3152    }
3153    put.setCellVisibility(new CellVisibility(PRIVATE));
3154    puts.add(put);
3155    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
3156      table.put(puts);
3157      Result r = table.get(new Get(row1));
3158      assertEquals(0, r.size());
3159      r = table.get(new Get(row1).setAuthorizations(new Authorizations(PRIVATE)));
3160      assertEquals(1, r.size());
3161      assertEquals(Bytes.toString(value1), Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
3162
3163      Delete d = addDeleteMark(new Delete(row1), mark, now);
3164      table.delete(d);
3165
3166      r = table.get(new Get(row1));
3167      assertEquals(0, r.size());
3168      r = table.get(new Get(row1).setAuthorizations(new Authorizations(PRIVATE)));
3169      assertEquals(1, r.size());
3170      assertEquals(Bytes.toString(value1), Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
3171
3172      d = addDeleteMark(new Delete(row1).setCellVisibility(new CellVisibility(PRIVATE)), mark, now);
3173      table.delete(d);
3174
3175      r = table.get(new Get(row1));
3176      assertEquals(0, r.size());
3177      r = table.get(new Get(row1).setAuthorizations(new Authorizations(PRIVATE)));
3178      assertEquals(0, r.size());
3179    }
3180  }
3181
3182  private void testDeleteCellWithVisibilityV2(DeleteMark mark)
3183    throws IOException, InterruptedException {
3184    setAuths();
3185    TableName tableName = TableName.valueOf("testDeleteCellWithVisibilityV2-" + mark.name());
3186    createTable(tableName, 5);
3187    long now = EnvironmentEdgeManager.currentTime();
3188    List<Put> puts = new ArrayList<>(2);
3189    Put put = new Put(row1);
3190    put.setCellVisibility(new CellVisibility(PRIVATE));
3191    if (mark == DeleteMark.FAMILY_VERSION) {
3192      put.addColumn(fam, qual, now, value);
3193    } else {
3194      put.addColumn(fam, qual, value);
3195    }
3196    puts.add(put);
3197    put = new Put(row1);
3198    if (mark == DeleteMark.FAMILY_VERSION) {
3199      put.addColumn(fam, qual, now, value1);
3200    } else {
3201      put.addColumn(fam, qual, value1);
3202    }
3203    puts.add(put);
3204    try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
3205      table.put(puts);
3206      Result r = table.get(new Get(row1));
3207      assertEquals(1, r.size());
3208      assertEquals(Bytes.toString(value1), Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
3209      r = table.get(new Get(row1).setAuthorizations(new Authorizations(PRIVATE)));
3210      assertEquals(1, r.size());
3211      assertEquals(Bytes.toString(value1), Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
3212
3213      Delete d = addDeleteMark(new Delete(row1), mark, now);
3214      table.delete(d);
3215
3216      r = table.get(new Get(row1));
3217      assertEquals(0, r.size());
3218      r = table.get(new Get(row1).setAuthorizations(new Authorizations(PRIVATE)));
3219      assertEquals(0, r.size());
3220
3221      d = addDeleteMark(new Delete(row1).setCellVisibility(new CellVisibility(PRIVATE)), mark, now);
3222      table.delete(d);
3223
3224      r = table.get(new Get(row1));
3225      assertEquals(0, r.size());
3226      r = table.get(new Get(row1).setAuthorizations(new Authorizations(PRIVATE)));
3227      assertEquals(0, r.size());
3228    }
3229  }
3230}