Skip to content

Commit

Permalink
[tests] Unit tests and code refactoring.
Browse files Browse the repository at this point in the history
Signed-off-by: Xiangyu Bu <[email protected]>
  • Loading branch information
xybu committed Feb 3, 2017
1 parent c7d9225 commit 02576ad
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 49 deletions.
15 changes: 14 additions & 1 deletion onedrived/lang/od_pref.en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"configurator.error_generic": "Invalid value for \"{key}\": {error_message}.",

"od_pref.drive.submain.short_help": "List all remote OneDrive repositories (Drives) of linked accounts, add new Drives to sync, edit configurations of existing Drives, or remove a Drive from local list.",
"od_pref.list_drive.short_help": "List all available Drives.",
"od_pref.del_drive.short_help": "Stop syncing a Drive with local directory.",

"od_pref.config.submain.short_help": "Modify config (e.g., intervals, number of workers, etc.) for current user.",
"od_pref.set_config.short_help": "Update a config parameter.",
Expand All @@ -40,5 +42,16 @@
"od_pref.authenticate_account.paste_url_prompt": "Paste URL here",
"od_pref.authenticate_account.error.code_not_found_in_url": "Error: did not find authorization code in URL.",
"od_pref.authenticate_account.success.authorized": "Successfully authorized onedrived.",
"od_pref.authenticate_account.error.authorization": "Failed to authorize onedrived: {error_message}."
"od_pref.authenticate_account.error.authorization": "Failed to authorize onedrived: {error_message}.",

"od_pref.print_all_drives.fetching_drives.note": "Reading drives information from OneDrive server...",
"od_pref.print_all_drives.all_drives_table.note": "All available Drives of authorized accounts:",
"od_pref.print_all_drives.all_drives_table.header.index": "#",
"od_pref.print_all_drives.all_drives_table.header.account_email": "Account Email",
"od_pref.print_all_drives.all_drives_table.header.drive_id": "Drive ID",
"od_pref.print_all_drives.all_drives_table.header.type": "Type",
"od_pref.print_all_drives.all_drives_table.header.quota": "Quota",
"od_pref.print_all_drives.all_drives_table.header.status": "Status",

"api.drive.quota.short_format": "{used} Used / {total} Total"
}
22 changes: 12 additions & 10 deletions onedrived/od_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,21 @@
webhook_worker = None


def init_task_pool_and_workers():
global task_pool
task_pool = od_task.TaskPool()
for _ in range(context.config['num_workers']):
w = od_threads.TaskWorkerThread(name='Worker-%d' % len(task_workers), task_pool=task_pool)
w.start()
task_workers.add(w)


def shutdown_workers():
for w in task_workers:
if w:
w.stop()
if task_pool:
task_pool.close(len(task_workers))
od_threads.TaskWorkerThread.exit()
for w in task_workers:
if w:
w.join()
Expand Down Expand Up @@ -127,15 +138,6 @@ def delete_temp_files(all_accounts):
os.system('find "%s" -type f -name "%s" -delete' % (repo.local_root, repo.path_filter.get_temp_name('*')))


def init_task_pool_and_workers():
global task_pool
task_pool = od_task.TaskPool()
for _ in range(context.config['num_workers']):
w = od_threads.TaskWorkerThread(name='Worker-%d' % len(task_workers), task_pool=task_pool)
w.start()
task_workers.add(w)


def repo_updated_callback(repo):
global task_pool, webhook_server
if task_pool:
Expand Down
9 changes: 0 additions & 9 deletions onedrived/od_models/pretty_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,3 @@ def pretty_print_bytes(size, precision=2):
index += 1 # increment the index of the suffix
size /= 1024.0 # apply the division
return "%.*f %s" % (precision, size, suffixes[index])


def pretty_quota(q):
"""
Return a string for Quota object.
:param onedrivesdk.model.Quota q:
:return:
"""
return '%s Used / %s Total' % (pretty_print_bytes(q.used, precision=1), pretty_print_bytes(q.total, precision=1))
38 changes: 28 additions & 10 deletions onedrived/od_pref.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ def success(s):
click.secho(s, fg='green')


def quota_short_str(q):
"""
Return a string for Quota object.
:param onedrivesdk.model.Quota q:
:return:
"""
return translator['api.drive.quota.short_format'].format(
used=pretty_api.pretty_print_bytes(q.used, precision=1),
total=pretty_api.pretty_print_bytes(q.total, precision=1))


def print_all_accounts(ctx):
all_accounts = []
all_account_ids = ctx.all_accounts()
Expand Down Expand Up @@ -191,20 +202,28 @@ def change_drive():


def print_all_drives():
click.echo('Reading drives information from OneDrive server...\n')
click.echo(translator['od_pref.print_all_drives.fetching_drives.note'])
click.echo()
all_drives = {}
drive_table = [('#', 'Account Email', 'Drive ID', 'Type', 'Quota', 'Status')]
drive_table = []
for i in context.all_accounts():
drive_objs = []
profile = context.get_account(i)
authenticator, drives = od_auth.get_authenticator_and_drives(context, i)
for d in drives:
drive_objs.append(d)
drive_table.append((str(len(drive_table) - 1), profile.account_email,
d.id, d.drive_type, pretty_api.pretty_quota(d.quota), d.status.state))
d.id, d.drive_type, quota_short_str(d.quota), d.status.state))
all_drives[i] = (profile, authenticator, drive_objs)
click.echo(click.style('All available Drives of authorized accounts:\n', bold=True))
click.echo(tabulate.tabulate(drive_table, headers='firstrow'))
click.secho(translator['od_pref.print_all_drives.all_drives_table.note'], bold=True)
click.echo()
click.echo(tabulate.tabulate(drive_table, headers=(
translator['od_pref.print_all_drives.all_drives_table.header.index'],
translator['od_pref.print_all_drives.all_drives_table.header.account_email'],
translator['od_pref.print_all_drives.all_drives_table.header.drive_id'],
translator['od_pref.print_all_drives.all_drives_table.header.type'],
translator['od_pref.print_all_drives.all_drives_table.header.quota'],
translator['od_pref.print_all_drives.all_drives_table.header.status'])))
return all_drives, drive_table


Expand Down Expand Up @@ -234,15 +253,14 @@ def index_to_drive_table_row(index, drive_table):
raise ValueError('Index is not a valid row number.')


@click.command(name='list', short_help='List all available Drives.')
@click.command(name='list', short_help=translator['od_pref.list_drive.short_help'])
def list_drives():
try:
print_all_drives()
click.echo()
print_saved_drives()
except Exception as e:
click.echo(click.style('Error: %s.' % e, fg='red'))
return
error('Error: %s.' % e)


def read_drive_config_interactively(drive_exists, curr_drive_config):
Expand Down Expand Up @@ -374,7 +392,7 @@ def set_drive(drive_id=None, email=None, local_root=None, ignore_file=None):
click.echo(' Ignore file path: ' + d.ignorefile_path)


@click.command(name='del', short_help='Stop syncing a Drive with local directory.')
@click.command(name='del', short_help=translator['od_pref.del_drive.short_help'])
@click.option('--drive-id', '-d', type=str, required=False, default=None,
help='ID of the Drive.')
@click.option('--yes', '-y', is_flag=True, default=False, required=False,
Expand All @@ -384,7 +402,7 @@ def delete_drive(drive_id=None, yes=False):

if drive_id is None:
if yes:
click.echo(click.style('Please specify the Drive ID to delete.', fg='red'))
error('Please specify the Drive ID to delete.')
return
index = click.prompt('Please enter the # number of the Drive to delete (CTRL+C to abort)', type=int)
if isinstance(index, int) and 0 <= index < len(all_drive_ids):
Expand Down
12 changes: 5 additions & 7 deletions onedrived/od_threads.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,24 @@

class TaskWorkerThread(threading.Thread):

exit_signal = False

def __init__(self, name, task_pool):
"""
:param onedrived.od_task.TaskPool task_pool:
"""
super().__init__(name=name, daemon=False)
self.task_pool = task_pool
self._running = True

@classmethod
def exit(cls):
cls.exit_signal = True
def stop(self):
self._running = False

def run(self):
logging.debug('Started.')
while not self.exit_signal:
while self._running:
# logging.debug('Getting semaphore.')
self.task_pool.semaphore.acquire()
# logging.debug('Got semaphore.')
if self.exit_signal:
if not self._running:
break
task = self.task_pool.pop_task()
if task is not None:
Expand Down
67 changes: 67 additions & 0 deletions tests/data/list_drives.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"value":[
{
"quota":{
"remaining":29772095467,
"used":5661384725,
"total":35433480192,
"state":"normal",
"deleted":716108357,
"storagePlans":{
"upgradeAvailable":true
}
},
"status":{
"state":"active"
},
"owner":{
"user":{
"displayName":"Xiangyu Bu",
"id":"d781730a6d2c6611"
}
},
"id":"xb_drive_id",
"driveType":"personal"
},
{
"id":"xybu_id",
"driveType":"personal",
"owner":{
"user":{
"id":"713d61",
"displayName":"Ryan Gregg"
}
},
"status":{
"state":"active"
},
"quota":{
"total":1024000,
"used":514000,
"remaining":1010112,
"deleted":0,
"state":"normal"
}
},
{
"id":"0123456789abc",
"owner":{
"user":{
"id":"713d61",
"displayName":"Ryan Gregg"
}
},
"quota":{
"total":10240000,
"used":514133,
"remaining":1010112,
"deleted":0,
"state":"normal"
},
"status":{
"state":"active"
},
"driveType":"personal"
}
]
}
26 changes: 26 additions & 0 deletions tests/test_main_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import tempfile
import unittest

import click

from onedrived import od_main


class TestMainCLI(unittest.TestCase):

def setUp(self):
self.tempdir = tempfile.TemporaryDirectory()
click.get_app_dir = lambda x: self.tempdir.name + '/' + x
od_main.context = od_main.load_context()
od_main.context._create_config_dir_if_missing()

def tearDown(self):
self.tempdir.cleanup()

def test_init_and_shutdown_task_workers(self):
od_main.init_task_pool_and_workers()
od_main.shutdown_workers()


if __name__ == '__main__':
unittest.main()
4 changes: 0 additions & 4 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,6 @@ def test_pretty_print_bytes(self):
self.assertEqual('1.0 MB', od_models.pretty_api.pretty_print_bytes(size=1048576, precision=1))
self.assertEqual('1.50 GB', od_models.pretty_api.pretty_print_bytes(size=1610612736, precision=2))

def test_pretty_quota(self):
quota = onedrivesdk.Quota(json.loads(get_resource('data/quota_response.json', 'tests')))
self.assertIsInstance(od_models.pretty_api.pretty_quota(quota), str)


class TestDriveConfig(unittest.TestCase):

Expand Down
33 changes: 30 additions & 3 deletions tests/test_pref_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import unittest

import click
import onedrivesdk
import requests_mock

from onedrived import get_resource, od_pref
Expand Down Expand Up @@ -49,7 +50,7 @@ def test_config_set_key_typo(self):

def test_config_print(self):
try:
od_pref.print_config(args=[])
od_pref.print_config(args=())
except SystemExit:
pass

Expand All @@ -66,8 +67,9 @@ def callback_profile(request, context):
mock.get('https://apis.live.net/v5.0/me', json=callback_profile)
try:
od_pref.authenticate_account(args=args)
except SystemExit:
pass
except SystemExit as e:
if e.code == 0:
pass
context = od_pref.load_context()
self.assertIsNotNone(context.get_account(profile['id']))

Expand All @@ -81,6 +83,31 @@ def test_authenticate_account_with_url(self):
with requests_mock.Mocker() as mock:
self._call_authenticate_account(mock=mock, code='foobar_code', args=())

def test_list_account(self):
try:
od_pref.list_accounts(args=())
except SystemExit as e:
if e.code == 0:
pass

def test_quota_short_str(self):
quota = onedrivesdk.Quota(json.loads(get_resource('data/quota_response.json', 'tests')))
self.assertIsInstance(od_pref.quota_short_str(quota), str)

@requests_mock.mock()
def test_list_drives(self, mock):
all_drives = json.loads(get_resource('data/list_drives.json', pkg_name='tests'))
mock.register_uri('GET', 'https://api.onedrive.com/v1.0/drives',
[{'status_code': 200, 'json': {'value': all_drives['value'][0:-1]}},
{'status_code': 200, 'json': {'value': all_drives['value'][-1:]}}])
mock.post('https://login.live.com/oauth20_token.srf',
json=json.loads(get_resource('data/session_response.json', pkg_name='tests')))
try:
od_pref.list_drives(args=())
except SystemExit as e:
if e.code == 0:
pass


if __name__ == '__main__':
unittest.main()
10 changes: 5 additions & 5 deletions tests/test_threads.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from onedrived.od_tasks.base import TaskBase


class DummyTest(TaskBase):
class DummyTask(TaskBase):

def __init__(self, sem, repo=None, task_pool=None):
super().__init__(repo, task_pool)
Expand All @@ -23,14 +23,14 @@ def setUp(self):

def test_lifecycle(self):
sem = threading.Semaphore(value=0)
t = DummyTest(sem, None, self.task_pool)
t = DummyTask(sem, None, self.task_pool)
w = od_threads.TaskWorkerThread('DummyWorker', task_pool=self.task_pool)
w.start()
self.assertTrue(self.task_pool.add_task(t))
self.assertTrue(sem.acquire(timeout=10))
od_threads.TaskWorkerThread.exit()
self.assertTrue(sem.acquire(timeout=5))
w.stop()
self.task_pool.close(1)
w.join(timeout=10)
w.join(timeout=5)


if __name__ == '__main__':
Expand Down

0 comments on commit 02576ad

Please sign in to comment.