|
|
@@ -204,7 +204,7 @@ pub struct RPCInterface<PacketType, ErrorType> {
|
|
204
|
204
|
}
|
|
205
|
205
|
|
|
206
|
206
|
impl<PacketType, ErrorType> RPCInterface<PacketType, ErrorType> {
|
|
207
|
|
- pub async fn call(&mut self, call: PacketType) -> RPC<PacketType, ErrorType> {
|
|
|
207
|
+ pub fn call(&mut self, call: PacketType) -> RPC<PacketType, ErrorType> {
|
|
208
|
208
|
let (sender, receiver) = oneshot::channel();
|
|
209
|
209
|
let call_data = CallData {
|
|
210
|
210
|
data: call,
|
|
|
@@ -292,13 +292,136 @@ impl<PacketType> Stream for ServerEventStream<PacketType> {
|
|
292
|
292
|
}
|
|
293
|
293
|
}
|
|
294
|
294
|
|
|
295
|
|
-#[derive(Debug)]
|
|
|
295
|
+#[derive(Debug, PartialEq)]
|
|
296
|
296
|
pub enum RPCError<StreamError> {
|
|
297
|
297
|
Closed,
|
|
298
|
298
|
Timeout,
|
|
299
|
299
|
Stream(StreamError),
|
|
300
|
300
|
}
|
|
301
|
301
|
|
|
|
302
|
+#[cfg(test)]
|
|
|
303
|
+mod tests {
|
|
|
304
|
+ use super::*;
|
|
|
305
|
+ use crate::network::test_utils::{panic_after, Pipe};
|
|
|
306
|
+ use crate::network::Packet;
|
|
|
307
|
+
|
|
|
308
|
+ type TestPayload = u32;
|
|
|
309
|
+
|
|
|
310
|
+ fn serialize_packet<T>(id: u32, response: bool, payload: T) -> Vec<u8>
|
|
|
311
|
+ where
|
|
|
312
|
+ T: Serialize,
|
|
|
313
|
+ {
|
|
|
314
|
+ let packet = Packet {
|
|
|
315
|
+ id,
|
|
|
316
|
+ response,
|
|
|
317
|
+ payload,
|
|
|
318
|
+ };
|
|
|
319
|
+ let mut serialized = Vec::new();
|
|
|
320
|
+ packet
|
|
|
321
|
+ .serialize(
|
|
|
322
|
+ &mut Serializer::new(&mut serialized)
|
|
|
323
|
+ .with_struct_map()
|
|
|
324
|
+ .with_string_variants(),
|
|
|
325
|
+ )
|
|
|
326
|
+ .unwrap();
|
|
|
327
|
+ serialized
|
|
|
328
|
+ }
|
|
|
329
|
+
|
|
|
330
|
+ /// Test the basic RPC interface.
|
|
|
331
|
+ #[tokio::test]
|
|
|
332
|
+ async fn test_rpc_client() {
|
|
|
333
|
+ panic_after(Duration::from_secs(1), async move {
|
|
|
334
|
+ let (pipe1, mut pipe2) = Pipe::new();
|
|
|
335
|
+ let (mut client, events) = create::<_, _, TestPayload>(pipe1);
|
|
|
336
|
+ println!("init");
|
|
|
337
|
+
|
|
|
338
|
+ // Client task.
|
|
|
339
|
+ let tasks = (
|
|
|
340
|
+ tokio::spawn(async move {
|
|
|
341
|
+ assert_eq!(client.call(42).await, Ok(1337));
|
|
|
342
|
+ let delayed = client.call(43);
|
|
|
343
|
+ assert_eq!(client.call(44).await, Ok(1339));
|
|
|
344
|
+ assert_eq!(delayed.await, Ok(1338));
|
|
|
345
|
+ }),
|
|
|
346
|
+ tokio::spawn(async move {
|
|
|
347
|
+ // Invalid ID, should be ignored.
|
|
|
348
|
+ pipe2.send(serialize_packet(42, true, 42)).await.unwrap();
|
|
|
349
|
+
|
|
|
350
|
+ assert_eq!(pipe2.next().await, Some(Ok(serialize_packet(0, false, 42))));
|
|
|
351
|
+ pipe2.send(serialize_packet(0, true, 1337)).await.unwrap();
|
|
|
352
|
+
|
|
|
353
|
+ // Network errors shall be ignored if the stream is not closed.
|
|
|
354
|
+ pipe2.inject_error();
|
|
|
355
|
+
|
|
|
356
|
+ // The ID has to be reused, and a second concurrent call has to have a
|
|
|
357
|
+ // different ID.
|
|
|
358
|
+ assert_eq!(pipe2.next().await, Some(Ok(serialize_packet(0, false, 43))));
|
|
|
359
|
+ assert_eq!(pipe2.next().await, Some(Ok(serialize_packet(1, false, 44))));
|
|
|
360
|
+ pipe2.send(serialize_packet(1, true, 1339)).await.unwrap();
|
|
|
361
|
+ pipe2.send(serialize_packet(0, true, 1338)).await.unwrap();
|
|
|
362
|
+ }),
|
|
|
363
|
+ );
|
|
|
364
|
+
|
|
|
365
|
+ tasks.0.await.unwrap();
|
|
|
366
|
+ tasks.1.await.unwrap();
|
|
|
367
|
+ })
|
|
|
368
|
+ .await;
|
|
|
369
|
+ }
|
|
|
370
|
+
|
|
|
371
|
+ /// Test correct behaviour if the connection is closed during a call.
|
|
|
372
|
+ #[tokio::test]
|
|
|
373
|
+ async fn test_connection_closed() {
|
|
|
374
|
+ panic_after(Duration::from_secs(1), async move {
|
|
|
375
|
+ let (pipe1, pipe2) = Pipe::new();
|
|
|
376
|
+ let (mut client, _events) = create::<_, _, TestPayload>(pipe1);
|
|
|
377
|
+
|
|
|
378
|
+ // Client task.
|
|
|
379
|
+ let tasks = (
|
|
|
380
|
+ tokio::spawn(async move {
|
|
|
381
|
+ assert_eq!(client.call(42).await, Err(RPCError::Closed));
|
|
|
382
|
+ }),
|
|
|
383
|
+ tokio::spawn(async move {
|
|
|
384
|
+ drop(pipe2);
|
|
|
385
|
+ }),
|
|
|
386
|
+ );
|
|
|
387
|
+
|
|
|
388
|
+ tasks.0.await.unwrap();
|
|
|
389
|
+ tasks.1.await.unwrap();
|
|
|
390
|
+ })
|
|
|
391
|
+ .await;
|
|
|
392
|
+ }
|
|
|
393
|
+
|
|
|
394
|
+ /// Test server events.
|
|
|
395
|
+ #[tokio::test]
|
|
|
396
|
+ async fn test_events() {
|
|
|
397
|
+ panic_after(Duration::from_secs(1), async move {
|
|
|
398
|
+ let (pipe1, mut pipe2) = Pipe::new();
|
|
|
399
|
+ let (client, mut events) = create::<_, _, TestPayload>(pipe1);
|
|
|
400
|
+
|
|
|
401
|
+ // Client task.
|
|
|
402
|
+ let tasks = (
|
|
|
403
|
+ tokio::spawn(async move {
|
|
|
404
|
+ assert_eq!(events.next().await, Some(42));
|
|
|
405
|
+ assert_eq!(events.next().await, None);
|
|
|
406
|
+ }),
|
|
|
407
|
+ tokio::spawn(async move {
|
|
|
408
|
+ pipe2.send(serialize_packet(SERVER_EVENT_ID, false, 42)).await.unwrap();
|
|
|
409
|
+ drop(pipe2);
|
|
|
410
|
+ }),
|
|
|
411
|
+ );
|
|
|
412
|
+
|
|
|
413
|
+ tasks.0.await.unwrap();
|
|
|
414
|
+ tasks.1.await.unwrap();
|
|
|
415
|
+ }).await;
|
|
|
416
|
+ }
|
|
|
417
|
+
|
|
|
418
|
+ // TODO:
|
|
|
419
|
+ // - Test for unparseable response.
|
|
|
420
|
+ // - Test for server events.
|
|
|
421
|
+ // - Test wether the client correctly closes the connection and whether futures return an error
|
|
|
422
|
+ // in this case.
|
|
|
423
|
+}
|
|
|
424
|
+
|
|
302
|
425
|
pub async fn low_level_integration_test_client(_address: String) {
|
|
303
|
426
|
/*use super::websocket::WebSocketConnection;
|
|
304
|
427
|
|