bolt_client/client/
v3.rs

1#[cfg(test)]
2mod tests {
3    use bolt_proto::{message::*, value::*, version::*, ServerState::*};
4
5    use crate::{client::v1::tests::*, error::CommunicationError, skip_if_handshake_failed};
6
7    #[tokio::test]
8    async fn hello() {
9        let client = new_client(V3_0).await;
10        skip_if_handshake_failed!(client);
11        let mut client = client.unwrap();
12        assert_eq!(client.server_state(), Connected);
13        let response = initialize_client(&mut client, true).await.unwrap();
14        assert!(Success::try_from(response).is_ok());
15        assert_eq!(client.server_state(), Ready);
16    }
17
18    #[tokio::test]
19    async fn hello_fail() {
20        let client = new_client(V3_0).await;
21        skip_if_handshake_failed!(client);
22        let mut client = client.unwrap();
23        assert_eq!(client.server_state(), Connected);
24        let response = initialize_client(&mut client, false).await.unwrap();
25        assert!(Failure::try_from(response).is_ok());
26        assert_eq!(client.server_state(), Defunct);
27    }
28
29    #[tokio::test]
30    async fn goodbye() {
31        let client = get_initialized_client(V3_0).await;
32        skip_if_handshake_failed!(client);
33        let mut client = client.unwrap();
34        assert_eq!(client.server_state(), Ready);
35        assert!(client.goodbye().await.is_ok());
36        assert_eq!(client.server_state(), Defunct);
37    }
38
39    #[tokio::test]
40    async fn run() {
41        let client = get_initialized_client(V3_0).await;
42        skip_if_handshake_failed!(client);
43        let mut client = client.unwrap();
44        assert_eq!(client.server_state(), Ready);
45        let response = run_valid_query(&mut client).await.unwrap();
46        assert!(Success::try_from(response).is_ok());
47        assert_eq!(client.server_state(), Streaming);
48    }
49
50    #[tokio::test]
51    async fn run_pipelined() {
52        let client = get_initialized_client(V3_0).await;
53        skip_if_handshake_failed!(client);
54        let mut client = client.unwrap();
55        let messages = vec![
56            Message::RunWithMetadata(RunWithMetadata::new(
57                "MATCH (n {test: 'v3-pipelined'}) DETACH DELETE n;".to_string(),
58                Default::default(), Default::default())),
59            Message::PullAll,
60            Message::RunWithMetadata(RunWithMetadata::new(
61                "CREATE (:Database {name: 'neo4j', v1_release: date('2010-02-16'), test: 'v3-pipelined'});".to_string(),
62                Default::default(), Default::default())),
63            Message::PullAll,
64            Message::RunWithMetadata(RunWithMetadata::new(
65                "MATCH (neo4j:Database {name: 'neo4j', test: 'v3-pipelined'}) CREATE (:Library {name: 'bolt-client', v1_release: date('2019-12-23'), test: 'v3-pipelined'})-[:CLIENT_FOR]->(neo4j);".to_string(),
66                Default::default(), Default::default())),
67            Message::PullAll,
68            Message::RunWithMetadata(RunWithMetadata::new(
69                "MATCH (neo4j:Database {name: 'neo4j', test: 'v3-pipelined'}), (bolt_client:Library {name: 'bolt-client', test: 'v3-pipelined'}) RETURN duration.between(neo4j.v1_release, bolt_client.v1_release);".to_string(),
70                Default::default(), Default::default())),
71            Message::PullAll,
72        ];
73        for response in client.pipeline(messages).await.unwrap() {
74            assert!(match response {
75                Message::Success(_) => true,
76                Message::Record(record) => {
77                    assert_eq!(record.fields()[0], Value::from(Duration::new(118, 7, 0, 0)));
78                    true
79                }
80                _ => false,
81            });
82        }
83    }
84
85    #[tokio::test]
86    async fn run_and_pull() {
87        let client = get_initialized_client(V3_0).await;
88        skip_if_handshake_failed!(client);
89        let mut client = client.unwrap();
90        assert_eq!(client.server_state(), Ready);
91        let response = client
92            .run("RETURN 3458376 as n;", None, None)
93            .await
94            .unwrap();
95        assert!(Success::try_from(response).is_ok());
96        assert_eq!(client.server_state(), Streaming);
97
98        let (records, response) = client.pull(None).await.unwrap();
99        assert!(Success::try_from(response).is_ok());
100        assert_eq!(client.server_state(), Ready);
101        assert_eq!(records.len(), 1);
102        assert_eq!(records[0].fields(), &[Value::from(3_458_376)]);
103    }
104
105    #[tokio::test]
106    async fn discard_fail() {
107        let client = get_initialized_client(V3_0).await;
108        skip_if_handshake_failed!(client);
109        let mut client = client.unwrap();
110        assert_eq!(client.server_state(), Ready);
111        assert!(matches!(
112            client.discard(None).await,
113            Err(CommunicationError::InvalidState { state: Ready, .. })
114        ));
115    }
116
117    #[tokio::test]
118    async fn discard() {
119        let client = get_initialized_client(V3_0).await;
120        skip_if_handshake_failed!(client);
121        let mut client = client.unwrap();
122        assert_eq!(client.server_state(), Ready);
123        let response = run_valid_query(&mut client).await.unwrap();
124        assert!(Success::try_from(response).is_ok());
125        assert_eq!(client.server_state(), Streaming);
126        let response = client.discard(None).await.unwrap();
127        assert!(Success::try_from(response).is_ok());
128        assert_eq!(client.server_state(), Ready);
129    }
130
131    #[tokio::test]
132    async fn discard_and_pull() {
133        let client = get_initialized_client(V3_0).await;
134        skip_if_handshake_failed!(client);
135        let mut client = client.unwrap();
136        assert_eq!(client.server_state(), Ready);
137        let response = run_valid_query(&mut client).await.unwrap();
138        assert!(Success::try_from(response).is_ok());
139        assert_eq!(client.server_state(), Streaming);
140        let response = client.discard(None).await.unwrap();
141        assert!(Success::try_from(response).is_ok());
142        assert_eq!(client.server_state(), Ready);
143        assert!(matches!(
144            client.pull(None).await,
145            Err(CommunicationError::InvalidState { state: Ready, .. })
146        ));
147    }
148
149    #[tokio::test]
150    async fn begin() {
151        let client = get_initialized_client(V3_0).await;
152        skip_if_handshake_failed!(client);
153        let mut client = client.unwrap();
154        assert_eq!(client.server_state(), Ready);
155        let response = client.begin(None).await.unwrap();
156        assert!(Success::try_from(response).is_ok());
157        assert_eq!(client.server_state(), TxReady);
158    }
159
160    #[tokio::test]
161    async fn commit_empty_transaction() {
162        let client = get_initialized_client(V3_0).await;
163        skip_if_handshake_failed!(client);
164        let mut client = client.unwrap();
165        assert_eq!(client.server_state(), Ready);
166        client.begin(None).await.unwrap();
167        assert_eq!(client.server_state(), TxReady);
168        let response = client.commit().await.unwrap();
169        assert!(Success::try_from(response).is_ok());
170        assert_eq!(client.server_state(), Ready);
171    }
172
173    #[tokio::test]
174    async fn commit() {
175        let client = get_initialized_client(V3_0).await;
176        skip_if_handshake_failed!(client);
177        let mut client = client.unwrap();
178        assert_eq!(client.server_state(), Ready);
179        client.begin(None).await.unwrap();
180        assert_eq!(client.server_state(), TxReady);
181
182        let messages = vec![
183            Message::RunWithMetadata(RunWithMetadata::new(
184                "MATCH (n {test: 'v3-commit'}) DETACH DELETE n;".to_string(),
185                Default::default(), Default::default())),
186            Message::PullAll,
187            Message::RunWithMetadata(RunWithMetadata::new(
188                "CREATE (:Database {name: 'neo4j', v1_release: date('2010-02-16'), test: 'v3-commit'});".to_string(),
189                Default::default(), Default::default())),
190            Message::PullAll,
191        ];
192        client.pipeline(messages).await.unwrap();
193        assert_eq!(client.server_state(), TxReady);
194        let response = client.commit().await.unwrap();
195        assert!(Success::try_from(response).is_ok());
196        assert_eq!(client.server_state(), Ready);
197
198        let messages = vec![
199            Message::RunWithMetadata(RunWithMetadata::new(
200                "MATCH (n {test: 'v3-commit'}) RETURN n;".to_string(),
201                Default::default(),
202                Default::default(),
203            )),
204            Message::PullAll,
205        ];
206        let mut node_exists = false;
207        for response in client.pipeline(messages).await.unwrap() {
208            if let Message::Record(record) = response {
209                let node = Node::try_from(record.fields()[0].clone()).unwrap();
210                assert_eq!(node.labels(), &["Database"]);
211                node_exists = true;
212                break;
213            }
214        }
215        assert!(node_exists);
216    }
217
218    #[tokio::test]
219    async fn commit_with_no_begin_fails() {
220        let client = get_initialized_client(V3_0).await;
221        skip_if_handshake_failed!(client);
222        let mut client = client.unwrap();
223        assert!(matches!(
224            client.commit().await,
225            Err(CommunicationError::InvalidState { state: Ready, .. })
226        ));
227    }
228
229    #[tokio::test]
230    async fn rollback_empty_transaction() {
231        let client = get_initialized_client(V3_0).await;
232        skip_if_handshake_failed!(client);
233        let mut client = client.unwrap();
234        assert_eq!(client.server_state(), Ready);
235        client.begin(None).await.unwrap();
236        assert_eq!(client.server_state(), TxReady);
237        let response = client.rollback().await.unwrap();
238        assert!(Success::try_from(response).is_ok());
239        assert_eq!(client.server_state(), Ready);
240    }
241
242    #[tokio::test]
243    async fn rollback() {
244        let client = get_initialized_client(V3_0).await;
245        skip_if_handshake_failed!(client);
246        let mut client = client.unwrap();
247        assert_eq!(client.server_state(), Ready);
248        client.begin(None).await.unwrap();
249        assert_eq!(client.server_state(), TxReady);
250        let messages = vec![
251            Message::RunWithMetadata(RunWithMetadata::new(
252                "MATCH (n {test: 'v3-rollback'}) DETACH DELETE n;".to_string(),
253                Default::default(), Default::default())),
254            Message::PullAll,
255            Message::RunWithMetadata(RunWithMetadata::new(
256                "CREATE (:Database {name: 'neo4j', v1_release: date('2010-02-16'), test: 'v3-rollback'});".to_string(),
257                Default::default(), Default::default())),
258            Message::PullAll,
259        ];
260        client.pipeline(messages).await.unwrap();
261        assert_eq!(client.server_state(), TxReady);
262        let response = client.rollback().await.unwrap();
263        assert!(Success::try_from(response).is_ok());
264        assert_eq!(client.server_state(), Ready);
265
266        let messages = vec![
267            Message::RunWithMetadata(RunWithMetadata::new(
268                "MATCH (n {test: 'v3-rollback'}) RETURN n;".to_string(),
269                Default::default(),
270                Default::default(),
271            )),
272            Message::PullAll,
273        ];
274        for response in client.pipeline(messages).await.unwrap() {
275            // There should be no RECORD messages
276            assert!(matches!(response, Message::Success(_)));
277        }
278    }
279
280    #[tokio::test]
281    async fn rollback_with_no_begin_fails() {
282        let client = get_initialized_client(V3_0).await;
283        skip_if_handshake_failed!(client);
284        let mut client = client.unwrap();
285        assert!(matches!(
286            client.rollback().await,
287            Err(CommunicationError::InvalidState { state: Ready, .. })
288        ));
289    }
290
291    #[tokio::test]
292    async fn reset_internals_pipelined() {
293        let client = get_initialized_client(V3_0).await;
294        skip_if_handshake_failed!(client);
295        let mut client = client.unwrap();
296
297        let mut messages = client
298            .pipeline(vec![
299                Message::RunWithMetadata(RunWithMetadata::new(
300                    String::from("RETURN 1;"),
301                    Default::default(),
302                    Default::default(),
303                )),
304                Message::PullAll,
305                Message::RunWithMetadata(RunWithMetadata::new(
306                    String::from("RETURN 1;"),
307                    Default::default(),
308                    Default::default(),
309                )),
310                Message::PullAll,
311                Message::Reset,
312            ])
313            .await
314            .unwrap();
315
316        // Last message should be a SUCCESS...
317        assert_eq!(
318            messages.pop(),
319            Some(Message::Success(Success::new(Default::default())))
320        );
321
322        // ... preceded by 4 or more IGNORED
323        assert!(messages.len() >= 4);
324        for message in messages {
325            assert_eq!(message, Message::Ignored);
326        }
327    }
328
329    #[tokio::test]
330    async fn reset_internals() {
331        let client = get_initialized_client(V3_0).await;
332        skip_if_handshake_failed!(client);
333        let mut client = client.unwrap();
334
335        client.run("RETURN 1;", None, None).await.unwrap();
336        client.send_message(Message::PullAll).await.unwrap();
337        client.send_message(Message::Reset).await.unwrap();
338        assert_eq!(client.server_state(), Interrupted);
339
340        // Two situations can happen here - either the PULL_ALL is ignored, or the records of the
341        // PULL_ALL are ignored. The latter situation results in additional IGNORED messages in
342        // the result stream.
343
344        // RECORD or PULL_ALL summary, it's not consistent
345        assert_eq!(client.read_message().await.unwrap(), Message::Ignored);
346
347        match client.read_message().await.unwrap() {
348            // PULL_ALL summary
349            Message::Ignored => {
350                // RESET result
351                Success::try_from(client.read_message().await.unwrap()).unwrap();
352            }
353            // RESET result
354            Message::Success(_) => {}
355            other => panic!("unexpected response {:?}", other),
356        }
357    }
358}