From 0ef0eaf08c7b424e9f77a7587b3f16cb4b9d7d12 Mon Sep 17 00:00:00 2001 From: DaveTeng0 Date: Mon, 29 Apr 2024 14:07:32 -0700 Subject: [PATCH] add transactionInfoTable unit test --- .../ozone/shell/TestOzoneRepairShell.java | 28 +- hadoop-ozone/tools/pom.xml | 6 + .../admin/scm/DecommissionScmSubcommand.java | 2 +- .../apache/hadoop/ozone/repair/RDBRepair.java | 5 + .../ozone/repair/TransactionInfoRepair.java | 146 +++++++++++ .../ozone/repair/om/SnapshotRepair.java | 6 +- .../repair/om/TransactionInfoRepair.java | 113 -------- .../repair/TestTransactionInfoRepair.java | 247 ++++++++++++++++++ .../scm/TestDecommissionScmSubcommand.java | 2 +- .../org.mockito.plugins.MockMaker | 16 ++ 10 files changed, 432 insertions(+), 139 deletions(-) create mode 100644 hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/TransactionInfoRepair.java delete mode 100644 hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/TransactionInfoRepair.java create mode 100644 hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/repair/TestTransactionInfoRepair.java create mode 100644 hadoop-ozone/tools/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneRepairShell.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneRepairShell.java index 64c82455298..05b3728f5b6 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneRepairShell.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneRepairShell.java @@ -18,28 +18,19 @@ package org.apache.hadoop.ozone.shell; import org.apache.hadoop.hdds.conf.OzoneConfiguration; -import org.apache.hadoop.hdds.scm.container.replication.ReplicationManager; import org.apache.hadoop.ozone.MiniOzoneCluster; import org.apache.hadoop.ozone.debug.DBScanner; import org.apache.hadoop.ozone.debug.RDBParser; import org.apache.hadoop.ozone.om.OMStorage; import org.apache.hadoop.ozone.repair.RDBRepair; -import org.apache.hadoop.ozone.repair.om.TransactionInfoRepair; +import org.apache.hadoop.ozone.repair.TransactionInfoRepair; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import picocli.CommandLine; import java.io.PrintWriter; import java.io.StringWriter; -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_HEARTBEAT_INTERVAL; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_PIPELINE_REPORT_INTERVAL; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_COMMAND_STATUS_REPORT_INTERVAL; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_CONTAINER_REPORT_INTERVAL; -import static org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_HEARTBEAT_PROCESS_INTERVAL; import static org.apache.hadoop.ozone.OzoneConsts.OM_DB_NAME; import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX; import static org.assertj.core.api.Assertions.assertThat; @@ -56,19 +47,7 @@ public class TestOzoneRepairShell { @BeforeAll public static void init() throws Exception { conf = new OzoneConfiguration(); - conf.setTimeDuration(OZONE_SCM_HEARTBEAT_PROCESS_INTERVAL, - 100, TimeUnit.MILLISECONDS); - conf.setTimeDuration(HDDS_HEARTBEAT_INTERVAL, 1, SECONDS); - conf.setTimeDuration(HDDS_PIPELINE_REPORT_INTERVAL, 1, SECONDS); - conf.setTimeDuration(HDDS_COMMAND_STATUS_REPORT_INTERVAL, 1, SECONDS); - conf.setTimeDuration(HDDS_CONTAINER_REPORT_INTERVAL, 1, SECONDS); - ReplicationManager.ReplicationManagerConfiguration replicationConf = - conf.getObject( - ReplicationManager.ReplicationManagerConfiguration.class); - replicationConf.setInterval(Duration.ofSeconds(1)); - conf.setFromObject(replicationConf); - cluster = MiniOzoneCluster.newBuilder(conf) - .build(); + cluster = MiniOzoneCluster.newBuilder(conf).withoutDatanodes().build(); cluster.waitForClusterToBeReady(); } @@ -93,6 +72,9 @@ public void testUpdateTransactionInfoTable() throws Exception { cmdDBScanner.execute(argsDBScanner); String cmdOut = stdout.toString(); assertThat(cmdOut).contains(testTermIndex); + + cluster.getOzoneManager().start(); + } } diff --git a/hadoop-ozone/tools/pom.xml b/hadoop-ozone/tools/pom.xml index 839d01f0fa8..6c000188bc9 100644 --- a/hadoop-ozone/tools/pom.xml +++ b/hadoop-ozone/tools/pom.xml @@ -108,6 +108,12 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd"> hdds-test-utils test + + + + + + diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/scm/DecommissionScmSubcommand.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/scm/DecommissionScmSubcommand.java index aa8bd3abf60..f8a2221a12b 100644 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/scm/DecommissionScmSubcommand.java +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/admin/scm/DecommissionScmSubcommand.java @@ -56,7 +56,7 @@ public void execute(ScmClient scmClient) throws IOException { // Throwing exception to create non-zero exit code in case of failure. throw new IOException(errorMsg); } else { - System.out.println("Decommissioned Scm " + nodeId); + System.out.println("****_______yyyyyyyyyy,,, Decommissioned Scm " + nodeId); } } } diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/RDBRepair.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/RDBRepair.java index 0f36934ec14..22c19fdf685 100644 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/RDBRepair.java +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/RDBRepair.java @@ -45,6 +45,11 @@ public String getDbPath() { return dbPath; } +// public void setDbPath(String dbPath) { +// this.dbPath = dbPath; +// } + + @Override public Void call() { GenericCli.missingSubcommand(spec); diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/TransactionInfoRepair.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/TransactionInfoRepair.java new file mode 100644 index 00000000000..a3c45d3b22c --- /dev/null +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/TransactionInfoRepair.java @@ -0,0 +1,146 @@ +/* + * 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.hadoop.ozone.repair; + +import org.apache.hadoop.hdds.cli.HddsVersionProvider; +import org.apache.hadoop.hdds.cli.SubcommandWithParent; +import org.apache.hadoop.hdds.utils.IOUtils; +import org.apache.hadoop.hdds.utils.TransactionInfo; +import org.apache.hadoop.hdds.utils.db.StringCodec; +import org.apache.hadoop.hdds.utils.db.managed.ManagedRocksDB; +import org.apache.hadoop.ozone.debug.RocksDBUtils; +import org.kohsuke.MetaInfServices; +import org.rocksdb.ColumnFamilyDescriptor; +import org.rocksdb.ColumnFamilyHandle; +import org.rocksdb.RocksDBException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +import static org.apache.hadoop.ozone.OzoneConsts.TRANSACTION_INFO_KEY; +import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.TRANSACTION_INFO_TABLE; + + +/** + * Tool to update the highest term-index in transactionInfoTable. + */ +@CommandLine.Command( + name = "transaction", + description = "CLI to update the highest index in transactionInfoTable.", + mixinStandardHelpOptions = true, + versionProvider = HddsVersionProvider.class +) +@MetaInfServices(SubcommandWithParent.class) +public class TransactionInfoRepair + implements Callable, SubcommandWithParent { + + protected static final Logger LOG = LoggerFactory.getLogger(TransactionInfoRepair.class); + + @CommandLine.Spec + private static CommandLine.Model.CommandSpec spec; + + @CommandLine.ParentCommand + private RDBRepair parent; + + @CommandLine.Option(names = {"--highest-transaction"}, + required = true, + description = "Highest termIndex of transactionInfoTable. The input format is: {term}#{index}.") + private String highestTransactionTermIndex; + + + protected void setHighestTransactionTermIndex( + String highestTransactionTermIndex) { + this.highestTransactionTermIndex = highestTransactionTermIndex; + } + + @Override + public Void call() throws Exception { + List cfHandleList = new ArrayList<>(); + List cfDescList = RocksDBUtils.getColumnFamilyDescriptors( + getParent().getDbPath()); + + try { + ManagedRocksDB db = ManagedRocksDB.open(getParent().getDbPath(), cfDescList, cfHandleList); + try { +// (ManagedRocksDB db = getManagedRocksDB(cfDescList, cfHandleList)) +// { + ColumnFamilyHandle transactionInfoCfh = RocksDBUtils + .getColumnFamilyHandle(TRANSACTION_INFO_TABLE, cfHandleList); + ManagedRocksDB db2 = db; + if (transactionInfoCfh == null) { + System.err.println(TRANSACTION_INFO_TABLE + " is not in a column family in DB for the given path."); + return null; + } + TransactionInfo originalTransactionInfo = + RocksDBUtils.getValue(db, transactionInfoCfh, TRANSACTION_INFO_KEY, TransactionInfo.getCodec()); + + System.out.println("The original highest transaction Info was " + originalTransactionInfo.getTermIndex()); + + TransactionInfo transactionInfo = TransactionInfo.valueOf( + highestTransactionTermIndex); + + byte[] transactionInfoBytes = TransactionInfo.getCodec().toPersistedFormat(transactionInfo); + db.get() + .put(transactionInfoCfh, StringCodec.get().toPersistedFormat(TRANSACTION_INFO_KEY), transactionInfoBytes); + + System.out.println("The highest transaction info has been updated to: " + + RocksDBUtils.getValue(db, transactionInfoCfh, TRANSACTION_INFO_KEY, + TransactionInfo.getCodec()).getTermIndex()); +// LOG.error("******_________ pppppppppppp....."); + + + } catch (RocksDBException exception) { + System.err.println("Failed to update the RocksDB for the given path: " + getParent().getDbPath()); + System.err.println( + "Make sure that Ozone entity (OM, SCM or DN) is not running for the give database path and current host."); + LOG.error(exception.toString()); +// throw exception; + } finally { + IOUtils.closeQuietly(cfHandleList); + } + + } catch (Exception e) { + throw e; + } + + return null; + } + + protected RDBRepair getParent() { + return parent; + } + + @Override + public Class getParentType() { + return RDBRepair.class; + } + + protected ManagedRocksDB getManagedRocksDB(List cfDescList, + List cfHandleList) throws RocksDBException { + return ManagedRocksDB.open(getParent().getDbPath(), cfDescList, cfHandleList); + } + +} diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/SnapshotRepair.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/SnapshotRepair.java index 9c05ce8eade..d07fc13be8a 100644 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/SnapshotRepair.java +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/SnapshotRepair.java @@ -31,6 +31,8 @@ import org.rocksdb.ColumnFamilyDescriptor; import org.rocksdb.ColumnFamilyHandle; import org.rocksdb.RocksDBException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import picocli.CommandLine; import picocli.CommandLine.Model.CommandSpec; @@ -56,6 +58,8 @@ @MetaInfServices(SubcommandWithParent.class) public class SnapshotRepair implements Callable, SubcommandWithParent { + protected static final Logger LOG = LoggerFactory.getLogger(SnapshotRepair.class); + @CommandLine.Spec private static CommandSpec spec; @@ -152,7 +156,7 @@ public Void call() throws Exception { System.err.println("Failed to update the RocksDB for the given path: " + parent.getDbPath()); System.err.println( "Make sure that Ozone entity (OM, SCM or DN) is not running for the give dbPath and current host."); - System.err.println(exception); + LOG.error(exception.toString()); } finally { IOUtils.closeQuietly(cfHandleList); } diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/TransactionInfoRepair.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/TransactionInfoRepair.java deleted file mode 100644 index 81551dfb3f3..00000000000 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/repair/om/TransactionInfoRepair.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.hadoop.ozone.repair.om; - -import org.apache.hadoop.hdds.cli.HddsVersionProvider; -import org.apache.hadoop.hdds.cli.SubcommandWithParent; -import org.apache.hadoop.hdds.utils.IOUtils; -import org.apache.hadoop.hdds.utils.TransactionInfo; -import org.apache.hadoop.hdds.utils.db.StringCodec; -import org.apache.hadoop.hdds.utils.db.managed.ManagedRocksDB; -import org.apache.hadoop.ozone.debug.RocksDBUtils; -import org.apache.hadoop.ozone.repair.RDBRepair; -import org.kohsuke.MetaInfServices; -import org.rocksdb.ColumnFamilyDescriptor; -import org.rocksdb.ColumnFamilyHandle; -import org.rocksdb.RocksDBException; -import picocli.CommandLine; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -import static org.apache.hadoop.ozone.OzoneConsts.TRANSACTION_INFO_KEY; -import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.TRANSACTION_INFO_TABLE; - - -/** - * Tool to update the highest term-index in transactionInfoTable. - */ -@CommandLine.Command( - name = "transaction", - description = "CLI to update the highest index in transactionInfoTable.", - mixinStandardHelpOptions = true, - versionProvider = HddsVersionProvider.class -) -@MetaInfServices(SubcommandWithParent.class) -public class TransactionInfoRepair - implements Callable, SubcommandWithParent { - - @CommandLine.Spec - private static CommandLine.Model.CommandSpec spec; - - @CommandLine.ParentCommand - private RDBRepair parent; - - @CommandLine.Option(names = {"--highest-transaction"}, - required = true, - description = "highest termIndex of transactionInfoTable") - private String highestTransactionTermIndex; - - - @Override - public Void call() throws Exception { - - System.out.println("*****________ tir.c, " + System.getProperty("user.name")); - - List cfHandleList = new ArrayList<>(); - List cfDescList = RocksDBUtils.getColumnFamilyDescriptors(parent.getDbPath()); - - try (ManagedRocksDB db = ManagedRocksDB.open(parent.getDbPath(), cfDescList, cfHandleList)) { - ColumnFamilyHandle transactionInfoCfh = RocksDBUtils.getColumnFamilyHandle(TRANSACTION_INFO_TABLE, cfHandleList); - - if (transactionInfoCfh == null) { - System.err.println(TRANSACTION_INFO_TABLE + " is not in a column family in DB for the given path."); - return null; - } - TransactionInfo transactionInfo = TransactionInfo.valueOf( - highestTransactionTermIndex); - - byte[] transactionInfoBytes = TransactionInfo.getCodec().toPersistedFormat(transactionInfo); - db.get() - .put(transactionInfoCfh, StringCodec.get().toPersistedFormat(TRANSACTION_INFO_KEY), transactionInfoBytes); - - System.out.println("Highest Transaction Info is updated to : " + - RocksDBUtils.getValue(db, transactionInfoCfh, TRANSACTION_INFO_KEY, TransactionInfo.getCodec())); - - } catch (RocksDBException exception) { - System.err.println("Failed to update the RocksDB for the given path: " + parent.getDbPath()); - System.err.println( - "Make sure that Ozone entity (OM, SCM or DN) is not running for the give dbPath and current host."); - System.err.println(exception); - } finally { - IOUtils.closeQuietly(cfHandleList); - } - - return null; - } - - @Override - public Class getParentType() { - return RDBRepair.class; - } - -} diff --git a/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/repair/TestTransactionInfoRepair.java b/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/repair/TestTransactionInfoRepair.java new file mode 100644 index 00000000000..956987d8c47 --- /dev/null +++ b/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/repair/TestTransactionInfoRepair.java @@ -0,0 +1,247 @@ +package org.apache.hadoop.ozone.repair; + +import org.apache.hadoop.hdds.utils.TransactionInfo; +import org.apache.hadoop.hdds.utils.db.Codec; +import org.apache.hadoop.hdds.utils.db.managed.ManagedRocksDB; +import org.apache.hadoop.ozone.debug.RocksDBUtils; +import org.apache.ozone.test.GenericTestUtils; +import org.apache.ratis.server.protocol.TermIndex; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.rocksdb.ColumnFamilyHandle; +import org.rocksdb.RocksDB; +import org.rocksdb.RocksDBException; + +import java.io.UnsupportedEncodingException; +import java.util.function.Supplier; + +import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.TRANSACTION_INFO_TABLE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +/** + * Tests TransactionInfoRepair. + */ +public class TestTransactionInfoRepair { + + + private static final String DB_PATH = "testDBPath"; + private final long testTerm = 1; + private final long testIndex = 1; + + private void mockTransactionInfo(MockedStatic mockUtil) { + mockUtil.when(() -> + RocksDBUtils.getValue(any(ManagedRocksDB.class), any(ColumnFamilyHandle.class), anyString(), + any(Codec.class))).thenReturn(mock(TransactionInfo.class)); + + TransactionInfo transactionInfo2 = mock(TransactionInfo.class); + doReturn(TermIndex.valueOf(testTerm, testIndex)).when(transactionInfo2).getTermIndex(); + mockUtil.when(() -> + RocksDBUtils.getValue(any(ManagedRocksDB.class), any(ColumnFamilyHandle.class), anyString(), + any(Codec.class))).thenReturn(transactionInfo2); + + } + + @Test + public void testUpdateTransactionInfoTableSuccessful() throws Exception { + ManagedRocksDB mdb = mockRockDB(); + try (GenericTestUtils.SystemOutCapturer outCapturer = new GenericTestUtils.SystemOutCapturer()) { + testCommand(mdb, mock(ColumnFamilyHandle.class), () -> { + try { + return outCapturer.getOutput(); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + }, new String[]{String.format("The original highest transaction Info was (t:%s, i:%s)", testTerm, testIndex), + String.format("The highest transaction info has been updated to: (t:%s, i:%s)", testTerm, testIndex)}); + } + + + +// try (MockedStatic mocked = mockStatic(ManagedRocksDB.class); +// MockedStatic mockUtil = mockStatic(RocksDBUtils.class)) { +// ManagedRocksDB db = mock(ManagedRocksDB.class); +//// RocksDB rdb = ; +//// when(rdb.getName()).thenReturn("rrrrrrrrr"); +// doReturn(mock(RocksDB.class)).when(db).get(); +//// ManagedRocksDB db = spy(ManagedRocksDB.class); +// +// mocked.when(() -> ManagedRocksDB.open(anyString(), anyList(), anyList())).thenReturn(db); +//// mocked.when(() -> ManagedRocksDB.open(anyString(), anyList(), anyList())) +// .thenThrow(new RocksDBException("hello")); +// +// ColumnFamilyHandle columnFamilyHandle = mock(ColumnFamilyHandle.class); +//// doReturn("cccccccc".getBytes(StandardCharsets.UTF_8)).when(columnFamilyHandle).getName(); +// TransactionInfo transactionInfo = mock(TransactionInfo.class); +// List ls1 = new ArrayList<>(); +//// ls1.add(new ) +// mockUtil.when(() -> RocksDBUtils.getColumnFamilyDescriptors(anyString())) +// .thenReturn(ls1); +// +// mockUtil.when(() -> RocksDBUtils.getColumnFamilyHandle(anyString(), anyList())) +// .thenReturn(columnFamilyHandle); +// mockUtil.when(() -> +// RocksDBUtils.getValue(any(ManagedRocksDB.class), any(ColumnFamilyHandle.class), anyString(), +// any(Codec.class))).thenReturn(transactionInfo); +// TransactionInfo transactionInfo2 = mock(TransactionInfo.class); +// long testTerm = 1; +// long testIndex = 1; +// doReturn(TermIndex.valueOf(testTerm, testIndex)).when(transactionInfo2).getTermIndex(); +// mockUtil.when(() -> +// RocksDBUtils.getValue(any(ManagedRocksDB.class), any(ColumnFamilyHandle.class), anyString(), +// any(Codec.class))).thenReturn(transactionInfo2); +// +// TransactionInfoRepair cmd = spy(TransactionInfoRepair.class); +//// ManagedRocksDB db3 = mock(ManagedRocksDB.class); +//// doThrow(new RuntimeException("tttttttt")).when(cmd).getManagedRocksDB(anyList(), anyList()); +// cmd.setHighestTransactionTermIndex(testTerm + "#" + testIndex); +// RDBRepair rrr = mock(RDBRepair.class); +// when(rrr.getDbPath()).thenReturn("some path.....");// must have, otherwise test fail +// cmd.parent = rrr; +// +// try (GenericTestUtils.SystemOutCapturer outCapturer = new GenericTestUtils.SystemOutCapturer()) { +// cmd.call(); +//// IOException ioe = assertThrows(IOException.class, () -> cmd.execute(client)); +// assertThat(outCapturer.getOutput()).contains( +// String.format("The original highest transaction Info was (t:%s, i:%s)", testTerm, testIndex)); +// +// assertThat(outCapturer.getOutput()).contains( +// String.format("The highest transaction info has been updated to: (t:%s, i:%s)", testTerm, testIndex)); +// +//// assertThat(ioe.getMessage()).contains("remove current leader"); +// } +// } + } + + @Test + public void testCommandWhenTableNotInDBForGivenPath() throws Exception { + ManagedRocksDB mdb = mockRockDB(); + try (GenericTestUtils.SystemErrCapturer errCapturer = new GenericTestUtils.SystemErrCapturer()) { + testCommand(mdb, null, () -> { + try { + return errCapturer.getOutput(); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + }, new String[]{TRANSACTION_INFO_TABLE + " is not in a column family in DB for the given path"}); + } + +// try (MockedStatic mocked = mockStatic(ManagedRocksDB.class); +// MockedStatic mockUtil = mockStatic(RocksDBUtils.class)) { +// +// +// +// mockUtil.when(() -> RocksDBUtils.getColumnFamilyHandle(anyString(), anyList())) +// .thenReturn(null); +// TransactionInfoRepair cmd = spy(TransactionInfoRepair.class); +// RDBRepair rrr = mock(RDBRepair.class); +//// when(rrr.getDbPath()).thenReturn("some path....."); +// cmd.parent = rrr; +// +// try (GenericTestUtils.SystemErrCapturer errCapturer = new GenericTestUtils.SystemErrCapturer()) { +// cmd.call(); +// assertThat(errCapturer.getOutput()).contains(TRANSACTION_INFO_TABLE + +// " is not in a column family in DB for the given path"); +// } +// +// } + } + + @Test + public void testCommandWhenFailToUpdateRocksDBForGivenPath() throws Exception { + ManagedRocksDB mdb = mockRockDB(); + RocksDB rdb = mdb.get(); + + doThrow(RocksDBException.class).when(rdb) + .put(any(ColumnFamilyHandle.class), any(byte[].class), any(byte[].class)); + + try (GenericTestUtils.SystemErrCapturer errCapturer = new GenericTestUtils.SystemErrCapturer()) { + testCommand(mdb, mock(ColumnFamilyHandle.class), () -> { + try { + return errCapturer.getOutput(); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + }, new String[]{"Failed to update the RocksDB for the given path: " + DB_PATH}); + } + +// try (MockedStatic mocked = mockStatic(ManagedRocksDB.class); +// MockedStatic mockUtil = mockStatic(RocksDBUtils.class)) { +// ManagedRocksDB db = mock(ManagedRocksDB.class); +// RocksDB rocksDB = mock(RocksDB.class); +// doReturn(rocksDB).when(db).get(); +// +// doThrow(RocksDBException.class).when(rocksDB) +// .put(any(ColumnFamilyHandle.class), any(byte[].class), any(byte[].class)); +// mocked.when(() -> ManagedRocksDB.open(anyString(), anyList(), anyList())).thenReturn(db); +// mockUtil.when(() -> RocksDBUtils.getColumnFamilyHandle(anyString(), anyList())) +// .thenReturn(mock(ColumnFamilyHandle.class)); +// mockUtil.when(() -> +// RocksDBUtils.getValue(any(ManagedRocksDB.class), any(ColumnFamilyHandle.class), anyString(), +// any(Codec.class))).thenReturn(mock(TransactionInfo.class)); +// +// TransactionInfoRepair cmd = spy(TransactionInfoRepair.class); +// RDBRepair rdbRepair = mock(RDBRepair.class); +// String dbPath = "testDBPath"; +// when(rdbRepair.getDbPath()).thenReturn(dbPath); +// doReturn(rdbRepair).when(cmd).getParent(); +// long testTerm = 1; +// long testIndex = 1; +// cmd.setHighestTransactionTermIndex(testTerm + "#" + testIndex); +// +// try (GenericTestUtils.SystemErrCapturer errCapturer = new GenericTestUtils.SystemErrCapturer()) { +// cmd.call(); +// assertThat(errCapturer.getOutput()).contains("Failed to update the RocksDB for the given path: " + dbPath); +// } +// +// } + } + + + private void testCommand(ManagedRocksDB mdb, ColumnFamilyHandle columnFamilyHandle, Supplier capturer, + String[] messages) throws Exception { + try (MockedStatic mocked = mockStatic(ManagedRocksDB.class); + MockedStatic mockUtil = mockStatic(RocksDBUtils.class)) { + + mocked.when(() -> ManagedRocksDB.open(anyString(), anyList(), anyList())).thenReturn(mdb); + mockUtil.when(() -> RocksDBUtils.getColumnFamilyHandle(anyString(), anyList())) + .thenReturn(columnFamilyHandle); + + mockUtil.when(() -> + RocksDBUtils.getValue(any(ManagedRocksDB.class), any(ColumnFamilyHandle.class), anyString(), + any(Codec.class))).thenReturn(mock(TransactionInfo.class)); + + mockTransactionInfo(mockUtil); + + TransactionInfoRepair cmd = spy(TransactionInfoRepair.class); + RDBRepair rdbRepair = mock(RDBRepair.class); + when(rdbRepair.getDbPath()).thenReturn(DB_PATH); + doReturn(rdbRepair).when(cmd).getParent(); + cmd.setHighestTransactionTermIndex(testTerm + "#" + testIndex); + +// try (GenericTestUtils.SystemErrCapturer errCapturer = new GenericTestUtils.SystemErrCapturer()) { + cmd.call(); + for (String message : messages) { + assertThat(capturer.get()).contains(message); + } +// } + } + } + + private ManagedRocksDB mockRockDB() { + ManagedRocksDB db = mock(ManagedRocksDB.class); + RocksDB rocksDB = mock(RocksDB.class); + doReturn(rocksDB).when(db).get(); + return db; + } + + +} diff --git a/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/scm/TestDecommissionScmSubcommand.java b/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/scm/TestDecommissionScmSubcommand.java index d44aed70eb4..f954aa2c9c7 100644 --- a/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/scm/TestDecommissionScmSubcommand.java +++ b/hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/scm/TestDecommissionScmSubcommand.java @@ -73,7 +73,7 @@ public void testDecommissionScmInputParams() throws Exception { try (GenericTestUtils.SystemOutCapturer capture = new GenericTestUtils.SystemOutCapturer()) { cmd.execute(client); - assertThat(capture.getOutput()).contains(scmId); + assertThat(capture.getOutput()).contains(scmId + "____pppppp"); } } diff --git a/hadoop-ozone/tools/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/hadoop-ozone/tools/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 00000000000..3c9e1c8a697 --- /dev/null +++ b/hadoop-ozone/tools/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1,16 @@ +# 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. +mock-maker-inline \ No newline at end of file