test_demo.py 4.37 KB
Newer Older
Paul McCarthy's avatar
Paul McCarthy committed
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
#
# test_demo.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#


import time
10
11
12
import json
import glob
import shutil
13
import sys
14
import os
15
import signal
Paul McCarthy's avatar
Paul McCarthy committed
16
import os.path as op
17
18
import itertools as it
import subprocess as sp
Paul McCarthy's avatar
Paul McCarthy committed
19
20
import multiprocessing as mp

Paul McCarthy's avatar
Paul McCarthy committed
21
22
from unittest import mock

23
import jinja2 as j2
24
25
import numpy as np

Paul McCarthy's avatar
Paul McCarthy committed
26
import notebook.notebookapp as notebookapp
Paul McCarthy's avatar
Paul McCarthy committed
27
import funpack.scripts.demo as ukbdemo
Paul McCarthy's avatar
Paul McCarthy committed
28
29


30
31
32
from . import tempdir


Paul McCarthy's avatar
Paul McCarthy committed
33
34
def test_demo():

35
36
37
38
    def nbfunc():
        # add some extra args for running within docker
        if op.exists('/.dockerenv'): args = ['--allow-root', '--ip=0.0.0.0']
        else:                        args = None
Paul McCarthy's avatar
Paul McCarthy committed
39

Paul McCarthy's avatar
Paul McCarthy committed
40
        with mock.patch('sys.argv', ['fmrib_unpack_demo']):
41
            ukbdemo.main(args)
42

43
44
45
    nbproc = mp.Process(target=nbfunc)
    nbproc.start()
    time.sleep(3)
Paul McCarthy's avatar
Paul McCarthy committed
46

47
48
49
50
51
52
53
54
55
56
57
    servers = notebookapp.list_running_servers()

    assert sum([s['pid'] == nbproc.pid for s in servers]) == 1
    for s in servers:
        if s['pid'] == nbproc.pid:
            notebookapp.shutdown_server(s)
            break

    os.kill(nbproc.pid, signal.SIGKILL)
    nbproc.join(0.5)
    assert not nbproc.is_alive()
58
59
60
61


def test_demo_commands():

62
63
64
65
66
67
68
69
70
    # Issues with pytest-cov 3.0.0 / coveragepy 6.2
    # cause coverage to spit out error information
    # in subprocess-called invocations. Disabling for
    # the time being.
    env = os.environ.copy()
    for k in list(env.keys()):
        if 'COVERAGE' in k or k.startswith('COV_'):
            env.pop(k)

71
    def eval_cmd(cmd, out):
72

Paul McCarthy's avatar
Paul McCarthy committed
73
74
        # TODO extract all funpack calls, and turn
        #      them into funpack.main function calls.
75
        result = sp.run(['bash', cmd], stdout=sp.PIPE, env=env)
76
77
78
79
80
81
82

        with open(out, 'rt') as f:
            out = f.read()
        assert result.returncode              == 0
        assert result.stdout.decode().strip() == out.strip()

    with tempdir() as td:
83
        td = op.realpath(td)
84
        gen_demo_tests(rundir=td)
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
        demodir = op.join(op.dirname(__file__), '..', 'scripts', 'demo')

        for fname in glob.glob(op.join(demodir, '*.*')):
            shutil.copy(fname, td)

        commands = list(sorted(glob.glob('*_command.txt')))
        outputs  = list(sorted(glob.glob('*_output.txt')))

        for i, (cmd, out) in enumerate(zip(commands, outputs)):

            print('Command', i)
            print(open(cmd).read())
            print()

            eval_cmd(cmd, out)


102
def gen_demo_tests(outdir=None, rundir=None):
103

104
105
    if outdir is None: outdir = os.getcwd()
    if rundir is None: rundir = os.getcwd()
106
107

    demofile = op.join(op.dirname(__file__),
Paul McCarthy's avatar
Paul McCarthy committed
108
                       'funpack_demonstration_with_outputs.ipynb')
109
    with open(demofile, 'rt') as f:
110
        content = f.read()
111

112
113
114
115
    content = j2.Template(content)
    content = content.render(dir_prefix=rundir, op=op)
    nb      = json.loads(content)
    cells   = nb['cells']
116
117
118
119
120
121
122
123
124
125
126
127
128
129

    fname_prefix_format = '{{:0{}d}}'.format(
        int(np.ceil(np.log10(len(cells)))))

    i = 1
    for cell in cells:

        if cell['cell_type'] != 'code':
            continue

        source = cell['source']
        output = cell['outputs']

        # exclude some specific commands
130
        excludes = ['pygmentize',
Paul McCarthy's avatar
Paul McCarthy committed
131
                    'ls -l $ukbdir/configs/fmrib']
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

        if any([exc in line
                for exc, line
                in it.product(excludes, source)]):
            continue

        alloutput = []
        for o in output:
            if o['name'] == 'stdout':
                alloutput += o['text']
        output = alloutput

        cmd_file = '{}_command.txt'.format(
            fname_prefix_format.format(i))
        out_file = '{}_output.txt'.format(
            fname_prefix_format.format(i))

149
150
151
        # Todo abs paths in unknown var file output

        with open(op.join(outdir, cmd_file), 'wt') as f:
152
            f.write('#!/usr/bin/env bash\n')
153
154
            f.write('export PYTHONPATH="{}"\n'.format(
                op.join(op.dirname(__file__), '..', '..')))
155
            for line in source:
Paul McCarthy's avatar
Paul McCarthy committed
156
157
                # The demo uses an alias funpack='fmrib_unpack -q -ow'
                if line.startswith('funpack '):
158
                    line = line.replace('funpack ', 'funpack -q -ow ')
159
                    line = '{} -m '.format(sys.executable) + line
Paul McCarthy's avatar
Paul McCarthy committed
160
                f.write(line)
161
        with open(op.join(outdir, out_file), 'wt') as f:
162
163
164
165
            for line in output:
                f.write(line)

        i += 1