Skip to content
This repository was archived by the owner on Jul 6, 2023. It is now read-only.

Commit ad57330

Browse files
committed
Merge remote-tracking branch 'origin/1.1' into 1.2
# Conflicts: # cypher-shell/src/integration-test/java/org/neo4j/shell/MainIntegrationTest.java
2 parents b039dd4 + 4e94b2e commit ad57330

File tree

3 files changed

+193
-76
lines changed

3 files changed

+193
-76
lines changed

cypher-shell/src/integration-test/java/org/neo4j/shell/MainIntegrationTest.java

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.neo4j.shell;
22

3-
import org.junit.Ignore;
3+
import org.junit.Before;
44
import org.junit.Rule;
55
import org.junit.Test;
66
import org.junit.rules.ExpectedException;
@@ -36,45 +36,73 @@ private static class ShellAndConnection
3636

3737
@Rule
3838
public final ExpectedException exception = ExpectedException.none();
39-
40-
@Test
41-
public void connectInteractivelyPromptOnWrongAuthentication() throws Exception
42-
{
39+
private String inputString = String.format( "neo4j%nneo%n" );
40+
private ByteArrayOutputStream baos;
41+
private ConnectionConfig connectionConfig;
42+
private CypherShell shell;
43+
private Main main;
44+
45+
@Before
46+
public void setup() {
4347
// given
44-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
45-
Main main = getMain( baos );
48+
InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() );
49+
50+
baos = new ByteArrayOutputStream();
51+
PrintStream ps = new PrintStream( baos );
52+
53+
main = new Main( inputStream, ps );
4654

4755
CliArgs cliArgs = new CliArgs();
48-
cliArgs.setUsername( "", "" );
56+
cliArgs.setUsername("", "");
4957
cliArgs.setPassword( "", "" );
5058

5159
ShellAndConnection sac = getShell( cliArgs );
52-
CypherShell shell = sac.shell;
53-
ConnectionConfig connectionConfig = sac.connectionConfig;
60+
shell = sac.shell;
61+
connectionConfig = sac.connectionConfig;
62+
}
5463

64+
@Test
65+
public void promptsOnWrongAuthenticationIfInteractive() throws Exception {
5566
// when
56-
assertEquals( "", connectionConfig.username() );
57-
assertEquals( "", connectionConfig.password() );
67+
assertEquals("", connectionConfig.username());
68+
assertEquals("", connectionConfig.password());
5869

59-
main.connectMaybeInteractively( shell, connectionConfig, true );
70+
main.connectMaybeInteractively(shell, connectionConfig, true, true);
6071

6172
// then
6273
// should be connected
63-
assertTrue( shell.isConnected() );
74+
assertTrue(shell.isConnected());
6475
// should have prompted and set the username and password
65-
assertEquals( "neo4j", connectionConfig.username() );
66-
assertEquals( "neo", connectionConfig.password() );
76+
assertEquals("neo4j", connectionConfig.username());
77+
assertEquals("neo", connectionConfig.password());
6778

6879
String out = baos.toString();
6980
assertEquals( String.format( "username: neo4j%npassword: ***%n" ), out );
7081
}
7182

83+
@Test
84+
public void promptsSilentlyOnWrongAuthenticationIfOutputRedirected() throws Exception {
85+
// when
86+
assertEquals("", connectionConfig.username());
87+
assertEquals("", connectionConfig.password());
88+
89+
main.connectMaybeInteractively(shell, connectionConfig, true, false);
90+
91+
// then
92+
// should be connected
93+
assertTrue(shell.isConnected());
94+
// should have prompted silently and set the username and password
95+
assertEquals("neo4j", connectionConfig.username());
96+
assertEquals("neo", connectionConfig.password());
97+
98+
String out = baos.toString();
99+
assertEquals( "", out );
100+
}
101+
72102
@Test
73103
public void wrongPortWithBolt() throws Exception
74104
{
75105
// given
76-
Main main = getMain( new ByteArrayOutputStream() );
77-
78106
CliArgs cliArgs = new CliArgs();
79107
cliArgs.setScheme( "bolt://", "" );
80108
cliArgs.setPort( 1234 );
@@ -85,15 +113,13 @@ public void wrongPortWithBolt() throws Exception
85113

86114
exception.expect( ServiceUnavailableException.class );
87115
exception.expectMessage( "Unable to connect to localhost:1234, ensure the database is running and that there is a working network connection to it" );
88-
main.connectMaybeInteractively( shell, connectionConfig, true );
116+
main.connectMaybeInteractively( shell, connectionConfig, true, true );
89117
}
90118

91119
@Test
92120
public void wrongPortWithNeo4j() throws Exception
93121
{
94122
// given
95-
Main main = getMain( new ByteArrayOutputStream() );
96-
97123
CliArgs cliArgs = new CliArgs();
98124
cliArgs.setScheme( "neo4j://", "" );
99125
cliArgs.setPort( 1234 );
@@ -104,18 +130,7 @@ public void wrongPortWithNeo4j() throws Exception
104130

105131
exception.expect( ServiceUnavailableException.class );
106132
exception.expectMessage( "Unable to connect to database, ensure the database is running and that there is a working network connection to it" );
107-
main.connectMaybeInteractively( shell, connectionConfig, true );
108-
}
109-
110-
private Main getMain( ByteArrayOutputStream baos )
111-
{
112-
// what the user inputs when prompted
113-
String inputString = String.format( "neo4j%nneo%n" );
114-
InputStream inputStream = new ByteArrayInputStream( inputString.getBytes() );
115-
116-
PrintStream ps = new PrintStream( baos );
117-
118-
return new Main( inputStream, ps );
133+
main.connectMaybeInteractively( shell, connectionConfig, true, true );
119134
}
120135

121136
private ShellAndConnection getShell( CliArgs cliArgs )

cypher-shell/src/main/java/org/neo4j/shell/Main.java

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import org.neo4j.shell.build.Build;
66
import org.neo4j.shell.cli.CliArgHelper;
77
import org.neo4j.shell.cli.CliArgs;
8-
import org.neo4j.shell.cli.Format;
98
import org.neo4j.shell.commands.CommandHelper;
109
import org.neo4j.shell.exception.CommandException;
1110
import org.neo4j.shell.log.AnsiLogger;
@@ -15,9 +14,11 @@
1514
import javax.annotation.Nonnull;
1615
import javax.annotation.Nullable;
1716
import java.io.InputStream;
17+
import java.io.OutputStream;
1818
import java.io.PrintStream;
1919

2020
import static org.neo4j.shell.ShellRunner.isInputInteractive;
21+
import static org.neo4j.shell.ShellRunner.isOutputInteractive;
2122

2223
public class Main {
2324
static final String NEO_CLIENT_ERROR_SECURITY_UNAUTHORIZED = "Neo.ClientError.Security.Unauthorized";
@@ -73,7 +74,7 @@ void startShell(@Nonnull CliArgs cliArgs) {
7374
try {
7475
CypherShell shell = new CypherShell(logger, prettyConfig, ShellRunner.shouldBeInteractive( cliArgs ));
7576
// Can only prompt for password if input has not been redirected
76-
connectMaybeInteractively(shell, connectionConfig, isInputInteractive());
77+
connectMaybeInteractively(shell, connectionConfig, isInputInteractive(), isOutputInteractive());
7778

7879
// Construct shellrunner after connecting, due to interrupt handling
7980
ShellRunner shellRunner = ShellRunner.getShellRunner(cliArgs, shell, logger, connectionConfig);
@@ -93,9 +94,20 @@ void startShell(@Nonnull CliArgs cliArgs) {
9394
/**
9495
* Connect the shell to the server, and try to handle missing passwords and such
9596
*/
96-
void connectMaybeInteractively(@Nonnull CypherShell shell, @Nonnull ConnectionConfig connectionConfig,
97-
boolean interactively)
97+
void connectMaybeInteractively(@Nonnull CypherShell shell,
98+
@Nonnull ConnectionConfig connectionConfig,
99+
boolean inputInteractive,
100+
boolean outputInteractive)
98101
throws Exception {
102+
103+
OutputStream outputStream = outputInteractive ? out : new ThrowawayOutputStream();
104+
105+
ConsoleReader consoleReader = new ConsoleReader(in, outputStream);
106+
// Disable expansion of bangs: !
107+
consoleReader.setExpandEvents(false);
108+
// Ensure Reader does not handle user input for ctrl+C behaviour
109+
consoleReader.setHandleUserInterrupt(false);
110+
99111
try {
100112
shell.connect(connectionConfig);
101113
} catch (AuthenticationException e) {
@@ -104,19 +116,24 @@ void connectMaybeInteractively(@Nonnull CypherShell shell, @Nonnull ConnectionCo
104116
throw e;
105117
}
106118
// else need to prompt for username and password
107-
if (interactively) {
119+
if (inputInteractive) {
108120
if (connectionConfig.username().isEmpty()) {
109-
connectionConfig.setUsername(promptForNonEmptyText("username", null));
121+
String username = outputInteractive ?
122+
promptForNonEmptyText("username", consoleReader, null) :
123+
promptForText("username", consoleReader, null);
124+
connectionConfig.setUsername(username);
110125
}
111126
if (connectionConfig.password().isEmpty()) {
112-
connectionConfig.setPassword(promptForText("password", '*'));
127+
connectionConfig.setPassword(promptForText("password", consoleReader, '*'));
113128
}
114129
// try again
115130
shell.connect(connectionConfig);
116131
} else {
117132
// Can't prompt because input has been redirected
118133
throw e;
119134
}
135+
} finally {
136+
consoleReader.close();
120137
}
121138
}
122139

@@ -130,40 +147,41 @@ void connectMaybeInteractively(@Nonnull CypherShell shell, @Nonnull ConnectionCo
130147
* in case of errors
131148
*/
132149
@Nonnull
133-
private String promptForNonEmptyText(@Nonnull String prompt, @Nullable Character mask) throws Exception {
134-
String text = promptForText(prompt, mask);
150+
private String promptForNonEmptyText(@Nonnull String prompt, @Nonnull ConsoleReader consoleReader, @Nullable Character mask) throws Exception {
151+
String text = promptForText(prompt, consoleReader, mask);
135152
if (!text.isEmpty()) {
136153
return text;
137154
}
138-
out.println(prompt + " cannot be empty");
139-
out.println();
140-
return promptForNonEmptyText(prompt, mask);
155+
consoleReader.println( prompt + " cannot be empty" );
156+
consoleReader.println();
157+
return promptForNonEmptyText(prompt, consoleReader, mask);
141158
}
142159

143160
/**
144161
* @param prompt
145162
* to display to the user
146163
* @param mask
147164
* single character to display instead of what the user is typing, use null if text is not secret
165+
* @param consoleReader
166+
* the reader
148167
* @return the text which was entered
149168
* @throws Exception
150169
* in case of errors
151170
*/
152171
@Nonnull
153-
private String promptForText(@Nonnull String prompt, @Nullable Character mask) throws Exception {
154-
String line;
155-
ConsoleReader consoleReader = new ConsoleReader(in, out);
156-
// Disable expansion of bangs: !
157-
consoleReader.setExpandEvents(false);
158-
// Ensure Reader does not handle user input for ctrl+C behaviour
159-
consoleReader.setHandleUserInterrupt(false);
160-
line = consoleReader.readLine(prompt + ": ", mask);
161-
consoleReader.close();
162-
172+
private String promptForText(@Nonnull String prompt, @Nonnull ConsoleReader consoleReader, @Nullable Character mask) throws Exception {
173+
String line = consoleReader.readLine(prompt + ": ", mask);
163174
if (line == null) {
164175
throw new CommandException("No text could be read, exiting...");
165176
}
166177

167178
return line;
168179
}
180+
181+
private static class ThrowawayOutputStream extends OutputStream {
182+
@Override
183+
public void write( int b )
184+
{
185+
}
186+
}
169187
}

0 commit comments

Comments
 (0)