| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.accumulo.proxy.its; |
| |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| import static org.apache.accumulo.core.util.UtilWaitThread.sleepUninterruptibly; |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertNotEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| import static org.junit.jupiter.api.Assertions.fail; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.net.InetAddress; |
| import java.net.URI; |
| import java.nio.ByteBuffer; |
| import java.time.Duration; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.UUID; |
| import java.util.concurrent.TimeUnit; |
| import java.util.stream.Stream; |
| |
| import org.apache.accumulo.core.client.Accumulo; |
| import org.apache.accumulo.core.client.AccumuloClient; |
| import org.apache.accumulo.core.client.admin.compaction.TooManyDeletesSelector; |
| import org.apache.accumulo.core.client.summary.summarizers.DeletesSummarizer; |
| import org.apache.accumulo.core.clientImpl.Namespace; |
| import org.apache.accumulo.core.conf.DefaultConfiguration; |
| import org.apache.accumulo.core.conf.Property; |
| import org.apache.accumulo.core.data.Value; |
| import org.apache.accumulo.core.file.FileOperations; |
| import org.apache.accumulo.core.file.FileSKVWriter; |
| import org.apache.accumulo.core.iterators.DebugIterator; |
| import org.apache.accumulo.core.iterators.DevNull; |
| import org.apache.accumulo.core.iterators.SortedKeyValueIterator; |
| import org.apache.accumulo.core.iterators.user.SummingCombiner; |
| import org.apache.accumulo.core.iterators.user.VersioningIterator; |
| import org.apache.accumulo.core.metadata.MetadataTable; |
| import org.apache.accumulo.core.security.Authorizations; |
| import org.apache.accumulo.core.spi.crypto.NoCryptoServiceFactory; |
| import org.apache.accumulo.core.util.ByteBufferUtil; |
| import org.apache.accumulo.core.util.HostAndPort; |
| import org.apache.accumulo.harness.MiniClusterConfigurationCallback; |
| import org.apache.accumulo.harness.SharedMiniClusterBase; |
| import org.apache.accumulo.miniclusterImpl.MiniAccumuloClusterImpl; |
| import org.apache.accumulo.miniclusterImpl.MiniAccumuloConfigImpl; |
| import org.apache.accumulo.proxy.Proxy; |
| import org.apache.accumulo.proxy.thrift.AccumuloProxy.Client; |
| import org.apache.accumulo.proxy.thrift.AccumuloSecurityException; |
| import org.apache.accumulo.proxy.thrift.ActiveCompaction; |
| import org.apache.accumulo.proxy.thrift.ActiveScan; |
| import org.apache.accumulo.proxy.thrift.BatchScanOptions; |
| import org.apache.accumulo.proxy.thrift.Column; |
| import org.apache.accumulo.proxy.thrift.ColumnUpdate; |
| import org.apache.accumulo.proxy.thrift.CompactionReason; |
| import org.apache.accumulo.proxy.thrift.CompactionType; |
| import org.apache.accumulo.proxy.thrift.Condition; |
| import org.apache.accumulo.proxy.thrift.ConditionalStatus; |
| import org.apache.accumulo.proxy.thrift.ConditionalUpdates; |
| import org.apache.accumulo.proxy.thrift.ConditionalWriterOptions; |
| import org.apache.accumulo.proxy.thrift.DiskUsage; |
| import org.apache.accumulo.proxy.thrift.IteratorScope; |
| import org.apache.accumulo.proxy.thrift.IteratorSetting; |
| import org.apache.accumulo.proxy.thrift.Key; |
| import org.apache.accumulo.proxy.thrift.KeyValue; |
| import org.apache.accumulo.proxy.thrift.MutationsRejectedException; |
| import org.apache.accumulo.proxy.thrift.NamespaceExistsException; |
| import org.apache.accumulo.proxy.thrift.NamespaceNotEmptyException; |
| import org.apache.accumulo.proxy.thrift.NamespaceNotFoundException; |
| import org.apache.accumulo.proxy.thrift.NamespacePermission; |
| import org.apache.accumulo.proxy.thrift.PartialKey; |
| import org.apache.accumulo.proxy.thrift.PluginConfig; |
| import org.apache.accumulo.proxy.thrift.Range; |
| import org.apache.accumulo.proxy.thrift.ScanColumn; |
| import org.apache.accumulo.proxy.thrift.ScanOptions; |
| import org.apache.accumulo.proxy.thrift.ScanResult; |
| import org.apache.accumulo.proxy.thrift.ScanState; |
| import org.apache.accumulo.proxy.thrift.ScanType; |
| import org.apache.accumulo.proxy.thrift.SystemPermission; |
| import org.apache.accumulo.proxy.thrift.TableExistsException; |
| import org.apache.accumulo.proxy.thrift.TableNotFoundException; |
| import org.apache.accumulo.proxy.thrift.TablePermission; |
| import org.apache.accumulo.proxy.thrift.TimeType; |
| import org.apache.accumulo.proxy.thrift.UnknownScanner; |
| import org.apache.accumulo.proxy.thrift.UnknownWriter; |
| import org.apache.accumulo.proxy.thrift.WriterOptions; |
| import org.apache.accumulo.server.util.PortUtils; |
| import org.apache.accumulo.test.constraints.MaxMutationSize; |
| import org.apache.accumulo.test.constraints.NumericValueConstraint; |
| import org.apache.accumulo.test.functional.SlowIterator; |
| import org.apache.accumulo.test.util.Wait; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.FSDataInputStream; |
| import org.apache.hadoop.fs.FileSystem; |
| import org.apache.hadoop.fs.FileUtil; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.io.Text; |
| import org.apache.thrift.TApplicationException; |
| import org.apache.thrift.TException; |
| import org.apache.thrift.protocol.TProtocolFactory; |
| import org.apache.thrift.server.TServer; |
| import org.junit.jupiter.api.AfterAll; |
| import org.junit.jupiter.api.AfterEach; |
| import org.junit.jupiter.api.BeforeEach; |
| import org.junit.jupiter.api.Test; |
| import org.junit.jupiter.api.TestInfo; |
| import org.junit.jupiter.api.Timeout; |
| import org.junit.jupiter.api.function.Executable; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.collect.Sets; |
| |
| /** |
| * Call every method on the proxy and try to verify that it works. |
| */ |
| public abstract class SimpleProxyBase extends SharedMiniClusterBase { |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| @Override |
| protected Duration defaultTimeout() { |
| return Duration.ofMinutes(1); |
| } |
| |
| private static final long ZOOKEEPER_PROPAGATION_TIME = 10 * 1000; |
| private static TServer proxyServer; |
| private static int proxyPort; |
| |
| private TestProxyClient proxyClient; |
| private org.apache.accumulo.proxy.thrift.AccumuloProxy.Client client; |
| |
| private static String hostname; |
| private static String clientPrincipal; |
| |
| private static final String sharedSecret = "superSecret"; |
| |
| // Implementations can set this |
| static TProtocolFactory factory = null; |
| |
| private static void waitForAccumulo(AccumuloClient c) throws Exception { |
| assertTrue( |
| c.createScanner(MetadataTable.NAME, Authorizations.EMPTY).stream().findAny().isPresent()); |
| } |
| |
| /** |
| * The purpose of this callback is to setup the tests to NOT use the native libs |
| */ |
| protected static class TestConfig implements MiniClusterConfigurationCallback { |
| @Override |
| public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration coreSite) { |
| // Set the min span to 0 so we will definitely get all the traces back. See ACCUMULO-4365 |
| Map<String,String> siteConf = cfg.getSiteConfig(); |
| siteConf.put(Property.TSERV_NATIVEMAP_ENABLED.getKey(), "false"); |
| cfg.setSiteConfig(siteConf); |
| } |
| } |
| |
| /** |
| * Does the actual test setup, invoked by the concrete test class |
| */ |
| public static void setUpProxy() throws Exception { |
| assertNotNull(factory, "Implementations must initialize the TProtocolFactory"); |
| |
| try (AccumuloClient c = Accumulo.newClient().from(getClientProps()).build()) { |
| waitForAccumulo(c); |
| |
| hostname = InetAddress.getLocalHost().getCanonicalHostName(); |
| |
| Properties props = new Properties(); |
| props.put("sharedSecret", sharedSecret); |
| props.putAll(SharedMiniClusterBase.getCluster().getClientProperties()); |
| clientPrincipal = props.getProperty("auth.principal"); |
| proxyPort = PortUtils.getRandomFreePort(); |
| proxyServer = Proxy.createProxyServer(HostAndPort.fromParts(hostname, proxyPort), factory, |
| props).server; |
| while (!proxyServer.isServing()) { |
| sleepUninterruptibly(100, TimeUnit.MILLISECONDS); |
| } |
| } |
| } |
| |
| @AfterAll |
| public static void tearDownProxy() { |
| if (proxyServer != null) { |
| proxyServer.stop(); |
| } |
| |
| SharedMiniClusterBase.stopMiniCluster(); |
| } |
| |
| final IteratorSetting setting = new IteratorSetting(100, "slow", SlowIterator.class.getName(), |
| Collections.singletonMap("sleepTime", "200")); |
| String tableName; |
| String namespaceName; |
| String badSecret = "badSecret"; |
| |
| private String testName; |
| |
| private String[] getUniqueNameArray(int num) { |
| String[] names = new String[num]; |
| for (int i = 0; i < num; i++) { |
| names[i] = this.getClass().getSimpleName() + "_" + testName + i; |
| } |
| return names; |
| } |
| |
| @BeforeEach |
| public void setup(TestInfo info) throws Exception { |
| // Create a new client for each test |
| |
| proxyClient = new TestProxyClient(hostname, proxyPort, factory); |
| client = proxyClient.proxy(); |
| |
| testName = info.getTestMethod() |
| .orElseThrow(() -> new IllegalArgumentException("Test method is missing")).getName(); |
| |
| // Create some unique names for tables, namespaces, etc. |
| String[] uniqueNames = getUniqueNameArray(2); |
| |
| // Create a general table to be used |
| tableName = uniqueNames[0]; |
| client.createTable(sharedSecret, tableName, true, TimeType.MILLIS); |
| |
| // Create a general namespace to be used |
| namespaceName = uniqueNames[1]; |
| client.createNamespace(sharedSecret, namespaceName); |
| } |
| |
| @AfterEach |
| public void teardown() { |
| if (tableName != null) { |
| try { |
| if (client.tableExists(sharedSecret, tableName)) { |
| client.deleteTable(sharedSecret, tableName); |
| } |
| } catch (Exception e) { |
| log.warn("Failed to delete test table '{}'", tableName, e); |
| } |
| } |
| |
| if (namespaceName != null) { |
| try { |
| if (client.namespaceExists(sharedSecret, namespaceName)) { |
| client.deleteNamespace(sharedSecret, namespaceName); |
| } |
| } catch (Exception e) { |
| log.warn("Failed to delete test namespace '{}'", namespaceName, e); |
| } |
| } |
| |
| // Close the transport after the test |
| if (proxyClient != null) { |
| proxyClient.close(); |
| } |
| } |
| |
| /* |
| * Set a lower timeout for tests that should fail fast |
| */ |
| |
| @Test |
| @Timeout(5) |
| public void addConstraintBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.addConstraint(badSecret, tableName, NumericValueConstraint.class.getName())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void addSplitsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.addSplits(badSecret, tableName, Collections.singleton(s2bb("1")))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void clearLocatorCacheBadSharedSecret() { |
| assertThrows(TApplicationException.class, () -> client.clearLocatorCache(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void compactTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.compactTable(badSecret, tableName, null, null, null, true, false, null, null)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void cancelCompactionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.cancelCompaction(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void createTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.createTable(badSecret, tableName, false, TimeType.MILLIS)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void deleteTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.deleteTable(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void deleteRowsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.deleteRows(badSecret, tableName, null, null)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void tableExistsBadSharedSecret() { |
| assertThrows(TApplicationException.class, () -> client.tableExists(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void flushTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.flushTable(badSecret, tableName, null, null, false)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getLocalityGroupsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.getLocalityGroups(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getMaxRowBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.getMaxRow(badSecret, tableName, |
| Collections.emptySet(), null, false, null, false)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getTablePropertiesBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.getTableProperties(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listSplitsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.listSplits(badSecret, tableName, 10000)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listTablesBadSharedSecret() { |
| assertThrows(TApplicationException.class, () -> client.listTables(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listConstraintsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.listConstraints(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void mergeTabletsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.mergeTablets(badSecret, tableName, null, null)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void offlineTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.offlineTable(badSecret, tableName, false)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void onlineTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.onlineTable(badSecret, tableName, false)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void removeConstraintBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.removeConstraint(badSecret, tableName, 0)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void removeTablePropertyBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.removeTableProperty(badSecret, tableName, Property.TABLE_FILE_MAX.getKey())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void renameTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.renameTable(badSecret, tableName, "someTableName")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void setLocalityGroupsBadSharedSecret() { |
| Map<String,Set<String>> groups = new HashMap<>(); |
| groups.put("group1", Collections.singleton("cf1")); |
| groups.put("group2", Collections.singleton("cf2")); |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.setLocalityGroups(badSecret, tableName, groups)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void setTablePropertyBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.setTableProperty(badSecret, tableName, Property.TABLE_FILE_MAX.getKey(), "0")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void tableIdMapBadSharedSecret() { |
| assertThrows(TException.class, () -> client.tableIdMap(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getSiteConfigurationBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.getSiteConfiguration(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getSystemConfigurationBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.getSystemConfiguration(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getTabletServersBadSharedSecret() { |
| assertThrows(TException.class, () -> client.getTabletServers(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getActiveScansBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.getActiveScans(badSecret, "fake")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getActiveCompactionsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.getActiveCompactions(badSecret, "fake")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void removePropertyBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.removeProperty(badSecret, "table.split.threshold")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void setPropertyBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.setProperty(badSecret, "table.split.threshold", "500M")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void testClassLoadBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.testClassLoad(badSecret, |
| DevNull.class.getName(), SortedKeyValueIterator.class.getName())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void authenticateUserBadSharedSecret() { |
| Map<String,String> pw = s2pp(SharedMiniClusterBase.getRootPassword()); |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.authenticateUser(badSecret, "root", pw)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void changeUserAuthorizationsBadSharedSecret() { |
| HashSet<ByteBuffer> auths = new HashSet<>(List.of(s2bb("A"), s2bb("B"))); |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.changeUserAuthorizations(badSecret, "stooge", auths)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void changePasswordBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.changeLocalUserPassword(badSecret, "stooge", s2bb(""))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void createUserBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.createLocalUser(badSecret, "stooge", s2bb("password"))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void dropUserBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.dropLocalUser(badSecret, "stooge")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getUserAuthorizationsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.getUserAuthorizations(badSecret, "stooge")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void grantSystemPermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.grantSystemPermission(badSecret, "stooge", SystemPermission.CREATE_TABLE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void grantTablePermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.grantTablePermission(badSecret, "root", tableName, TablePermission.WRITE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void hasSystemPermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.hasSystemPermission(badSecret, "stooge", SystemPermission.CREATE_TABLE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void hasTablePermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.hasTablePermission(badSecret, "root", tableName, TablePermission.WRITE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listLocalUsersBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.listLocalUsers(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void revokeSystemPermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.revokeSystemPermission(badSecret, "stooge", SystemPermission.CREATE_TABLE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void revokeTablePermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.revokeTablePermission(badSecret, |
| "root", tableName, TablePermission.ALTER_TABLE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void createScannerBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.createScanner(badSecret, tableName, new ScanOptions())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void createBatchScannerBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.createBatchScanner(badSecret, tableName, new BatchScanOptions())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void updateAndFlushBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.updateAndFlush(badSecret, tableName, new HashMap<>())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void createWriterBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.createWriter(badSecret, tableName, new WriterOptions())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void attachIteratorBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.attachIterator(badSecret, "slow", |
| setting, EnumSet.allOf(IteratorScope.class))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void checkIteratorBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.checkIteratorConflicts(badSecret, |
| tableName, setting, EnumSet.allOf(IteratorScope.class))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void cloneTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.cloneTable(badSecret, tableName, tableName + "_clone", false, null, null)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void exportTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.exportTable(badSecret, tableName, "/tmp")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void importTableBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.importTable(badSecret, "testify", "/tmp")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getIteratorSettingBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.getIteratorSetting(badSecret, tableName, "foo", IteratorScope.SCAN)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listIteratorsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.listIterators(badSecret, tableName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void removeIteratorBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.removeIterator(badSecret, tableName, |
| "name", EnumSet.allOf(IteratorScope.class))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void splitRangeByTabletsBadSharedSecret() throws Exception { |
| Range range = client.getRowRange(ByteBuffer.wrap("row".getBytes(UTF_8))); |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.splitRangeByTablets(badSecret, tableName, range, 10)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void importDirectoryBadSharedSecret() throws Exception { |
| MiniAccumuloClusterImpl cluster = SharedMiniClusterBase.getCluster(); |
| Path base = cluster.getTemporaryPath(); |
| Path importDir = new Path(base, "importDir"); |
| Path failuresDir = new Path(base, "failuresDir"); |
| assertTrue(cluster.getFileSystem().mkdirs(importDir)); |
| assertTrue(cluster.getFileSystem().mkdirs(failuresDir)); |
| assertThrows(AccumuloSecurityException.class, () -> client.importDirectory(badSecret, tableName, |
| importDir.toString(), failuresDir.toString(), true)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void pingTabletServerBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.pingTabletServer(badSecret, "fake")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void testTableClassLoadBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.testTableClassLoad(badSecret, |
| tableName, VersioningIterator.class.getName(), SortedKeyValueIterator.class.getName())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void createConditionalWriterBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.createConditionalWriter(badSecret, tableName, new ConditionalWriterOptions())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void grantNamespacePermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.grantNamespacePermission(badSecret, |
| "stooge", namespaceName, NamespacePermission.ALTER_NAMESPACE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void hasNamespacePermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.hasNamespacePermission(badSecret, |
| "stooge", namespaceName, NamespacePermission.ALTER_NAMESPACE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void revokeNamespacePermissionBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.revokeNamespacePermission(badSecret, |
| "stooge", namespaceName, NamespacePermission.ALTER_NAMESPACE)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listNamespacesBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.listNamespaces(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void namespaceExistsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.namespaceExists(badSecret, namespaceName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void createNamespaceBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.createNamespace(badSecret, "abcdef")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void deleteNamespaceBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.deleteNamespace(badSecret, namespaceName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void renameNamespaceBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.renameNamespace(badSecret, namespaceName, "abcdef")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void setNamespacePropertyBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.setNamespaceProperty(badSecret, |
| namespaceName, "table.compaction.major.ratio", "4")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void removeNamespacePropertyBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.removeNamespaceProperty(badSecret, |
| namespaceName, "table.compaction.major.ratio")); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getNamespacePropertiesBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.getNamespaceProperties(badSecret, namespaceName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void namespaceIdMapBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.namespaceIdMap(badSecret)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void attachNamespaceIteratorBadSharedSecret() { |
| IteratorSetting setting = new IteratorSetting(100, "DebugTheThings", |
| DebugIterator.class.getName(), Collections.emptyMap()); |
| assertThrows(AccumuloSecurityException.class, () -> client.attachNamespaceIterator(badSecret, |
| namespaceName, setting, EnumSet.allOf(IteratorScope.class))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void removeNamespaceIteratorBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.removeNamespaceIterator(badSecret, |
| namespaceName, "DebugTheThings", EnumSet.allOf(IteratorScope.class))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void getNamespaceIteratorSettingBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.getNamespaceIteratorSetting(badSecret, namespaceName, "DebugTheThings", |
| IteratorScope.SCAN)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listNamespaceIteratorsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.listNamespaceIterators(badSecret, namespaceName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void checkNamespaceIteratorConflictsBadSharedSecret() { |
| IteratorSetting setting = new IteratorSetting(100, "DebugTheThings", |
| DebugIterator.class.getName(), Collections.emptyMap()); |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.checkNamespaceIteratorConflicts(badSecret, namespaceName, setting, |
| EnumSet.allOf(IteratorScope.class))); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void addNamespaceConstraintBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.addNamespaceConstraint(badSecret, |
| namespaceName, MaxMutationSize.class.getName())); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void removeNamespaceConstraintBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.removeNamespaceConstraint(badSecret, namespaceName, 1)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void listNamespaceConstraintsBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, |
| () -> client.listNamespaceConstraints(badSecret, namespaceName)); |
| } |
| |
| @Test |
| @Timeout(5) |
| public void testNamespaceClassLoadBadSharedSecret() { |
| assertThrows(AccumuloSecurityException.class, () -> client.testNamespaceClassLoad(badSecret, |
| namespaceName, DebugIterator.class.getName(), SortedKeyValueIterator.class.getName())); |
| } |
| |
| @Test |
| public void tableNotFound() throws IOException { |
| final String doesNotExist = "doesNotExist"; |
| |
| final IteratorSetting setting = new IteratorSetting(100, "slow", SlowIterator.class.getName(), |
| Collections.singletonMap("sleepTime", "200")); |
| |
| final String newTableName = getUniqueNameArray(1)[0]; |
| |
| final MiniAccumuloClusterImpl cluster = SharedMiniClusterBase.getCluster(); |
| final Path base = cluster.getTemporaryPath(); |
| final Path importDir = new Path(base, "importDir"); |
| final Path failuresDir = new Path(base, "failuresDir"); |
| assertTrue(cluster.getFileSystem().mkdirs(importDir)); |
| assertTrue(cluster.getFileSystem().mkdirs(failuresDir)); |
| |
| // @formatter:off |
| Stream<Executable> cases = Stream.of( |
| () -> client.addConstraint(sharedSecret, doesNotExist, NumericValueConstraint.class.getName()), |
| () -> client.addSplits(sharedSecret, doesNotExist, Collections.emptySet()), |
| () -> client.attachIterator(sharedSecret, doesNotExist, setting, EnumSet.allOf(IteratorScope.class)), |
| () -> client.cancelCompaction(sharedSecret, doesNotExist), |
| () -> client.checkIteratorConflicts(sharedSecret, doesNotExist, setting, EnumSet.allOf(IteratorScope.class)), |
| () -> client.clearLocatorCache(sharedSecret, doesNotExist), |
| () -> client.cloneTable(sharedSecret, doesNotExist, newTableName, false, null, null), |
| () -> client.compactTable(sharedSecret, doesNotExist, null, null, null, true, false, null,null), |
| () -> client.createBatchScanner(sharedSecret, doesNotExist, new BatchScanOptions()), |
| () -> client.createScanner(sharedSecret, doesNotExist, new ScanOptions()), |
| () -> client.createWriter(sharedSecret, doesNotExist, new WriterOptions()), |
| () -> client.deleteRows(sharedSecret, doesNotExist, null, null), |
| () -> client.deleteTable(sharedSecret, doesNotExist), |
| () -> client.exportTable(sharedSecret, doesNotExist, "/tmp"), |
| () -> client.flushTable(sharedSecret, doesNotExist, null, null, false), |
| () -> client.getIteratorSetting(sharedSecret, doesNotExist, "foo", IteratorScope.SCAN), |
| () -> client.getLocalityGroups(sharedSecret, doesNotExist), |
| () -> client.getMaxRow(sharedSecret, doesNotExist, Collections.emptySet(), null, false, null, false), |
| () -> client.getTableProperties(sharedSecret, doesNotExist), |
| () -> client.grantTablePermission(sharedSecret, "root", doesNotExist, TablePermission.WRITE), |
| () -> client.hasTablePermission(sharedSecret, "root", doesNotExist, TablePermission.WRITE), |
| () -> client.importDirectory(sharedSecret, doesNotExist, importDir.toString(), failuresDir.toString(), true), |
| () -> client.listConstraints(sharedSecret, doesNotExist), |
| () -> client.listSplits(sharedSecret, doesNotExist, 10000), |
| () -> client.mergeTablets(sharedSecret, doesNotExist, null, null), |
| () -> client.offlineTable(sharedSecret, doesNotExist, false), |
| () -> client.onlineTable(sharedSecret, doesNotExist, false), |
| () -> client.removeConstraint(sharedSecret, doesNotExist, 0), |
| () -> client.removeIterator(sharedSecret, doesNotExist, "name", EnumSet.allOf(IteratorScope.class)), |
| () -> client.removeTableProperty(sharedSecret, doesNotExist, Property.TABLE_FILE_MAX.getKey()), |
| () -> client.renameTable(sharedSecret, doesNotExist, "someTableName"), |
| () -> client.revokeTablePermission(sharedSecret, "root", doesNotExist, TablePermission.ALTER_TABLE), |
| () -> client.setTableProperty(sharedSecret, doesNotExist, Property.TABLE_FILE_MAX.getKey(), "0"), |
| () -> client.splitRangeByTablets(sharedSecret, doesNotExist, client.getRowRange(ByteBuffer.wrap("row".getBytes(UTF_8))), 10), |
| () -> client.updateAndFlush(sharedSecret, doesNotExist, new HashMap<>()), |
| () -> client.getDiskUsage(sharedSecret, Collections.singleton(doesNotExist)), |
| () -> client.testTableClassLoad(sharedSecret, doesNotExist, VersioningIterator.class.getName(), SortedKeyValueIterator.class.getName()), |
| () -> client.createConditionalWriter(sharedSecret, doesNotExist, new ConditionalWriterOptions()) |
| ); |
| // @formatter:on |
| |
| cases.forEach(e -> assertThrows(TableNotFoundException.class, e)); |
| } |
| |
| @Test |
| public void namespaceNotFound() { |
| final String doesNotExist = "doesNotExist"; |
| final IteratorSetting iteratorSetting = new IteratorSetting(100, "DebugTheThings", |
| DebugIterator.class.getName(), Collections.emptyMap()); |
| |
| // @formatter:off |
| Stream<Executable> cases = Stream.of( |
| () -> client.deleteNamespace(sharedSecret, doesNotExist), |
| () -> client.renameNamespace(sharedSecret, doesNotExist, "abcdefg"), |
| () -> client.setNamespaceProperty(sharedSecret, doesNotExist, "table.compaction.major.ratio", "4"), |
| () -> client.removeNamespaceProperty(sharedSecret, doesNotExist, "table.compaction.major.ratio"), |
| () -> client.getNamespaceProperties(sharedSecret, doesNotExist), |
| () -> client.attachNamespaceIterator(sharedSecret, doesNotExist, setting, EnumSet.allOf(IteratorScope.class)), |
| () -> client.removeNamespaceIterator(sharedSecret, doesNotExist, "DebugTheThings", EnumSet.allOf(IteratorScope.class)), |
| () -> client.getNamespaceIteratorSetting(sharedSecret, doesNotExist, "DebugTheThings", IteratorScope.SCAN), |
| () -> client.listNamespaceIterators(sharedSecret, doesNotExist), |
| () -> client.checkNamespaceIteratorConflicts(sharedSecret, doesNotExist, iteratorSetting, EnumSet.allOf(IteratorScope.class)), |
| () -> client.addNamespaceConstraint(sharedSecret, doesNotExist, MaxMutationSize.class.getName()), |
| () -> client.removeNamespaceConstraint(sharedSecret, doesNotExist, 1), |
| () -> client.listNamespaceConstraints(sharedSecret, doesNotExist), |
| () -> client.testNamespaceClassLoad(sharedSecret, doesNotExist, DebugIterator.class.getName(), SortedKeyValueIterator.class.getName()) |
| ); |
| // @formatter:on |
| |
| cases.forEach(executable -> assertThrows(NamespaceNotFoundException.class, executable)); |
| } |
| |
| @Test |
| public void testExists() throws TException { |
| final String table1 = "ett1"; |
| final String table2 = "ett2"; |
| |
| client.createTable(sharedSecret, table1, false, TimeType.MILLIS); |
| client.createTable(sharedSecret, table2, false, TimeType.MILLIS); |
| |
| // @formatter:off |
| Stream<Executable> cases = Stream.of( |
| () -> client.createTable(sharedSecret, table1, false, TimeType.MILLIS), |
| () -> client.renameTable(sharedSecret, table1, table2), |
| () -> client.cloneTable(sharedSecret, table1, table2, false, new HashMap<>(), new HashSet<>()) |
| ); |
| // @formatter:on |
| |
| cases.forEach(executable -> assertThrows(TableExistsException.class, executable)); |
| } |
| |
| @Test |
| public void testNamespaceExists() throws TException { |
| client.createNamespace(sharedSecret, "foobar"); |
| |
| // @formatter:off |
| Stream<Executable> cases = Stream.of( |
| () -> client.createNamespace(sharedSecret, namespaceName), |
| () -> client.renameNamespace(sharedSecret, "foobar", namespaceName) |
| ); |
| // @formatter:on |
| |
| cases.forEach(executable -> assertThrows(NamespaceExistsException.class, executable)); |
| } |
| |
| @Test |
| public void testNamespaceNotEmpty() throws Exception { |
| final String tableInNamespace = namespaceName + ".abcdefg"; |
| client.createTable(sharedSecret, tableInNamespace, true, TimeType.MILLIS); |
| |
| assertThrows(NamespaceNotEmptyException.class, |
| () -> client.deleteNamespace(sharedSecret, namespaceName)); |
| |
| // delete table so namespace can also be deleted |
| client.deleteTable(sharedSecret, tableInNamespace); |
| } |
| |
| @Test |
| public void testUnknownScanner() throws TException { |
| String scanner = client.createScanner(sharedSecret, tableName, null); |
| assertFalse(client.hasNext(scanner)); |
| client.closeScanner(scanner); |
| |
| // @formatter:off |
| Stream<Executable> cases = Stream.of( |
| () -> client.hasNext(scanner), |
| () -> client.closeScanner(scanner), |
| () -> client.nextEntry("99999999"), |
| () -> client.nextK("99999999", 6), |
| () -> client.hasNext("99999999"), |
| () -> client.hasNext(UUID.randomUUID().toString()) |
| ); |
| // @formatter:on |
| |
| cases.forEach(executable -> assertThrows(UnknownScanner.class, executable)); |
| } |
| |
| @Test |
| public void testUnknownWriter() throws TException { |
| String writer = client.createWriter(sharedSecret, tableName, null); |
| client.update(writer, mutation("row0", "cf", "cq", "value")); |
| client.flush(writer); |
| client.update(writer, mutation("row2", "cf", "cq", "value2")); |
| client.closeWriter(writer); |
| |
| // this is a oneway call, so it does not throw exceptions |
| client.update(writer, mutation("row2", "cf", "cq", "value2")); |
| |
| // @formatter:off |
| Stream<Executable> cases = Stream.of( |
| () -> client.flush(writer), |
| () -> client.flush("99999"), |
| () -> client.flush(UUID.randomUUID().toString()), |
| () -> client.closeWriter("99999") |
| ); |
| // @formatter:on |
| |
| cases.forEach(executable -> assertThrows(UnknownWriter.class, executable)); |
| } |
| |
| @Test |
| public void testDelete() throws Exception { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row0", "cf", "cq", "value")); |
| |
| assertScan(new String[][] {{"row0", "cf", "cq", "value"}}, tableName); |
| |
| ColumnUpdate upd = new ColumnUpdate(s2bb("cf"), s2bb("cq")); |
| upd.setDeleteCell(false); |
| Map<ByteBuffer,List<ColumnUpdate>> notDelete = |
| Collections.singletonMap(s2bb("row0"), Collections.singletonList(upd)); |
| client.updateAndFlush(sharedSecret, tableName, notDelete); |
| String scanner = client.createScanner(sharedSecret, tableName, null); |
| ScanResult entries = client.nextK(scanner, 10); |
| client.closeScanner(scanner); |
| assertFalse(entries.more); |
| assertEquals(1, entries.results.size(), "Results: " + entries.results); |
| |
| upd = new ColumnUpdate(s2bb("cf"), s2bb("cq")); |
| upd.setDeleteCell(true); |
| Map<ByteBuffer,List<ColumnUpdate>> delete = |
| Collections.singletonMap(s2bb("row0"), Collections.singletonList(upd)); |
| |
| client.updateAndFlush(sharedSecret, tableName, delete); |
| |
| assertScan(new String[][] {}, tableName); |
| } |
| |
| @Test |
| public void testSystemProperties() throws Exception { |
| Map<String,String> cfg = client.getSiteConfiguration(sharedSecret); |
| |
| // set generic property |
| client.setProperty(sharedSecret, "general.custom.test.systemprop", "whistletips"); |
| assertEquals(proxyClient.proxy().getSystemConfiguration(sharedSecret) |
| .get("general.custom.test.systemprop"), "whistletips"); |
| client.removeProperty(sharedSecret, "general.custom.test.systemprop"); |
| assertNull(client.getSystemConfiguration(sharedSecret).get("general.custom.test.systemprop")); |
| |
| // set a property in zookeeper |
| client.setProperty(sharedSecret, "table.split.threshold", "500M"); |
| |
| // check that we can read it |
| for (int i = 0; i < 5; i++) { |
| cfg = client.getSystemConfiguration(sharedSecret); |
| if ("500M".equals(cfg.get("table.split.threshold"))) { |
| break; |
| } |
| sleepUninterruptibly(200, TimeUnit.MILLISECONDS); |
| } |
| assertEquals("500M", cfg.get("table.split.threshold")); |
| |
| // unset the setting, check that it's not what it was |
| client.removeProperty(sharedSecret, "table.split.threshold"); |
| for (int i = 0; i < 5; i++) { |
| cfg = client.getSystemConfiguration(sharedSecret); |
| if (!"500M".equals(cfg.get("table.split.threshold"))) { |
| break; |
| } |
| sleepUninterruptibly(200, TimeUnit.MILLISECONDS); |
| } |
| assertNotEquals("500M", cfg.get("table.split.threshold")); |
| } |
| |
| @Test |
| public void pingTabletServers() throws Exception { |
| int tservers = 0; |
| for (String tserver : client.getTabletServers(sharedSecret)) { |
| client.pingTabletServer(sharedSecret, tserver); |
| tservers++; |
| } |
| assertTrue(tservers > 0); |
| } |
| |
| @Test |
| public void testSiteConfiguration() throws Exception { |
| // get something we know is in the site config |
| MiniAccumuloClusterImpl cluster = SharedMiniClusterBase.getCluster(); |
| Map<String,String> cfg = client.getSiteConfiguration(sharedSecret); |
| assertEquals(new File(new URI(cfg.get("instance.volumes"))).getCanonicalPath(), |
| cluster.getConfig().getAccumuloDir().getCanonicalPath()); |
| } |
| |
| @Test |
| public void testClassLoad() throws Exception { |
| // try to load some classes via the proxy |
| assertTrue(client.testClassLoad(sharedSecret, DevNull.class.getName(), |
| SortedKeyValueIterator.class.getName())); |
| assertFalse( |
| client.testClassLoad(sharedSecret, "foo.bar", SortedKeyValueIterator.class.getName())); |
| } |
| |
| @Test |
| public void attachIteratorsWithScans() throws Exception { |
| if (client.tableExists(sharedSecret, "slow")) { |
| client.deleteTable(sharedSecret, "slow"); |
| } |
| |
| // create a table that's very slow, so we can look for scans |
| client.createTable(sharedSecret, "slow", true, TimeType.MILLIS); |
| IteratorSetting setting = new IteratorSetting(100, "slow", SlowIterator.class.getName(), |
| Collections.singletonMap("sleepTime", "250")); |
| client.attachIterator(sharedSecret, "slow", setting, EnumSet.allOf(IteratorScope.class)); |
| |
| // Should take 10 seconds to read every record |
| for (int i = 0; i < 40; i++) { |
| client.updateAndFlush(sharedSecret, "slow", mutation("row" + i, "cf", "cq", "value")); |
| } |
| |
| // scan |
| Thread t = new Thread(() -> { |
| try (TestProxyClient proxyClient2 = new TestProxyClient(hostname, proxyPort, factory)) { |
| Client client2 = proxyClient2.proxy(); |
| String scanner = client2.createScanner(sharedSecret, "slow", null); |
| client2.nextK(scanner, 10); |
| client2.closeScanner(scanner); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| }); |
| t.start(); |
| |
| // look for the scan many times |
| Optional<ActiveScan> scanFromClient = Optional.empty(); |
| for (int i = 0; i < 100 && scanFromClient.isEmpty(); i++) { |
| for (String tserver : client.getTabletServers(sharedSecret)) { |
| scanFromClient = client.getActiveScans(sharedSecret, tserver).stream() |
| .filter(scan -> clientPrincipal.equals(scan.getUser())).findAny(); |
| |
| if (scanFromClient.isPresent()) { |
| break; |
| } |
| } |
| sleepUninterruptibly(100, TimeUnit.MILLISECONDS); |
| } |
| t.join(); |
| |
| assertTrue(scanFromClient.isPresent(), "Could not find any scan matching the client principal"); |
| |
| ActiveScan scan = |
| scanFromClient.orElseThrow(() -> new IllegalArgumentException("ActiveScan is missing")); |
| |
| assertTrue( |
| ScanState.RUNNING.equals(scan.getState()) || ScanState.QUEUED.equals(scan.getState())); |
| assertEquals(ScanType.SINGLE, scan.getType()); |
| assertEquals("slow", scan.getTable()); |
| |
| assertEquals(client.tableIdMap(sharedSecret).get("slow"), scan.getExtent().tableId); |
| assertNull(scan.getExtent().endRow); |
| assertNull(scan.getExtent().prevEndRow); |
| } |
| |
| @Test |
| public void attachIteratorWithCompactions() throws Exception { |
| if (client.tableExists(sharedSecret, "slow")) { |
| client.deleteTable(sharedSecret, "slow"); |
| } |
| |
| // create a table that's very slow, so we can look for compactions |
| client.createTable(sharedSecret, "slow", true, TimeType.MILLIS); |
| IteratorSetting setting = new IteratorSetting(100, "slow", SlowIterator.class.getName(), |
| Collections.singletonMap("sleepTime", "250")); |
| client.attachIterator(sharedSecret, "slow", setting, EnumSet.allOf(IteratorScope.class)); |
| |
| // Should take 10 seconds to read every record |
| for (int i = 0; i < 40; i++) { |
| client.updateAndFlush(sharedSecret, "slow", mutation("row" + i, "cf", "cq", "value")); |
| } |
| |
| Map<String,String> map = client.tableIdMap(sharedSecret); |
| |
| // start a compaction |
| Thread t = new Thread(() -> { |
| try (TestProxyClient proxyClient2 = new TestProxyClient(hostname, proxyPort, factory)) { |
| Client client2 = proxyClient2.proxy(); |
| client2.compactTable(sharedSecret, "slow", null, null, null, true, true, null, null); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| }); |
| t.start(); |
| |
| final String desiredTableId = map.get("slow"); |
| |
| // Make sure we can find the slow table |
| assertNotNull(desiredTableId); |
| |
| // try to catch it in the act |
| List<ActiveCompaction> compactions = new ArrayList<>(); |
| for (int i = 0; i < 100 && compactions.isEmpty(); i++) { |
| // Iterate over the tservers |
| for (String tserver : client.getTabletServers(sharedSecret)) { |
| // And get the compactions on each |
| List<ActiveCompaction> compactionsOnServer = |
| client.getActiveCompactions(sharedSecret, tserver); |
| for (ActiveCompaction compact : compactionsOnServer) { |
| // There might be other compactions occurring (e.g. on METADATA) in which |
| // case we want to prune out those that aren't for our slow table |
| if (desiredTableId.equals(compact.getExtent().tableId)) { |
| compactions.add(compact); |
| } |
| } |
| |
| // If we found a compaction for the table we wanted, so we can stop looking |
| if (!compactions.isEmpty()) { |
| break; |
| } |
| } |
| sleepUninterruptibly(10, TimeUnit.MILLISECONDS); |
| } |
| t.join(); |
| |
| // verify the compaction information |
| assertFalse(compactions.isEmpty()); |
| for (ActiveCompaction c : compactions) { |
| if (desiredTableId.equals(c.getExtent().tableId)) { |
| assertTrue(c.inputFiles.isEmpty()); |
| assertEquals(CompactionType.MINOR, c.getType()); |
| assertEquals(CompactionReason.USER, c.getReason()); |
| assertEquals("", c.localityGroup); |
| assertTrue(c.outputFile.contains("default_tablet")); |
| |
| return; |
| } |
| } |
| |
| fail("Expection to find running compaction for table 'slow' but did not find one"); |
| } |
| |
| @Test |
| public void userAuthentication() throws Exception { |
| // check password |
| assertTrue(client.authenticateUser(sharedSecret, "root", |
| s2pp(SharedMiniClusterBase.getRootPassword()))); |
| assertFalse(client.authenticateUser(sharedSecret, "otheruser", s2pp(""))); |
| } |
| |
| @Test |
| public void userManagement() throws Exception { |
| |
| String user = getUniqueNameArray(1)[0]; |
| ByteBuffer password = s2bb("password"); |
| |
| // create a user |
| client.createLocalUser(sharedSecret, user, password); |
| // change auths |
| Set<String> users = client.listLocalUsers(sharedSecret); |
| Set<String> expectedUsers = Set.of(clientPrincipal, user); |
| assertTrue(users.containsAll(expectedUsers), |
| "Did not find all expected users: " + expectedUsers); |
| Set<ByteBuffer> auths = Set.of(s2bb("A"), s2bb("B")); |
| client.changeUserAuthorizations(sharedSecret, user, auths); |
| List<ByteBuffer> update = client.getUserAuthorizations(sharedSecret, user); |
| assertEquals(auths, new HashSet<>(update)); |
| |
| client.dropLocalUser(sharedSecret, user); |
| } |
| |
| @Test |
| public void createAndDropUser() throws Exception { |
| |
| Set<String> expectedUsers = new HashSet<>(); |
| |
| expectedUsers.add(clientPrincipal); |
| |
| assertEquals(expectedUsers, client.listLocalUsers(sharedSecret)); |
| |
| final String newUser = "user" + getUniqueNameArray(1)[0]; |
| |
| expectedUsers.add(newUser); |
| client.createLocalUser(sharedSecret, newUser, s2bb("password")); |
| |
| assertEquals(expectedUsers, client.listLocalUsers(sharedSecret)); |
| |
| expectedUsers.remove(newUser); |
| client.dropLocalUser(sharedSecret, newUser); |
| |
| assertEquals(expectedUsers, client.listLocalUsers(sharedSecret)); |
| } |
| |
| @Test |
| public void tablePermissions() throws Exception { |
| |
| final String newUser = "user" + getUniqueNameArray(1)[0]; |
| client.createLocalUser(sharedSecret, newUser, s2bb("password")); |
| |
| final TablePermission[] tablePermissions = TablePermission.values(); |
| |
| for (TablePermission tablePermission : tablePermissions) { |
| |
| // make sure user doesn't have table permission |
| assertFalse(client.hasTablePermission(sharedSecret, newUser, tableName, tablePermission), |
| "A newly created user should not have any permissions, but has " + tablePermission); |
| |
| // grant table permission |
| client.grantTablePermission(sharedSecret, newUser, tableName, tablePermission); |
| |
| // assert user has table permission |
| assertTrue(client.hasTablePermission(sharedSecret, newUser, tableName, tablePermission), |
| "The user was granted, and should have " + tablePermission); |
| |
| // revoke table permission |
| client.revokeTablePermission(sharedSecret, newUser, tableName, tablePermission); |
| |
| // assert table permission has been revoked |
| assertFalse(client.hasTablePermission(sharedSecret, newUser, tableName, tablePermission), |
| "The users permissions have been revoked. Should NOT have " + tablePermission); |
| } |
| |
| client.dropLocalUser(sharedSecret, newUser); |
| |
| } |
| |
| @Test |
| public void namespacePermissions() throws Exception { |
| |
| final String newUser = "user" + getUniqueNameArray(1)[0]; |
| client.createLocalUser(sharedSecret, newUser, s2bb("password")); |
| |
| final NamespacePermission[] namespacePermissions = NamespacePermission.values(); |
| |
| for (NamespacePermission namespacePermission : namespacePermissions) { |
| |
| // make sure user doesn't have namespace permission |
| assertFalse( |
| client.hasNamespacePermission(sharedSecret, newUser, namespaceName, namespacePermission), |
| "A newly created user should not have any permissions, but has " + namespacePermission); |
| |
| // grant namespace permission |
| client.grantNamespacePermission(sharedSecret, newUser, namespaceName, namespacePermission); |
| |
| // assert user has namespace permission |
| assertTrue( |
| client.hasNamespacePermission(sharedSecret, newUser, namespaceName, namespacePermission), |
| "The user was granted, and should have " + namespacePermission); |
| |
| // revoke namespace permission |
| client.revokeNamespacePermission(sharedSecret, newUser, namespaceName, namespacePermission); |
| |
| // assert namespace permission has been revoked |
| assertFalse( |
| client.hasNamespacePermission(sharedSecret, newUser, namespaceName, namespacePermission), |
| "The users permissions have been revoked. Should NOT have " + namespacePermission); |
| } |
| |
| client.dropLocalUser(sharedSecret, newUser); |
| |
| } |
| |
| @Test |
| public void systemPermissions() throws Exception { |
| |
| final String newUser = "user" + getUniqueNameArray(1)[0]; |
| client.createLocalUser(sharedSecret, newUser, s2bb("password")); |
| |
| final SystemPermission[] systemPermissions = SystemPermission.values(); |
| |
| for (SystemPermission systemPermission : systemPermissions) { |
| |
| // make sure user doesn't have system permission |
| assertFalse(client.hasSystemPermission(sharedSecret, newUser, systemPermission), |
| "A newly created user should not have any permissions, but has " + systemPermission); |
| |
| // grant system permission |
| client.grantSystemPermission(sharedSecret, newUser, systemPermission); |
| |
| // assert user has system permission |
| assertTrue(client.hasSystemPermission(sharedSecret, newUser, systemPermission), |
| "The user was granted, and should have " + systemPermission); |
| |
| // revoke system permission |
| client.revokeSystemPermission(sharedSecret, newUser, systemPermission); |
| |
| // assert system permission has been revoked |
| assertFalse(client.hasSystemPermission(sharedSecret, newUser, systemPermission), |
| "The users permissions have been revoked. Should NOT have " + systemPermission); |
| } |
| |
| client.dropLocalUser(sharedSecret, newUser); |
| |
| } |
| |
| @Test |
| public void testBatchWriter() throws Exception { |
| client.addConstraint(sharedSecret, tableName, NumericValueConstraint.class.getName()); |
| // zookeeper propagation time |
| sleepUninterruptibly(ZOOKEEPER_PROPAGATION_TIME, TimeUnit.MILLISECONDS); |
| |
| // Take the table offline and online to force a config update |
| client.offlineTable(sharedSecret, tableName, true); |
| client.onlineTable(sharedSecret, tableName, true); |
| |
| WriterOptions writerOptions = new WriterOptions(); |
| writerOptions.setLatencyMs(10000); |
| writerOptions.setMaxMemory(2); |
| writerOptions.setThreads(1); |
| writerOptions.setTimeoutMs(100000); |
| |
| assertNumericValueConstraintIsPresent(); |
| |
| boolean success = false; |
| for (int i = 0; i < 15; i++) { |
| String batchWriter = client.createWriter(sharedSecret, tableName, writerOptions); |
| client.update(batchWriter, mutation("row1", "cf", "cq", "x")); |
| client.update(batchWriter, mutation("row1", "cf", "cq", "x")); |
| try { |
| client.flush(batchWriter); |
| log.debug("Constraint failed to fire. Waiting and retrying"); |
| Thread.sleep(5000); |
| continue; |
| } catch (MutationsRejectedException ex) {} |
| try { |
| client.closeWriter(batchWriter); |
| log.debug("Constraint failed to fire. Waiting and retrying"); |
| Thread.sleep(5000); |
| continue; |
| } catch (MutationsRejectedException e) {} |
| success = true; |
| break; |
| } |
| |
| if (!success) { |
| fail("constraint did not fire"); |
| } |
| |
| client.removeConstraint(sharedSecret, tableName, 2); |
| |
| // Take the table offline and online to force a config update |
| client.offlineTable(sharedSecret, tableName, true); |
| client.onlineTable(sharedSecret, tableName, true); |
| |
| assertNumericValueConstraintIsAbsent(); |
| |
| assertScan(new String[][] {}, tableName); |
| |
| sleepUninterruptibly(ZOOKEEPER_PROPAGATION_TIME, TimeUnit.MILLISECONDS); |
| |
| writerOptions = new WriterOptions(); |
| writerOptions.setLatencyMs(10000); |
| writerOptions.setMaxMemory(3000); |
| writerOptions.setThreads(1); |
| writerOptions.setTimeoutMs(100000); |
| |
| success = false; |
| for (int i = 0; i < 15; i++) { |
| try { |
| String batchWriter = client.createWriter(sharedSecret, tableName, writerOptions); |
| |
| client.update(batchWriter, mutation("row1", "cf", "cq", "x")); |
| client.flush(batchWriter); |
| client.closeWriter(batchWriter); |
| success = true; |
| break; |
| } catch (MutationsRejectedException e) { |
| log.info("Mutations were rejected, assuming constraint is still active", e); |
| Thread.sleep(5000); |
| } |
| } |
| |
| if (!success) { |
| fail("Failed to successfully write data after constraint was removed"); |
| } |
| |
| assertScan(new String[][] {{"row1", "cf", "cq", "x"}}, tableName); |
| |
| client.deleteTable(sharedSecret, tableName); |
| } |
| |
| @Test |
| public void testTableConstraints() throws Exception { |
| log.debug("Setting NumericValueConstraint on table {}", tableName); |
| |
| // constraints |
| client.addConstraint(sharedSecret, tableName, NumericValueConstraint.class.getName()); |
| |
| // zookeeper propagation time |
| Thread.sleep(ZOOKEEPER_PROPAGATION_TIME); |
| |
| // Take the table offline and online to force a config update |
| client.offlineTable(sharedSecret, tableName, true); |
| client.onlineTable(sharedSecret, tableName, true); |
| |
| log.debug("Attempting to verify client-side that constraints are observed"); |
| |
| assertNumericValueConstraintIsPresent(); |
| |
| assertEquals(2, client.listConstraints(sharedSecret, tableName).size()); |
| log.debug("Verified client-side that constraints exist"); |
| |
| // Write data that satisfies the constraint |
| client.updateAndFlush(sharedSecret, tableName, mutation("row1", "cf", "cq", "123")); |
| |
| log.debug("Successfully wrote data that satisfies the constraint"); |
| log.debug("Trying to write data that the constraint should reject"); |
| |
| // Expect failure on data that fails the constraint |
| while (true) { |
| try { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row1", "cf", "cq", "x")); |
| log.debug("Expected mutation to be rejected, but was not. Waiting and retrying"); |
| Thread.sleep(5000); |
| } catch (MutationsRejectedException ex) { |
| break; |
| } |
| } |
| |
| log.debug("Saw expected failure on data which fails the constraint"); |
| |
| log.debug("Removing constraint from table"); |
| client.removeConstraint(sharedSecret, tableName, 2); |
| |
| sleepUninterruptibly(ZOOKEEPER_PROPAGATION_TIME, TimeUnit.MILLISECONDS); |
| |
| // Take the table offline and online to force a config update |
| client.offlineTable(sharedSecret, tableName, true); |
| client.onlineTable(sharedSecret, tableName, true); |
| |
| assertNumericValueConstraintIsAbsent(); |
| |
| assertEquals(1, client.listConstraints(sharedSecret, tableName).size()); |
| log.debug("Verified client-side that the constraint was removed"); |
| |
| log.debug("Attempting to write mutation that should succeed after constraints was removed"); |
| // Make sure we can write the data after we removed the constraint |
| while (true) { |
| try { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row1", "cf", "cq", "x")); |
| break; |
| } catch (MutationsRejectedException ex) { |
| log.debug("Expected mutation accepted, but was not. Waiting and retrying"); |
| Thread.sleep(5000); |
| } |
| } |
| |
| log.debug("Verifying that record can be read from the table"); |
| assertScan(new String[][] {{"row1", "cf", "cq", "x"}}, tableName); |
| } |
| |
| @Test |
| public void tableMergesAndSplits() throws Exception { |
| // add some splits |
| client.addSplits(sharedSecret, tableName, |
| new HashSet<>(List.of(s2bb("a"), s2bb("m"), s2bb("z")))); |
| List<ByteBuffer> splits = client.listSplits(sharedSecret, tableName, 1); |
| assertEquals(List.of(s2bb("m")), splits); |
| |
| // Merge some of the splits away |
| client.mergeTablets(sharedSecret, tableName, null, s2bb("m")); |
| splits = client.listSplits(sharedSecret, tableName, 10); |
| assertEquals(List.of(s2bb("m"), s2bb("z")), splits); |
| |
| // Merge the entire table |
| client.mergeTablets(sharedSecret, tableName, null, null); |
| splits = client.listSplits(sharedSecret, tableName, 10); |
| List<ByteBuffer> empty = Collections.emptyList(); |
| |
| // No splits after merge on whole table |
| assertEquals(empty, splits); |
| } |
| |
| @Test |
| public void iteratorFunctionality() throws Exception { |
| // iterators |
| HashMap<String,String> options = new HashMap<>(); |
| options.put("type", "STRING"); |
| options.put("columns", "cf"); |
| IteratorSetting setting = |
| new IteratorSetting(10, tableName, SummingCombiner.class.getName(), options); |
| client.attachIterator(sharedSecret, tableName, setting, EnumSet.allOf(IteratorScope.class)); |
| for (int i = 0; i < 10; i++) { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row1", "cf", "cq", "1")); |
| } |
| // 10 updates of "1" in the value w/ SummingCombiner should return value of "10" |
| assertScan(new String[][] {{"row1", "cf", "cq", "10"}}, tableName); |
| |
| assertThrows(Exception.class, () -> client.checkIteratorConflicts(sharedSecret, tableName, |
| setting, EnumSet.allOf(IteratorScope.class))); |
| |
| client.deleteRows(sharedSecret, tableName, null, null); |
| client.removeIterator(sharedSecret, tableName, "test", EnumSet.allOf(IteratorScope.class)); |
| String[][] expected = new String[10][]; |
| for (int i = 0; i < 10; i++) { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row" + i, "cf", "cq", "" + i)); |
| expected[i] = new String[] {"row" + i, "cf", "cq", "" + i}; |
| client.flushTable(sharedSecret, tableName, null, null, true); |
| } |
| assertScan(expected, tableName); |
| } |
| |
| @Test |
| public void cloneTable() throws Exception { |
| String TABLE_TEST2 = getUniqueNameArray(2)[1]; |
| |
| String[][] expected = new String[10][]; |
| for (int i = 0; i < 10; i++) { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row" + i, "cf", "cq", "" + i)); |
| expected[i] = new String[] {"row" + i, "cf", "cq", "" + i}; |
| client.flushTable(sharedSecret, tableName, null, null, true); |
| } |
| assertScan(expected, tableName); |
| |
| // clone |
| client.cloneTable(sharedSecret, tableName, TABLE_TEST2, true, null, null); |
| assertScan(expected, TABLE_TEST2); |
| client.deleteTable(sharedSecret, TABLE_TEST2); |
| } |
| |
| @Test |
| public void clearLocatorCache() throws Exception { |
| // don't know how to test this, call it just for fun |
| client.clearLocatorCache(sharedSecret, tableName); |
| } |
| |
| @Test |
| public void compactTable() throws Exception { |
| String[][] expected = new String[10][]; |
| for (int i = 0; i < 10; i++) { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row" + i, "cf", "cq", "" + i)); |
| expected[i] = new String[] {"row" + i, "cf", "cq", "" + i}; |
| client.flushTable(sharedSecret, tableName, null, null, true); |
| } |
| assertScan(expected, tableName); |
| |
| // compact |
| client.compactTable(sharedSecret, tableName, null, null, null, true, true, null, null); |
| assertEquals(1, countFiles(tableName)); |
| assertScan(expected, tableName); |
| } |
| |
| @Test |
| public void diskUsage() throws Exception { |
| String TABLE_TEST2 = getUniqueNameArray(2)[1]; |
| |
| // Write some data |
| String[][] expected = new String[10][]; |
| for (int i = 0; i < 10; i++) { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row" + i, "cf", "cq", "" + i)); |
| expected[i] = new String[] {"row" + i, "cf", "cq", "" + i}; |
| client.flushTable(sharedSecret, tableName, null, null, true); |
| } |
| assertScan(expected, tableName); |
| |
| // compact |
| client.compactTable(sharedSecret, tableName, null, null, null, true, true, null, null); |
| assertEquals(1, countFiles(tableName)); |
| assertScan(expected, tableName); |
| |
| // Clone the table |
| client.cloneTable(sharedSecret, tableName, TABLE_TEST2, true, null, null); |
| Set<String> tablesToScan = new HashSet<>(); |
| tablesToScan.add(tableName); |
| tablesToScan.add(TABLE_TEST2); |
| tablesToScan.add("foo"); |
| |
| client.createTable(sharedSecret, "foo", true, TimeType.MILLIS); |
| |
| // get disk usage |
| List<DiskUsage> diskUsage = (client.getDiskUsage(sharedSecret, tablesToScan)); |
| assertEquals(2, diskUsage.size()); |
| // The original table and the clone are lumped together (they share the same files) |
| assertEquals(2, diskUsage.get(0).getTables().size()); |
| // The empty table we created |
| assertEquals(1, diskUsage.get(1).getTables().size()); |
| |
| // Compact the clone so it writes its own files instead of referring to the original |
| client.compactTable(sharedSecret, TABLE_TEST2, null, null, null, true, true, null, null); |
| |
| diskUsage = (client.getDiskUsage(sharedSecret, tablesToScan)); |
| assertEquals(3, diskUsage.size()); |
| // The original |
| assertEquals(1, diskUsage.get(0).getTables().size()); |
| // The clone w/ its own files now |
| assertEquals(1, diskUsage.get(1).getTables().size()); |
| // The empty table |
| assertEquals(1, diskUsage.get(2).getTables().size()); |
| client.deleteTable(sharedSecret, "foo"); |
| client.deleteTable(sharedSecret, TABLE_TEST2); |
| } |
| |
| @Test |
| public void importExportTable() throws Exception { |
| // Write some data |
| String[][] expected = new String[10][]; |
| for (int i = 0; i < 10; i++) { |
| client.updateAndFlush(sharedSecret, tableName, mutation("row" + i, "cf", "cq", "" + i)); |
| expected[i] = new String[] {"row" + i, "cf", "cq", "" + i}; |
| client.flushTable(sharedSecret, tableName, null, null, true); |
| } |
| assertScan(expected, tableName); |
| |
| // export/import |
| MiniAccumuloClusterImpl cluster = SharedMiniClusterBase.getCluster(); |
| FileSystem fs = cluster.getFileSystem(); |
| Path base = cluster.getTemporaryPath(); |
| Path dir = new Path(base, "test"); |
| assertTrue(fs.mkdirs(dir)); |
| Path destDir = new Path(base, "test_dest"); |
| assertTrue(fs.mkdirs(destDir)); |
| client.offlineTable(sharedSecret, tableName, false); |
| client.exportTable(sharedSecret, tableName, dir.toString()); |
| // copy files to a new location |
| Path f = new Path(dir, "distcp.txt"); |
| try (FSDataInputStream is = fs.open(f); |
| InputStreamReader isr = new InputStreamReader(is, UTF_8); |
| BufferedReader r = new BufferedReader(isr)) { |
| while (true) { |
| String line = r.readLine(); |
| if (line == null) { |
| break; |
| } |
| Path srcPath = new Path(line); |
| FileUtil.copy(fs, srcPath, fs, destDir, false, fs.getConf()); |
| } |
| } |
| client.deleteTable(sharedSecret, tableName); |
| client.importTable(sharedSecret, "testify", destDir.toString()); |
| assertScan(expected, "testify"); |
| client.deleteTable(sharedSecret, "testify"); |
| |
| assertThrows(org.apache.accumulo.proxy.thrift.AccumuloException.class, |
| () -> client.importTable(sharedSecret, "testify2", destDir.toString())); |
| |
| assertFalse(client.listTables(sharedSecret).contains("testify2")); |
| } |
| |
| @Test |
| public void localityGroups() throws Exception { |
| Map<String,Set<String>> groups = new HashMap<>(); |
| groups.put("group1", Collections.singleton("cf1")); |
| groups.put("group2", Collections.singleton("cf2")); |
| client.setLocalityGroups(sharedSecret, tableName, groups); |
| assertEquals(groups, client.getLocalityGroups(sharedSecret, tableName)); |
| } |
| |
| @Test |
| public void tableProperties() throws Exception { |
| Map<String,String> systemProps = client.getSystemConfiguration(sharedSecret); |
| String systemTableSplitThreshold = systemProps.get("table.split.threshold"); |
| |
| Map<String,String> orig = client.getTableProperties(sharedSecret, tableName); |
| client.setTableProperty(sharedSecret, tableName, "table.split.threshold", "500M"); |
| |
| // Get the new table property value |
| Map<String,String> update = client.getTableProperties(sharedSecret, tableName); |
| assertEquals(update.get("table.split.threshold"), "500M"); |
| |
| // Table level properties shouldn't affect system level values |
| assertEquals(systemTableSplitThreshold, |
| client.getSystemConfiguration(sharedSecret).get("table.split.threshold")); |
| |
| client.removeTableProperty(sharedSecret, tableName, "table.split.threshold"); |
| update = client.getTableProperties(sharedSecret, tableName); |
| |
| var difference = Sets.symmetricDifference(orig.entrySet(), update.entrySet()); |
| |
| assertTrue(difference.isEmpty(), |
| "Properties should have been the same. Found difference: " + difference); |
| } |
| |
| @Test |
| public void tableRenames() throws Exception { |
| final String newTableName = "bar"; |
| |
| Map<String,String> tableIds = client.tableIdMap(sharedSecret); |
| final String originalTableID = tableIds.get(tableName); |
| |
| client.renameTable(sharedSecret, tableName, newTableName); |
| |
| tableIds = client.tableIdMap(sharedSecret); |
| final String newTableID = tableIds.get(newTableName); |
| |
| assertEquals(originalTableID, newTableID, |
| "Table ID should be the same before and after the table has been renamed"); |
| |
| assertTrue(client.tableExists(sharedSecret, newTableName), |
| "Expected to find table with new name"); |
| assertFalse(client.tableExists(sharedSecret, tableName), |
| "Did not expect to find table with original name"); |
| |
| client.deleteTable(sharedSecret, newTableName); |
| } |
| |
| @Test |
| public void bulkImport() throws Exception { |
| MiniAccumuloClusterImpl cluster = SharedMiniClusterBase.getCluster(); |
| FileSystem fs = cluster.getFileSystem(); |
| Path base = cluster.getTemporaryPath(); |
| Path dir = new Path(base, "test"); |
| assertTrue(fs.mkdirs(dir)); |
| |
| // Write an RFile |
| String filename = dir + "/bulk/import/rfile.rf"; |
| try (FileSKVWriter writer = FileOperations.getInstance().newWriterBuilder() |
| .forFile(filename, fs, fs.getConf(), NoCryptoServiceFactory.NONE) |
| .withTableConfiguration(DefaultConfiguration.getInstance()).build()) { |
| writer.startDefaultLocalityGroup(); |
| writer.append( |
| new org.apache.accumulo.core.data.Key(new Text("a"), new Text("b"), new Text("c")), |
| new Value("value".getBytes(UTF_8))); |
| } |
| |
| // Create failures directory |
| fs.mkdirs(new Path(dir + "/bulk/fail")); |
| |
| // Run the bulk import |
| client.importDirectory(sharedSecret, tableName, dir + "/bulk/import", dir + "/bulk/fail", true); |
| |
| // Make sure we find the data |
| String scanner = client.createScanner(sharedSecret, tableName, null); |
| ScanResult more = client.nextK(scanner, 100); |
| client.closeScanner(scanner); |
| assertEquals(1, more.results.size()); |
| ByteBuffer maxRow = client.getMaxRow(sharedSecret, tableName, null, null, false, null, false); |
| assertEquals(s2bb("a"), maxRow); |
| } |
| |
| @Test |
| public void testTableClassLoad() throws Exception { |
| assertFalse(client.testTableClassLoad(sharedSecret, tableName, "abc123", |
| SortedKeyValueIterator.class.getName())); |
| assertTrue(client.testTableClassLoad(sharedSecret, tableName, |
| VersioningIterator.class.getName(), SortedKeyValueIterator.class.getName())); |
| } |
| |
| private Condition newCondition(String cf, String cq) { |
| return new Condition(new Column(s2bb(cf), s2bb(cq), s2bb(""))); |
| } |
| |
| private Condition newCondition(String cf, String cq, String val) { |
| return newCondition(cf, cq).setValue(s2bb(val)); |
| } |
| |
| private Condition newCondition(String cf, String cq, long ts, String val) { |
| return newCondition(cf, cq).setValue(s2bb(val)).setTimestamp(ts); |
| } |
| |
| private ColumnUpdate newColUpdate(String cf, String cq, String val) { |
| return new ColumnUpdate(s2bb(cf), s2bb(cq)).setValue(s2bb(val)); |
| } |
| |
| private ColumnUpdate newColUpdate(String cf, String cq, long ts, String val) { |
| return new ColumnUpdate(s2bb(cf), s2bb(cq)).setTimestamp(ts).setValue(s2bb(val)); |
| } |
| |
| private void assertScan(String[][] expected, String table) throws Exception { |
| String scid = client.createScanner(sharedSecret, table, new ScanOptions()); |
| ScanResult keyValues = client.nextK(scid, expected.length + 1); |
| |
| assertEquals(expected.length, keyValues.results.size(), "Saw " + keyValues.results); |
| assertFalse(keyValues.more); |
| |
| for (int i = 0; i < keyValues.results.size(); i++) { |
| checkKey(expected[i][0], expected[i][1], expected[i][2], expected[i][3], |
| keyValues.results.get(i)); |
| } |
| |
| client.closeScanner(scid); |
| } |
| |
| @Test |
| public void testConditionalWriter() throws Exception { |
| log.debug("Adding constraint {} to {}", tableName, NumericValueConstraint.class.getName()); |
| client.addConstraint(sharedSecret, tableName, NumericValueConstraint.class.getName()); |
| sleepUninterruptibly(ZOOKEEPER_PROPAGATION_TIME, TimeUnit.MILLISECONDS); |
| |
| // Take the table offline and online to force a config update |
| client.offlineTable(sharedSecret, tableName, true); |
| client.onlineTable(sharedSecret, tableName, true); |
| |
| assertNumericValueConstraintIsPresent(); |
| |
| String cwid = |
| client.createConditionalWriter(sharedSecret, tableName, new ConditionalWriterOptions()); |
| |
| Map<ByteBuffer,ConditionalUpdates> updates = new HashMap<>(); |
| |
| updates.put(s2bb("00345"), new ConditionalUpdates(List.of(newCondition("meta", "seq")), |
| List.of(newColUpdate("meta", "seq", 10, "1"), newColUpdate("data", "img", "73435435")))); |
| |
| Map<ByteBuffer,ConditionalStatus> results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00345"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "73435435"}, {"00345", "meta", "seq", "1"}}, |
| tableName); |
| |
| // test not setting values on conditions |
| updates.clear(); |
| |
| updates.put(s2bb("00345"), new ConditionalUpdates(List.of(newCondition("meta", "seq")), |
| List.of(newColUpdate("meta", "seq", "2")))); |
| updates.put(s2bb("00346"), new ConditionalUpdates(List.of(newCondition("meta", "seq")), |
| List.of(newColUpdate("meta", "seq", "1")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(2, results.size()); |
| assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00345"))); |
| assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00346"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "73435435"}, {"00345", "meta", "seq", "1"}, |
| {"00346", "meta", "seq", "1"}}, tableName); |
| |
| // test setting values on conditions |
| updates.clear(); |
| |
| updates.put(s2bb("00345"), |
| new ConditionalUpdates(List.of(newCondition("meta", "seq", "1")), Arrays |
| .asList(newColUpdate("meta", "seq", 20, "2"), newColUpdate("data", "img", "567890")))); |
| |
| updates.put(s2bb("00346"), new ConditionalUpdates(List.of(newCondition("meta", "seq", "2")), |
| List.of(newColUpdate("meta", "seq", "3")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(2, results.size()); |
| assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00345"))); |
| assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00346"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "567890"}, {"00345", "meta", "seq", "2"}, |
| {"00346", "meta", "seq", "1"}}, tableName); |
| |
| // test setting timestamp on condition to a nonexistent version |
| updates.clear(); |
| |
| updates.put(s2bb("00345"), new ConditionalUpdates(List.of(newCondition("meta", "seq", 10, "2")), |
| List.of(newColUpdate("meta", "seq", 30, "3"), newColUpdate("data", "img", "1234567890")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00345"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "567890"}, {"00345", "meta", "seq", "2"}, |
| {"00346", "meta", "seq", "1"}}, tableName); |
| |
| // test setting timestamp to an existing version |
| |
| updates.clear(); |
| |
| updates.put(s2bb("00345"), new ConditionalUpdates(List.of(newCondition("meta", "seq", 20, "2")), |
| List.of(newColUpdate("meta", "seq", 30, "3"), newColUpdate("data", "img", "1234567890")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00345"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "1234567890"}, |
| {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"}}, tableName); |
| |
| // run test w/ condition that has iterators |
| // following should fail w/o iterator |
| client.updateAndFlush(sharedSecret, tableName, |
| Collections.singletonMap(s2bb("00347"), List.of(newColUpdate("data", "count", "1")))); |
| client.updateAndFlush(sharedSecret, tableName, |
| Collections.singletonMap(s2bb("00347"), List.of(newColUpdate("data", "count", "1")))); |
| client.updateAndFlush(sharedSecret, tableName, |
| Collections.singletonMap(s2bb("00347"), List.of(newColUpdate("data", "count", "1")))); |
| |
| updates.clear(); |
| updates.put(s2bb("00347"), new ConditionalUpdates(List.of(newCondition("data", "count", "3")), |
| List.of(newColUpdate("data", "img", "1234567890")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00347"))); |
| |
| assertScan( |
| new String[][] {{"00345", "data", "img", "1234567890"}, {"00345", "meta", "seq", "3"}, |
| {"00346", "meta", "seq", "1"}, {"00347", "data", "count", "1"}}, |
| tableName); |
| |
| // following test w/ iterator setup should succeed |
| Condition iterCond = newCondition("data", "count", "3"); |
| Map<String,String> props = new HashMap<>(); |
| props.put("type", "STRING"); |
| props.put("columns", "data:count"); |
| IteratorSetting is = new IteratorSetting(1, "sumc", SummingCombiner.class.getName(), props); |
| iterCond.setIterators(List.of(is)); |
| |
| updates.clear(); |
| updates.put(s2bb("00347"), new ConditionalUpdates(List.of(iterCond), |
| List.of(newColUpdate("data", "img", "1234567890")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00347"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "1234567890"}, |
| {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"}, |
| {"00347", "data", "count", "1"}, {"00347", "data", "img", "1234567890"}}, tableName); |
| |
| ConditionalStatus status = null; |
| for (int i = 0; i < 30; i++) { |
| // test a mutation that violated a constraint |
| updates.clear(); |
| updates.put(s2bb("00347"), |
| new ConditionalUpdates(List.of(newCondition("data", "img", "1234567890")), |
| List.of(newColUpdate("data", "count", "A")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| status = results.get(s2bb("00347")); |
| if (status != ConditionalStatus.VIOLATED) { |
| log.info("ConditionalUpdate was not rejected by server due to table" |
| + " constraint. Sleeping and retrying"); |
| Thread.sleep(5000); |
| continue; |
| } |
| |
| assertEquals(ConditionalStatus.VIOLATED, status); |
| break; |
| } |
| |
| // Final check to make sure we succeeded and didn't exceed the retries |
| assertEquals(ConditionalStatus.VIOLATED, status); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "1234567890"}, |
| {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"}, |
| {"00347", "data", "count", "1"}, {"00347", "data", "img", "1234567890"}}, tableName); |
| |
| // run test with two conditions |
| // both conditions should fail |
| updates.clear(); |
| updates.put(s2bb("00347"), new ConditionalUpdates( |
| List.of(newCondition("data", "img", "565"), newCondition("data", "count", "2")), |
| List.of(newColUpdate("data", "count", "3"), newColUpdate("data", "img", "0987654321")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00347"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "1234567890"}, |
| {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"}, |
| {"00347", "data", "count", "1"}, {"00347", "data", "img", "1234567890"}}, tableName); |
| |
| // one condition should fail |
| updates.clear(); |
| updates.put(s2bb("00347"), new ConditionalUpdates( |
| List.of(newCondition("data", "img", "1234567890"), newCondition("data", "count", "2")), |
| List.of(newColUpdate("data", "count", "3"), newColUpdate("data", "img", "0987654321")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00347"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "1234567890"}, |
| {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"}, |
| {"00347", "data", "count", "1"}, {"00347", "data", "img", "1234567890"}}, tableName); |
| |
| // one condition should fail |
| updates.clear(); |
| updates.put(s2bb("00347"), new ConditionalUpdates( |
| List.of(newCondition("data", "img", "565"), newCondition("data", "count", "1")), |
| List.of(newColUpdate("data", "count", "3"), newColUpdate("data", "img", "0987654321")))); |
| |
| results = client.updateRowsConditionally(cwid, updates); |
| |
| assertEquals(1, results.size()); |
| assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00347"))); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "1234567890"}, |
| {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"}, |
| {"00347", "data", "count", "1"}, {"00347", "data", "img", "1234567890"}}, tableName); |
| |
| // both conditions should succeed |
| |
| ConditionalStatus result = client.updateRowConditionally(sharedSecret, tableName, s2bb("00347"), |
| new ConditionalUpdates( |
| List.of(newCondition("data", "img", "1234567890"), newCondition("data", "count", "1")), |
| List.of(newColUpdate("data", "count", "3"), |
| newColUpdate("data", "img", "0987654321")))); |
| |
| assertEquals(ConditionalStatus.ACCEPTED, result); |
| |
| assertScan(new String[][] {{"00345", "data", "img", "1234567890"}, |
| {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"}, |
| {"00347", "data", "count", "3"}, {"00347", "data", "img", "0987654321"}}, tableName); |
| |
| client.closeConditionalWriter(cwid); |
| assertThrows(UnknownWriter.class, () -> client.updateRowsConditionally(cwid, updates), |
| "conditional writer not closed"); |
| } |
| |
| private void assertNumericValueConstraintIsPresent() throws Exception { |
| Wait.waitFor( |
| () -> client.listConstraints(sharedSecret, tableName) |
| .containsKey(NumericValueConstraint.class.getName()), |
| 30_000L, 2_000L, "Expected to find NumericValueConstraint in constraints."); |
| } |
| |
| private void assertNumericValueConstraintIsAbsent() throws Exception { |
| Wait.waitFor( |
| () -> !client.listConstraints(sharedSecret, tableName) |
| .containsKey(NumericValueConstraint.class.getName()), |
| 30_000L, 2_000L, "Found NumericValueConstraint in constraints, expected it to be absent."); |
| } |
| |
| private void checkKey(String row, String cf, String cq, String val, KeyValue keyValue) { |
| assertEquals(row, ByteBufferUtil.toString(keyValue.key.row)); |
| assertEquals(cf, ByteBufferUtil.toString(keyValue.key.colFamily)); |
| assertEquals(cq, ByteBufferUtil.toString(keyValue.key.colQualifier)); |
| assertEquals("", ByteBufferUtil.toString(keyValue.key.colVisibility)); |
| assertEquals(val, ByteBufferUtil.toString(keyValue.value)); |
| } |
| |
| // scan metadata for file entries for the given table |
| private int countFiles(String table) throws Exception { |
| Map<String,String> tableIdMap = client.tableIdMap(sharedSecret); |
| String tableId = tableIdMap.get(table); |
| Key start = new Key(); |
| start.row = s2bb(tableId + ";"); |
| Key end = new Key(); |
| end.row = s2bb(tableId + "<"); |
| end = client.getFollowing(end, PartialKey.ROW); |
| ScanOptions opt = new ScanOptions(); |
| opt.range = new Range(start, true, end, false); |
| opt.columns = Collections.singletonList(new ScanColumn(s2bb("file"))); |
| String scanner = client.createScanner(sharedSecret, MetadataTable.NAME, opt); |
| int result = 0; |
| while (true) { |
| ScanResult more = client.nextK(scanner, 100); |
| result += more.getResults().size(); |
| if (!more.more) { |
| break; |
| } |
| } |
| client.closeScanner(scanner); |
| return result; |
| } |
| |
| private Map<ByteBuffer,List<ColumnUpdate>> mutation(String row, String cf, String cq, |
| String value) { |
| ColumnUpdate upd = new ColumnUpdate(s2bb(cf), s2bb(cq)); |
| upd.setValue(value.getBytes(UTF_8)); |
| return Collections.singletonMap(s2bb(row), Collections.singletonList(upd)); |
| } |
| |
| private ByteBuffer s2bb(String cf) { |
| return ByteBuffer.wrap(cf.getBytes(UTF_8)); |
| } |
| |
| private Map<String,String> s2pp(String cf) { |
| return Map.of("password", cf); |
| } |
| |
| private static ByteBuffer t2bb(Text t) { |
| return ByteBuffer.wrap(t.getBytes()); |
| } |
| |
| @Test |
| public void testGetRowRange() throws Exception { |
| Range range = client.getRowRange(s2bb("xyzzy")); |
| org.apache.accumulo.core.data.Range range2 = |
| new org.apache.accumulo.core.data.Range(new Text("xyzzy")); |
| assertEquals(0, range.start.row.compareTo(t2bb(range2.getStartKey().getRow()))); |
| assertEquals(0, range.stop.row.compareTo(t2bb(range2.getEndKey().getRow()))); |
| assertEquals(range.startInclusive, range2.isStartKeyInclusive()); |
| assertEquals(range.stopInclusive, range2.isEndKeyInclusive()); |
| assertEquals(0, range.start.colFamily.compareTo(t2bb(range2.getStartKey().getColumnFamily()))); |
| assertEquals(0, |
| range.start.colQualifier.compareTo(t2bb(range2.getStartKey().getColumnQualifier()))); |
| assertEquals(0, range.stop.colFamily.compareTo(t2bb(range2.getEndKey().getColumnFamily()))); |
| assertEquals(0, |
| range.stop.colQualifier.compareTo(t2bb(range2.getEndKey().getColumnQualifier()))); |
| assertEquals(range.start.timestamp, range.start.timestamp); |
| assertEquals(range.stop.timestamp, range.stop.timestamp); |
| } |
| |
| private void addFile(String tableName, int startRow, int endRow, boolean delete) |
| throws TException { |
| Map<ByteBuffer,List<ColumnUpdate>> mutation = new HashMap<>(); |
| |
| for (int i = startRow; i < endRow; i++) { |
| String row = String.format("%09d", i); |
| ColumnUpdate columnUpdate = newColUpdate("cf", "cq", "v" + i); |
| columnUpdate.setDeleteCell(delete); |
| mutation.put(s2bb(row), List.of(columnUpdate)); |
| } |
| |
| client.updateAndFlush(sharedSecret, tableName, mutation); |
| client.flushTable(sharedSecret, tableName, null, null, true); |
| } |
| |
| /** |
| * Test to make sure we can specify a Selector from the proxy client, and it will take effect when |
| * compactions occur |
| */ |
| @Test |
| public void testCompactionSelector() throws Exception { |
| |
| // delete table so new tables won't have the same name |
| client.deleteTable(sharedSecret, tableName); |
| |
| final String[] tableNames = getUniqueNameArray(3); |
| |
| // for each table, set the summarizer property needed for TooManyDeletesSelector |
| final String summarizerKey = Property.TABLE_SUMMARIZER_PREFIX + "s1"; |
| final String summarizerClassName = DeletesSummarizer.class.getName(); |
| |
| for (String tableName : tableNames) { |
| client.createTable(sharedSecret, tableName, true, TimeType.MILLIS); |
| client.setTableProperty(sharedSecret, tableName, summarizerKey, summarizerClassName); |
| } |
| |
| // add files to each table |
| |
| addFile(tableNames[0], 1, 1000, false); |
| addFile(tableNames[0], 1, 1000, true); |
| |
| addFile(tableNames[1], 1, 1000, false); |
| addFile(tableNames[1], 1000, 2000, false); |
| |
| addFile(tableNames[2], 1, 2000, false); |
| addFile(tableNames[2], 1, 1000, true); |
| |
| final String messagePrefix = "Unexpected file count on table "; |
| |
| for (String tableName : tableNames) { |
| assertEquals(2, countFiles(tableName), messagePrefix + tableName); |
| } |
| |
| // compact the tables and check for expected file counts |
| |
| final String selectorClassname = TooManyDeletesSelector.class.getName(); |
| PluginConfig selector = new PluginConfig(selectorClassname, Map.of("threshold", ".99")); |
| |
| for (String tableName : tableNames) { |
| client.compactTable(sharedSecret, tableName, null, null, null, true, true, selector, null); |
| } |
| |
| assertEquals(0, countFiles(tableNames[0]), messagePrefix + tableNames[0]); |
| assertEquals(2, countFiles(tableNames[1]), messagePrefix + tableNames[1]); |
| assertEquals(2, countFiles(tableNames[2]), messagePrefix + tableNames[2]); |
| |
| // create a selector with different properties then compact and check file counts |
| |
| selector = new PluginConfig(selectorClassname, Map.of("threshold", ".40")); |
| |
| for (String tableName : tableNames) { |
| client.compactTable(sharedSecret, tableName, null, null, null, true, true, selector, null); |
| } |
| |
| assertEquals(0, countFiles(tableNames[0]), messagePrefix + tableNames[0]); |
| assertEquals(2, countFiles(tableNames[1]), messagePrefix + tableNames[1]); |
| assertEquals(1, countFiles(tableNames[2]), messagePrefix + tableNames[2]); |
| |
| client.compactTable(sharedSecret, tableNames[1], null, null, null, true, true, null, null); |
| |
| assertEquals(1, countFiles(tableNames[1]), messagePrefix + tableNames[2]); |
| } |
| |
| @Test |
| public void namespaceOperations() throws Exception { |
| // default namespace and accumulo namespace |
| assertEquals(client.systemNamespace(), Namespace.ACCUMULO.name(), "System namespace is wrong"); |
| assertEquals(client.defaultNamespace(), Namespace.DEFAULT.name(), "Default namespace is wrong"); |
| |
| // namespace existence and namespace listing |
| assertTrue(client.namespaceExists(sharedSecret, namespaceName), |
| "Namespace created during setup should exist"); |
| assertTrue(client.listNamespaces(sharedSecret).contains(namespaceName), |
| "Namespace listing should contain namespace created during setup"); |
| |
| // create new namespace |
| String newNamespace = "foobar"; |
| client.createNamespace(sharedSecret, newNamespace); |
| |
| assertTrue(client.namespaceExists(sharedSecret, newNamespace), |
| "Namespace just created should exist"); |
| assertTrue(client.listNamespaces(sharedSecret).contains(newNamespace), |
| "Namespace listing should contain just created"); |
| |
| // rename the namespace |
| String renamedNamespace = "foobar_renamed"; |
| client.renameNamespace(sharedSecret, newNamespace, renamedNamespace); |
| |
| assertTrue(client.namespaceExists(sharedSecret, renamedNamespace), |
| "Renamed namespace should exist"); |
| assertTrue(client.listNamespaces(sharedSecret).contains(renamedNamespace), |
| "Namespace listing should contain renamed namespace"); |
| |
| assertFalse(client.namespaceExists(sharedSecret, newNamespace), |
| "Original namespace should no longer exist"); |
| assertFalse(client.listNamespaces(sharedSecret).contains(newNamespace), |
| "Namespace listing should no longer contain original namespace"); |
| |
| // delete the namespace |
| client.deleteNamespace(sharedSecret, renamedNamespace); |
| assertFalse(client.namespaceExists(sharedSecret, renamedNamespace), |
| "Renamed namespace should no longer exist"); |
| assertFalse(client.listNamespaces(sharedSecret).contains(renamedNamespace), |
| "Namespace listing should no longer contain renamed namespace"); |
| |
| // namespace properties |
| Map<String,String> cfg = client.getNamespaceProperties(sharedSecret, namespaceName); |
| String defaultProp = cfg.get("table.compaction.major.ratio"); |
| assertNotEquals(defaultProp, "10"); // let's make sure we are setting this value to something |
| // different than default... |
| client.setNamespaceProperty(sharedSecret, namespaceName, "table.compaction.major.ratio", "10"); |
| for (int i = 0; i < 5; i++) { |
| cfg = client.getNamespaceProperties(sharedSecret, namespaceName); |
| if ("10".equals(cfg.get("table.compaction.major.ratio"))) { |
| break; |
| } |
| sleepUninterruptibly(200, TimeUnit.MILLISECONDS); |
| } |
| assertTrue( |
| client.getNamespaceProperties(sharedSecret, namespaceName) |
| .containsKey("table.compaction.major.ratio"), |
| "Namespace should contain table.compaction.major.ratio property"); |
| assertEquals( |
| client.getNamespaceProperties(sharedSecret, namespaceName) |
| .get("table.compaction.major.ratio"), |
| "10", "Namespace property table.compaction.major.ratio property should equal 10"); |
| client.removeNamespaceProperty(sharedSecret, namespaceName, "table.compaction.major.ratio"); |
| for (int i = 0; i < 5; i++) { |
| cfg = client.getNamespaceProperties(sharedSecret, namespaceName); |
| if (!defaultProp.equals(cfg.get("table.compaction.major.ratio"))) { |
| break; |
| } |
| sleepUninterruptibly(200, TimeUnit.MILLISECONDS); |
| } |
| assertEquals(defaultProp, cfg.get("table.compaction.major.ratio"), |
| "Namespace should have default value for table.compaction.major.ratio"); |
| |
| // namespace ID map |
| assertTrue(client.namespaceIdMap(sharedSecret).containsKey("accumulo"), |
| "Namespace ID map should contain accumulo"); |
| assertTrue(client.namespaceIdMap(sharedSecret).containsKey(namespaceName), |
| "Namespace ID map should contain namespace created during setup"); |
| |
| // namespace iterators |
| IteratorSetting setting = new IteratorSetting(100, "DebugTheThings", |
| DebugIterator.class.getName(), Collections.emptyMap()); |
| client.attachNamespaceIterator(sharedSecret, namespaceName, setting, |
| EnumSet.of(IteratorScope.SCAN)); |
| assertEquals(setting, client.getNamespaceIteratorSetting(sharedSecret, namespaceName, |
| "DebugTheThings", IteratorScope.SCAN), "Wrong iterator setting returned"); |
| assertTrue( |
| client.listNamespaceIterators(sharedSecret, namespaceName).containsKey("DebugTheThings"), |
| "Namespace iterator settings should contain iterator just added"); |
| assertEquals(EnumSet.of(IteratorScope.SCAN), |
| client.listNamespaceIterators(sharedSecret, namespaceName).get("DebugTheThings"), |
| "Namespace iterator listing should contain iterator scope just added"); |
| client.checkNamespaceIteratorConflicts(sharedSecret, namespaceName, setting, |
| EnumSet.of(IteratorScope.MAJC)); |
| client.removeNamespaceIterator(sharedSecret, namespaceName, "DebugTheThings", |
| EnumSet.of(IteratorScope.SCAN)); |
| assertFalse( |
| client.listNamespaceIterators(sharedSecret, namespaceName).containsKey("DebugTheThings"), |
| "Namespace iterator settings should contain iterator just added"); |
| |
| // namespace constraints |
| int id = |
| client.addNamespaceConstraint(sharedSecret, namespaceName, MaxMutationSize.class.getName()); |
| assertTrue( |
| client.listNamespaceConstraints(sharedSecret, namespaceName) |
| .containsKey(MaxMutationSize.class.getName()), |
| "Namespace should contain max mutation size constraint"); |
| assertEquals(id, |
| (int) client.listNamespaceConstraints(sharedSecret, namespaceName) |
| .get(MaxMutationSize.class.getName()), |
| "Namespace max mutation size constraint id is wrong"); |
| client.removeNamespaceConstraint(sharedSecret, namespaceName, id); |
| assertFalse( |
| client.listNamespaceConstraints(sharedSecret, namespaceName) |
| .containsKey(MaxMutationSize.class.getName()), |
| "Namespace should no longer contain max mutation size constraint"); |
| |
| // namespace class load |
| assertTrue(client.testNamespaceClassLoad(sharedSecret, namespaceName, |
| DebugIterator.class.getName(), SortedKeyValueIterator.class.getName()), |
| "Namespace class load should work"); |
| assertFalse(client.testNamespaceClassLoad(sharedSecret, namespaceName, "foo.bar", |
| SortedKeyValueIterator.class.getName()), "Namespace class load should not work"); |
| } |
| } |