Skip to content

Commit 4f805cf

Browse files
authored
Improve rcopy tree tests (#588)
* tests: use mock hostname command remotely As `hostname` is used by rcopy in tree mode via tar, mock it remotely so we can simulate multiple target nodes in tests. * tests: improve rcopy tree tests Add test for rcopy with file as the source and with multiple targets. Test the change from #545.
1 parent 05d012f commit 4f805cf

File tree

4 files changed

+114
-30
lines changed

4 files changed

+114
-30
lines changed

.github/workflows/nosetests.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,17 @@ jobs:
3535
run: |
3636
sed -i "1iexport CLUSTERSHELL_GW_PYTHON_EXECUTABLE=$(which python)" ~/.bashrc
3737
sed -i "2iexport PYTHONPATH=\$PYTHONPATH:$(realpath $pythonLocation/lib/python*/site-packages)" ~/.bashrc
38-
head ~/.bashrc
38+
head -2 ~/.bashrc
3939
- name: Install pdsh to test WorkerPdsh
4040
run: |
4141
sudo apt-get -y install pdsh
4242
sudo sh -c 'echo ssh > /etc/pdsh/rcmd_default'
43+
- name: Add tests/bin to remote PATH
44+
run: |
45+
sed -i "1iexport PATH=$PWD/tests/bin:\$PATH" ~/.bashrc
46+
head -1 ~/.bashrc
47+
ssh 127.0.0.2 which hostname
48+
ssh 127.0.0.2 hostname
4349
- name: Post to Slack (start)
4450
continue-on-error: true
4551
id: slack-start

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ include doc/examples/*.py
3232
include doc/examples/defaults.conf-rsh
3333
include doc/epydoc/*.conf
3434
include tests/*.py
35+
include tests/bin/*

tests/TreeWorkerTest.py

Lines changed: 102 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
NODE_HEAD = HOSTNAME
2929
NODE_GATEWAY = 'localhost'
3030
NODE_DISTANT = '127.0.0.2'
31-
NODE_DIRECT = '127.0.0.3'
32-
NODE_FOREIGN = '127.0.0.4'
31+
NODE_DISTANT2 = '127.0.0.[2-3]'
32+
NODE_DIRECT = '127.0.0.4'
33+
NODE_FOREIGN = '127.0.0.5'
3334

3435

3536
class TEventHandlerBase(object):
@@ -105,7 +106,7 @@ class TreeWorkerTest(unittest.TestCase):
105106
"""
106107
TreeWorkerTest: test TreeWorker
107108
108-
NODE_HEAD -> NODE_GATEWAY -> NODE_DISTANT
109+
NODE_HEAD -> NODE_GATEWAY -> NODE_DISTANT2
109110
-> NODE_DIRECT [defined in topology]
110111
-> NODE_FOREIGN [not defined in topology]
111112
@@ -120,7 +121,7 @@ def setUp(self):
120121
# set task topology
121122
graph = TopologyGraph()
122123
graph.add_route(NodeSet(HOSTNAME), NodeSet(NODE_GATEWAY))
123-
graph.add_route(NodeSet(NODE_GATEWAY), NodeSet(NODE_DISTANT))
124+
graph.add_route(NodeSet(NODE_GATEWAY), NodeSet(NODE_DISTANT2))
124125
graph.add_route(NodeSet(HOSTNAME), NodeSet(NODE_DIRECT))
125126
# NODE_FOREIGN is not included
126127
self.task.topology = graph.to_tree(HOSTNAME)
@@ -254,12 +255,13 @@ def _tree_run_write(self, target, separate_thread=False):
254255
if separate_thread:
255256
task_wait()
256257
task_cleanup()
258+
target_cnt = len(NodeSet(target))
257259
self.assertEqual(teh.ev_start_cnt, 1)
258-
self.assertEqual(teh.ev_pickup_cnt, 1)
259-
self.assertEqual(teh.ev_read_cnt, 1)
260-
self.assertEqual(teh.ev_written_cnt, 1)
261-
self.assertEqual(teh.ev_written_sz, len('Lorem Ipsum'))
262-
self.assertEqual(teh.ev_hup_cnt, 1)
260+
self.assertEqual(teh.ev_pickup_cnt, target_cnt)
261+
self.assertEqual(teh.ev_read_cnt, target_cnt)
262+
self.assertEqual(teh.ev_written_cnt, target_cnt)
263+
self.assertEqual(teh.ev_written_sz, target_cnt * len('Lorem Ipsum'))
264+
self.assertEqual(teh.ev_hup_cnt, target_cnt)
263265
self.assertEqual(teh.ev_timedout_cnt, 0)
264266
self.assertEqual(teh.ev_close_cnt, 1)
265267
self.assertEqual(teh.last_read, b'Lorem Ipsum')
@@ -268,6 +270,10 @@ def test_tree_run_write_distant(self):
268270
"""test tree run with write(), distant target"""
269271
self._tree_run_write(NODE_DISTANT)
270272

273+
def test_tree_run_write_distant2(self):
274+
"""test tree run with write(), distant 2 targets"""
275+
self._tree_run_write(NODE_DISTANT2)
276+
271277
def test_tree_run_write_direct(self):
272278
"""test tree run with write(), direct target, in topology"""
273279
self._tree_run_write(NODE_DIRECT)
@@ -284,6 +290,10 @@ def test_tree_run_write_distant_mt(self):
284290
"""test tree run with write(), distant target, separate thread"""
285291
self._tree_run_write(NODE_DISTANT, separate_thread=True)
286292

293+
def test_tree_run_write_distant2_mt(self):
294+
"""test tree run with write(), distant 2 targets, separate thread"""
295+
self._tree_run_write(NODE_DISTANT2, separate_thread=True)
296+
287297
def test_tree_run_write_direct_mt(self):
288298
"""test tree run with write(), direct target, in topology, separate thread"""
289299
self._tree_run_write(NODE_DIRECT, separate_thread=True)
@@ -303,11 +313,12 @@ def _tree_copy_file(self, target):
303313
try:
304314
worker = self.task.copy(srcf.name, dest, nodes=target, handler=teh)
305315
self.task.run()
316+
target_cnt = len(NodeSet(target))
306317
self.assertEqual(teh.ev_start_cnt, 1)
307-
self.assertEqual(teh.ev_pickup_cnt, 1)
318+
self.assertEqual(teh.ev_pickup_cnt, target_cnt)
308319
self.assertEqual(teh.ev_read_cnt, 0)
309320
#self.assertEqual(teh.ev_written_cnt, 0) # FIXME
310-
self.assertEqual(teh.ev_hup_cnt, 1)
321+
self.assertEqual(teh.ev_hup_cnt, target_cnt)
311322
self.assertEqual(teh.ev_timedout_cnt, 0)
312323
self.assertEqual(teh.ev_close_cnt, 1)
313324
with open(dest, 'r') as destf:
@@ -319,6 +330,10 @@ def test_tree_copy_file_distant(self):
319330
"""test tree copy: file, distant target"""
320331
self._tree_copy_file(NODE_DISTANT)
321332

333+
def test_tree_copy_file_distant2(self):
334+
"""test tree copy: file, distant 2 targets"""
335+
self._tree_copy_file(NODE_DISTANT2)
336+
322337
def test_tree_copy_file_direct(self):
323338
"""test tree copy: file, direct target, in topology"""
324339
self._tree_copy_file(NODE_DIRECT)
@@ -346,11 +361,12 @@ def _tree_copy_dir(self, target):
346361
worker = self.task.copy(srcdir.name, destdir.name + '/',
347362
nodes=target, handler=teh)
348363
self.task.run()
364+
target_cnt = len(NodeSet(target))
349365
self.assertEqual(teh.ev_start_cnt, 1)
350-
self.assertEqual(teh.ev_pickup_cnt, 1)
366+
self.assertEqual(teh.ev_pickup_cnt, target_cnt)
351367
self.assertEqual(teh.ev_read_cnt, 0)
352368
#self.assertEqual(teh.ev_written_cnt, 0) # FIXME
353-
self.assertEqual(teh.ev_hup_cnt, 1)
369+
self.assertEqual(teh.ev_hup_cnt, target_cnt)
354370
self.assertEqual(teh.ev_timedout_cnt, 0)
355371
self.assertEqual(teh.ev_close_cnt, 1)
356372

@@ -370,6 +386,11 @@ def test_tree_copy_dir_distant(self):
370386
"""test tree copy: directory, distant target"""
371387
self._tree_copy_dir(NODE_DISTANT)
372388

389+
def test_tree_copy_dir_distant2(self):
390+
"""test tree copy: directory, distant 2 targets"""
391+
self._tree_copy_dir(NODE_DISTANT2)
392+
393+
373394
def test_tree_copy_dir_direct(self):
374395
"""test tree copy: directory, direct target, in topology"""
375396
self._tree_copy_dir(NODE_DIRECT)
@@ -382,37 +403,37 @@ def test_tree_copy_dir_gateway(self):
382403
"""test tree copy: directory, gateway is target"""
383404
self._tree_copy_dir(NODE_GATEWAY)
384405

385-
def _tree_rcopy_dir(self, target, dirsuffix=None):
406+
def _tree_rcopy_dir(self, target):
386407
teh = TEventHandler()
387408

409+
b1 = b'Lorem Ipsum Unum' * 100
410+
b2 = b'Lorem Ipsum Duo' * 100
411+
388412
srcdir = make_temp_dir()
389413
destdir = make_temp_dir()
390-
file1 = make_temp_file(b'Lorem Ipsum Unum', suffix=".txt",
391-
dir=srcdir.name)
392-
file2 = make_temp_file(b'Lorem Ipsum Duo', suffix=".txt",
393-
dir=srcdir.name)
414+
file1 = make_temp_file(b1, suffix=".txt", dir=srcdir.name)
415+
file2 = make_temp_file(b2, suffix=".txt", dir=srcdir.name)
394416

395417
try:
396418
worker = self.task.rcopy(srcdir.name, destdir.name, nodes=target,
397419
handler=teh)
398420
self.task.run()
421+
target_cnt = len(NodeSet(target))
399422
self.assertEqual(teh.ev_start_cnt, 1)
400-
self.assertEqual(teh.ev_pickup_cnt, 1)
423+
self.assertEqual(teh.ev_pickup_cnt, target_cnt)
401424
self.assertEqual(teh.ev_read_cnt, 0)
402425
#self.assertEqual(teh.ev_written_cnt, 0) # FIXME
403-
self.assertEqual(teh.ev_hup_cnt, 1)
426+
self.assertEqual(teh.ev_hup_cnt, target_cnt)
404427
self.assertEqual(teh.ev_timedout_cnt, 0)
405428
self.assertEqual(teh.ev_close_cnt, 1)
406429

407430
# rcopy successful?
408-
if not dirsuffix:
409-
dirsuffix = target
410-
rcopy_dest = join(destdir.name,
411-
basename(srcdir.name) + '.' + dirsuffix)
412-
with open(join(rcopy_dest, basename(file1.name)), 'rb') as rfile1:
413-
self.assertEqual(rfile1.read(), b'Lorem Ipsum Unum')
414-
with open(join(rcopy_dest, basename(file2.name)), 'rb') as rfile2:
415-
self.assertEqual(rfile2.read(), b'Lorem Ipsum Duo')
431+
for tgt in NodeSet(target):
432+
rcopy_dest = join(destdir.name, basename(srcdir.name) + '.' + tgt)
433+
with open(join(rcopy_dest, basename(file1.name)), 'rb') as rfile1:
434+
self.assertEqual(rfile1.read(), b1)
435+
with open(join(rcopy_dest, basename(file2.name)), 'rb') as rfile2:
436+
self.assertEqual(rfile2.read(), b2)
416437
finally:
417438
file1.close()
418439
file2.close()
@@ -423,7 +444,11 @@ def test_tree_rcopy_dir_distant(self):
423444
"""test tree rcopy: directory, distant target"""
424445
# In distant tree mode, the returned result will include the
425446
# hostname of the distant host, not target name
426-
self._tree_rcopy_dir(NODE_DISTANT, dirsuffix=HOSTNAME)
447+
self._tree_rcopy_dir(NODE_DISTANT)
448+
449+
def test_tree_rcopy_dir_distant2(self):
450+
"""test tree rcopy: directory, distant 2 targets"""
451+
self._tree_rcopy_dir(NODE_DISTANT2)
427452

428453
def test_tree_rcopy_dir_direct(self):
429454
"""test tree rcopy: directory, direct target, in topology"""
@@ -437,6 +462,54 @@ def test_tree_rcopy_dir_gateway(self):
437462
"""test tree rcopy: directory, gateway is target"""
438463
self._tree_rcopy_dir(NODE_GATEWAY)
439464

465+
def _tree_rcopy_file(self, target):
466+
teh = TEventHandler()
467+
468+
# The file needs to be large enough to test GH#545
469+
b1 = b'Lorem Ipsum' * 1100000
470+
471+
srcdir = make_temp_dir()
472+
destdir = make_temp_dir()
473+
srcfile = make_temp_file(b1, suffix=".txt", dir=srcdir.name)
474+
475+
try:
476+
worker = self.task.rcopy(srcfile.name, destdir.name, nodes=target, handler=teh)
477+
self.task.run()
478+
target_cnt = len(NodeSet(target))
479+
self.assertEqual(teh.ev_start_cnt, 1)
480+
self.assertEqual(teh.ev_pickup_cnt, target_cnt)
481+
self.assertEqual(teh.ev_read_cnt, 0)
482+
#self.assertEqual(teh.ev_written_cnt, 0) # FIXME
483+
self.assertEqual(teh.ev_hup_cnt, target_cnt)
484+
self.assertEqual(teh.ev_timedout_cnt, 0)
485+
self.assertEqual(teh.ev_close_cnt, 1)
486+
487+
# rcopy successful?
488+
for tgt in NodeSet(target):
489+
rcopy_dest = join(destdir.name, basename(srcfile.name) + '.' + tgt)
490+
with open(rcopy_dest, 'rb') as tfile:
491+
self.assertEqual(tfile.read(), b1)
492+
finally:
493+
srcfile.close()
494+
srcdir.cleanup()
495+
destdir.cleanup()
496+
497+
def test_tree_rcopy_file_distant(self):
498+
"""test tree rcopy: file, distant target"""
499+
self._tree_rcopy_file(NODE_DISTANT)
500+
501+
def test_tree_rcopy_file_distant2(self):
502+
"""test tree rcopy: file, distant 2 targets"""
503+
self._tree_rcopy_file(NODE_DISTANT2)
504+
505+
def test_tree_rcopy_file_direct(self):
506+
"""test tree rcopy: file, direct target, in topology"""
507+
self._tree_rcopy_file(NODE_DIRECT)
508+
509+
def test_tree_rcopy_file_foreign(self):
510+
"""test tree rcopy: file, direct target, not in topology"""
511+
self._tree_rcopy_file(NODE_FOREIGN)
512+
440513
def test_tree_worker_missing_arguments(self):
441514
"""test TreeWorker with missing arguments"""
442515
teh = TEventHandler()

tests/bin/hostname

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
# This is useful for simulating multiple nodes on localhost IPs,
3+
# such as 127.0.0.2, during testing scenarios.
4+
echo $SSH_CONNECTION | { IFS=' ' read -r _ _ IP _; echo "$IP"; }

0 commit comments

Comments
 (0)