diff --git a/hadoop-plugin/src/main/groovy/com/linkedin/gradle/azkaban/AzkabanHelper.groovy b/hadoop-plugin/src/main/groovy/com/linkedin/gradle/azkaban/AzkabanHelper.groovy index f982a35..20732e4 100644 --- a/hadoop-plugin/src/main/groovy/com/linkedin/gradle/azkaban/AzkabanHelper.groovy +++ b/hadoop-plugin/src/main/groovy/com/linkedin/gradle/azkaban/AzkabanHelper.groovy @@ -252,15 +252,22 @@ class AzkabanHelper { * @param shortDelay Whether or not to introduce a short delay to allow Gradle to complete writing to the console * @return The secret password */ - static char[] consoleSecretInput(Console console, String message, boolean shortDelay) { + static char[] consoleSecretInput(Console console, String message, boolean shortDelay, boolean retryIfEmpty = false) { // Give Gradle time to flush the logger to the screen and write its progress log line at the // bottom of the screen, so we can augment this line with a prompt for the input if (shortDelay) { sleep(500); } - console.format(message).flush(); - return console.readPassword(); + char[] secretInput; + while (true) { + console.format(message).flush(); + secretInput = console.readPassword(); + if (!retryIfEmpty || (secretInput != null && secretInput.length > 0)) { + break; + } + } + return secretInput; } /** @@ -455,7 +462,7 @@ class AzkabanHelper { if (azkProject.azkabanPassword == null) { def console = getSystemConsole(); - sessionId = azkabanLogin(azkProject.azkabanUrl, azkProject.azkabanUserName, consoleSecretInput(console, " > Enter ${passwordString}: ", true)); + sessionId = azkabanLogin(azkProject.azkabanUrl, azkProject.azkabanUserName, consoleSecretInput(console, " > Enter ${passwordString}: ", true, true)); } else { logger.lifecycle("Azkaban ${passwordString}: *********"); sessionId = azkabanLogin(azkProject.azkabanUrl, azkProject.azkabanUserName, azkProject.azkabanPassword.toCharArray()); diff --git a/hadoop-plugin/src/test/groovy/com/linkedin/gradle/azkaban/AzkabanHelperTest.groovy b/hadoop-plugin/src/test/groovy/com/linkedin/gradle/azkaban/AzkabanHelperTest.groovy index 6dde0ec..006f377 100644 --- a/hadoop-plugin/src/test/groovy/com/linkedin/gradle/azkaban/AzkabanHelperTest.groovy +++ b/hadoop-plugin/src/test/groovy/com/linkedin/gradle/azkaban/AzkabanHelperTest.groovy @@ -22,6 +22,7 @@ import org.junit.Test import org.junit.rules.ExpectedException import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.* class AzkabanHelperTest { @Test @@ -44,4 +45,27 @@ class AzkabanHelperTest { expectedEx.expectMessage(AzkabanHelper.CONSOLE_EXCEPTION_MESSAGE); AzkabanHelper.getSystemConsole(); } + + // Since Console is final class, it requires `mock-maker-inline` extension to run below test. + // More details: https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#unmockable + // Enabling this extension causes several other test cases failure. Keeping below test case commented for now. +// @Test +// void testConsoleSecretInput() { +// String consoleInputMessage = "Enter test input: " +// char[] nonEmptyInput = "test".toCharArray() +// char[] emptyInput = "".toCharArray() +// Console mockedConsole = mock(Console.class) +// +// when(mockedConsole.readPassword()).thenReturn(nonEmptyInput) +// assertEquals(AzkabanHelper.consoleSecretInput(mockedConsole, consoleInputMessage, false, false), nonEmptyInput) +// +// when(mockedConsole.readPassword()).thenReturn(nonEmptyInput) +// assertEquals(AzkabanHelper.consoleSecretInput(mockedConsole, consoleInputMessage, false, true), nonEmptyInput) +// +// when(mockedConsole.readPassword()).thenReturn(emptyInput) +// assertEquals(AzkabanHelper.consoleSecretInput(mockedConsole, consoleInputMessage, false, false), emptyInput) +// +// when(mockedConsole.readPassword()).thenReturn(emptyInput, emptyInput, nonEmptyInput) +// assertEquals(AzkabanHelper.consoleSecretInput(mockedConsole, consoleInputMessage, false, true), nonEmptyInput) +// } }