Skip to content

Commit b75c2b0

Browse files
committed
FIX: Minor fixes to serial tests
- Moved and modified test.sh script - All serial and parallel tests passing
1 parent cf172ae commit b75c2b0

File tree

14 files changed

+593
-47
lines changed

14 files changed

+593
-47
lines changed

misc/fabfile/fabfile.py

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
import time
2+
import os
3+
4+
from fabric.contrib.project import rsync_project
5+
from fabric.decorators import task
6+
from fabric.operations import sudo, run, put, get
7+
from fabric.context_managers import cd, shell_env, settings, prefix
8+
from fabric.tasks import Task
9+
from saws import AwsManager
10+
from saws.tasks import ebs_mount
11+
from helpers import set_rwx_permissions, set_rx_permisions, fcmd, parser
12+
13+
14+
@task
15+
def deploy_test_local_copy(dest):
16+
from ocgis.test.base import TestBase
17+
18+
dest = os.path.expanduser(dest)
19+
if not os.path.exists(dest):
20+
os.path.makedirs(dest)
21+
tdata = TestBase.get_tst_data()
22+
tdata.copy_files(dest, verbose=True)
23+
24+
25+
@task()
26+
def deploy_test_rsync():
27+
remote_dir = parser.get('server', 'dir_data')
28+
local_dir = os.getenv('OCGIS_DIR_TEST_DATA')
29+
30+
# we want to create the local test directory on the remote server:
31+
# http://docs.fabfile.org/en/latest/api/contrib/project.html#fabric.contrib.project.rsync_project
32+
assert not local_dir.endswith('/')
33+
34+
# update permissions so files may be copied
35+
local_dir_name = os.path.split(local_dir)[1]
36+
test_data_path = os.path.join(remote_dir, local_dir_name)
37+
set_rwx_permissions(test_data_path)
38+
try:
39+
# synchronize the project
40+
rsync_project(remote_dir, local_dir=local_dir)
41+
finally:
42+
# remove write permissions on the files/directories
43+
set_rx_permisions(test_data_path)
44+
45+
46+
@task
47+
def ebs_mkfs():
48+
"""Make a file system on a newly attached device."""
49+
50+
cmd = ['mkfs', '-t', 'ext4', parser.get('aws', 'ebs_mount_name')]
51+
fcmd(sudo, cmd)
52+
53+
54+
@task
55+
def list_storage():
56+
"""List storage size of connected devices."""
57+
58+
fcmd(run, ['lsblk'])
59+
60+
@task
61+
def put_file(local_path, remote_path):
62+
"""
63+
Put a file on the remote server: local_path,remote_path
64+
"""
65+
66+
put(local_path=local_path, remote_path=remote_path)
67+
68+
69+
@task
70+
def remove_dir(path, use_sudo='false'):
71+
"""Remove the source directory."""
72+
73+
cmd = ['rm', '-r', path]
74+
if use_sudo == 'true':
75+
fmeth = sudo
76+
elif use_sudo == 'false':
77+
fmeth = run
78+
else:
79+
raise NotImplementedError(use_sudo)
80+
81+
fcmd(fmeth, cmd)
82+
83+
84+
class RunAwsTests(Task):
85+
"""
86+
Run tests on remote server and return the path to a local log file of tests results.
87+
"""
88+
name = 'run_aws_tests'
89+
90+
def run(self, path_local_log=None, branch='next', sched='false', launch_pause='false'):
91+
"""
92+
:param str path_local_log: Path to the local log file copied from the remote server. If ``None``, do not copy
93+
remote log file.
94+
:param str branch: Target git branch to test.
95+
:param str sched: If ``'true'``, run tests only once. Otherwise, run tests at 23:00 hours daily.
96+
:param str launch_pause: If ``'true'``, pause at a breakpoint after launching the instance and mounting the data
97+
volume. Continuing from the breakpoint will terminate the instance and destroy the volume.
98+
"""
99+
100+
import schedule
101+
from logbook import Logger
102+
103+
self.log = Logger('nesii-testing')
104+
105+
self.path_local_log = path_local_log
106+
self.branch = branch
107+
self.launch_pause = launch_pause
108+
109+
if self.launch_pause == 'true':
110+
self.log.info('launching instance then pausing')
111+
self._run_tests_(should_email=False)
112+
else:
113+
if sched == 'true':
114+
self.log.info('begin continous loop')
115+
schedule.every().day.at("6:00").do(self._run_tests_, should_email=True)
116+
while True:
117+
schedule.run_pending()
118+
time.sleep(1)
119+
else:
120+
self.log.info('running tests once')
121+
self._run_tests_(should_email=True)
122+
123+
def _run_tests_(self, should_email=False):
124+
aws_src = os.getenv('OCGIS_SIMPLEAWS_SRC')
125+
aws_conf = os.getenv('OCGIS_CONF_PATH')
126+
aws_testing_section = 'aws-testing'
127+
128+
ebs_volumesize = int(parser.get(aws_testing_section, 'ebs_volumesize'))
129+
ebs_snapshot = parser.get(aws_testing_section, 'ebs_snapshot')
130+
ebs_mount_name = parser.get(aws_testing_section, 'ebs_mount_name')
131+
ebs_placement = parser.get(aws_testing_section, 'ebs_placement')
132+
test_results_path = parser.get(aws_testing_section, 'test_results_path')
133+
test_instance_name = parser.get(aws_testing_section, 'test_instance_name')
134+
test_instance_type = parser.get(aws_testing_section, 'test_instance_type')
135+
test_image_id = parser.get(aws_testing_section, 'test_image_id')
136+
dest_email = parser.get(aws_testing_section, 'dest_email')
137+
dir_clone = parser.get('server', 'dir_clone')
138+
key_name = parser.get('simple-aws', 'key_name')
139+
140+
import sys
141+
sys.path.append(aws_src)
142+
import saws
143+
import ipdb
144+
145+
am = saws.AwsManager(aws_conf)
146+
147+
self.log.info('launching instance')
148+
instance = am.launch_new_instance(test_instance_name, image_id=test_image_id, instance_type=test_instance_type,
149+
placement=ebs_placement)
150+
151+
with settings(host_string=instance.ip_address, disable_known_hosts=True, connection_attempts=10):
152+
try:
153+
self.log.info('creating volume')
154+
volume = am.conn.create_volume(ebs_volumesize, ebs_placement, snapshot=ebs_snapshot)
155+
am.wait_for_status(volume, 'available')
156+
try:
157+
self.log.info('attaching volume')
158+
am.conn.attach_volume(volume.id, instance.id, ebs_mount_name, dry_run=False)
159+
am.wait_for_status(volume, 'in-use')
160+
161+
ebs_mount()
162+
163+
if self.launch_pause == 'true':
164+
self.log.info('pausing. continue to terminate instance...')
165+
msg = 'ssh -i ~/.ssh/{0}.pem ubuntu@{1}'.format(key_name, instance.public_dns_name)
166+
self.log.info(msg)
167+
ipdb.set_trace()
168+
else:
169+
path = os.path.join(dir_clone, parser.get('git', 'name'))
170+
test_target = os.path.join(path, 'src', 'ocgis', 'test')
171+
# test_target = os.path.join(path, 'src', 'ocgis', 'test', 'test_simple')
172+
nose_runner = os.path.join(path, 'fabfile', 'nose_runner.py')
173+
path_src = os.path.join(path, 'src')
174+
with cd(path):
175+
fcmd(run, ['git', 'pull'])
176+
fcmd(run, ['git', 'checkout', self.branch])
177+
fcmd(run, ['git', 'pull'])
178+
with cd(path_src):
179+
with shell_env(OCGIS_TEST_TARGET=test_target):
180+
fcmd(run, ['python', nose_runner])
181+
if self.path_local_log is not None:
182+
get(test_results_path, local_path=self.path_local_log)
183+
184+
ebs_umount()
185+
186+
finally:
187+
self.log.info('detaching volume')
188+
volume.detach(force=True)
189+
am.wait_for_status(volume, 'available')
190+
self.log.info('deleting volume')
191+
volume.delete()
192+
finally:
193+
self.log.info('terminating instance')
194+
instance.terminate()
195+
196+
if should_email and self.launch_pause == 'false' and self.path_local_log is not None:
197+
self.log.info('sending email')
198+
with open(self.path_local_log, 'r') as f:
199+
content = f.read()
200+
am.send_email(dest_email, dest_email, 'OCGIS_AWS', content)
201+
202+
self.log.info('success')
203+
204+
205+
r = RunAwsTests()
206+
207+
208+
@task
209+
def test_node_launch(instance_type='m3.xlarge'):
210+
am = AwsManager()
211+
instance_name = 'ocgis-test-node'
212+
image_id = 'ami-d1878fe1'
213+
ebs_mount_dir = '~/data'
214+
ebs_mount_name = '/dev/xvdf'
215+
instance = am.launch_new_instance(instance_name, image_id=image_id, instance_type=instance_type)
216+
test_node_ebs_mount(instance_name=instance_name, ebs_mount_name=ebs_mount_name, ebs_mount_dir=ebs_mount_dir)
217+
print am.get_ssh_command(instance=instance)
218+
219+
220+
@task
221+
def test_node_ebs_mount(instance_name='ocgis-test-node', ebs_mount_name='/dev/xvdg', ebs_mount_dir='~/data'):
222+
am = AwsManager()
223+
instance = am.get_instance_by_name(instance_name)
224+
kwargs = {'mount_name': ebs_mount_name, 'mount_dir': ebs_mount_dir}
225+
am.do_task(ebs_mount, instance=instance, kwargs=kwargs)
226+
227+
228+
@task
229+
def test_node_run_tests(instance_name='ocgis-test-node', branch='next', failed='false'):
230+
am = AwsManager()
231+
instance = am.get_instance_by_name(instance_name)
232+
tcenv = 'test-ocgis'
233+
texclude = '!slow,!remote,!esmpy7'
234+
tgdal_data = '/home/ubuntu/anaconda/envs/{0}/share/gdal'.format(tcenv)
235+
tocgis_dir_shpcabinet = '/home/ubuntu/data/ocgis_test_data/shp'
236+
tocgis_dir_test_data = '/home/ubuntu/data/ocgis_test_data/'
237+
tsrc = '~/git/ocgis/src'
238+
239+
def _run_():
240+
senv = dict(OCGIS_DIR_SHPCABINET=tocgis_dir_shpcabinet, OCGIS_DIR_TEST_DATA=tocgis_dir_test_data,
241+
GDAL_DATA=tgdal_data)
242+
with shell_env(**senv):
243+
with prefix('source activate {0}'.format(tcenv)):
244+
with cd(tsrc):
245+
run('git checkout next')
246+
run('git pull')
247+
if failed == 'true':
248+
cmd = 'cp .noseids /tmp; git checkout {tbranch}; git pull; nosetests -vs --failed --with-id -a {texclude} ocgis/test'
249+
else:
250+
cmd = 'cp .noseids /tmp; rm .noseids; git checkout {tbranch}; git pull; nosetests -vs --with-id -a {texclude} ocgis/test'
251+
cmd = cmd.format(tbranch=branch, texclude=texclude)
252+
run(cmd)
253+
254+
am.do_task(_run_, instance=instance)
255+
256+
257+
@task
258+
def test_node_terminate():
259+
am = AwsManager()
260+
instance_name = 'ocgis-test-node'
261+
instance = am.get_instance_by_name(instance_name)
262+
instance.terminate()

misc/fabfile/fabric-commands.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
3+
# Launch the test server.
4+
fab test_node_launch
5+
6+
# Run tests on the launched server.
7+
fab test_node_run_tests:branch=next,failed=false
8+
9+
# Terminate the test server.
10+
fab test_node_terminate

misc/fabfile/helpers.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from ConfigParser import SafeConfigParser
2+
from fabric.operations import local, sudo
3+
from fabric.state import env
4+
import os
5+
6+
7+
conf_path = os.getenv('OCGIS_CONF_PATH')
8+
parser = SafeConfigParser()
9+
parser.read(conf_path)
10+
11+
env.user = parser.get('fabric', 'user')
12+
env.hosts = [parser.get('fabric', 'hosts')]
13+
env.key_filename = parser.get('fabric', 'key_filename')
14+
15+
16+
def tfs(sequence):
17+
return ' '.join(sequence)
18+
19+
20+
def fcmd(name, cmd):
21+
return name(tfs(cmd))
22+
23+
24+
def fecho(msg):
25+
local('echo "{0}"'.format(msg), capture=True)
26+
27+
28+
def set_rwx_permissions(path):
29+
# set the owner for the files to the environment user
30+
fcmd(sudo, ['chown', '-R', env.user, path])
31+
# set read, write, execute...
32+
fcmd(sudo, ['chmod', '-R', 'u=rwx', path])
33+
34+
35+
def set_rx_permisions(path):
36+
# set the owner for the files to the environment user
37+
fcmd(sudo, ['chown', '-R', env.user, path])
38+
# set read, execute...
39+
fcmd(sudo, ['chmod', '-R', 'a-rwx', path])
40+
fcmd(sudo, ['chmod', '-R', 'ug=rwx', path])

misc/fabfile/nose_runner.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import datetime
2+
from email.mime.text import MIMEText
3+
import os
4+
import smtplib
5+
import tempfile
6+
import nose
7+
from nose.plugins.plugintest import run
8+
9+
PATH_LOG = '/tmp/foo.txt'
10+
11+
class SimpleStream(object):
12+
13+
def __init__(self, path):
14+
self.path = path
15+
self.write('', mode='w')
16+
self.writeln('OpenClimateGIS Test Results')
17+
self.writeln('Started {0} UTC'.format(datetime.datetime.utcnow()))
18+
self.writeln()
19+
20+
def flush(self):
21+
pass
22+
23+
def write(self, msg, mode='a'):
24+
print msg
25+
with open(self.path, mode) as f:
26+
f.write(msg)
27+
28+
def writeln(self, msg=None, mode='a'):
29+
if msg is None:
30+
msg = '\n'
31+
else:
32+
msg = '{0}\n'.format(msg)
33+
print msg
34+
self.write(msg, mode=mode)
35+
36+
37+
class NESIITestRunner(nose.plugins.Plugin):
38+
name = 'nesii-remote-tests'
39+
_days = {0: 'Sunday', 1: 'Monday', 2: 'Tuesday', 3: 'Wednesday', 4: 'Thursday', 5: 'Friday', 6: 'Saturday'}
40+
41+
def __init__(self, *args, **kwargs):
42+
self._path_log = kwargs.pop('path_log')
43+
super(NESIITestRunner, self).__init__(*args, **kwargs)
44+
self._ss = None
45+
46+
def finalize(self, result):
47+
# skipped = len(result.skipped)
48+
errors = len(result.errors)
49+
failures = len(result.failures)
50+
# total = result.testsRun
51+
52+
self._ss.writeln()
53+
total_bad = errors + failures
54+
self._ss.writeln('Test_Failures:{0}'.format(total_bad))
55+
self._ss.writeln('Day_of_Week:{0}'.format(self._days[datetime.datetime.now().weekday()]))
56+
57+
if total_bad > 0:
58+
color = 'yellow'
59+
elif total_bad == 0:
60+
color = 'green'
61+
else:
62+
raise NotImplementedError(total_bad)
63+
64+
self._ss.writeln('Test_results:{0}'.format(color))
65+
66+
def setOutputStream(self, stream):
67+
self._ss = SimpleStream(self._path_log)
68+
return self._ss
69+
70+
71+
if __name__ == '__main__':
72+
nose.main(addplugins=[NESIITestRunner(path_log='/tmp/nesii_test_results.log')],
73+
argv=[__file__, '-vs', os.getenv('OCGIS_TEST_TARGET'), '--with-nesii-remote-tests'])
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)