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

Commit aa0b07b

Browse files
committed
In interactive mode, do not switch when DB not found.
1 parent 2684011 commit aa0b07b

File tree

12 files changed

+150
-79
lines changed

12 files changed

+150
-79
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
public class MainIntegrationTest {
1818

1919
@Test
20-
public void connectInteractivelyPromptsOnWrongAuthentication() throws Exception {
20+
public void connectInteractivelyPromptOnWrongAuthentication() throws Exception {
2121
// given
2222
// what the user inputs when prompted
2323
String inputString = String.format( "neo4j%nneo%n" );
@@ -43,7 +43,7 @@ public void connectInteractivelyPromptsOnWrongAuthentication() throws Exception
4343
cliArgs.getEncryption(),
4444
cliArgs.getDatabase());
4545

46-
CypherShell shell = new CypherShell(logger, prettyConfig);
46+
CypherShell shell = new CypherShell(logger, prettyConfig, true);
4747

4848
// when
4949
assertEquals("", connectionConfig.username());

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellFailureIntegrationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class CypherShellFailureIntegrationTest {
2626
@Before
2727
public void setUp() throws Exception {
2828
linePrinter.clear();
29-
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000));
29+
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false);
3030
}
3131

3232
@Test

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellMultiDatabaseIntegrationTest.java

Lines changed: 90 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static org.hamcrest.CoreMatchers.containsString;
1818
import static org.hamcrest.CoreMatchers.is;
1919
import static org.hamcrest.MatcherAssert.assertThat;
20+
import static org.junit.Assert.fail;
2021
import static org.junit.Assume.assumeTrue;
2122
import static org.neo4j.driver.internal.messaging.request.MultiDatabaseUtil.ABSENT_DB_NAME;
2223
import static org.neo4j.shell.DatabaseManager.DEFAULT_DEFAULT_DB_NAME;
@@ -35,94 +36,141 @@ public class CypherShellMultiDatabaseIntegrationTest
3536
private CypherShell shell;
3637

3738
@Before
38-
public void setUp() throws Exception {
39+
public void setUp() throws Exception
40+
{
3941
linePrinter.clear();
40-
shell = new CypherShell(linePrinter, new PrettyConfig(Format.PLAIN, true, 1000));
41-
useCommand = new Use(shell);
42-
beginCommand = new Begin(shell);
43-
rollbackCommand = new Rollback(shell);
42+
shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), false );
43+
useCommand = new Use( shell );
44+
beginCommand = new Begin( shell );
45+
rollbackCommand = new Rollback( shell );
4446

45-
shell.connect(new ConnectionConfig("bolt://", "localhost", 7687, "neo4j", "neo", true, ABSENT_DB_NAME));
47+
shell.connect( new ConnectionConfig( "bolt://", "localhost", 7687, "neo4j", "neo", true, ABSENT_DB_NAME ) );
4648

4749
// Multiple databases are only available from 4.0
4850
assumeTrue( majorVersion( shell.getServerVersion() ) >= 4 );
4951
}
5052

5153
@After
52-
public void tearDown() throws Exception {
54+
public void tearDown() throws Exception
55+
{
5356
}
5457

5558
@Test
56-
public void switchingToSystemDatabaseWorks() throws CommandException {
57-
useCommand.execute(SYSTEM_DB_NAME);
59+
public void switchingToSystemDatabaseWorks() throws CommandException
60+
{
61+
useCommand.execute( SYSTEM_DB_NAME );
5862

59-
assertThat(linePrinter.output(), is(""));
63+
assertThat( linePrinter.output(), is( "" ) );
6064
assertOnSystemDB();
6165
}
6266

6367
@Test
64-
public void switchingToSystemDatabaseIsNotCaseSensitive() throws CommandException {
65-
useCommand.execute("SyStEm");
68+
public void switchingToSystemDatabaseIsNotCaseSensitive() throws CommandException
69+
{
70+
useCommand.execute( "SyStEm" );
6671

67-
assertThat(linePrinter.output(), is(""));
72+
assertThat( linePrinter.output(), is( "" ) );
6873
assertOnSystemDB();
6974
}
7075

7176
@Test
72-
public void switchingToSystemDatabaseAndBackToNeo4jWorks() throws CommandException {
73-
useCommand.execute(SYSTEM_DB_NAME);
74-
useCommand.execute(DEFAULT_DEFAULT_DB_NAME);
77+
public void switchingToSystemDatabaseAndBackToNeo4jWorks() throws CommandException
78+
{
79+
useCommand.execute( SYSTEM_DB_NAME );
80+
useCommand.execute( DEFAULT_DEFAULT_DB_NAME );
7581

76-
assertThat(linePrinter.output(), is(""));
82+
assertThat( linePrinter.output(), is( "" ) );
7783
assertOnRegularDB();
7884
}
7985

8086
@Test
81-
public void switchingToSystemDatabaseAndBackToDefaultWorks() throws CommandException {
82-
useCommand.execute(SYSTEM_DB_NAME);
83-
useCommand.execute(ABSENT_DB_NAME);
87+
public void switchingToSystemDatabaseAndBackToDefaultWorks() throws CommandException
88+
{
89+
useCommand.execute( SYSTEM_DB_NAME );
90+
useCommand.execute( ABSENT_DB_NAME );
8491

85-
assertThat(linePrinter.output(), is(""));
92+
assertThat( linePrinter.output(), is( "" ) );
8693
assertOnRegularDB();
8794
}
8895

8996
@Test
90-
public void switchingDatabaseInOpenTransactionShouldFail() throws CommandException {
91-
thrown.expect(CommandException.class);
92-
thrown.expectMessage("There is an open transaction.");
97+
public void switchingDatabaseInOpenTransactionShouldFail() throws CommandException
98+
{
99+
thrown.expect( CommandException.class );
100+
thrown.expectMessage( "There is an open transaction." );
93101

94-
beginCommand.execute("");
95-
useCommand.execute("another_database");
102+
beginCommand.execute( "" );
103+
useCommand.execute( "another_database" );
96104
}
97105

98106
@Test
99-
public void switchingDatabaseAfterRollbackTransactionWorks() throws CommandException {
100-
beginCommand.execute("");
101-
rollbackCommand.execute("");
102-
useCommand.execute(SYSTEM_DB_NAME);
107+
public void switchingDatabaseAfterRollbackTransactionWorks() throws CommandException
108+
{
109+
beginCommand.execute( "" );
110+
rollbackCommand.execute( "" );
111+
useCommand.execute( SYSTEM_DB_NAME );
103112

104-
assertThat(linePrinter.output(), is(""));
113+
assertThat( linePrinter.output(), is( "" ) );
105114
assertOnSystemDB();
106115
}
107116

108117
@Test
109-
public void switchingToNonExistingDatabaseShouldGiveErrorResponseFromServer() throws CommandException {
110-
thrown.expect(ClientException.class);
111-
thrown.expectMessage("Database does not exist");
118+
public void switchingToNonExistingDatabaseShouldGiveErrorResponseFromServer() throws CommandException
119+
{
120+
useCommand.execute( SYSTEM_DB_NAME );
121+
122+
try
123+
{
124+
useCommand.execute( "this_database_name_does_not_exist_in_test_container" );
125+
fail( "No ClientException thrown" );
126+
}
127+
catch ( ClientException e )
128+
{
129+
// In non-interactive we want to switch even if the database does not exist (in case we don't have fail-fast)
130+
assertOnNoValidDB();
131+
}
132+
}
112133

113-
useCommand.execute("this_database_name_does_not_exist_in_test_container");
134+
@Test
135+
public void switchingToNonExistingDatabaseShouldGiveErrorResponseFromServerInteractive() throws CommandException
136+
{
137+
shell = new CypherShell( linePrinter, new PrettyConfig( Format.PLAIN, true, 1000 ), true );
138+
useCommand = new Use( shell );
139+
shell.connect( new ConnectionConfig( "bolt://", "localhost", 7687, "neo4j", "neo", true, ABSENT_DB_NAME ) );
140+
141+
useCommand.execute( SYSTEM_DB_NAME );
142+
143+
try
144+
{
145+
useCommand.execute( "this_database_name_does_not_exist_in_test_container" );
146+
fail( "No ClientException thrown" );
147+
}
148+
catch ( ClientException e )
149+
{
150+
// In interactive we do not want to switch if the database does not exist
151+
assertOnSystemDB();
152+
}
114153
}
115154

116155
// HELPERS
117156

118-
private void assertOnRegularDB() throws CommandException {
119-
shell.execute("RETURN 'toadstool'");
120-
assertThat(linePrinter.output(), containsString("toadstool"));
157+
private void assertOnRegularDB() throws CommandException
158+
{
159+
shell.execute( "RETURN 'toadstool'" );
160+
assertThat( linePrinter.output(), containsString( "toadstool" ) );
161+
}
162+
163+
private void assertOnSystemDB() throws CommandException
164+
{
165+
shell.execute( "SHOW DATABASES" );
166+
assertThat( linePrinter.output(), containsString( "neo4j" ) );
167+
assertThat( linePrinter.output(), containsString( "system" ) );
121168
}
122169

123-
private void assertOnSystemDB() throws CommandException {
124-
shell.execute("SHOW DATABASES");
125-
assertThat(linePrinter.output(), containsString("neo4j"));
126-
assertThat(linePrinter.output(), containsString("system"));
170+
private void assertOnNoValidDB() throws CommandException
171+
{
172+
thrown.expect( ClientException.class );
173+
thrown.expectMessage( "Database does not exist" );
174+
shell.execute( "RETURN 1" );
127175
}
128176
}

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellPlainIntegrationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class CypherShellPlainIntegrationTest {
2828
@Before
2929
public void setUp() throws Exception {
3030
linePrinter.clear();
31-
shell = new CypherShell(linePrinter, new PrettyConfig(Format.PLAIN, true, 1000));
31+
shell = new CypherShell(linePrinter, new PrettyConfig(Format.PLAIN, true, 1000), false);
3232
shell.connect(new ConnectionConfig("bolt://", "localhost", 7687, "neo4j", "neo", true, ABSENT_DB_NAME));
3333
}
3434

cypher-shell/src/integration-test/java/org/neo4j/shell/commands/CypherShellVerboseIntegrationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class CypherShellVerboseIntegrationTest {
3434
@Before
3535
public void setUp() throws Exception {
3636
linePrinter.clear();
37-
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000));
37+
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false);
3838
rollbackCommand = new Rollback(shell);
3939
commitCommand = new Commit(shell);
4040
beginCommand = new Begin(shell);

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ public class CypherShell implements StatementExecuter, Connector, TransactionHan
4040
private ExpressionEvaluator evaluator = Evaluator.expressionEvaluator();
4141
private String lastNeo4jErrorCode;
4242

43-
public CypherShell(@Nonnull LinePrinter linePrinter, @Nonnull PrettyConfig prettyConfig) {
44-
this(linePrinter, new BoltStateHandler(), new PrettyPrinter(prettyConfig));
43+
public CypherShell(@Nonnull LinePrinter linePrinter,
44+
@Nonnull PrettyConfig prettyConfig,
45+
boolean isInteractive) {
46+
this(linePrinter, new BoltStateHandler(isInteractive), new PrettyPrinter(prettyConfig));
4547
}
4648

4749
protected CypherShell(@Nonnull LinePrinter linePrinter,

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ public interface DatabaseManager
1111
String SYSTEM_DB_NAME = "system";
1212
String DEFAULT_DEFAULT_DB_NAME = "neo4j";
1313

14-
String DATABASE_NOT_FOUND_ERROR_CODE = "Neo.ClientError.Database.DatabaseNotFound";
1514
String DATABASE_UNAVAILABLE_ERROR_CODE = "Neo.TransientError.General.DatabaseUnavailable";
1615

1716
void setActiveDatabase(String databaseName) throws CommandException;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void startShell(@Nonnull CliArgs cliArgs) {
7171
cliArgs.getDatabase());
7272

7373
try {
74-
CypherShell shell = new CypherShell(logger, prettyConfig);
74+
CypherShell shell = new CypherShell(logger, prettyConfig, ShellRunner.shouldBeInteractive( cliArgs ));
7575
// Can only prompt for password if input has not been redirected
7676
connectMaybeInteractively(shell, connectionConfig, isInputInteractive());
7777

cypher-shell/src/main/java/org/neo4j/shell/cli/InteractiveShellRunner.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.concurrent.atomic.AtomicBoolean;
2828

2929
import static org.neo4j.shell.DatabaseManager.ABSENT_DB_NAME;
30-
import static org.neo4j.shell.DatabaseManager.DATABASE_NOT_FOUND_ERROR_CODE;
3130
import static org.neo4j.shell.DatabaseManager.DATABASE_UNAVAILABLE_ERROR_CODE;
3231

3332
/**
@@ -41,7 +40,6 @@ public class InteractiveShellRunner implements ShellRunner, SignalHandler {
4140
private final static String USERNAME_DB_DELIMITER = "@";
4241
private final static int ONELINE_PROMPT_MAX_LENGTH = 50;
4342
private static final String UNRESOLVED_DEFAULT_DB_PROPMPT_TEXT = "<default_database>";
44-
private static final String DATABASE_NOT_FOUND_ERROR_PROMPT_TEXT = "[NOT_FOUND]";
4543
private static final String DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT = "[UNAVAILABLE]";
4644

4745
// Need to know if we are currently executing when catch Ctrl-C, needs to be atomic due to
@@ -212,9 +210,7 @@ AnsiFormattedText updateAndGetPrompt() {
212210
private String getErrorPrompt(String errorCode) {
213211
// NOTE: errorCode can be null
214212
String errorPromptSuffix;
215-
if (DATABASE_NOT_FOUND_ERROR_CODE.equals(errorCode)) {
216-
errorPromptSuffix = DATABASE_NOT_FOUND_ERROR_PROMPT_TEXT;
217-
} else if (DATABASE_UNAVAILABLE_ERROR_CODE.equals(errorCode)) {
213+
if (DATABASE_UNAVAILABLE_ERROR_CODE.equals(errorCode)) {
218214
errorPromptSuffix = DATABASE_UNAVAILABLE_ERROR_PROMPT_TEXT;
219215
} else {
220216
errorPromptSuffix = "";

cypher-shell/src/main/java/org/neo4j/shell/state/BoltStateHandler.java

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
package org.neo4j.shell.state;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Optional;
7+
import java.util.function.BiFunction;
8+
import java.util.function.Consumer;
9+
import java.util.stream.Collectors;
10+
import javax.annotation.Nonnull;
11+
import javax.annotation.Nullable;
12+
313
import org.neo4j.driver.AccessMode;
414
import org.neo4j.driver.AuthToken;
515
import org.neo4j.driver.AuthTokens;
@@ -11,6 +21,7 @@
1121
import org.neo4j.driver.Statement;
1222
import org.neo4j.driver.StatementResult;
1323
import org.neo4j.driver.Transaction;
24+
import org.neo4j.driver.exceptions.ClientException;
1425
import org.neo4j.driver.exceptions.SessionExpiredException;
1526
import org.neo4j.driver.summary.DatabaseInfo;
1627
import org.neo4j.shell.ConnectionConfig;
@@ -21,16 +32,6 @@
2132
import org.neo4j.shell.exception.CommandException;
2233
import org.neo4j.shell.log.NullLogging;
2334

24-
import javax.annotation.Nonnull;
25-
import javax.annotation.Nullable;
26-
import java.util.ArrayList;
27-
import java.util.List;
28-
import java.util.Map;
29-
import java.util.Optional;
30-
import java.util.function.BiFunction;
31-
import java.util.function.Consumer;
32-
import java.util.stream.Collectors;
33-
3435
/**
3536
* Handles interactions with the driver
3637
*/
@@ -42,14 +43,17 @@ public class BoltStateHandler implements TransactionHandler, Connector, Database
4243
private List<Statement> transactionStatements;
4344
private String activeDatabaseNameAsSetByUser;
4445
private String actualDatabaseNameAsReportedByServer;
46+
private final boolean isInteractive;
4547

46-
public BoltStateHandler() {
47-
this(GraphDatabase::driver);
48+
public BoltStateHandler(boolean isInteractive) {
49+
this(GraphDatabase::driver, isInteractive);
4850
}
4951

50-
BoltStateHandler(TriFunction<String, AuthToken, Config, Driver> driverProvider) {
52+
BoltStateHandler(TriFunction<String, AuthToken, Config, Driver> driverProvider,
53+
boolean isInteractive) {
5154
this.driverProvider = driverProvider;
5255
activeDatabaseNameAsSetByUser = ABSENT_DB_NAME;
56+
this.isInteractive = isInteractive;
5357
}
5458

5559
@Override
@@ -58,9 +62,31 @@ public void setActiveDatabase(String databaseName) throws CommandException
5862
if (isTransactionOpen()) {
5963
throw new CommandException("There is an open transaction. You need to close it before you can switch database.");
6064
}
65+
String previousDatabaseName = activeDatabaseNameAsSetByUser;
6166
activeDatabaseNameAsSetByUser = databaseName;
62-
if (isConnected()) {
63-
reconnect(false);
67+
try
68+
{
69+
if ( isConnected() )
70+
{
71+
reconnect( false );
72+
}
73+
}
74+
catch ( ClientException e )
75+
{
76+
if ( isInteractive )
77+
{
78+
// We want to try to connect to the previous database
79+
activeDatabaseNameAsSetByUser = previousDatabaseName;
80+
try
81+
{
82+
reconnect( false );
83+
}
84+
catch ( ClientException e2 )
85+
{
86+
e.addSuppressed( e2 );
87+
}
88+
}
89+
throw e;
6490
}
6591
}
6692

0 commit comments

Comments
 (0)