Newer
Older
import tempfile
import subprocess
import random
import os
import time
import requests
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
# Generic usefule fixtures
@pytest.fixture
def temp():
"""Write data to a temporary file and return the handle
This is a fixture instead of a utility function so that
temporary files have a test-scoped lifetime
"""
handles = []
def fun(data):
handle = tempfile.NamedTemporaryFile(delete=False)
if type(data) is str:
data = data.encode("utf8")
handle.write(data)
handle.flush()
handles.append(handle)
return handle.name
yield fun
del handles # Useless but explicit
# Test application instance
@pytest.fixture(scope="module")
def app(username, password):
"""Run an isolated application instance and return the URL"""
data = tempfile.TemporaryDirectory()
port = 5000 + random.randint(1, 999) # Port = 5XXX
url = f"http://localhost:{port}"
env = os.environ
env.update(FLASK_APP="hiboo", SQLALCHEMY_DATABASE_URI=f"sqlite:///{data.name}/hiboo.db")
subprocess.run(["flask", "db", "upgrade"], env=env)
subprocess.run(["flask", "user", "create", username, password], env=env)
subprocess.run(["flask", "user", "promote", username], env=env)
proc = subprocess.Popen(["flask", "run", "-p", str(port)], env=env)
# Wait for the server to be ready
for _ in range(30):
try:
assert requests.get(url).status_code == 200
except Exception as e:
print(e)
time.sleep(1)
else:
yield url
break
proc.terminate()
proc.wait()
del data
@pytest.fixture(scope="session")
def username():
"""Default username for tests"""
return "admin"
def password():
"""Default password for tests"""
return "admin"
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
@pytest.fixture
def service_name():
"""A randomly generated service name"""
return "Test service " + random.randbytes(3).hex()
# Test webserver
@pytest.fixture
def httpd(temp):
"""Test httpd server"""
proc = []
def start(config):
print(config)
proc.append(subprocess.Popen(["httpd", "-DFOREGROUND", "-f", temp(config)]))
time.sleep(1) # Sleep so apache can start
yield start
for pid in proc:
pid.terminate()
pid.wait()
@pytest.fixture
def httpd_minimal():
"""Minimal httpd config"""
rootDirectory = tempfile.TemporaryDirectory()
with open(os.path.join(rootDirectory.name, "index.html"), "w") as handle:
handle.write("Hello world!")
yield f"""
ServerName localhost
ServerRoot /usr/lib/httpd
PidFile /tmp/apache.pid
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule env_module modules/mod_env.so
LoadModule dir_module modules/mod_dir.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_user_module modules/mod_authz_user.so
LogLevel debug
ErrorLog /dev/stderr
TransferLog /dev/stdout
Listen 127.0.0.1:8123
DocumentRoot {rootDirectory.name}
DirectoryIndex index.html
"""
del rootDirectory
@pytest.fixture
def httpd_saml(httpd_minimal):
return (httpd_minimal + """
LoadModule auth_mellon_module modules/mod_auth_mellon.so
<Location />
Require valid-user
AuthType "Mellon"
MellonEnable "auth"
MellonEndpointPath "/mellon"
MellonSPPrivateKeyFile {key}
MellonSPCertFile {cert}
MellonIdPMetadataFile {metadata}
SetEnv MELLON_DISABLE_SAMESITE 1
</Location>
""")
@pytest.fixture
def httpd_oidc(httpd_minimal):
return (httpd_minimal + """
LoadModule auth_openidc_module modules/mod_auth_openidc.so
OIDCProviderMetadataURL {metadata}
OIDCClientID {client_id}
OIDCClientSecret {client_secret}
OIDCRedirectURI http://localhost:8123/redirect_uri
OIDCCryptoPassphrase changeme
OIDCScope "openid email profile"
<Location />
Require valid-user
AuthType "openid-connect"
</Location>
""")