1
- use std:: { convert:: Infallible , net:: SocketAddr , sync:: Arc , time:: Duration } ;
1
+ use std:: {
2
+ convert:: Infallible ,
3
+ net:: SocketAddr ,
4
+ sync:: { Arc , RwLockWriteGuard } ,
5
+ time:: Duration ,
6
+ } ;
2
7
8
+ use async_trait:: async_trait;
3
9
use bytes:: { Bytes , BytesMut } ;
4
10
use futures:: { future:: BoxFuture , StreamExt } ;
5
11
use http:: { HeaderMap , HeaderValue , Request , Response } ;
@@ -12,7 +18,7 @@ use tokio_stream::wrappers::ReceiverStream;
12
18
use tracing:: { debug, error, info} ;
13
19
use url:: Url ;
14
20
15
- use super :: ServerState ;
21
+ use super :: { MockServer , ServerState } ;
16
22
use crate :: {
17
23
mock:: { MockPath , MockSet , TonicBoxBody } ,
18
24
utils:: { find_available_port, has_content_type, tonic:: CodeExt } ,
@@ -23,6 +29,7 @@ use crate::{
23
29
pub struct GrpcMockServer {
24
30
name : & ' static str ,
25
31
addr : SocketAddr ,
32
+ base_url : Url ,
26
33
state : Arc < ServerState > ,
27
34
}
28
35
@@ -31,14 +38,20 @@ impl GrpcMockServer {
31
38
pub fn new ( name : & ' static str , mocks : MockSet ) -> Result < Self , Error > {
32
39
let port = find_available_port ( ) . unwrap ( ) ;
33
40
let addr: SocketAddr = format ! ( "0.0.0.0:{}" , port) . parse ( ) . unwrap ( ) ;
41
+ let base_url = Url :: parse ( & format ! ( "http://{}" , & addr) ) . unwrap ( ) ;
42
+ let state = Arc :: new ( ServerState :: new ( mocks) ) ;
34
43
Ok ( Self {
35
44
name,
36
45
addr,
37
- state : Arc :: new ( ServerState :: new ( mocks) ) ,
46
+ base_url,
47
+ state,
38
48
} )
39
49
}
50
+ }
40
51
41
- pub async fn start ( & self ) -> Result < ( ) , Error > {
52
+ #[ async_trait]
53
+ impl MockServer for GrpcMockServer {
54
+ async fn start ( & self ) -> Result < ( ) , Error > {
42
55
let service = GrpcMockSvc {
43
56
state : self . state . clone ( ) ,
44
57
} ;
@@ -63,28 +76,26 @@ impl GrpcMockServer {
63
76
}
64
77
} ) ;
65
78
66
- // Cushion for server to become ready, there is probably a better approach :)
67
- tokio:: time:: sleep ( Duration :: from_secs ( 1 ) ) . await ;
79
+ // Give the server time to become ready
80
+ tokio:: time:: sleep ( Duration :: from_millis ( 10 ) ) . await ;
68
81
69
82
Ok ( ( ) )
70
83
}
71
84
72
- /// Returns the server's service name.
73
- pub fn name ( & self ) -> & str {
85
+ fn name ( & self ) -> & str {
74
86
self . name
75
87
}
76
88
77
- /// Returns the server's address.
78
- pub fn addr ( & self ) -> SocketAddr {
89
+ fn addr ( & self ) -> SocketAddr {
79
90
self . addr
80
91
}
81
92
82
- pub fn base_url ( & self ) -> Url {
83
- Url :: parse ( & format ! ( "http://{}" , self . addr ( ) ) ) . unwrap ( )
93
+ fn url ( & self , path : & str ) -> Url {
94
+ self . base_url . join ( path ) . unwrap ( )
84
95
}
85
96
86
- pub fn url ( & self , path : & str ) -> Url {
87
- self . base_url ( ) . join ( path ) . unwrap ( )
97
+ fn mocks ( & self ) -> RwLockWriteGuard < ' _ , MockSet > {
98
+ self . state . mocks . write ( ) . unwrap ( )
88
99
}
89
100
}
90
101
@@ -140,7 +151,13 @@ impl Service<Request<Incoming>> for GrpcMockSvc {
140
151
buf. extend ( chunk) ;
141
152
// Attempt to match buffered data to mock
142
153
let body = buf. clone ( ) . freeze ( ) ;
143
- if let Some ( mock) = state. mocks . match_by_body ( & path, & body) {
154
+ let mock = state
155
+ . mocks
156
+ . read ( )
157
+ . unwrap ( )
158
+ . match_by_body ( & path, & body)
159
+ . cloned ( ) ;
160
+ if let Some ( mock) = mock {
144
161
matched = true ;
145
162
// A matching mock has been found, send response
146
163
debug ! ( "mock found, sending response" ) ;
@@ -166,7 +183,6 @@ impl Service<Request<Incoming>> for GrpcMockSvc {
166
183
debug ! ( "request stream closed" ) ;
167
184
if !matched {
168
185
debug ! ( "no mocks found, sending error" ) ;
169
- dbg ! ( & state. mocks) ;
170
186
let mut trailers = HeaderMap :: new ( ) ;
171
187
trailers. insert ( "grpc-status" , ( tonic:: Code :: NotFound as i32 ) . into ( ) ) ;
172
188
trailers. insert ( "grpc-message" , HeaderValue :: from_static ( "mock not found" ) ) ;
0 commit comments