1- use std:: fs ;
1+ use std:: { fs , time :: Duration } ;
22
33use integration:: {
4- wait_for_usock, PIVOT_ABORT_PATH , PIVOT_OK_PATH , PIVOT_PANIC_PATH ,
5- PIVOT_POOL_SIZE_PATH ,
4+ wait_for_usock, PivotSocketStressMsg , PIVOT_ABORT_PATH , PIVOT_OK_PATH ,
5+ PIVOT_PANIC_PATH , PIVOT_POOL_SIZE_PATH , PIVOT_SOCKET_STRESS_PATH ,
66} ;
77use qos_core:: {
8+ client:: SocketClient ,
89 handles:: Handles ,
910 io:: { SocketAddress , StreamPool } ,
10- protocol:: services:: boot:: ManifestEnvelope ,
11+ protocol:: {
12+ msg:: ProtocolMsg , services:: boot:: ManifestEnvelope , ProtocolError ,
13+ ProtocolPhase ,
14+ } ,
1115 reaper:: { Reaper , REAPER_EXIT_DELAY } ,
1216} ;
1317use qos_nsm:: mock:: MockNsm ;
@@ -16,7 +20,6 @@ use qos_test_primitives::PathWrapper;
1620#[ tokio:: test]
1721async fn reaper_works ( ) {
1822 let secret_path: PathWrapper = "/tmp/reaper_works.secret" . into ( ) ;
19- // let eph_path = "reaper_works.eph.key";
2023 let usock: PathWrapper = "/tmp/reaper_works.sock" . into ( ) ;
2124 let manifest_path: PathWrapper = "/tmp/reaper_works.manifest" . into ( ) ;
2225 let msg = "durp-a-durp" ;
@@ -36,16 +39,15 @@ async fn reaper_works() {
3639 let mut manifest_envelope = ManifestEnvelope :: default ( ) ;
3740 manifest_envelope. manifest . pivot . args =
3841 vec ! [ "--msg" . to_string( ) , msg. to_string( ) ] ;
39- manifest_envelope. manifest . client_timeout_ms = Some ( 2000 ) ; // check if this gets applied
4042
4143 handles. put_manifest_envelope ( & manifest_envelope) . unwrap ( ) ;
4244 assert ! ( handles. pivot_exists( ) ) ;
4345
4446 let enclave_pool =
45- StreamPool :: new ( SocketAddress :: new_unix ( & usock) , 1 ) . unwrap ( ) ;
47+ StreamPool :: single ( SocketAddress :: new_unix ( & usock) ) . unwrap ( ) ;
4648
4749 let app_pool =
48- StreamPool :: new ( SocketAddress :: new_unix ( "./never.sock" ) , 1 ) . unwrap ( ) ;
50+ StreamPool :: single ( SocketAddress :: new_unix ( "./never.sock" ) ) . unwrap ( ) ;
4951
5052 let reaper_handle = tokio:: spawn ( async move {
5153 Reaper :: execute (
@@ -59,7 +61,7 @@ async fn reaper_works() {
5961 } ) ;
6062
6163 // Give the enclave server time to bind to the socket
62- tokio :: time :: sleep ( std :: time :: Duration :: from_secs ( 1 ) ) . await ;
64+ wait_for_usock ( & usock ) . await ;
6365
6466 // Check that the reaper is still running, presumably waiting for
6567 // the secret.
@@ -76,6 +78,94 @@ async fn reaper_works() {
7678 assert ! ( fs:: remove_file( integration:: PIVOT_OK_SUCCESS_FILE ) . is_ok( ) ) ;
7779}
7880
81+ #[ tokio:: test]
82+ async fn reaper_timeout_works ( ) {
83+ let secret_path: PathWrapper = "/tmp/reaper_timeout_works.secret" . into ( ) ;
84+ let enclave_sock: PathWrapper = "/tmp/reaper_timeout_works.sock" . into ( ) ;
85+ let app_sock: PathWrapper = "/tmp/reaper_timeout_works_app.sock" . into ( ) ;
86+ let manifest_path: PathWrapper =
87+ "/tmp/reaper_timeout_works.manifest" . into ( ) ;
88+
89+ // clean up old manifest if it's left from a panic
90+ drop ( std:: fs:: remove_file ( & * manifest_path) ) ;
91+
92+ // For our sanity, ensure the secret does not yet exist
93+ drop ( fs:: remove_file ( & * secret_path) ) ;
94+
95+ let handles = Handles :: new (
96+ "eph_path" . to_string ( ) ,
97+ ( * secret_path) . to_string ( ) ,
98+ ( * manifest_path) . to_string ( ) ,
99+ PIVOT_SOCKET_STRESS_PATH . to_string ( ) ,
100+ ) ;
101+
102+ // Make sure we have written everything necessary to pivot, except the
103+ // quorum key
104+ let mut manifest_envelope = ManifestEnvelope :: default ( ) ;
105+ // Tell pivot where to open up the server app socket
106+ manifest_envelope. manifest . pivot . args = vec ! [ app_sock. to_string( ) ] ;
107+
108+ // we'll be checking if this is set by passing slow and fast requests
109+ manifest_envelope. manifest . client_timeout_ms = Some ( 2000 ) ;
110+
111+ handles. put_manifest_envelope ( & manifest_envelope) . unwrap ( ) ;
112+ assert ! ( handles. pivot_exists( ) ) ;
113+
114+ let enclave_pool =
115+ StreamPool :: single ( SocketAddress :: new_unix ( & enclave_sock) ) . unwrap ( ) ;
116+
117+ let app_pool =
118+ StreamPool :: single ( SocketAddress :: new_unix ( & app_sock) ) . unwrap ( ) ;
119+
120+ let reaper_handle = tokio:: spawn ( async move {
121+ Reaper :: execute (
122+ & handles,
123+ Box :: new ( MockNsm ) ,
124+ enclave_pool,
125+ app_pool,
126+ Some ( ProtocolPhase :: QuorumKeyProvisioned ) ,
127+ )
128+ . await ;
129+ } ) ;
130+
131+ // Give the enclave server time to bind to the socket
132+ wait_for_usock ( & enclave_sock) . await ;
133+
134+ // Check that the reaper is still running, presumably waiting for
135+ // the secret.
136+ assert ! ( !reaper_handle. is_finished( ) ) ;
137+
138+ // Create the file with the secret, which should cause the reaper
139+ // to start executable.
140+ fs:: write ( & * secret_path, b"super dank tank secret tech" ) . unwrap ( ) ;
141+
142+ // Give the app server time to bind to the socket
143+ wait_for_usock ( & app_sock) . await ;
144+
145+ // create a "slow" app request longer than client timeout from `Manifest`, but longer than 5s timeout on our local client.
146+ let app_request =
147+ borsh:: to_vec ( & PivotSocketStressMsg :: SlowRequest ( 3000 ) ) . unwrap ( ) ;
148+ let request =
149+ borsh:: to_vec ( & ProtocolMsg :: ProxyRequest { data : app_request } )
150+ . unwrap ( ) ;
151+
152+ // ensure our client to the enclave has longer timeout than the configured 2s and the slow request 3s
153+ let client = SocketClient :: single (
154+ SocketAddress :: new_unix ( & enclave_sock) ,
155+ Duration :: from_millis ( 5000 ) ,
156+ )
157+ . unwrap ( ) ;
158+
159+ let response: ProtocolMsg =
160+ borsh:: from_slice ( & client. call ( & request) . await . unwrap ( ) ) . unwrap ( ) ;
161+
162+ // The response should be AppClientRecvTimeout which indicates the enclave short-circuited the timeout
163+ assert_eq ! (
164+ response,
165+ ProtocolMsg :: ProtocolErrorResponse ( ProtocolError :: AppClientRecvTimeout )
166+ ) ;
167+ }
168+
79169#[ tokio:: test]
80170async fn reaper_handles_non_zero_exits ( ) {
81171 let secret_path: PathWrapper =
@@ -117,7 +207,7 @@ async fn reaper_handles_non_zero_exits() {
117207 } ) ;
118208
119209 // Give the enclave server time to bind to the socket
120- tokio :: time :: sleep ( std :: time :: Duration :: from_secs ( 1 ) ) . await ;
210+ wait_for_usock ( & usock ) . await ;
121211
122212 // Check that the reaper is still running, presumably waiting for
123213 // the secret.
@@ -174,7 +264,7 @@ async fn reaper_handles_panic() {
174264 } ) ;
175265
176266 // Give the enclave server time to bind to the socket
177- tokio :: time :: sleep ( std :: time :: Duration :: from_secs ( 1 ) ) . await ;
267+ wait_for_usock ( & usock ) . await ;
178268
179269 // Check that the reaper is still running, presumably waiting for
180270 // the secret.
@@ -195,11 +285,10 @@ async fn reaper_handles_panic() {
195285async fn reaper_handles_pool_size ( ) {
196286 let secret_path: PathWrapper =
197287 "/tmp/reaper_handles_pool_size.secret" . into ( ) ;
198- // let eph_path = "reaper_works.eph.key";
199288 let usock: PathWrapper = "/tmp/reaper_handles_pool_size.sock" . into ( ) ;
200289 let manifest_path: PathWrapper =
201290 "/tmp/reaper_handles_pool_size.manifest" . into ( ) ;
202- let msg = "5" ; // must match pool-size in manifest bellow (test thing)
291+ let msg = "5" ; // must match pool-size in manifest below (test thing)
203292
204293 // For our sanity, ensure the secret does not yet exist
205294 drop ( fs:: remove_file ( & * secret_path) ) ;
0 commit comments