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

Commit 742fab1

Browse files
authored
Merge pull request #233 from sherfert/4.2-tx-handle-error
4.2 tx handle error
2 parents 7b9ca1a + c99a784 commit 742fab1

File tree

7 files changed

+258
-88
lines changed

7 files changed

+258
-88
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
package org.neo4j.shell.commands;
2+
3+
import org.junit.Before;
4+
import org.junit.Rule;
5+
import org.junit.Test;
6+
import org.junit.rules.ExpectedException;
7+
8+
import org.neo4j.shell.CypherShell;
9+
import org.neo4j.shell.ShellParameterMap;
10+
import org.neo4j.shell.StringLinePrinter;
11+
import org.neo4j.shell.cli.Format;
12+
import org.neo4j.shell.exception.CommandException;
13+
import org.neo4j.shell.prettyprint.PrettyConfig;
14+
import org.neo4j.shell.state.ErrorWhileInTransactionException;
15+
16+
import static org.hamcrest.CoreMatchers.containsString;
17+
import static org.hamcrest.CoreMatchers.not;
18+
import static org.hamcrest.MatcherAssert.assertThat;
19+
20+
public class CypherShellTransactionIntegrationTest extends CypherShellIntegrationTest
21+
{
22+
@Rule
23+
public final ExpectedException thrown = ExpectedException.none();
24+
25+
private final StringLinePrinter linePrinter = new StringLinePrinter();
26+
private Command rollbackCommand;
27+
private Command commitCommand;
28+
private Command beginCommand;
29+
30+
@Before
31+
public void setUp() throws Exception
32+
{
33+
linePrinter.clear();
34+
shell = new CypherShell( linePrinter, new PrettyConfig( Format.VERBOSE, true, 1000 ), false, new ShellParameterMap() );
35+
rollbackCommand = new Rollback( shell );
36+
commitCommand = new Commit( shell );
37+
beginCommand = new Begin( shell );
38+
39+
connect( "neo" );
40+
shell.execute( "MATCH (n) DETACH DELETE (n)" );
41+
}
42+
43+
@Test
44+
public void rollbackScenario() throws CommandException
45+
{
46+
//given
47+
shell.execute( "CREATE (:TestPerson {name: \"Jane Smith\"})" );
48+
49+
//when
50+
beginCommand.execute( "" );
51+
shell.execute( "CREATE (:NotCreated)" );
52+
rollbackCommand.execute( "" );
53+
54+
//then
55+
shell.execute( "MATCH (n) RETURN n" );
56+
57+
String output = linePrinter.output();
58+
assertThat( output, containsString( "| n " ) );
59+
assertThat( output, containsString( "| (:TestPerson {name: \"Jane Smith\"}) |" ) );
60+
assertThat( output, not( containsString( ":NotCreated" ) ) );
61+
}
62+
63+
@Test
64+
public void failureInTxScenario() throws CommandException
65+
{
66+
// given
67+
beginCommand.execute( "" );
68+
69+
// then
70+
thrown.expect( ErrorWhileInTransactionException.class );
71+
thrown.expectMessage( "/ by zero" );
72+
thrown.expectMessage( "An error occurred while in an open transaction. The transaction will be rolled back and terminated." );
73+
74+
shell.execute( "RETURN 1/0" );
75+
}
76+
77+
@Test
78+
public void failureInTxScenarioWithCypherFollowing() throws CommandException
79+
{
80+
// given
81+
beginCommand.execute( "" );
82+
try
83+
{
84+
shell.execute( "RETURN 1/0" );
85+
}
86+
catch ( ErrorWhileInTransactionException ignored )
87+
{
88+
// This is OK
89+
}
90+
91+
// when
92+
shell.execute( "RETURN 42" );
93+
94+
// then
95+
assertThat(linePrinter.output(), containsString("42"));
96+
}
97+
98+
@Test
99+
public void failureInTxScenarioWithCommitFollowing() throws CommandException
100+
{
101+
// given
102+
beginCommand.execute( "" );
103+
try
104+
{
105+
shell.execute( "RETURN 1/0" );
106+
}
107+
catch ( ErrorWhileInTransactionException ignored )
108+
{
109+
// This is OK
110+
}
111+
112+
// then
113+
thrown.expect( CommandException.class );
114+
thrown.expectMessage( "There is no open transaction to commit" );
115+
116+
// when
117+
commitCommand.execute( "" );
118+
}
119+
120+
@Test
121+
public void failureInTxScenarioWithRollbackFollowing() throws CommandException
122+
{
123+
// given
124+
beginCommand.execute( "" );
125+
try
126+
{
127+
shell.execute( "RETURN 1/0" );
128+
}
129+
catch ( ErrorWhileInTransactionException ignored )
130+
{
131+
// This is OK
132+
}
133+
134+
// then
135+
thrown.expect( CommandException.class );
136+
thrown.expectMessage( "There is no open transaction to rollback" );
137+
138+
// when
139+
rollbackCommand.execute( "" );
140+
}
141+
142+
@Test
143+
public void resetInFailedTxScenario() throws CommandException
144+
{
145+
//when
146+
beginCommand.execute( "" );
147+
try
148+
{
149+
shell.execute( "RETURN 1/0" );
150+
}
151+
catch ( ErrorWhileInTransactionException ignored )
152+
{
153+
// This is OK
154+
}
155+
shell.reset();
156+
157+
//then
158+
shell.execute( "CREATE (:TestPerson {name: \"Jane Smith\"})" );
159+
shell.execute( "MATCH (n) RETURN n" );
160+
161+
String result = linePrinter.output();
162+
assertThat( result, containsString( "| (:TestPerson {name: \"Jane Smith\"}) |" ) );
163+
assertThat( result, not( containsString( ":NotCreated" ) ) );
164+
}
165+
166+
@Test
167+
public void resetInTxScenario() throws CommandException
168+
{
169+
//when
170+
beginCommand.execute( "" );
171+
shell.execute( "CREATE (:NotCreated)" );
172+
shell.reset();
173+
174+
//then
175+
shell.execute( "CREATE (:TestPerson {name: \"Jane Smith\"})" );
176+
shell.execute( "MATCH (n) RETURN n" );
177+
178+
String result = linePrinter.output();
179+
assertThat( result, containsString( "| (:TestPerson {name: \"Jane Smith\"}) |" ) );
180+
assertThat( result, not( containsString( ":NotCreated" ) ) );
181+
}
182+
183+
@Test
184+
public void commitScenario() throws CommandException
185+
{
186+
beginCommand.execute( "" );
187+
shell.execute( "CREATE (:TestPerson {name: \"Joe Smith\"})" );
188+
assertThat( linePrinter.output(), containsString( "0 rows available after" ) );
189+
190+
linePrinter.clear();
191+
shell.execute( "CREATE (:TestPerson {name: \"Jane Smith\"})" );
192+
assertThat( linePrinter.output(), containsString( "0 rows available after" ) );
193+
194+
linePrinter.clear();
195+
shell.execute( "MATCH (n:TestPerson) RETURN n ORDER BY n.name" );
196+
assertThat( linePrinter.output(), containsString( "\n| (:TestPerson {name: \"Jane Smith\"}) |\n| (:TestPerson {name: \"Joe Smith\"}) |\n" ) );
197+
198+
commitCommand.execute( "" );
199+
}
200+
}

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

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,11 @@ public class CypherShellVerboseIntegrationTest extends CypherShellIntegrationTes
3131
public final ExpectedException thrown = ExpectedException.none();
3232

3333
private StringLinePrinter linePrinter = new StringLinePrinter();
34-
private Command rollbackCommand;
35-
private Command commitCommand;
36-
private Command beginCommand;
3734

3835
@Before
3936
public void setUp() throws Exception {
4037
linePrinter.clear();
4138
shell = new CypherShell(linePrinter, new PrettyConfig(Format.VERBOSE, true, 1000), false, new ShellParameterMap());
42-
rollbackCommand = new Rollback(shell);
43-
commitCommand = new Commit(shell);
44-
beginCommand = new Begin(shell);
4539

4640
connect( "neo" );
4741
}
@@ -81,25 +75,6 @@ public void connectTwiceThrows() throws CommandException {
8175
connect( "neo" );
8276
}
8377

84-
@Test
85-
public void rollbackScenario() throws CommandException {
86-
//given
87-
shell.execute("CREATE (:TestPerson {name: \"Jane Smith\"})");
88-
89-
//when
90-
beginCommand.execute("");
91-
shell.execute("CREATE (:NotCreated)");
92-
rollbackCommand.execute("");
93-
94-
//then
95-
shell.execute("MATCH (n) RETURN n");
96-
97-
String output = linePrinter.output();
98-
assertThat(output, containsString("| n "));
99-
assertThat(output, containsString("| (:TestPerson {name: \"Jane Smith\"}) |"));
100-
assertThat(output, not(containsString(":NotCreated")));
101-
}
102-
10378
@Test
10479
public void resetOutOfTxScenario() throws CommandException {
10580
//when
@@ -116,39 +91,6 @@ public void resetOutOfTxScenario() throws CommandException {
11691
"| (:TestPerson {name: \"Jane Smith\"}) |"));
11792
}
11893

119-
@Test
120-
public void resetInTxScenario() throws CommandException {
121-
//when
122-
beginCommand.execute("");
123-
shell.execute("CREATE (:NotCreated)");
124-
shell.reset();
125-
126-
//then
127-
shell.execute("CREATE (:TestPerson {name: \"Jane Smith\"})");
128-
shell.execute("MATCH (n) RETURN n");
129-
130-
String result = linePrinter.output();
131-
assertThat(result, containsString("| (:TestPerson {name: \"Jane Smith\"}) |"));
132-
assertThat(result, not(containsString(":NotCreated")));
133-
}
134-
135-
@Test
136-
public void commitScenario() throws CommandException {
137-
beginCommand.execute("");
138-
shell.execute("CREATE (:TestPerson {name: \"Joe Smith\"})");
139-
assertThat(linePrinter.output(), containsString("0 rows available after"));
140-
141-
linePrinter.clear();
142-
shell.execute("CREATE (:TestPerson {name: \"Jane Smith\"})");
143-
assertThat(linePrinter.output(), containsString("0 rows available after"));
144-
145-
linePrinter.clear();
146-
shell.execute("MATCH (n:TestPerson) RETURN n ORDER BY n.name");
147-
assertThat(linePrinter.output(), containsString("\n| (:TestPerson {name: \"Jane Smith\"}) |\n| (:TestPerson {name: \"Joe Smith\"}) |\n"));
148-
149-
commitCommand.execute("");
150-
}
151-
15294
@Test
15395
public void paramsAndListVariables() throws EvaluationException, CommandException {
15496
assertTrue(shell.getParameterMap().allParameterValues().isEmpty());

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

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

3-
import java.util.List;
43
import java.util.Optional;
54
import java.util.regex.Matcher;
65
import java.util.regex.Pattern;
@@ -102,7 +101,7 @@ private void executeCypher(@Nonnull final String cypher) throws CommandException
102101
lastNeo4jErrorCode = null;
103102
} catch (Neo4jException e) {
104103
lastNeo4jErrorCode = getErrorCode(e);
105-
throw e;
104+
throw boltStateHandler.handleException( e );
106105
}
107106
}
108107

@@ -158,12 +157,10 @@ public void beginTransaction() throws CommandException {
158157
}
159158

160159
@Override
161-
public Optional<List<BoltResult>> commitTransaction() throws CommandException {
160+
public void commitTransaction() throws CommandException {
162161
try {
163-
Optional<List<BoltResult>> results = boltStateHandler.commitTransaction();
164-
results.ifPresent(boltResult -> boltResult.forEach(result -> prettyPrinter.format(result, linePrinter)));
162+
boltStateHandler.commitTransaction();
165163
lastNeo4jErrorCode = null;
166-
return results;
167164
} catch (Neo4jException e) {
168165
lastNeo4jErrorCode = getErrorCode(e);
169166
throw e;

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

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

33
import org.neo4j.shell.exception.CommandException;
4-
import org.neo4j.shell.state.BoltResult;
5-
6-
import java.util.List;
7-
import java.util.Optional;
84

95
/**
106
* An object capable of starting, committing, and rolling back transactions.
@@ -21,7 +17,7 @@ public interface TransactionHandler {
2117
*
2218
* @throws CommandException if current transaction could not be committed
2319
*/
24-
Optional<List<BoltResult>> commitTransaction() throws CommandException;
20+
void commitTransaction() throws CommandException;
2521

2622
/**
2723
*

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public void beginTransaction() throws CommandException {
118118
}
119119

120120
@Override
121-
public Optional<List<BoltResult>> commitTransaction() throws CommandException {
121+
public void commitTransaction() throws CommandException {
122122
if (!isConnected()) {
123123
throw new CommandException("Not connected to Neo4j");
124124
}
@@ -128,8 +128,6 @@ public Optional<List<BoltResult>> commitTransaction() throws CommandException {
128128
tx.commit();
129129
tx.close();
130130
tx = null;
131-
132-
return Optional.empty();
133131
}
134132

135133
@Override
@@ -145,6 +143,29 @@ public void rollbackTransaction() throws CommandException {
145143
tx = null;
146144
}
147145

146+
/**
147+
* Handle an exception while getting or consuming the result.
148+
* If not in TX, return the given exception.
149+
* If in a TX, terminate the TX and return a more verbose error message.
150+
*
151+
* @param e the thrown exception.
152+
* @return a suitable exception to rethrow.
153+
*/
154+
public Neo4jException handleException( Neo4jException e )
155+
{
156+
if ( isTransactionOpen() )
157+
{
158+
tx.close();
159+
tx = null;
160+
return new ErrorWhileInTransactionException(
161+
"An error occurred while in an open transaction. The transaction will be rolled back and terminated. Error: " + e.getMessage(), e );
162+
}
163+
else
164+
{
165+
return e;
166+
}
167+
}
168+
148169
@Override
149170
public boolean isTransactionOpen() {
150171
return tx != null;

0 commit comments

Comments
 (0)