Ejemplo n.º 1
0
def test_follow_email_auth_link_twice(auth_fc):
    fc = auth_fc

    from pykern import pkconfig, pkunit, pkio, pkcompat
    from pykern.pkunit import pkok, pkre
    from pykern.pkdebug import pkdp
    import json

    r = fc.sr_post(
        'authEmailLogin',
        {
            'email': '[email protected]',
            'simulationType': fc.sr_sim_type
        },
    )
    # The link comes back in dev mode so we don't have to check email
    s = fc.sr_auth_state(isLoggedIn=False)
    fc.get(r.uri)
    # get the url twice - should still be logged in
    d = fc.sr_get(r.uri)
    assert not re.search(r'login-fail', pkcompat.from_bytes(d.data))
    fc.sr_email_confirm(fc, r)
    fc.sr_get('authLogout', {'simulation_type': fc.sr_sim_type})
    # now logged out, should see login fail for bad link
    pkre('login-fail', pkcompat.from_bytes(fc.get(r.uri).data))
Ejemplo n.º 2
0
def test_login():
    from pykern import pkunit, pkcompat
    from pykern.pkunit import pkeq, pkok, pkre, pkfail, pkexcept
    from sirepo import auth
    import flask
    import sirepo.auth.guest
    import sirepo.cookie
    import sirepo.http_request
    import sirepo.util

    r = auth.api_authState()
    pkre('LoggedIn": false.*Registration": false', pkcompat.from_bytes(r.data))
    delattr(flask.g, 'sirepo_cookie')
    auth.process_request()
    with pkunit.pkexcept('SRException.*routeName=login'):
        auth.logged_in_user()
    with pkexcept('SRException.*routeName=login'):
        auth.require_user()
    sirepo.cookie.set_sentinel()
    # copying examples for new user takes time
    try:
        r = auth.login(sirepo.auth.guest, sim_type='myapp')
        pkfail('expecting sirepo.util.Response')
    except sirepo.util.Response as e:
        r = e.sr_args.response
    pkre(r'LoggedIn":\s*true.*Registration":\s*false',
         pkcompat.from_bytes(r.data))
    u = auth.logged_in_user()
    pkok(u, 'user should exist')
    # guests do not require completeRegistration
    auth.require_user()
Ejemplo n.º 3
0
def install_crt_and_login(compt, j2_ctx):
    from rsconf.pkcli import tls

    if not update_j2_ctx(j2_ctx):
        return
    jf = db.secret_path(j2_ctx,
                        _PASSWD_SECRET_JSON_F,
                        visibility=_PASSWD_VISIBILITY)
    with jf.open() as f:
        y = pkjson.load_any(jf)
    u = j2_ctx.rsconf_db.host
    p = y.get(u, None)
    if not p:
        return
    j2_ctx.docker.auths[j2_ctx.docker_registry.http_addr] = dict(
        auth=pkcompat.from_bytes(
            base64.b64encode(
                pkcompat.to_bytes(u + ':' + pkcompat.from_bytes(p))), ), )
    compt.install_access(mode='700', owner=j2_ctx.docker_registry.run_u)
    crt = component.tls_key_and_crt(j2_ctx, j2_ctx.docker_registry.host).crt
    if not tls.is_self_signed_crt(crt):
        return
    compt.install_directory(_CERTS_D)
    d = _CERTS_D.join(j2_ctx.docker_registry.http_addr)
    compt.install_directory(d)
    compt.install_access(mode='400', owner=j2_ctx.docker_registry.run_u)
    compt.install_abspath(crt, d.join('ca.crt'))
    # need in /etc/pki as well (now)
    # https://success.docker.com/article/i-get-x509-certificate-signed-by-unknown-authority-error-when-i-try-to-login-to-my-dtr-with-default-certificates
    compt.install_abspath(
        crt, _CA_TRUST_D.join(j2_ctx.docker_registry.host + '.crt'))
    compt.append_root_bash('update-ca-trust')
Ejemplo n.º 4
0
def test_myapp_basic(fc):
    from pykern import pkunit, pkcompat

    r = fc.get('/old')
    assert 'LandingPageController' in pkcompat.from_bytes(r.data), \
        'Top level document is the landing page'
    r = fc.get('/robots.txt')
    pkunit.pkre('elegant.*myapp.*srw', pkcompat.from_bytes(r.data))
Ejemplo n.º 5
0
def test_myapp_basic(fc):
    from pykern import pkunit, pkcompat
    from pykern.pkunit import pkok, pkeq

    r = fc.sr_get('/robots.txt')
    pkunit.pkre('elegant.*myapp.*srw', pkcompat.from_bytes(r.data))
    r = fc.sr_get('/')
    pkok(not re.search(r'googletag', pkcompat.from_bytes(r.data)),
         'Unexpected injection of googletag data={}', r.data)
Ejemplo n.º 6
0
def _run(cmd):
    try:
        pkdc('{}', ' '.join(cmd))
        return pkcompat.from_bytes(
            subprocess.check_output(cmd, stderr=subprocess.STDOUT), )
    except Exception as e:
        o = ''
        if hasattr(e, 'output'):
            o = pkcompat.from_bytes(e.output)
        pkdlog('command error: cmd={} error={} out={}', cmd, e, o)
        raise
Ejemplo n.º 7
0
def test_injection(fc):
    from pykern import pkcompat, pkunit
    from pykern.pkdebug import pkdc, pkdp, pkdlog
    from pykern.pkunit import pkeq, pkok, pkre
    import re

    # test non-static page
    r = fc.get('myapp')
    pkok(not re.search(r'googletag', pkcompat.from_bytes(r.data)),
         'Unexpected injection of googletag data={}', r.data)

    # test successful injection
    r = fc.get('/en/landing.html')
    pkre(_TEST_ID, pkcompat.from_bytes(r.data))
Ejemplo n.º 8
0
def test_set_get():
    from pykern import pkunit, pkcompat
    from pykern.pkunit import pkeq
    from pykern.pkdebug import pkdp
    from pykern import pkcollections
    from sirepo import cookie

    class _Response(pkcollections.Dict):
        def set_cookie(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

    cookie.process_header('x')
    with pkunit.pkexcept('KeyError'):
        cookie.get_value('hi1')
    with pkunit.pkexcept('AssertionError'):
        cookie.set_value('hi2', 'hello')
    pkeq(None, cookie.unchecked_get_value('hi3'))
    cookie.set_cookie_for_utils()
    cookie.set_value('hi4', 'hello')
    r = _Response(status_code=200)
    cookie.save_to_cookie(r)
    pkeq('sirepo_dev', r.args[0])
    pkeq(False, r.kwargs['secure'])
    pkeq('hello', cookie.get_value('hi4'))
    cookie.unchecked_remove('hi4')
    pkeq(None, cookie.unchecked_get_value('hi4'))
    cookie.process_header(
        'sirepo_dev={}'.format(pkcompat.from_bytes(r.args[1])), )
    pkeq('hello', cookie.get_value('hi4'))
Ejemplo n.º 9
0
def gen_private_key():
    """Generate 32 byte random private key"""
    import base64
    import os
    from pykern import pkcompat

    return pkcompat.from_bytes(base64.urlsafe_b64encode(os.urandom(32)))
Ejemplo n.º 10
0
def import_file(req, test_data=None, **kwargs):
    # input_data is passed by test cases only
    input_data = test_data
    text = pkcompat.from_bytes(req.file_stream.read())
    if 'simulationId' in req.req_data:
        input_data = simulation_db.read_simulation_json(
            SIM_TYPE, sid=req.req_data.simulationId)
    if re.search(r'\.ele$', req.filename, re.IGNORECASE):
        data = elegant_command_importer.import_file(text)
    elif re.search(r'\.lte$', req.filename, re.IGNORECASE):
        data = elegant_lattice_importer.import_file(text, input_data)
        if input_data:
            _map_commands_to_lattice(data)
    elif re.search(r'\.madx$', req.filename, re.IGNORECASE):
        from sirepo.template import madx_converter, madx_parser
        data = madx_converter.from_madx(
            SIM_TYPE, madx_parser.parse_file(text, downcase_variables=True))
    else:
        raise IOError('invalid file extension, expecting .ele or .lte')
    data.models.simulation.name = re.sub(r'\.(lte|ele|madx)$',
                                         '',
                                         req.filename,
                                         flags=re.IGNORECASE)
    if input_data and not test_data:
        simulation_db.delete_simulation(
            SIM_TYPE, input_data.models.simulation.simulationId)
    return data
Ejemplo n.º 11
0
    def sr_auth_state(self, **kwargs):
        """Gets authState and prases

        Returns:
            dict: parsed auth_state
        """
        from pykern import pkunit
        import pykern.pkcollections

        m = re.search(
            r'(\{.*\})',
            pkcompat.from_bytes(self.sr_get('authState').data),
        )
        s = pykern.pkcollections.json_load_any(m.group(1))
        for k, v in kwargs.items():
            pkunit.pkeq(
                v,
                s[k],
                'key={} expected={} != actual={}: auth_state={}',
                k,
                v,
                s[k],
                s,
            )
        return s
Ejemplo n.º 12
0
def _parameters(f):
    res = {}
    for name in ('integer scalars', 'integer runtime parameters',
                 'real scalars', 'real runtime parameters'):
        for v in f[name]:
            res[pkcompat.from_bytes(v[0].strip())] = v[1]
    return res
Ejemplo n.º 13
0
def subprocess_output(cmd, env):
    """Run cmd and return output or None, logging errors.

    Args:
        cmd (list): what to run
    Returns:
        str: output is None on error else a stripped string
    """
    err = None
    out = None
    try:

        p = subprocess.Popen(
            cmd,
            env=env,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        out, err = p.communicate()
        if p.wait() != 0:
            raise subprocess.CalledProcessError(returncode=p.returncode,
                                                cmd=cmd)
    except subprocess.CalledProcessError as e:
        pkdlog('{}: exit={} err={}', cmd, e.returncode, err)
        return None
    if out:
        out = pkcompat.from_bytes(out)
        return out.strip()
    return ''
Ejemplo n.º 14
0
def import_file(req, unit_test_mode=False, **kwargs):
    from sirepo.template import opal_parser
    text = pkcompat.from_bytes(req.file_stream.read())
    if re.search(r'\.in$', req.filename, re.IGNORECASE):
        data, input_files = opal_parser.parse_file(text, filename=req.filename)
        missing_files = []
        for infile in input_files:
            if not _SIM_DATA.lib_file_exists(infile.lib_filename):
                missing_files.append(infile)
        if len(missing_files):
            return PKDict(
                error='Missing data files',
                missingFiles=missing_files,
            )
    elif re.search(r'\.madx$', req.filename, re.IGNORECASE):
        from sirepo.template import madx_converter, madx_parser
        madx = madx_parser.parse_file(text)
        data = madx_converter.from_madx(SIM_TYPE, madx)
        data.models.simulation.name = re.sub(r'\.madx$',
                                             '',
                                             req.filename,
                                             flags=re.IGNORECASE)
        _fixup_madx(madx, data)
    else:
        raise IOError('invalid file extension, expecting .in or .madx')
    return data
Ejemplo n.º 15
0
 def parse_response(self, resp, expect_binary_body=False):
     assert resp.code == 200, 'resp={}'.format(resp)
     if 'Set-Cookie' in resp.headers:
         self._headers.Cookie = resp.headers['Set-Cookie']
     if 'json' in resp.headers['content-type']:
         return pkjson.load_any(resp.body)
     try:
         b = pkcompat.from_bytes(resp.body)
         assert not expect_binary_body, \
             'expecting binary body resp={} body={}'.format(
                 resp,
                 b[:1000],
             )
     except UnicodeDecodeError:
         assert expect_binary_body, \
             'unexpected binary body resp={}'.format(resp)
         # Binary data files can't be decoded
         return
     if 'html' in resp.headers['content-type']:
         m = re.search('location = "(/[^"]+)', b)
         if m:
             if 'error' in m.group(1):
                 return PKDict(state='error', error='server error')
             return PKDict(state='redirect', uri=m.group(1))
     return b
Ejemplo n.º 16
0
def _do(fc, file_ext, parse):
    from pykern.pkcollections import PKDict
    from pykern import pkio, pkcompat
    from pykern import pkunit
    from pykern import pkcollections
    from pykern.pkdebug import pkdp, pkdlog
    from pykern.pkunit import pkeq, pkfail, pkok, pkre
    import re

    for suffix in (('',) if file_ext == 'py' else ('', ' 2', ' 3')):
        for f in pkio.sorted_glob(pkunit.data_dir().join('*.' + file_ext)):
            pkdlog('file={}', f)
            json = pkcompat.from_bytes(parse(f))
            sim_type = re.search(r'^([a-z]+)_', f.basename).group(1)
            fc.sr_get_root(sim_type)
            is_dev = 'deviance' in f.basename
            res = fc.sr_post_form(
                'importFile',
                PKDict(folder='/importer_test'),
                PKDict(simulation_type=sim_type),
                file=f,
            )
            if is_dev:
                m = re.search(r'Error: (.+)', json)
                if m:
                    expect = m.group(1)
                    pkre(expect, res.error)
                continue
            elif file_ext == 'py':
                sim_name = f.purebasename
            else:
                sim_name = pkcollections.json_load_any(json).models.simulation.name
            assert 'models' in res, \
                f'file={f} res={res}'
            pkeq(sim_name + suffix, res.models.simulation.name)
Ejemplo n.º 17
0
def create_token(value):
    if pkconfig.channel_in_internal_test() and cfg.create_token_secret:
        v = base64.b32encode(
            hashlib.sha256(
                pkcompat.to_bytes(value + cfg.create_token_secret)).digest())
        return pkcompat.from_bytes(v[:TOKEN_SIZE])
    return random_base62(TOKEN_SIZE)
Ejemplo n.º 18
0
def test_srw_upload(fc):
    from pykern import pkunit, pkcompat
    from pykern.pkcollections import PKDict
    from pykern.pkdebug import pkdp
    import sirepo.sim_data

    d = fc.sr_sim_data('NSLS-II CHX beamline')
    s = sirepo.sim_data.get_class(fc.sr_sim_type)
    f = s.lib_file_resource_dir().join('mirror_1d.dat')
    t = 'mirror'
    r = fc.sr_post_form(
        'uploadFile',
        params=PKDict(
            simulation_type=fc.sr_sim_type,
            simulation_id=d.models.simulation.simulationId,
            file_type=t,
        ),
        data=PKDict(),
        file=f,
    )
    pkunit.pkre('in use in other', r.get('error', ''))
    r = fc.sr_post_form(
        'uploadFile',
        params=PKDict(
            simulation_type=fc.sr_sim_type,
            simulation_id=d.models.simulation.simulationId,
            file_type=t,
        ),
        data=PKDict(confirm='1'),
        file=f,
    )
    e = r.get('error', '')
    pkunit.pkok(not e, 'unexpected error={}', e)
    r = fc.sr_post_form(
        'uploadFile',
        params=PKDict(
            simulation_type=fc.sr_sim_type,
            simulation_id=d.models.simulation.simulationId,
            file_type='invalid file type',
        ),
        data=PKDict(),
        file=f,
    )
    pkunit.pkre('invalid file type', r.get('error', ''))
    # the above used to delete the file
    r = fc.sr_get(
        'downloadFile',
        params=PKDict(
            simulation_type=fc.sr_sim_type,
            simulation_id=d.models.simulation.simulationId,
            filename=f.basename,
        ),
        data=PKDict(),
    )
    pkunit.pkre(r'^\s*-1.39500', pkcompat.from_bytes(r.data))
Ejemplo n.º 19
0
    def secret_path_value(self, filename, gen_secret=None, visibility=None):
        from rsconf import db

        src = db.secret_path(self.hdb, filename, visibility=visibility)
        if src.check():
            return pkio.read_text(src), src
        assert gen_secret, \
            'unable to generate secret: path={}'.format(src)
        res = gen_secret()
        res = pkcompat.from_bytes(self._write_binary(src, res))
        return res, src
Ejemplo n.º 20
0
def import_file(req, **kwargs):
    text = pkcompat.from_bytes(req.file_stream.read())
    assert re.search(r'\.madx$', req.filename, re.IGNORECASE), \
        'invalid file extension, expecting .madx'
    data = madx_parser.parse_file(text, downcase_variables=True)
    # TODO(e-carlin): need to clean this up. copied from elegant
    data.models.simulation.name = re.sub(r'\.madx$',
                                         '',
                                         req.filename,
                                         flags=re.IGNORECASE)
    return data
Ejemplo n.º 21
0
def test_from_bytes():
    from pykern import pkcompat
    from pykern.pkunit import pkeq
    b = pkcompat.to_bytes('你好')
    s = pkcompat.from_bytes(b)
    pkeq(s, '你好')
    pkeq(b, b'\xe4\xbd\xa0\xe5\xa5\xbd')
    if six.PY2:
        pkeq(b, s)
    else:
        pkeq(False, b == s)
Ejemplo n.º 22
0
def _read_last_line(path):
    # for performance, don't read whole file if only last line is needed
    try:
        with open(str(path), 'rb') as f:
            f.readline()
            f.seek(-2, os.SEEK_END)
            while f.read(1) != b'\n':
                f.seek(-2, os.SEEK_CUR)
            return pkcompat.from_bytes(f.readline())
    except IOError:
        return ''
Ejemplo n.º 23
0
def test_srw(fc):
    from pykern import pkio, pkcompat
    from pykern.pkdebug import pkdpretty
    from pykern.pkunit import pkeq, pkre
    import json

    r = fc.sr_get_root()
    pkre('<!DOCTYPE html', pkcompat.from_bytes(r.data))
    d = fc.sr_post('listSimulations', {'simulationType': fc.sr_sim_type})
    pkeq(fc.get('/find-by-name-auth/srw/default/UndulatorRadiation').status_code, 404)
    for sep in (' ', '%20', '+'):
        pkeq(fc.get('/find-by-name-auth/srw/default/Undulator{}Radiation'.format(sep)).status_code, 200)
Ejemplo n.º 24
0
def test_deprecated():
    fc, sim_type = _fc(guest_deprecated=True)

    from pykern import pkconfig, pkunit, pkio, pkcompat
    from pykern.pkunit import pkok, pkre, pkeq
    from pykern.pkdebug import pkdp
    import re

    r = fc.sr_get('authGuestLogin', {'simulation_type': sim_type},
                  redirect=False)
    pkeq(302, r.status_code)
    pkre('guest/deprecated', pkcompat.from_bytes(r.data))
Ejemplo n.º 25
0
def _run_tests():
    """Runs the SRW "Undulator Radiation" simulation's initialIntensityReport"""
    _validate_auth_state()
    simulation_type = _SIM_TYPE
    res = uri_router.call_api(
        'findByNameWithAuth',
        dict(
            simulation_type=simulation_type,
            application_mode='default',
            simulation_name=_SIM_NAME,
        ),
    )
    m = re.search(r'\/source\/(\w+)"', pkcompat.from_bytes(res.data))
    if not m:
        raise RuntimeError('failed to find sid in resp={}'.format(res.data))
    i = m.group(1)
    d = simulation_db.read_simulation_json(simulation_type, sid=i)
    try:
        d.models.electronBeam.current = d.models.electronBeam.current + (
            random.random() / 10)
    except AttributeError:
        assert _SIM_TYPE == 'myapp', \
            f'{_SIM_TYPE} should be myapp or have models.electronBeam.current'
        pass
    d.simulationId = i
    d.report = _SIM_REPORT
    r = None
    try:
        resp = uri_router.call_api('runSimulation', data=d)
        for _ in range(_MAX_CALLS):
            r = simulation_db.json_load(resp.data)
            pkdlog('resp={}', r)
            if r.state == 'error':
                raise RuntimeError('simulation error: resp={}'.format(r))
            if r.state == 'completed':
                if 'initialIntensityReport' == d.report:
                    min_size = 50
                    if len(r.z_matrix) < min_size or len(
                            r.z_matrix[0]) < min_size:
                        raise RuntimeError(
                            'received bad report output: resp={}', r)
                return
            d = r.nextRequest
            resp = uri_router.call_api('runStatus', data=d)
            time.sleep(_SLEEP)
        raise RuntimeError(
            'simulation timed out: seconds={} resp='.format(
                _MAX_CALLS * _SLEEP, r), )
    finally:
        try:
            uri_router.call_api('runCancel', data=d)
        except Exception:
            pass
Ejemplo n.º 26
0
    def sr_run_sim(self,
                   data,
                   model,
                   expect_completed=True,
                   timeout=10,
                   **post_args):
        from pykern import pkunit
        from pykern.pkdebug import pkdlog, pkdexc
        import time

        if self.sr_job_run_mode:
            data.models[model].jobRunMode = self.sr_job_run_mode

        cancel = None
        try:
            r = self.sr_post(
                'runSimulation',
                PKDict(
                    models=data.models,
                    report=model,
                    simulationId=data.models.simulation.simulationId,
                    simulationType=data.simulationType,
                ).pkupdate(**post_args),
            )
            if r.state == 'completed':
                return r
            cancel = r.get('nextRequest')
            for _ in range(timeout):
                if r.state in ('completed', 'error'):
                    pkdlog(r.state)
                    cancel = None
                    break
                r = self.sr_post('runStatus', r.nextRequest)
                time.sleep(1)
            else:
                pkunit.pkok(not expect_completed,
                            'did not complete: runStatus={}', r)
            if expect_completed:
                pkunit.pkeq('completed', r.state)
            return r
        finally:
            if cancel:
                pkdlog('runCancel')
                self.sr_post('runCancel', cancel)
            import subprocess
            o = pkcompat.from_bytes(
                subprocess.check_output(['ps', 'axww'],
                                        stderr=subprocess.STDOUT), )
            o = list(filter(lambda x: 'mpiexec' in x, o.split('\n')))
            if o:
                pkdlog('found "mpiexec" after cancel in ps={}', '\n'.join(o))
                # this exception won't be seen because in finally
                raise AssertionError('cancel failed')
Ejemplo n.º 27
0
 def install_perl_rpm(self, j2_ctx, rpm_base, channel=None):
     src = self.rpm_file(j2_ctx, rpm_base, channel)
     r = src.basename
     if r in self.hdb.component.setdefault('_installed_rpms', set()):
         return r
     self.hdb.component._installed_rpms.add(r)
     dst = j2_ctx.build.dst_d.join(r)
     dst.mksymlinkto(src, absolute=False)
     self.append_root_bash("rsconf_install_perl_rpm '{}' '{}' '{}'".format(
         rpm_base,
         r,
         pkcompat.from_bytes(
             subprocess.check_output(['rpm', '-qp', str(src)]), ).strip(),
     ))
     return r
Ejemplo n.º 28
0
def import_file(req, unit_test_mode=False, **kwargs):
    from sirepo.template import opal_parser
    data, input_files = opal_parser.parse_file(pkcompat.from_bytes(
        req.file_stream.read()),
                                               filename=req.filename)
    missing_files = []
    for infile in input_files:
        if not _SIM_DATA.lib_file_exists(infile.lib_filename):
            missing_files.append(infile)
    if len(missing_files):
        return PKDict(
            error='Missing data files',
            missingFiles=missing_files,
        )
    return data
Ejemplo n.º 29
0
def _passwd_entry(j2_ctx, host):
    from rsconf import db
    import subprocess

    pw = db.random_string()
    pf = passwd_secret_f(j2_ctx)
    p = subprocess.Popen(
        ['openssl', 'passwd', '-stdin', '-apr1'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE,
    )
    out, err = p.communicate(input=pkcompat.to_bytes(pw))
    with pf.open(mode='at') as f:
        f.write('{}:{}\n'.format(host, pkcompat.from_bytes(out).rstrip()))
    return pw
Ejemplo n.º 30
0
def test_create_zip(fc):
    from pykern import pkio
    from pykern import pkunit
    from pykern import pkcompat
    from pykern.pkcollections import PKDict
    from pykern.pkdebug import pkdp, pkdpretty
    from pykern.pkunit import pkeq
    from sirepo import srunit
    import base64
    import re
    import zipfile

    imported = _import(fc)
    for sim_type, sim_name, expect in imported + [
        ('elegant', 'bunchComp - fourDipoleCSR',
         ['WAKE-inputfile.knsl45.liwake.sdds', 'run.py', 'sirepo-data.json']),
        ('srw', 'Tabulated Undulator Example',
         ['magnetic_measurements.zip', 'run.py', 'sirepo-data.json']),
        ('warppba', 'Laser Pulse', ['run.py', 'sirepo-data.json']),
    ]:
        sim_id = fc.sr_sim_data(
            sim_name, sim_type)['models']['simulation']['simulationId']
        with pkio.save_chdir(pkunit.work_dir()) as d:
            for t in 'zip', 'html':
                r = fc.sr_get(
                    'exportArchive',
                    PKDict(
                        simulation_type=sim_type,
                        simulation_id=sim_id,
                        filename='anything.' + t,
                    ))
                p = d.join(sim_name + '.' + t)
                x = r.data
                if t == 'html':
                    x = pkcompat.from_bytes(x)
                    m = re.search(r'name="zip" \S+ value="([^"]+)"',
                                  x,
                                  flags=re.DOTALL)
                    x = base64.b64decode(pkcompat.to_bytes(m.group(1)))
                p.write_binary(x)
                e = expect
                if t == 'html':
                    e.remove('run.py')
                pkeq(
                    e,
                    sorted(zipfile.ZipFile(str(p)).namelist()),
                )