1
1
#[ cfg( any( feature = "test_go_interop" , feature = "test_js_interop" ) ) ]
2
- pub use common:: ForeignNode ;
2
+ pub use common:: { api_call , ForeignNode } ;
3
3
4
4
#[ cfg( all( not( feature = "test_go_interop" ) , not( feature = "test_js_interop" ) ) ) ]
5
5
#[ allow( dead_code) ]
@@ -11,43 +11,49 @@ pub mod common {
11
11
use libp2p:: { core:: PublicKey , Multiaddr , PeerId } ;
12
12
use rand:: prelude:: * ;
13
13
use serde:: Deserialize ;
14
- use std:: time:: Duration ;
15
14
use std:: {
16
15
env, fs,
17
16
path:: PathBuf ,
18
17
process:: { Child , Command , Stdio } ,
19
- thread,
20
18
} ;
21
19
20
+ #[ derive( Debug ) ]
22
21
pub struct ForeignNode {
23
22
pub dir : PathBuf ,
24
23
pub daemon : Child ,
25
24
pub id : PeerId ,
26
25
pub pk : PublicKey ,
27
26
pub addrs : Vec < Multiaddr > ,
27
+ pub binary_path : String ,
28
+ pub api_port : u16 ,
28
29
}
29
30
30
31
impl ForeignNode {
31
32
#[ allow( dead_code) ]
32
33
pub fn new ( ) -> ForeignNode {
34
+ use std:: { io:: Read , net:: SocketAddr , str} ;
35
+
33
36
// this environment variable should point to the location of the foreign ipfs binary
34
37
#[ cfg( feature = "test_go_interop" ) ]
35
38
const ENV_IPFS_PATH : & str = "GO_IPFS_PATH" ;
36
39
#[ cfg( feature = "test_js_interop" ) ]
37
40
const ENV_IPFS_PATH : & str = "JS_IPFS_PATH" ;
38
41
42
+ // obtain the path of the foreign ipfs binary from an environment variable
39
43
let binary_path = env:: vars ( )
40
44
. find ( |( key, _val) | key == ENV_IPFS_PATH )
41
45
. unwrap_or_else ( || {
42
46
panic ! ( "the {} environment variable was not found" , ENV_IPFS_PATH )
43
47
} )
44
48
. 1 ;
45
49
50
+ // create the temporary directory for the repo etc
46
51
let mut tmp_dir = env:: temp_dir ( ) ;
47
52
let mut rng = rand:: thread_rng ( ) ;
48
53
tmp_dir. push ( & format ! ( "ipfs_test_{}" , rng. gen :: <u64 >( ) ) ) ;
49
54
let _ = fs:: create_dir ( & tmp_dir) ;
50
55
56
+ // initialize the node and assign the temporary directory to it
51
57
Command :: new ( & binary_path)
52
58
. env ( "IPFS_PATH" , & tmp_dir)
53
59
. arg ( "init" )
@@ -59,16 +65,44 @@ pub mod common {
59
65
. status ( )
60
66
. unwrap ( ) ;
61
67
62
- let daemon = Command :: new ( & binary_path)
68
+ #[ cfg( feature = "test_go_interop" ) ]
69
+ let daemon_args = & [ "daemon" , "--enable-pubsub-experiment" ] ;
70
+ #[ cfg( feature = "test_js_interop" ) ]
71
+ let daemon_args = & [ "daemon" ] ;
72
+
73
+ // start the ipfs daemon
74
+ let mut daemon = Command :: new ( & binary_path)
63
75
. env ( "IPFS_PATH" , & tmp_dir)
64
- . arg ( "daemon" )
65
- . stdout ( Stdio :: null ( ) )
76
+ . args ( daemon_args )
77
+ . stdout ( Stdio :: piped ( ) )
66
78
. spawn ( )
67
79
. unwrap ( ) ;
68
80
69
- // give the daemon a little bit of time to start
70
- thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
81
+ // read the stdout of the spawned daemon...
82
+ let mut buf = vec ! [ 0 ; 2048 ] ;
83
+ let mut index = 0 ;
84
+ if let Some ( ref mut stdout) = daemon. stdout {
85
+ while let Ok ( read) = stdout. read ( & mut buf[ index..] ) {
86
+ index += read;
87
+ if str:: from_utf8 ( & buf) . unwrap ( ) . contains ( "Daemon is ready" ) {
88
+ break ;
89
+ }
90
+ }
91
+ }
92
+
93
+ // ...so that the randomly assigned API port can be registered
94
+ let mut api_port = None ;
95
+ for line in str:: from_utf8 ( & buf) . unwrap ( ) . lines ( ) {
96
+ if line. contains ( "webui" ) {
97
+ let addr = line. rsplitn ( 2 , ' ' ) . next ( ) . unwrap ( ) ;
98
+ let addr = addr. strip_prefix ( "http://" ) . unwrap ( ) ;
99
+ let addr: SocketAddr = addr. rsplitn ( 2 , '/' ) . nth ( 1 ) . unwrap ( ) . parse ( ) . unwrap ( ) ;
100
+ api_port = Some ( addr. port ( ) ) ;
101
+ }
102
+ }
103
+ let api_port = api_port. unwrap ( ) ;
71
104
105
+ // run /id in order to register the PeerId, PublicKey and Multiaddrs assigned to the node
72
106
let node_id = Command :: new ( & binary_path)
73
107
. env ( "IPFS_PATH" , & tmp_dir)
74
108
. arg ( "id" )
@@ -96,6 +130,8 @@ pub mod common {
96
130
id,
97
131
pk,
98
132
addrs : addresses,
133
+ binary_path,
134
+ api_port,
99
135
}
100
136
}
101
137
@@ -112,6 +148,25 @@ pub mod common {
112
148
}
113
149
}
114
150
151
+ // this one is not a method on ForeignNode, as only its port number is needed and we don't
152
+ // want to restrict ourselves from calling it from spawned tasks or threads (or to make the
153
+ // internals of ForeignNode complicated by making it Clone)
154
+ #[ allow( dead_code) ]
155
+ pub async fn api_call < T : AsRef < str > > ( api_port : u16 , call : T ) -> String {
156
+ let bytes = Command :: new ( "curl" )
157
+ . arg ( "-X" )
158
+ . arg ( "POST" )
159
+ . arg ( & format ! (
160
+ "http://127.0.0.1:{}/api/v0/{}" ,
161
+ api_port,
162
+ call. as_ref( )
163
+ ) )
164
+ . output ( )
165
+ . unwrap ( )
166
+ . stdout ;
167
+ String :: from_utf8 ( bytes) . unwrap ( )
168
+ }
169
+
115
170
#[ derive( Deserialize , Debug ) ]
116
171
#[ cfg_attr( feature = "test_go_interop" , serde( rename_all = "PascalCase" ) ) ]
117
172
#[ cfg_attr( feature = "test_js_interop" , serde( rename_all = "camelCase" ) ) ]
0 commit comments