예제 #1
0
def test_proxy_returns_ServerProxy_object(url, exp_uri, exp_transport,
                                          exp_socket_path, mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(type(client), 'config',
                        PropertyMock(return_value={'url': url}))
    ScgiTransport_mock = mocker.patch(
        'upsies.utils.btclients.rtorrent._scgi.ScgiTransport')
    ServerProxy_mock = mocker.patch('xmlrpc.client.ServerProxy')
    proxy = client._proxy

    if exp_transport == 'ScgiTransport':
        if exp_socket_path:
            assert ScgiTransport_mock.call_args_list == [
                call(socket_path=exp_socket_path)
            ]
            exp_serverproxy_kwargs = {
                'uri': 'http://1',
                'transport': ScgiTransport_mock.return_value,
            }
        else:
            assert ScgiTransport_mock.call_args_list == [call()]
            exp_serverproxy_kwargs = {
                'uri': 'http://' + urllib.parse.urlsplit(url).netloc,
                'transport': ScgiTransport_mock.return_value,
            }
    else:
        assert ScgiTransport_mock.call_args_list == []
        exp_serverproxy_kwargs = {
            'uri': url,
        }

    assert ServerProxy_mock.call_args_list == [call(**exp_serverproxy_kwargs)]
    # Test if client._proxy is singleton
    assert client._proxy is proxy
예제 #2
0
def test_get_mtime_returns_int():
    client = rtorrent.RtorrentClientApi()
    with patch('os.stat') as stat_mock:
        stat_mock.return_value = Mock(st_mtime=123.123)
        mtime = client._get_mtime('some/path')
        assert mtime == 123
        assert stat_mock.call_args_list == [call('some/path')]
예제 #3
0
def test_get_torrent_data(exception, config, download_path, mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(type(client), 'config',
                        PropertyMock(return_value=config))
    if exception:
        mocker.patch.object(client,
                            '_get_torrent_data_with_resume_fields',
                            side_effect=exception)
    else:
        mocker.patch.object(client,
                            '_get_torrent_data_with_resume_fields',
                            return_value=Mock(dump=Mock(
                                return_value='torrent with resume fields')))
    mocker.patch.object(client,
                        'read_torrent',
                        return_value=Mock(dump=Mock(
                            return_value='torrent without resume fields')))

    torrent_path = 'path/to/file.torrent'
    torrent_data = client._get_torrent_data(torrent_path,
                                            download_path=download_path)

    if download_path and not config['check_after_add']:
        assert client._get_torrent_data_with_resume_fields.call_args_list == [
            call(torrent_path, download_path)
        ]
        if exception:
            assert client.read_torrent.call_args_list == [call(torrent_path)]
            assert torrent_data == 'torrent without resume fields'
        else:
            assert client.read_torrent.call_args_list == []
            assert torrent_data == 'torrent with resume fields'
    else:
        assert client.read_torrent.call_args_list == [call(torrent_path)]
        assert torrent_data == 'torrent without resume fields'
예제 #4
0
async def test_add_torrent_fails_to_read_torrent(mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(client, '_get_load_command',
                        AsyncMock(return_value='load.raw_start_verbose'))
    mocker.patch.object(client,
                        '_get_torrent_data',
                        return_value='mock torrent data')
    mocker.patch.object(client,
                        'read_torrent',
                        side_effect=errors.TorrentError('no'))
    mocker.patch.object(client, '_request')
    mocker.patch.object(client, '_get_torrent_hashes', return_value=[])
    mocker.patch.object(type(client), 'add_torrent_check_delay', 0)

    with pytest.raises(errors.RequestError, match=r'^no$'):
        await client.add_torrent('/path/to/file.torrent',
                                 download_path='/path/to/downloads/')

    assert client._get_torrent_data.call_args_list == [
        call('/path/to/file.torrent', '/path/to/downloads')
    ]
    assert client._request.call_args_list == [
        call(
            'load.raw_start_verbose',
            '',
            'mock torrent data',
            'd.directory.set="/path/to/downloads"',
        )
    ]
    assert client.read_torrent.call_args_list == [
        call('/path/to/file.torrent')
    ]
    assert client._get_torrent_hashes.call_args_list == []
예제 #5
0
def test_request_fails(exception):
    client = rtorrent.RtorrentClientApi()
    client._proxy = Mock()
    client._proxy.foo.bar.baz.side_effect = exception
    with pytest.raises(errors.RequestError, match=r'^nope$'):
        client._request('foo.bar.baz', 'a', 'b', 'c')
    assert client._proxy.foo.bar.baz.call_args_list == [call('a', 'b', 'c')]
예제 #6
0
async def test_add_torrent_succeeds(download_path, exp_directory_set, mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(client, '_get_load_command',
                        AsyncMock(return_value='load.raw_start_verbose'))
    mocker.patch.object(client,
                        '_get_torrent_data',
                        return_value='mock torrent data')
    mocker.patch.object(client,
                        'read_torrent',
                        return_value=Mock(infohash='D34DB33F'))
    mocker.patch.object(client, '_request')
    mocker.patch.object(client,
                        '_get_torrent_hashes',
                        side_effect=[
                            ['C0FF33', 'B4B3'],
                            ['C0FF33', 'B4B3'],
                            ['C0FF33', 'B4B3', 'D34DB33F'],
                        ])
    mocker.patch.object(type(client), 'add_torrent_check_delay', 0)

    torrent_path = 'path/to/file.torrent'
    torrent_path_abs = os.path.abspath(torrent_path)
    download_path_abs = os.path.abspath(
        download_path) if download_path else download_path
    await client.add_torrent(torrent_path, download_path=download_path)

    assert client._get_torrent_data.call_args_list == [
        call(torrent_path_abs, download_path_abs)
    ]
    exp_request_args = ['', 'mock torrent data']
    if exp_directory_set:
        exp_request_args.append(
            exp_directory_set.format(
                escaped_absolute_download_path=download_path_abs.replace(
                    '"', r'\"'), ))
    assert client._request.call_args_list == [
        call('load.raw_start_verbose', *exp_request_args)
    ]
    assert client.read_torrent.call_args_list == [call(torrent_path_abs)]
    assert client._get_torrent_hashes.call_args_list == [
        call(), call(), call()
    ]
예제 #7
0
async def test_add_torrent_fails_to_get_torrent_data(mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(client,
                        '_get_torrent_data',
                        side_effect=errors.TorrentError('no'))
    mocker.patch.object(client, 'read_torrent')
    mocker.patch.object(client, '_request')
    mocker.patch.object(client, '_get_torrent_hashes', return_value=[])
    mocker.patch.object(type(client), 'add_torrent_check_delay', 0)

    with pytest.raises(errors.RequestError, match=r'^no$'):
        await client.add_torrent('/path/to/file.torrent',
                                 download_path='/path/to/downloads/')

    assert client._get_torrent_data.call_args_list == [
        call('/path/to/file.torrent', '/path/to/downloads')
    ]
    assert client._request.call_args_list == []
    assert client.read_torrent.call_args_list == []
    assert client._get_torrent_hashes.call_args_list == []
예제 #8
0
async def test_add_torrent_fails_after_timeout(mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(client, '_get_load_command',
                        AsyncMock(return_value='load.raw_start_verbose'))
    mocker.patch.object(client,
                        '_get_torrent_data',
                        return_value='mock torrent data')
    mocker.patch.object(client,
                        'read_torrent',
                        return_value=Mock(infohash='D34DB33F'))
    mocker.patch.object(client, '_request')
    mocker.patch.object(type(client), 'add_torrent_check_delay', 0.01)
    mocker.patch.object(type(client), 'add_torrent_timeout', 0.03)
    exp_attempts = int(client.add_torrent_timeout /
                       client.add_torrent_check_delay)
    mocker.patch.object(client,
                        '_get_torrent_hashes',
                        side_effect=(([['C0FF33', 'B4B3']] * exp_attempts) +
                                     [['C0FF33', 'B4B3', 'D34DB33F']]))

    with pytest.raises(errors.RequestError, match=r'^Unknown error$'):
        await client.add_torrent('/path/to/file.torrent',
                                 download_path='/path/to/downloads/')

    assert client._get_torrent_data.call_args_list == [
        call('/path/to/file.torrent', '/path/to/downloads')
    ]
    assert client._request.call_args_list == [
        call(
            'load.raw_start_verbose',
            '',
            'mock torrent data',
            'd.directory.set="/path/to/downloads"',
        )
    ]
    assert client.read_torrent.call_args_list == [
        call('/path/to/file.torrent')
    ]
    assert client._get_torrent_hashes.call_args_list == [call()] * exp_attempts
예제 #9
0
def test_request_succeeds():
    client = rtorrent.RtorrentClientApi()
    client._proxy = Mock()
    return_value = client._request('foo.bar.baz', 'a', 'b', 'c')
    assert client._proxy.foo.bar.baz.call_args_list == [call('a', 'b', 'c')]
    assert return_value == client._proxy.foo.bar.baz.return_value
예제 #10
0
def test_get_mtime_catches_OSError(exception):
    client = rtorrent.RtorrentClientApi()
    with patch('os.stat', side_effect=exception) as stat_mock:
        with pytest.raises(errors.TorrentError, match=r'^nope$'):
            client._get_mtime('some/path')
        assert stat_mock.call_args_list == [call('some/path')]
예제 #11
0
def test_get_torrent_data_with_resume_fields(mocker):
    mocks = Mock()
    client = rtorrent.RtorrentClientApi()
    metainfo = {
        'info': {
            'pieces': b'\x00' * 100,
        },
        'comment': 'This should be preserved.',
    }
    file_data = (
        {
            'path': 'this/file.txt',
            'mtime': 123,
            'piece_indexes': [0, 1, 2]
        },
        {
            'path': 'that/file.jpg',
            'mtime': 456,
            'piece_indexes': [2, 3, 4, 5, 6]
        },
        {
            'path': 'another/file/path.mp4',
            'mtime': 789,
            'piece_indexes': [7, 8]
        },
    )

    mocks.attach_mock(
        mocker.patch.object(client,
                            'read_torrent',
                            return_value=types.SimpleNamespace(
                                metainfo=metainfo,
                                files=[fd['path'] for fd in file_data],
                            )),
        'read_torrent',
    )
    mocks.attach_mock(
        mocker.patch('upsies.utils.torrent.TorrentFileStream', ),
        'TorrentFileStream',
    )
    mocks.TorrentFileStream.return_value.__enter__.return_value.get_piece_indexes_for_file.side_effect = [
        fd['piece_indexes'] for fd in file_data
    ]
    mocks.attach_mock(
        mocker.patch.object(client,
                            '_get_mtime',
                            side_effect=[fd['mtime'] for fd in file_data]),
        '_get_mtime',
    )

    torrent = client._get_torrent_data_with_resume_fields(
        'path/to/file.torrent',
        'path/to/content',
    )

    exp_metainfo = copy.deepcopy(metainfo)
    exp_metainfo['libtorrent_resume'] = {
        'files': [{
            'mtime': fd['mtime'],
            'completed': len(fd['piece_indexes']),
            'priority': 0
        } for fd in file_data],
        'bitfield':
        len(metainfo['info']['pieces']) // 20,
    }
    assert torrent.metainfo == exp_metainfo

    exp_mock_calls = [
        call.read_torrent('path/to/file.torrent'),
        call.TorrentFileStream(mocks.read_torrent.return_value,
                               'path/to/content'),
        call.TorrentFileStream().__enter__(),
    ]
    for fd in file_data:
        exp_mock_calls.extend((
            call._get_mtime(os.path.join('path/to/content', fd['path'])),
            call.TorrentFileStream().__enter__().get_piece_indexes_for_file(
                fd['path']),
        ))
    exp_mock_calls.append(call.TorrentFileStream().__exit__(None, None, None))
    assert mocks.mock_calls == exp_mock_calls
예제 #12
0
def test_proxy_with_empty_url(mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(type(client), 'config',
                        PropertyMock(return_value={'url': ''}))
    with pytest.raises(errors.RequestError, match=r'^No URL provided$'):
        client._proxy
예제 #13
0
def test_get_torrent_hashes(mocker):
    client = rtorrent.RtorrentClientApi()
    mocker.patch.object(client, '_request', return_value=['D34D', 'B33F'])
    hashes = client._get_torrent_hashes()
    assert hashes == ('d34d', 'b33f')
    assert client._request.call_args_list == [call('download_list')]