Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new REST-based Webapi and interactive webapi Docs with Swagger-UI #276

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ deluge/ui/web/js/extjs/ext-extensions*.js
osx/app
RELEASE-VERSION
.venv*

swagger_ui/package-lock.json
swagger_ui/node_modules/
deluge/ui/web/js/swagger-ui
9 changes: 4 additions & 5 deletions deluge/tests/daemon_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,16 @@ def get_pytest_basetemp(self, request):
def common_set_up(self):
common.set_tmp_config_dir()
self.listen_port = 58900
self.core = None
self.process_protocol = None
return component.start()

def terminate_core(self, *args):
if args[0] is not None:
if hasattr(args[0], 'getTraceback'):
print('terminate_core: Errback Exception: %s' % args[0].getTraceback())

if not self.core.killed:
d = self.core.kill()
return d
if not self.process_protocol.killed:
return self.process_protocol.kill()

@defer.inlineCallbacks
def start_core(
Expand All @@ -69,7 +68,7 @@ def start_core(

for dummy in range(port_range):
try:
d, self.core = common.start_core(
d, self.process_protocol = common.start_core(
listen_port=self.listen_port,
logfile=logfile,
timeout=timeout,
Expand Down
40 changes: 28 additions & 12 deletions deluge/tests/test_json_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from deluge.error import DelugeError
from deluge.ui.client import client
from deluge.ui.web.auth import Auth
from deluge.ui.web.json_api import JSON, JSONException
from deluge.ui.web.json_api import ERROR_RESPONSE_CODE, JSON, JsonAPIException

from . import common
from .basetest import BaseTestCase
Expand Down Expand Up @@ -85,9 +85,9 @@ def write(response_str):
self.assertEqual(response['result'], None)
self.assertEqual(response['id'], None)
self.assertEqual(
response['error']['message'], 'JSONException: JSON not decodable'
response['error']['message'], 'JsonAPIException: JSON not decodable'
)
self.assertEqual(response['error']['code'], 5)
self.assertEqual(response['error']['code'], ERROR_RESPONSE_CODE.RPC_ERROR)

request.write = write
request.write_was_called = False
Expand All @@ -102,20 +102,29 @@ def test_handle_request_invalid_method(self):
json_data = {'method': 'no-existing-module.test', 'id': 0, 'params': []}
request.json = json_lib.dumps(json_data).encode()
request_id, result, error = json._handle_request(request)
self.assertEqual(error, {'message': 'Unknown method', 'code': 2})
self.assertEqual(
error,
{
'message': 'Unknown method',
'code': ERROR_RESPONSE_CODE.RPC_UNKNOWN_METHOD,
},
)

def test_handle_request_invalid_json_request(self):
json = JSON()
request = MagicMock()
# Missing method
json_data = {'id': 0, 'params': []}
request.json = json_lib.dumps(json_data).encode()
self.assertRaises(JSONException, json._handle_request, request)
json_data = {'method': 'some.method', 'params': []}
request.json = json_lib.dumps(json_data).encode()
self.assertRaises(JSONException, json._handle_request, request)
self.assertRaises(JsonAPIException, json._handle_request, request)
# Missing param
json_data = {'method': 'some.method', 'id': 0}
request.json = json_lib.dumps(json_data).encode()
self.assertRaises(JSONException, json._handle_request, request)
self.assertRaises(JsonAPIException, json._handle_request, request)
# No id is valid
json_data = {'method': 'system.listMethods', 'params': []}
request.json = json_lib.dumps(json_data).encode()
json._handle_request(request)

def test_on_json_request_invalid_content_type(self):
"""Test for exception with content type not application/json"""
Expand All @@ -124,7 +133,7 @@ def test_on_json_request_invalid_content_type(self):
request.getHeader.return_value = b'text/plain'
json_data = {'method': 'some.method', 'id': 0, 'params': []}
request.json = json_lib.dumps(json_data).encode()
self.assertRaises(JSONException, json._on_json_request, request)
self.assertRaises(JsonAPIException, json._on_json_request, request)


class JSONCustomUserTestCase(JSONBase):
Expand All @@ -148,7 +157,13 @@ def test_handle_request_auth_error(self):
json_data = {'method': 'core.get_libtorrent_version', 'id': 0, 'params': []}
request.json = json_lib.dumps(json_data).encode()
request_id, result, error = json._handle_request(request)
self.assertEqual(error, {'message': 'Not authenticated', 'code': 1})
self.assertEqual(
error,
{
'message': 'Not authenticated',
'code': ERROR_RESPONSE_CODE.RPC_NOT_AUTHENTICATED,
},
)


class RPCRaiseDelugeErrorJSONTestCase(JSONBase):
Expand Down Expand Up @@ -181,6 +196,7 @@ def get_session_id(s_id):
auth = Auth(auth_conf)
request = Request(MagicMock(), False)
request.base = b''
request.path = b'json'
auth._create_session(request)
methods = yield json.get_remote_methods()
# Verify the function has been registered
Expand Down Expand Up @@ -273,7 +289,7 @@ def write(response_str):
'Failure: [Failure instance: Traceback (failure with no frames):'
" <class 'deluge.error.DelugeError'>: DelugeERROR\n]",
)
self.assertEqual(response['error']['code'], 4)
self.assertEqual(response['error']['code'], ERROR_RESPONSE_CODE.RPC_ERROR)

request.write = write
request.write_was_called = False
Expand Down
27 changes: 23 additions & 4 deletions deluge/tests/test_ui_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,23 +370,41 @@ def test_console_unrecognized_arguments(self):


class ConsoleUIWithDaemonBaseTestCase(UIWithDaemonBaseTestCase):
"""Implement Console tests that require a running daemon"""
"""
Implement Console tests that require a running daemon

NOTE: The tests in this class must not be run directly. They must be run
through a subclass that also inherits from unittest.TestCase
"""

def set_up(self):
# Avoid calling reactor.shutdown after commands are executed by main.exec_args()
deluge.ui.console.main.reactor = common.ReactorOverride()
# Avoid calling reactor.stop (in ConsoleUI.quit) after commands are executed by main.exec_args()
mock_reactor = common.ReactorOverride()
self.patcher = mock.patch('deluge.ui.console.main.reactor', mock_reactor)
self.patcher.start()
return UIWithDaemonBaseTestCase.set_up(self)

def tear_down(self):
d = UIWithDaemonBaseTestCase.tear_down(self)

def stop_patch(*args):
# Must stop the patcher as late as possible (after the ConsoleUI.quit method is called)
self.patcher.stop()

d.addCallback(stop_patch)
return d

def patch_arg_command(self, command):
if type(command) == str:
command = [command]
username, password = get_localhost_auth()

self.patch(
sys,
'argv',
self.var['sys_arg_cmd']
+ ['--port']
+ ['58900']
+ [str(self.listen_port)]
+ ['--username']
+ [username]
+ ['--password']
Expand Down Expand Up @@ -427,6 +445,7 @@ def test_console_command_add_move_completed(self):
yield self.exec_command()

std_output = fd.out.getvalue()

self.assertTrue(
std_output.endswith('move_completed: True\nmove_completed_path: /tmp\n')
or std_output.endswith('move_completed_path: /tmp\nmove_completed: True\n')
Expand Down
10 changes: 8 additions & 2 deletions deluge/tests/test_web_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,14 @@ def test_add_host(self):

# Add invalid port
conn[2] = 'bad port'
ret = self.deluge_web.web_api.add_host(conn[1], conn[2], conn[3], conn[4])
self.assertEqual(ret, (False, 'Invalid port. Must be an integer'))

from deluge.ui.hostlist import InvalidHostPort

with self.assertRaises(InvalidHostPort) as context:
self.deluge_web.web_api.add_host(conn[1], conn[2], conn[3], conn[4])
self.assertEqual(
'Invalid port: "bad port" Must be an integer', str(context.exception)
)

def test_remove_host(self):
conn = ['connection_id', '', 0, '', '']
Expand Down
Loading