Skip to content

Commit 7749944

Browse files
committed
Update MySQL/MariaDB stuff
1 parent cfae046 commit 7749944

6 files changed

Lines changed: 79 additions & 118 deletions

File tree

doc/authors.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ current affiliation of a contributor.
3131
* Dan Padilha [18]
3232
* Simon Chabot [19]
3333
* @maharjun
34+
* David Kleiven [20]
3435

3536
1. Unité de Neuroscience, Information et Complexité, CNRS UPR 3293, Gif-sur-Yvette, France
3637
2. Ecole Centrale de Lille, Lille, France
@@ -51,6 +52,7 @@ current affiliation of a contributor.
5152
17. Institute of Nanotechnology, Karlsruhe Institute of Technology, Germany
5253
18. Shoal Engineering Pty Ltd, Canberra, Australia
5354
19. CEREMA Direction territoriale Méditerranée, Nice, France
55+
20. NTNU, Trondheim, Norway
5456

5557
If we've somehow missed you off the list I'm very sorry - please let us know.
5658

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ remote = ["httplib2"]
6363

6464
postgres = ["psycopg2-binary"]
6565

66+
mysql = ["mysqlclient"]
67+
6668
latex = ["jinja2"]
6769

6870
sphinx = ["docutils"]

sumatra/commands.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,14 @@
4040
"repeat", "diff", "help", "export", "upgrade", "sync", "migrate", "version",
4141
"view")
4242

43-
store_arg_help = "The argument can take the following forms: (1) `/path/to/sqlitedb` - DjangoRecordStore is used with the specified Sqlite database, (2) `http[s]://location` - remote HTTPRecordStore is used with a remote Sumatra server, (3) `postgres://username:password@hostname/databasename` - DjangoRecordStore is used with specified Postgres database."
43+
store_arg_help = (
44+
"The argument can take the following forms: "
45+
"(1) `/path/to/sqlitedb` - DjangoRecordStore is used with the specified Sqlite database, "
46+
"(2) `http[s]://location` - remote HTTPRecordStore is used with a remote Sumatra server, "
47+
"(3) `postgres://username:password@hostname/databasename` - DjangoRecordStore is used with specified PostgreSQL database."
48+
"(4) `mysql://username:password@hostname/databasename` - DjangoRecordStore is used with specified MySQL database."
49+
"(5) `mariadb://username:password@hostname/databasename` - DjangoRecordStore is used with specified MariaDB database."
50+
)
4451

4552
## recommended method for modifying warning formatting
4653
## see https://docs.python.org/2/library/warnings.html#warnings.showwarning

sumatra/recordstore/django_store/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ def _dump(self, indent=2):
349349

350350
@classmethod
351351
def accepts_uri(cls, uri):
352-
return uri[:8] == "postgres" or uri.startswith(('mysql', 'mariadb')) or os.path.exists(uri) or os.path.exists(uri + ".db")
352+
return uri.startswith(("postgres", "mysql", "mariadb")) or os.path.exists(uri) or os.path.exists(uri + ".db")
353353

354354
def backup(self):
355355
"""

test/system/fixtures/Dockerfile.mysql

Lines changed: 0 additions & 20 deletions
This file was deleted.

test/system/test_mysql.py

Lines changed: 66 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,90 @@
11
"""
2-
Tests using a MySQL-based record store.
2+
Tests using a MariaDB/MySQL-based record store.
33
4-
5-
Usage:
6-
nosetests -v test_mysql.py
7-
or:
8-
python test_mysql.py
94
"""
10-
from __future__ import print_function
11-
from __future__ import unicode_literals
12-
from future import standard_library
13-
standard_library.install_aliases()
14-
from builtins import input
155

166
import os
17-
from urllib.parse import urlparse
7+
import shutil
8+
import tempfile
189
try:
1910
import docker
20-
if "DOCKER_HOST" in os.environ:
21-
have_docker = True
22-
else:
23-
have_docker = False
11+
have_docker = True
2412
except ImportError:
2513
have_docker = False
26-
from unittest import SkipTest
27-
import utils
28-
from utils import setup, teardown as default_teardown, run_test, build_command
14+
try:
15+
import mysqlclient
16+
have_mysql = True
17+
except ImportError:
18+
have_mysql = False
2919

30-
ctr = None
31-
dkr = None
32-
image = "mysql_test"
3320

21+
from utils import run_test, build_command
3422

35-
def create_script():
36-
with open(os.path.join(utils.working_dir, "main.py"), "w") as fp:
37-
fp.write("print('Hello world!')\n")
23+
import pytest
3824

25+
DOCKER_IMAGE = "mariadb:latest"
3926

40-
def get_url():
41-
info = dkr.containers()[0]
42-
assert info["Image"] == image
43-
host = urlparse(dkr.base_url).hostname
44-
return "{0}:{1}".format(host, info["Ports"][0]["PublicPort"])
4527

28+
def get_url(ctr):
29+
ctr.reload() # required to get auto-assigned ports
30+
info = ctr.ports["3306/tcp"][0]
31+
return f"{info['HostIp']}:{info['HostPort']}"
4632

47-
def start_pg_container():
48-
"""
49-
Launch a Docker container running MySQL, return the URL.
5033

51-
Requires the "mysql_test" image. If this does not yet exist, run
34+
@pytest.fixture(scope="module")
35+
def mysql_container():
36+
"""
37+
Launch a Docker container running MariaDB, return the URL.
5238
53-
docker build -t mysql_test - < fixtures/Dockerfile.mysql
5439
"""
55-
global ctr, dkr
56-
env = docker.utils.kwargs_from_env(assert_hostname=False)
57-
dkr = docker.Client(timeout=60, **env)
58-
59-
host_config = dkr.create_host_config(publish_all_ports=True)
60-
# docker run -rm -P -name ms_test mysql_test
61-
ctr = dkr.create_container(image, command=None, hostname=None, user=None,
62-
detach=False, stdin_open=False, tty=False,
63-
ports=None, environment=None, dns=None,
64-
volumes=None, volumes_from=None,
65-
network_disabled=False, name=None,
66-
entrypoint=None, cpu_shares=None,
67-
working_dir=None, host_config=host_config)
68-
dkr.start(ctr)
69-
utils.env["url"] = get_url()
70-
71-
72-
def teardown():
73-
global ctr, dkr
74-
default_teardown()
75-
if dkr is not None:
76-
dkr.stop(ctr)
77-
78-
79-
test_steps = [
80-
create_script,
81-
("Create repository", "git init"),
82-
("Add main file", "git add main.py"),
83-
("Commit main file", "git commit -m 'initial'"),
84-
start_pg_container,
85-
("Set up a Sumatra project",
86-
build_command("smt init --store=mysql://docker:docker@{}/sumatra_test -m main.py -e python MyProject", "url")),
87-
("Show project configuration", "smt info"), # TODO: add assert
88-
("Run a computation", "smt run")
89-
]
90-
91-
92-
# TODO: add test skips where docker not found
93-
94-
95-
def test_all():
96-
"""Test generator for Nose."""
97-
if not have_docker:
98-
raise SkipTest("Tests require docker")
40+
dkr = docker.from_env()
41+
42+
ctr = dkr.containers.run(
43+
DOCKER_IMAGE, detach=True, publish_all_ports=True,
44+
environment={
45+
"MARIADB_ROOT_PASSWORD": "the_root_password",
46+
"MARIADB_DATABASE": "sumatra_test",
47+
"MARIADB_USER": "docker",
48+
"MARIADB_PASSWORD": "docker"
49+
}
50+
)
51+
container_url = get_url(ctr)
52+
yield container_url
53+
ctr.stop()
54+
55+
56+
@pytest.mark.skipif(not have_docker, reason="Tests require docker Python package")
57+
@pytest.mark.skipif(not have_mysql, reason="Tests require mysqlclient")
58+
def test_all(mysql_container):
59+
"""Run a series of Sumatra commands"""
60+
temporary_dir = os.path.realpath(tempfile.mkdtemp())
61+
working_dir = os.path.join(temporary_dir, "sumatra_exercise")
62+
os.mkdir(working_dir)
63+
env = {
64+
"labels": [],
65+
"working_dir": working_dir,
66+
"url": mysql_container
67+
}
68+
69+
def create_script():
70+
with open(os.path.join(working_dir, "main.py"), "w") as fp:
71+
fp.write("print('Hello world!')\n")
72+
73+
test_steps = [
74+
create_script,
75+
("Create repository", "git init"),
76+
("Add main file", "git add main.py"),
77+
("Commit main file", "git commit -m 'initial'"),
78+
("Set up a Sumatra project",
79+
build_command("smt init --store=mysql://docker:docker@{}/sumatra_test -m main.py -e python MyProject", "url")),
80+
#"smt init -m main.py -e python MyProject"),
81+
("Show project configuration", "smt info"), # TODO: add assert
82+
("Run a computation", "smt run")
83+
]
9984
for step in test_steps:
10085
if callable(step):
10186
step()
10287
else:
103-
run_test.description = step[0]
104-
yield tuple([run_test] + list(step[1:]))
88+
run_test(*step[1:], env=env)
10589

106-
107-
if __name__ == '__main__':
108-
# Run the tests without using Nose.
109-
setup()
110-
for step in test_steps:
111-
if callable(step):
112-
step()
113-
else:
114-
print(step[0]) # description
115-
run_test(*step[1:])
116-
response = input("Do you want to delete the temporary directory (default: yes)? ")
117-
if response not in ["n", "N", "no", "No"]:
118-
teardown()
119-
else:
120-
print("Temporary directory %s not removed" % utils.temporary_dir)
90+
shutil.rmtree(temporary_dir)

0 commit comments

Comments
 (0)