View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to you under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.hadoop.hbase.quotas;
18  
19  import static org.mockito.Matchers.argThat;
20  import static org.mockito.Mockito.mock;
21  import static org.mockito.Mockito.verify;
22  import static org.mockito.Mockito.when;
23  
24  import java.util.Arrays;
25  import java.util.List;
26  import java.util.Map.Entry;
27  import java.util.NavigableMap;
28  import java.util.Objects;
29  
30  import org.apache.hadoop.hbase.Cell;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.client.Connection;
33  import org.apache.hadoop.hbase.client.Mutation;
34  import org.apache.hadoop.hbase.client.Put;
35  import org.apache.hadoop.hbase.client.Table;
36  import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
37  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos;
38  import org.apache.hadoop.hbase.testclassification.SmallTests;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.junit.Before;
41  import org.junit.Test;
42  import org.junit.experimental.categories.Category;
43  import org.mockito.ArgumentMatcher;
44  
45  /**
46   * Test case for {@link TableSpaceQuotaSnapshotNotifier}.
47   */
48  @Category(SmallTests.class)
49  public class TestTableSpaceQuotaViolationNotifier {
50  
51    private TableSpaceQuotaSnapshotNotifier notifier;
52    private Connection conn;
53  
54    @Before
55    public void setup() throws Exception {
56      notifier = new TableSpaceQuotaSnapshotNotifier();
57      conn = mock(Connection.class);
58      notifier.initialize(conn);
59    }
60  
61    @Test
62    public void testToViolation() throws Exception {
63      final TableName tn = TableName.valueOf("inviolation");
64      final SpaceQuotaSnapshot snapshot = new SpaceQuotaSnapshot(
65          new SpaceQuotaStatus(SpaceViolationPolicy.NO_INSERTS), 1024L, 512L);
66      final Table quotaTable = mock(Table.class);
67      when(conn.getTable(QuotaTableUtil.QUOTA_TABLE_NAME)).thenReturn(quotaTable);
68  
69      final Put expectedPut = new Put(Bytes.toBytes("t." + tn.getNameAsString()));
70      final QuotaProtos.SpaceQuotaSnapshot protoQuota = QuotaProtos.SpaceQuotaSnapshot.newBuilder()
71          .setQuotaStatus(QuotaProtos.SpaceQuotaStatus.newBuilder().setInViolation(true)
72          .setViolationPolicy(QuotaProtos.SpaceViolationPolicy.NO_INSERTS))
73          .setQuotaLimit(512L)
74          .setQuotaUsage(1024L)
75          .build();
76      expectedPut.addColumn(Bytes.toBytes("u"), Bytes.toBytes("p"), protoQuota.toByteArray());
77  
78      notifier.transitionTable(tn, snapshot);
79  
80      verify(quotaTable).put(argThat(new SingleCellPutMatcher(expectedPut)));
81    }
82  
83    /**
84     * Parameterized for Puts.
85     */
86    private static class SingleCellPutMatcher extends SingleCellMutationMatcher<Put> {
87      private SingleCellPutMatcher(Put expected) {
88        super(expected);
89      }
90    }
91  
92    /**
93     * Quick hack to verify a Mutation with one column.
94     */
95    private static class SingleCellMutationMatcher<T> extends ArgumentMatcher<T> {
96      private final Mutation expected;
97  
98      private SingleCellMutationMatcher(Mutation expected) {
99        this.expected = expected;
100     }
101 
102     @Override
103     public boolean matches(Object argument) {
104       if (!expected.getClass().isAssignableFrom(argument.getClass())) {
105         return false;
106       }
107       Mutation actual = (Mutation) argument;
108       if (!Arrays.equals(expected.getRow(), actual.getRow())) {
109         return false;
110       }
111       if (expected.size() != actual.size()) {
112         return false;
113       }
114       NavigableMap<byte[],List<Cell>> expectedCells = expected.getFamilyCellMap();
115       NavigableMap<byte[],List<Cell>> actualCells = actual.getFamilyCellMap();
116       Entry<byte[],List<Cell>> expectedEntry = expectedCells.entrySet().iterator().next();
117       Entry<byte[],List<Cell>> actualEntry = actualCells.entrySet().iterator().next();
118       if (!Arrays.equals(expectedEntry.getKey(), actualEntry.getKey())) {
119         return false;
120       }
121       return Objects.equals(expectedEntry.getValue(), actualEntry.getValue());
122     }
123   }
124 }