/
bin.js
235 lines (218 loc) · 6.48 KB
/
bin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
var fs = require('fs')
var test = require('tape')
var spawn = require('child_process').spawn
var exec = require('child_process').exec
var crypto = require('crypto')
var net = require('net')
var mkdirp = require('mkdirp')
var join = require('path').join
var ma = require('multiserver-address')
// travis currently does not support ipv6, becaue GCE does not.
var has_ipv6 = process.env.TRAVIS === undefined
function sbot(t, argv, opts) {
opts = opts || {}
// we spawn a shell with job control enabled
// that starts sbot on the background and then
// reads from stdin, which is a pipe to our node process
// When that pipe closes (because we do so when the tests ends, or
// it happens because our process dies), sbot will be killed
// by the shell automatically.
// Because the last command in the shell is 'wait %1', the shells' exit code
// will be sbot's exit code (which is >128 if it was killed)
var sh = spawn('bash', [
'-c',
'set -o monitor; echo pwd: $(pwd); node ' + join(__dirname, '../bin.js') + ' ' +
argv.join(' ') +
' & read dummy; echo killing sbot; kill %1; wait %1'
], Object.assign({
env: Object.assign({}, process.env, {ssb_appname: 'test'}),
stdio: ['pipe', 'inherit', 'inherit']
}, opts))
return function end() {
console.log('ending ...')
sh.on('exit', function(code) {
if (code>128) {
t.comment('sbot was killed as expected')
} else {
t.fail('sbot exited with code ' + code)
}
t.end()
})
// closing shell's stdin will make it kill sbot
// if it is still running at this point.
// Either way, we'll get sbot's original exit code
// in the exit event above.
sh.stdin.end()
}
}
function try_often(times, opts, work, done) {
if (typeof opts == 'function') {
done = work
work = opts
opts = {}
}
const delay = 2000
setTimeout(function() { // delay first try
work(function(err, result) {
if (err) {
if (opts.ignore && err.message && !err.message.match(err.ignore)) {
console.error('Fatal error:', err)
return done(err)
}
if (times) return setTimeout(function () {
console.warn('retry run', times)
console.error('work(err):', err)
try_often(times-1, work, done)
}, delay)
return done(err)
}
return done(null, result)
})
}, delay)
}
test('run bin.js server with command line option --host and --port (IPv4)', function(t) {
var end = sbot(t, [
'server',
'--host=127.0.0.1',
'--port=9001',
'--ws.port=9002',
'--path=/tmp/sbot_binjstest_' + Date.now()
])
try_often(10, function work(cb) {
var socket = net.connect(9001, '127.0.0.1')
socket.on('error', cb)
socket.on('connect', cb)
}, function done(err) {
t.error(err, 'Successfully connect eventually')
end()
})
})
if (has_ipv6)
test('run bin.js server with command line option --host and --port (IPv6)', function(t) {
var end = sbot(t, [
'server',
'--host=::1',
'--port=9001',
'--ws.port=9002',
'--path=/tmp/sbot_binjstest_' + Date.now()
])
try_often(10, function work(cb) {
var socket = net.connect(9001, '::1')
socket.on('error', cb)
socket.on('connect', cb)
}, function done(err) {
t.error(err, 'Successfully connect eventually')
end()
})
})
test('run bin.js server with local config file (port, host) (IPv4)', function(t) {
var dir = '/tmp/sbot_binjstest_' + Date.now()
mkdirp.sync(dir)
fs.writeFileSync(join(dir, '.testrc'), JSON.stringify({
host: '127.0.0.1',
port: 9001,
ws: {
port: 9002
}
}))
var end = sbot(t, [
'server',
'--path', dir
], {
cwd: dir
})
try_often(10, {
ignore: /ECONNREFUSED/
}, function work(cb) {
var socket = net.connect(9001, '127.0.0.1')
socket.on('error', cb)
socket.on('connect', cb)
}, function done(err) {
t.error(err, 'Successfully connect eventually')
end()
})
})
if (has_ipv6)
test('run bin.js server with local config file (port, host) (IPv6)', function(t) {
var dir = '/tmp/sbot_binjstest_' + Date.now()
mkdirp.sync(dir)
fs.writeFileSync(join(dir, '.testrc'), JSON.stringify({
host: '::',
port: 9001,
ws: {
port: 9002
}
}))
var end = sbot(t, [
'server',
'--path', dir
], {
cwd: dir
})
try_often(10, function work(cb) {
var socket = net.connect(9001, '::1')
socket.on('error', cb)
socket.on('connect', cb)
}, function done(err) {
t.error(err, 'Successfully connect eventually')
end()
})
})
test('sbot should have websockets and http server by default', function(t) {
var path = '/tmp/sbot_binjstest_' + Date.now()
var caps = crypto.randomBytes(32).toString('base64')
var end = sbot(t, [
'server',
'--host=127.0.0.1',
'--port=9001',
'--ws.port=9002',
'--path', path,
'--caps.shs', caps
])
try_often(10, function work(cb) {
exec([
join(__dirname, '../bin.js'),
'getAddress',
'--',
'--host=127.0.0.1',
'--port=9001',
'--path', path,
'--caps.shs', caps
].join(' '), {
env: Object.assign({}, process.env, {ssb_appname: 'test'})
}, function(err, stdout, sderr) {
if (err) return cb(err)
cb(null, JSON.parse(stdout)) // remove quotes
})
}, function(err, addr) {
t.error(err, 'sbot getAdress succeeds eventually')
if (err) return end()
t.comment('result of sbot getAddress: ' + addr)
var ws_remotes = ma.decode(addr).filter(function(a) {
return a.find(function(component) {
return component.name == 'ws'
})
})
t.equal(ws_remotes.length, 1, 'has one ws remote')
var remote = ma.encode([ws_remotes[0]])
// this breaks if multiserver address encoding changes
t.ok(remote.indexOf('9002') > 0, 'ws address contains expected port')
// this is a bit annoying. we can't signal ssb-client to load the secret from .path
// it either has to be the first argument, already loaded
var key = require('ssb-keys').loadOrCreateSync(join(path, 'secret'))
require('ssb-client')(key, {
path: path,
caps: { shs: caps }, // has to be set when setting any config
remote: remote
}, function(err, ssb) {
t.error(err, 'ssb-client returns no error')
t.ok(ssb.manifest, 'got manifest from api')
t.ok(ssb.version, 'got version from api')
ssb.whoami(function(err, feed) {
t.error(err, 'ssb.whoami succeeds')
t.equal(feed.id[0], '@', 'feed.id has @ sigil')
end()
})
})
})
})