Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Moved common tests from etorrent application. Add etorrent_console - …

…torrent progress logger.
  • Loading branch information...
commit ef15c7e44dafdf0785c4d8afc3af6fb7f90d7c8e 1 parent d6fcf5d
@arcusfelis arcusfelis authored
View
5 .gitignore
@@ -3,3 +3,8 @@ deps/
ebin/*.app
log/*
.eunit
+# Common tests
+/test/etorrent_SUITE_data/test_file_30M.random
+/test/etorrent_SUITE_data/test_file_30M.random.torrent
+/logs/*
+test/etorrent_SUITE_data/log/
View
4 ct-run.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+cd `dirname $0`
+ct_run -spec etorrent_test.spec -pa $PWD/ebin edit $PWD/deps/*/ebin
+
View
17 etorrent_test.cfg
@@ -0,0 +1,17 @@
+{etorrent_common_config, [{dirwatch_interval, 20 },
+ {use_upnp, false},
+ {dht, false },
+ {dht_port, 6882 },
+ {max_peers, 200},
+ {max_download_rate, 2000},
+ {max_upload_rate, 2000},
+ {max_upload_slots, auto},
+ {fs_watermark_high, 128},
+ {fs_watermark_low, 100},
+ {min_uploads, 2},
+ {preallocation_strategy, sparse },
+ {webui, false },
+ {webui_logger_dir, "log/webui"},
+ {webui_bind_address, {127,0,0,1}},
+ {webui_port, 8080},
+ {profiling, false}]}.
View
5 etorrent_test.spec
@@ -0,0 +1,5 @@
+{logdir, "logs"}.
+{config, "etorrent_test.cfg"}.
+{alias, test, "test"}.
+{cover, "test/etorrent.cover"}.
+{suites, test, etorrent_SUITE}.
View
233 src/etorrent_console.erl
@@ -0,0 +1,233 @@
+%% @doc Console writer.
+-module(etorrent_console).
+-behaviour(gen_server).
+
+%% ------------------------------------------------------------------
+%% API Function Exports
+%% ------------------------------------------------------------------
+
+-export([start_link/0]).
+
+%% ------------------------------------------------------------------
+%% gen_server Function Exports
+%% ------------------------------------------------------------------
+
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
+
+
+-define(SERVER, ?MODULE).
+
+-type torrent_id() :: integer().
+
+
+% There are 4 different formats of torrent.
+-type etorrent_pl() :: [{atom(), term()}].
+
+-record(torrent, {
+ 'id' :: torrent_id(),
+ 'total' :: non_neg_integer(),
+ 'left' :: integer(),
+ 'leechers' :: integer(),
+ 'seeders' :: integer(),
+ 'all_time_downloaded' :: integer(),
+ 'all_time_uploaded' :: integer(),
+ 'downloaded' :: integer(),
+ 'uploaded' :: integer(),
+ 'state' :: atom(),
+
+ 'speed_in' = 0 :: integer(),
+ 'speed_out' = 0 :: integer()
+}).
+
+-record(state, {
+ timer :: reference(),
+ torrents :: [#torrent{}],
+ tick :: integer()
+}).
+
+
+%% ------------------------------------------------------------------
+%% API Function Definitions
+%% ------------------------------------------------------------------
+
+start_link() ->
+ Args = [2000],
+ gen_server:start_link({local, ?SERVER}, ?MODULE, Args, []).
+
+
+%% ------------------------------------------------------------------
+%% gen_server Function Definitions
+%% ------------------------------------------------------------------
+
+init([Timeout]) ->
+ timer:send_interval(Timeout, update),
+ SD = #state{
+ tick = Timeout,
+ torrents=[]
+ },
+ {ok, SD}.
+
+handle_call(_Mess, _From, SD) ->
+ {reply, ok, SD}.
+
+handle_cast(_Mess, SD) ->
+ {noreply, SD}.
+
+
+handle_info(update, SD=#state{torrents=OldTorrents, tick=Timeout}) ->
+ % proplists from etorrent.
+ PLs = query_torrent_list(),
+ UnsortedNewTorrents = lists:map(fun to_record/1, PLs),
+ NewTorrents = sort_records(UnsortedNewTorrents),
+ NewTorrents2 = calc_speed_records(OldTorrents, NewTorrents, Timeout),
+ map_records2(fun print_torent_info/2, OldTorrents, NewTorrents),
+ {noreply, SD#state{torrents=NewTorrents2}}.
+
+terminate(_Reason, _SD) ->
+ cascadae_event:delete(),
+ ok.
+
+code_change(_OldVsn, SD, _Extra) ->
+ {ok, SD}.
+
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------
+
+
+-spec query_torrent_list() -> [etorrent_pl()].
+query_torrent_list() ->
+ etorrent_query:torrent_list().
+
+
+-spec to_record(etorrent_pl()) -> #torrent{}.
+to_record(X) ->
+ #torrent{
+ id = proplists:get_value('id', X),
+ total = proplists:get_value('total', X),
+ left = proplists:get_value('left', X),
+ leechers = proplists:get_value('leechers', X),
+ seeders = proplists:get_value('seeders', X),
+ state = proplists:get_value('state', X),
+ downloaded = proplists:get_value('downloaded', X),
+ uploaded = proplists:get_value('uploaded', X),
+ all_time_downloaded = proplists:get_value('all_time_downloaded', X),
+ all_time_uploaded = proplists:get_value('all_time_uploaded', X)
+ }.
+
+
+%% @doc Sort a list by id.
+-spec sort_records([#torrent{}]) -> [#torrent{}].
+sort_records(List) ->
+ lists:keysort(#torrent.id, List).
+
+
+calc_speed_records(Olds, News, Tick) ->
+ FU = fun(#torrent{uploaded=X, speed_out=0},
+ #torrent{uploaded=X, speed_out=0}=New) -> New;
+ (#torrent{uploaded=X},
+ #torrent{uploaded=X}=New) -> New#torrent{speed_out=0};
+ (#torrent{uploaded=O},
+ #torrent{uploaded=N}=New) ->
+ New#torrent{speed_out=calc_speed(O, N, Tick)}
+ end,
+
+ FD = fun(#torrent{downloaded=X, speed_in=0},
+ #torrent{downloaded=X, speed_in=0}=New) -> New;
+ (#torrent{downloaded=X},
+ #torrent{downloaded=X}=New) -> New#torrent{speed_in=0};
+ (#torrent{downloaded=O},
+ #torrent{downloaded=N}=New) ->
+ New#torrent{speed_in=calc_speed(O, N, Tick)}
+ end,
+
+ F = fun(Old, New) -> FU(Old, FD(Old, New)) end,
+ map_records(F, Olds, News).
+
+
+calc_speed(Old, New, Interval) ->
+ Bytes = New - Old,
+ Seconds = Interval / 1000,
+ Bytes / Seconds.
+
+
+
+map_records(F, [Old=#torrent{id=Id} | OldT],
+ [New=#torrent{id=Id} | NewT]) ->
+ [F(Old, New)|map_records(F, OldT, NewT)];
+
+% Element Old was deleted.
+map_records(F, [#torrent{id=OldId} | OldT],
+ [#torrent{id=NewId} | _] = NewT)
+ when NewId>OldId ->
+ map_records(F, OldT, NewT);
+
+% Element New was added.
+% Add New as is.
+map_records(F, OldT, [New | NewT]) -> % Copy new torrent.
+ [New|map_records(F, OldT, NewT)];
+
+map_records(_F, _OldLeft, _NewLeft) ->
+ [].
+
+
+map_records2(F, [Old=#torrent{id=Id} | OldT],
+ [New=#torrent{id=Id} | NewT]) ->
+ [F(Old, New)|map_records2(F, OldT, NewT)];
+
+% Element Old was deleted.
+map_records2(F, [Old=#torrent{id=OldId} | OldT],
+ [#torrent{id=NewId} | _] = NewT)
+ when NewId>OldId ->
+ [F(Old, undefined)|map_records2(F, OldT, NewT)];
+
+% Element New was added.
+% Add New as is.
+map_records2(F, OldT, [New | NewT]) -> % Copy new torrent.
+ [F(undefined, New)|map_records2(F, OldT, NewT)];
+
+map_records2(F, OldT, []) ->
+ [F(Old, undefined) || Old <- OldT].
+
+
+print_torent_info(X, X) -> skip;
+print_torent_info(undefined, #torrent{id=Id}) ->
+ log("STARTED torrent #~p.", [Id]);
+print_torent_info(#torrent{id=Id}, undefined) ->
+ log("STOPPED torrent #~p.", [Id]);
+print_torent_info(_Old, #torrent{state=Status, id=Id, left=Left, total=Total}) ->
+ DownloadedPercent = (Total-Left)/Total * 100,
+ log("~.10s #~p: ~6.2f%", [string:to_upper(atom_to_list(Status)),
+ Id, DownloadedPercent]).
+
+% 'leechers' :: integer(),
+% 'seeders' :: integer(),
+% 'speed_in' = 0 :: integer(),
+% 'speed_out' = 0 :: integer()
+
+log(Pattern, Args) ->
+ io:format(user, Pattern ++ "~n", Args),
+ ok.
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+
+sort_records_test_() ->
+ Unsorted = [#torrent{id=1}, #torrent{id=3}, #torrent{id=2}],
+ Sorted = sort_records(Unsorted),
+ [R1, R2, R3] = Sorted,
+
+ [?_assertEqual(R1#torrent.id, 1)
+ ,?_assertEqual(R2#torrent.id, 2)
+ ,?_assertEqual(R3#torrent.id, 3)
+ ].
+
+-endif.
+
View
3  src/etorrent_sup.erl
@@ -44,6 +44,7 @@ init([PeerId]) ->
PeerStates = ?CHILD(etorrent_peer_states),
Choker = ?CHILD(etorrent_choker),
Tasks = ?CHILD(etorrent_tasks),
+ Console = ?CHILD(etorrent_console),
Listener = {etorrent_listen_sup,
{etorrent_listen_sup, start_link, [PeerId]},
@@ -85,7 +86,7 @@ init([PeerId]) ->
FastResume, PeerStates,
Choker, Listener,
UdpTracking, TorrentPool, Ctl,
- DirWatcherSup, Tasks] ++ DHTSup ++ UPNPSup}}.
+ DirWatcherSup, Tasks, Console] ++ DHTSup ++ UPNPSup}}.
View
1  test/etorrent.cover
@@ -0,0 +1 @@
+{incl_app, etorrent, details}.
View
411 test/etorrent_SUITE.erl
@@ -0,0 +1,411 @@
+-module(etorrent_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-export([suite/0, all/0, groups/0,
+ init_per_group/2, end_per_group/2,
+ init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, end_per_testcase/2]).
+
+-export([seed_leech/0, seed_leech/1,
+ seed_transmission/0, seed_transmission/1,
+ leech_transmission/0, leech_transmission/1]).
+
+-define(TESTFILE30M, "test_file_30M.random").
+-define(ET_WORK_DIR, "work-et").
+-define(TR_WORK_DIR, "work-tr").
+
+suite() ->
+ [{timetrap, {minutes, 3}}].
+
+%% Setup/Teardown
+%% ----------------------------------------------------------------------
+init_per_group(main_group, Config) ->
+ init_locations(Config);
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(main_group, Config) ->
+ end_locations(Config);
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_suite(Config) ->
+ %% We should really use priv_dir here, but as we are for-once creating
+ %% files we will later rely on for fetching, this is ok I think.
+ Directory = ?config(data_dir, Config),
+ io:format("Data directory: ~s~n", [Directory]),
+ TestFn = ?TESTFILE30M,
+ Fn = filename:join([Directory, TestFn]),
+ ensure_random_file(Fn),
+ file:set_cwd(Directory),
+ ensure_torrent_file(TestFn),
+ Pid = start_opentracker(Directory),
+ {ok, SeedNode} = test_server:start_node('seeder', slave, []),
+ {ok, LeechNode} = test_server:start_node('leecher', slave, []),
+ rpc:call(SeedNode, code, set_path, [code:get_path()]),
+ rpc:call(LeechNode, code, set_path, [code:get_path()]),
+ %% Start SASL before lager, because SASL will set its error_handler
+ %% otherwise.
+% ok = rpc:call(SeedNode, application, start, [sasl]),
+% ok = rpc:call(LeechNode, application, start, [sasl]),
+% ok = rpc:call(SeedNode, lager, start, []),
+% ok = rpc:call(LeechNode, lager, start, []),
+ [{tracker_port, Pid},
+ {leech_node, LeechNode},
+ {seed_node, SeedNode} | Config].
+
+end_per_suite(Config) ->
+ Pid = ?config(tracker_port, Config),
+ LN = ?config(leech_node, Config),
+ SN = ?config(seed_node, Config),
+ stop_opentracker(Pid),
+ test_server:stop_node(SN),
+ test_server:stop_node(LN),
+ ok.
+
+end_locations(Config) ->
+ io:format(user, "Cleaning private directory~n", []),
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ %% Remove locations
+ %%
+% ok = file:delete(filename:join([PrivDir, ?ET_WORK_DIR, ?TESTFILE30M])),
+ ok = del_dir(filename:join([PrivDir, ?ET_WORK_DIR])),
+ ok = file:delete(filename:join([PrivDir, ?TR_WORK_DIR, "settings.json"])),
+ ok = del_dir(filename:join([PrivDir, ?TR_WORK_DIR])).
+
+
+init_locations(Config) ->
+ io:format(user, "Init locations~n", []),
+ %% Setup locations that some of the test cases use
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ io:format(user, "PrivDir: ~p~n", [PrivDir]),
+
+ %% Create locations
+ file:make_dir(filename:join([PrivDir, ?ET_WORK_DIR])),
+ file:make_dir(filename:join([PrivDir, ?TR_WORK_DIR])),
+
+ %% Setup common locations
+ SeedTorrent = filename:join([DataDir, ?TESTFILE30M ++ ".torrent"]),
+ SeedFile = filename:join([DataDir, ?TESTFILE30M]),
+ SeedFastResume = filename:join([PrivDir, "seed_fast_resume"]),
+
+ LeechFile = filename:join([PrivDir, ?TESTFILE30M]),
+ LeechFastResume = filename:join([PrivDir, "leech_fast_resume"]),
+
+ %% Setup Etorrent location
+ EtorrentWorkDir = filename:join([PrivDir, ?ET_WORK_DIR]),
+ EtorrentLeechFile = filename:join([PrivDir, ?ET_WORK_DIR, ?TESTFILE30M]),
+
+ %% Setup Transmission locations
+ TransMissionWorkDir = filename:join([PrivDir, ?TR_WORK_DIR]),
+ TransMissionFile = filename:join([PrivDir, ?TR_WORK_DIR, ?TESTFILE30M]),
+ {ok, _} = file:copy(filename:join([DataDir, "transmission", "settings.json"]),
+ filename:join([TransMissionWorkDir, "settings.json"])),
+
+ [{seed_torrent, SeedTorrent},
+ {seed_file, SeedFile},
+ {seed_fast_resume, SeedFastResume},
+ {leech_file, LeechFile},
+ {leech_fast_resume, LeechFastResume},
+ {et_work_dir, EtorrentWorkDir},
+ {et_leech_file, EtorrentLeechFile},
+ {tr_work_dir, TransMissionWorkDir},
+ {tr_file, TransMissionFile} | Config].
+
+spawn_leecher(Config) ->
+ CommonConf = ct:get_config(common_conf),
+ LeechConfig = leech_configuration(Config,
+ CommonConf,
+ ?config(priv_dir, Config),
+ ?ET_WORK_DIR),
+ ok = rpc:call(?config(leech_node, Config), etorrent, start_app, [LeechConfig]).
+
+spawn_seeder(Config) ->
+ CommonConf = ct:get_config(common_conf),
+ SeedConfig = seed_configuration(Config,
+ CommonConf,
+ ?config(priv_dir, Config),
+ ?config(data_dir, Config)),
+ ok = rpc:call(?config(seed_node, Config), etorrent, start_app, [SeedConfig]).
+
+init_per_testcase(leech_transmission, Config) ->
+ %% Feed transmission the file to work with
+ {ok, _} = file:copy(?config(seed_file, Config),
+ ?config(tr_file, Config)),
+ {Ref, Pid} = start_transmission(?config(data_dir, Config),
+ ?config(tr_work_dir, Config),
+ ?config(seed_torrent, Config)),
+ ok = ct:sleep({seconds, 10}), %% Wait for transmission to start up
+ spawn_leecher(Config),
+ [{transmission_port, {Ref, Pid}} | Config];
+init_per_testcase(seed_transmission, Config) ->
+ {Ref, Pid} = start_transmission(?config(data_dir, Config),
+ ?config(tr_work_dir, Config),
+ ?config(seed_torrent, Config)),
+ ok = ct:sleep({seconds, 8}), %% Wait for transmission to start up
+ spawn_seeder(Config),
+ [{transmission_port, {Ref, Pid}} | Config];
+init_per_testcase(seed_leech, Config) ->
+ spawn_seeder(Config),
+ spawn_leecher(Config),
+ Config;
+init_per_testcase(_Case, Config) ->
+ Config.
+
+end_per_testcase(leech_transmission, Config) ->
+ {_Ref, Pid} = ?config(transmission_port, Config),
+ stop_transmission(Config, Pid),
+ stop_leecher(Config),
+ ?line ok = file:delete(?config(tr_file, Config)),
+ ?line ok = file:delete(?config(et_leech_file, Config));
+end_per_testcase(seed_transmission, Config) ->
+ {_Ref, Pid} = ?config(transmission_port, Config),
+ stop_transmission(Config, Pid),
+ stop_seeder(Config),
+ ?line ok = file:delete(?config(tr_file, Config));
+end_per_testcase(seed_leech, Config) ->
+ stop_seeder(Config),
+ stop_leecher(Config),
+ ?line ok = file:delete(?config(et_leech_file, Config));
+end_per_testcase(_Case, _Config) ->
+ ok.
+
+%% Configuration
+%% ----------------------------------------------------------------------
+seed_configuration(Config, CConf, PrivDir, DataDir) ->
+ [{port, 1739 },
+ {udp_port, 1740 },
+ {dht_state, filename:join([PrivDir, "seeder_state.persistent"])},
+ {dir, DataDir},
+ {download_dir, DataDir},
+ {logger_dir, PrivDir},
+ {logger_fname, "seed_etorrent.log"},
+ {fast_resume_file, ?config(seed_fast_resume, Config)} | CConf].
+
+leech_configuration(Config, CConf, PrivDir) ->
+ leech_configuration(CConf, PrivDir, ?ET_WORK_DIR).
+
+leech_configuration(Config, CConf, PrivDir, DownloadSuffix) ->
+ [{port, 1769 },
+ {udp_port, 1760 },
+ {dht_state, filename:join([PrivDir, "leecher_state.persistent"])},
+ {dir, filename:join([PrivDir, DownloadSuffix])},
+ {download_dir, filename:join([PrivDir, DownloadSuffix])},
+ {logger_dir, PrivDir},
+ {logger_fname, "leech_etorrent.log"},
+ {fast_resume_file, ?config(leech_fast_resume, Config)} | CConf].
+
+%% Tests
+%% ----------------------------------------------------------------------
+groups() ->
+ [{main_group, [shuffle], [seed_transmission, seed_leech, leech_transmission]}].
+
+all() ->
+ [{group, main_group}].
+
+seed_transmission() ->
+ [{require, common_conf, etorrent_common_config}].
+
+%% Etorrent => Transmission
+seed_transmission(Config) ->
+ io:format(user, "~n======START SEED TRANSMISSION TEST CASE======~n", []),
+ {Ref, Pid} = ?config(transmission_port, Config),
+ receive
+ {Ref, done} -> ok
+ after
+ 120*1000 -> exit(timeout_error)
+ end,
+ sha1_file(?config(seed_file, Config))
+ =:= sha1_file(?config(tr_file, Config)).
+
+%% Transmission => Etorrent
+leech_transmission() ->
+ [{require, common_conf, etorrent_common_config}].
+
+leech_transmission(Config) ->
+ io:format(user, "~n======START LEECH TRANSMISSION TEST CASE======~n", []),
+ %% Set callback and wait for torrent completion.
+ {Ref, Pid} = {make_ref(), self()},
+ ok = rpc:call(?config(leech_node, Config),
+ etorrent, start,
+ [?config(seed_torrent, Config), {Ref, Pid}]),
+ receive
+ {Ref, done} -> ok
+ after
+ 120*1000 -> exit(timeout_error)
+ end,
+ sha1_file(?config(tr_file, Config))
+ =:= sha1_file(?config(et_leech_file, Config)).
+
+seed_leech() ->
+ [{require, common_conf, etorrent_common_config}].
+
+seed_leech(Config) ->
+ io:format(user, "~n======START SEED AND LEECHING TEST CASE======~n", []),
+ {Ref, Pid} = {make_ref(), self()},
+ ok = rpc:call(?config(leech_node, Config),
+ etorrent, start,
+ [?config(seed_torrent, Config), {Ref, Pid}]),
+ receive
+ {Ref, done} -> ok
+ after
+ 120*1000 -> exit(timeout_error)
+ end,
+ sha1_file(?config(et_leech_file, Config))
+ =:= sha1_file(?config(seed_file, Config)).
+
+%% Helpers
+%% ----------------------------------------------------------------------
+start_opentracker(Dir) ->
+ ToSpawn = "run_opentracker.sh -i 127.0.0.1 -p 6969",
+ Spawn = filename:join([Dir, ToSpawn]),
+ Pid = spawn(fun() ->
+ Port = open_port(
+ {spawn, Spawn}, [binary, stream, eof]),
+ receive
+ close ->
+ port_close(Port)
+ end
+ end),
+ Pid.
+
+quote(Str) ->
+ lists:concat(["'", Str, "'"]).
+
+start_transmission(DataDir, DownDir, Torrent) ->
+ io:format(user, "Start transmission~n", []),
+ ToSpawn = ["run_transmission-cli.sh ", quote(Torrent),
+ " -w ", quote(DownDir),
+ " -g ", quote(DownDir),
+ " -p 1780"],
+ Spawn = filename:join([DataDir, lists:concat(ToSpawn)]),
+ error_logger:info_report([{spawn, Spawn}]),
+ Ref = make_ref(),
+ Self = self(),
+ Pid = spawn_link(fun() ->
+ Port = open_port(
+ {spawn, Spawn},
+ [stream, binary, eof]),
+ transmission_loop(Port, Ref, Self, <<>>, <<>>)
+ end),
+ {Ref, Pid}.
+
+stop_transmission(Config, Pid) when is_pid(Pid) ->
+ io:format(user, "Stop transmission~n", []),
+ Pid ! close,
+ end_transmission_locations(Config),
+ ok.
+
+end_transmission_locations(Config) ->
+ io:format(user, "Cleaning transmission directory.", []),
+ PrivDir = ?config(priv_dir, Config),
+
+ %% Transmission dir needs some help:
+ ok = del_dir_r(filename:join([PrivDir, ?TR_WORK_DIR, "resume"])),
+ ok = del_dir_r(filename:join([PrivDir, ?TR_WORK_DIR, "torrents"])),
+ ok = del_dir_r(filename:join([PrivDir, ?TR_WORK_DIR, "blocklists"])),
+ ok.
+
+
+stop_leecher(Config) ->
+ ok = rpc:call(?config(leech_node, Config), etorrent, stop_app, []),
+ ok = file:delete(filename:join([?config(priv_dir, Config),
+ "leech_etorrent.log"])),
+ ok = file:delete(?config(leech_fast_resume, Config)).
+
+stop_seeder(Config) ->
+ ok = rpc:call(?config(seed_node, Config), etorrent, stop_app, []),
+ ok = file:delete(filename:join([?config(priv_dir, Config),
+ "seed_etorrent.log"])),
+ ok = file:delete(?config(seed_fast_resume, Config)).
+
+transmission_complete_criterion() ->
+% "Seeding, uploading to".
+ "Verifying local files (0.00%, 100.00% valid)".
+
+transmission_loop(Port, Ref, ReturnPid, OldBin, OldLine) ->
+ case binary:split(OldBin, [<<"\r">>, <<"\n">>]) of
+ [OnePart] ->
+ receive
+ {Port, {data, Data}} ->
+ transmission_loop(Port, Ref, ReturnPid, <<OnePart/binary,
+ Data/binary>>, OldLine);
+ close ->
+ port_close(Port);
+ M ->
+ error_logger:error_report([received_unknown_msg, M]),
+ transmission_loop(Port, Ref, ReturnPid, OnePart, OldLine)
+ end;
+ [L, Rest] ->
+ %% Is it a different line? than show it.
+ [io:format(user, "TRANS: ~s.~n", [L]) || L =/= OldLine],
+ case string:str(binary_to_list(L), transmission_complete_criterion()) of
+ 0 -> ok;
+ N when is_integer(N) ->
+ ReturnPid ! {Ref, done}
+ end,
+ transmission_loop(Port, Ref, ReturnPid, Rest, L)
+ end.
+
+stop_opentracker(Pid) ->
+ Pid ! close.
+
+ensure_torrent_file(Fn) ->
+ case filelib:is_regular(Fn ++ ".torrent") of
+ true ->
+ ok;
+ false ->
+ etorrent_mktorrent:create(
+ Fn, "http://localhost:6969/announce", Fn ++ ".torrent")
+ end.
+
+ensure_random_file(Fn) ->
+ case filelib:is_regular(Fn) of
+ true ->
+ ok;
+ false ->
+ create_torrent_file(Fn)
+ end.
+
+create_torrent_file(FName) ->
+ random:seed({137, 314159265, 1337}),
+ Bin = create_binary(30*1024*1024, <<>>),
+ file:write_file(FName, Bin).
+
+create_binary(0, Bin) -> Bin;
+create_binary(N, Bin) ->
+ Byte = random:uniform(256) - 1,
+ create_binary(N-1, <<Bin/binary, Byte:8/integer>>).
+
+sha1_file(F) ->
+ Ctx = crypto:sha_init(),
+ {ok, FD} = file:open(F, [read,binary,raw]),
+ FinCtx = sha1_round(FD, file:read(FD, 1024*1024), Ctx),
+ crypto:sha_final(FinCtx).
+
+sha1_round(_FD, eof, Ctx) ->
+ Ctx;
+sha1_round(FD, {ok, Data}, Ctx) ->
+ sha1_round(FD, file:read(FD, 1024*1024), crypto:sha_update(Ctx, Data)).
+
+
+
+del_dir_r(DirName) ->
+ {ok, SubFiles} = file:list_dir(DirName),
+ [file:delete(X) || X <- SubFiles],
+ del_dir(DirName).
+
+del_dir(DirName) ->
+ io:format(user, "Try to delete directory ~p.~n", [DirName]),
+ case file:del_dir(DirName) of
+ {error,eexist} ->
+ io:format(user, "Directory is not empty. Content: ~n~p~n",
+ [element(2, file:list_dir(DirName))]),
+ ok;
+ ok ->
+ ok
+ end.
View
3  test/etorrent_SUITE_data/run_opentracker.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+(cat && kill 0) | opentracker $*
View
3  test/etorrent_SUITE_data/run_transmission-cli.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+(cat && kill 0) | transmission-cli $*
View
59 test/etorrent_SUITE_data/transmission/settings.json
@@ -0,0 +1,59 @@
+{
+ "alt-speed-down": 50,
+ "alt-speed-enabled": false,
+ "alt-speed-time-begin": 540,
+ "alt-speed-time-day": 127,
+ "alt-speed-time-enabled": false,
+ "alt-speed-time-end": 1020,
+ "alt-speed-up": 50,
+ "bind-address-ipv4": "0.0.0.0",
+ "bind-address-ipv6": "::",
+ "blocklist-enabled": false,
+ "blocklist-url": "http://www.example.com/blocklist",
+ "cache-size-mb": 4,
+ "dht-enabled": false,
+ "download-dir": ".",
+ "encryption": 1,
+ "idle-seeding-limit": 30,
+ "idle-seeding-limit-enabled": false,
+ "incomplete-dir": "/home/jlouis/Downloads",
+ "incomplete-dir-enabled": false,
+ "lazy-bitfield-enabled": true,
+ "lpd-enabled": false,
+ "message-level": 5,
+ "open-file-limit": 32,
+ "peer-congestion-algorithm": "",
+ "peer-limit-global": 240,
+ "peer-limit-per-torrent": 60,
+ "peer-port": 51413,
+ "peer-port-random-high": 65535,
+ "peer-port-random-low": 49152,
+ "peer-port-random-on-start": false,
+ "peer-socket-tos": "default",
+ "pex-enabled": false,
+ "port-forwarding-enabled": false,
+ "preallocation": 1,
+ "prefetch-enabled": 1,
+ "ratio-limit": 2,
+ "ratio-limit-enabled": false,
+ "rename-partial-files": true,
+ "rpc-authentication-required": false,
+ "rpc-bind-address": "0.0.0.0",
+ "rpc-enabled": false,
+ "rpc-password": "{8e9b4d6222faf86bf3a8046e73d00d37a1ae6959Y0kPqg3w",
+ "rpc-port": 9091,
+ "rpc-url": "/transmission/",
+ "rpc-username": "",
+ "rpc-whitelist": "127.0.0.1",
+ "rpc-whitelist-enabled": true,
+ "script-torrent-done-enabled": false,
+ "script-torrent-done-filename": "",
+ "speed-limit-down": 100,
+ "speed-limit-down-enabled": false,
+ "speed-limit-up": 100,
+ "speed-limit-up-enabled": false,
+ "start-added-torrents": true,
+ "trash-original-torrent-files": false,
+ "umask": 18,
+ "upload-slots-per-torrent": 14
+}
View
BIN  test/etorrent_eunit_SUITE_data/debian-6.0.2.1-amd64-netinst.iso.torrent
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.