aboutsummaryrefslogtreecommitdiffstats
path: root/test/rlx_depsolver_tester.erl
blob: 9defd91fc4b573b2849b41abae563f40b9ecba51 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 92 -*-
%% ex: ts=4 sx=4 et
%%-------------------------------------------------------------------
%%
%% Copyright 2012 Opscode, Inc. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License.  You may obtain
%% a copy of the License at
%%
%%   http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied.  See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% @author Eric Merritt <[email protected]>
%% @doc
%% Additional testing for depsolver
%% @end
%%-------------------------------------------------------------------
-module(rlx_depsolver_tester).

-export([run_data/1, run_log/1]).
-include_lib("eunit/include/eunit.hrl").

-define(ADD_PKG, "^DepSelector\\sinst#\\s(\\d+)\\s-\\s"
        "Adding\\spackage\\sid\\s(\\d+)\\/(\\d+):\\smin\\s=\\s-1,"
        "\\smax\\s=\\s(\\d+),\\scurrent\\sversion\\s0$").
-define(ADD_VC, "^DepSelector\\sinst#\\s(\\d+)\\s-\\sAdding\\sVC\\s"
        "for\\s(\\d+)\\s@\\s(\\d+)\\sdepPkg\\s(\\d+)\\s\\[\\s(\\d+)"
        "\\s(\\d+)\\s\\]$").
-define(ADD_GOAL, "^DepSelector\\sinst#\\s(\\d+)\\s-\\s"
        "Marking\\sPackage\\sRequired\\s(\\d+)$").

%%============================================================================
%% Public Api
%%============================================================================
run_data(FileName) ->
    {ok, Device} = file:open(FileName, [read]),
    run_data_file(Device).

run_log(FileName) ->
    {ok, Device} = file:open(FileName, [read]),
    run_log_file(Device).

data1_test() ->
    ExpectedResult = versionify([{"app6","0.0.1"},
                                 {"dep_pkg13","0.0.2"},
                                 {"app13","0.0.1"},
                                 {"dep_pkg2","0.0.5"},
                                 {"dep_pkg1","0.0.2"},
                                 {"dep_pkg7","0.1.2"},
                                 {"app9","0.0.1"}]),
    ?assertMatch({ok, ExpectedResult},
                 run_data(fix_rebar_brokenness("data1.txt"))).

data2_test() ->
    ExpectedResult = versionify([{"app18","0.0.1"},
                                 {"app4","0.0.7"},
                                 {"app1","0.0.1"},
                                 {"app6","0.0.1"},
                                 {"dep_pkg13","0.0.2"},
                                 {"app13","0.0.1"},
                                 {"dep_pkg5","0.0.3"},
                                 {"dep_pkg1","0.0.2"},
                                 {"dep_pkg2","0.0.5"},
                                 {"dep_pkg7","0.1.2"},
                                 {"app9","0.0.1"},
                                 {"dep_pkg16","1.0.2"}]),
    ?assertMatch({ok, ExpectedResult},
                 run_data(fix_rebar_brokenness("data2.txt"))).

data3_test() ->
    ExpectedResult = versionify([{"app68","0.0.1"},
                                 {"app58","0.0.1"},
                                 {"app48","0.0.7"},
                                 {"app38","0.0.1"},
                                 {"app28","0.0.1"},
                                 {"app18","0.0.1"},
                                 {"app4","0.0.7"},
                                 {"app1","0.0.1"},
                                 {"app6","0.0.1"},
                                 {"dep_pkg13","0.0.2"},
                                 {"app13","0.0.1"},
                                 {"dep_pkg5","0.0.3"},
                                 {"dep_pkg1","0.0.2"},
                                 {"dep_pkg2","0.0.5"},
                                 {"dep_pkg7","0.1.2"},
                                 {"app9","0.0.1"},
                                 {"dep_pkg16","1.0.2"}]),
    ?assertMatch({ok,ExpectedResult}, run_data(fix_rebar_brokenness("data3.txt"))).

data4_test() ->
    ExpectedResult = versionify([{"dep_pkg20","0.0.2"},
                                 {"app78","0.0.1"},
                                 {"app68","0.0.1"},
                                 {"app58","0.0.1"},
                                 {"app48","0.0.7"},
                                 {"app38","0.0.1"},
                                 {"app28","0.0.1"},
                                 {"app18","0.0.1"},
                                 {"app4","0.0.7"},
                                 {"app1","0.0.1"},
                                 {"app6","0.0.1"},
                                 {"dep_pkg13","0.0.2"},
                                 {"app13","0.0.1"},
                                 {"dep_pkg5","0.0.3"},
                                 {"dep_pkg1","0.0.2"},
                                 {"dep_pkg2","0.0.5"},
                                 {"dep_pkg7","0.1.2"},
                                 {"app9","0.0.1"},
                                 {"dep_pkg16","1.0.2"}]),
    ?assertMatch({ok, ExpectedResult},
                 run_data(fix_rebar_brokenness("data4.txt"))).

data5_test() ->
    ExpectedResult = versionify([{"dep_pkg14","0.0.2"},
                                 {"dep_pkg22","0.0.2"},
                                 {"dep_pkg20","0.0.2"},
                                 {"app78","0.0.1"},
                                 {"app68","0.0.1"},
                                 {"app58","0.0.1"},
                                 {"app48","0.0.7"},
                                 {"app38","0.0.1"},
                                 {"app28","0.0.1"},
                                 {"app18","0.0.1"},
                                 {"app4","0.0.7"},
                                 {"app1","0.0.1"},
                                 {"app6","0.0.1"},
                                 {"dep_pkg13","0.0.2"},
                                 {"app13","0.0.1"},
                                 {"dep_pkg5","0.0.3"},
                                 {"dep_pkg1","0.0.2"},
                                 {"dep_pkg2","0.0.5"},
                                 {"dep_pkg7","0.1.2"},
                                 {"app9","0.0.1"},
                                 {"dep_pkg16","1.0.2"}]),
    ?assertMatch({ok, ExpectedResult},
                 run_data(fix_rebar_brokenness("data5.txt"))).

data6_test() ->
    ExpectedResult = versionify([{"app108","0.0.1"},
                                 {"app98","0.0.1"},
                                 {"app88","0.0.1"},
                                 {"dep_pkg14","0.0.2"},
                                 {"dep_pkg22","0.0.2"},
                                 {"dep_pkg20","0.0.2"},
                                 {"app78","0.0.1"},
                                 {"app68","0.0.1"},
                                 {"app58","0.0.1"},
                                 {"app48","0.0.7"},
                                 {"app38","0.0.1"},
                                 {"app28","0.0.1"},
                                 {"app18","0.0.1"},
                                 {"app4","0.0.7"},
                                 {"app1","0.0.1"},
                                 {"app6","0.0.1"},
                                 {"dep_pkg13","0.0.2"},
                                 {"app13","0.0.1"},
                                 {"dep_pkg5","0.0.3"},
                                 {"dep_pkg1","0.0.2"},
                                 {"dep_pkg2","0.0.5"},
                                 {"dep_pkg7","0.1.2"},
                                 {"app9","0.0.1"},
                                 {"dep_pkg16","1.0.2"}]),
    ?assertMatch({ok, ExpectedResult},
                 run_data(fix_rebar_brokenness("data6.txt"))).

log_07be9e47_test() ->
    Data = run_log(fix_rebar_brokenness("log-07be9e47-6f42-4a5d-b8b5-1d2eae1ad83b.txt")),
    ExpectedResult = versionify([{"0","0"},
                                  {"1","0"},
                                  {"3","0"},
                                  {"4","0"},
                                  {"5","0"},
                                  {"6","0"},
                                  {"7","0"},
                                  {"8","0"},
                                  {"9","0"},
                                  {"10","0"},
                                  {"11","0"},
                                  {"12","0"},
                                  {"13","0"},
                                  {"14","0"},
                                  {"15","0"},
                                  {"16","0"},
                                  {"18","0"},
                                  {"19","0"},
                                  {"21","0"},
                                  {"22","0"},
                                  {"23","0"},
                                  {"24","0"},
                                  {"25","0"}]),
    ?assertMatch({ok, ExpectedResult},
                 Data).

log_183998c1_test() ->
    ?assertMatch({error, {unreachable_package,<<"9">>}},
                 run_log(fix_rebar_brokenness("log-183998c1-2ada-4214-b308-e480345c42f2.txt"))).


log_311a15e7_test() ->
    {ok, Data} = run_log(fix_rebar_brokenness("log-311a15e7-3378-4c5b-beb7-86a1b9cf0ea9.txt")),
    ExpectedResult = lists:sort(versionify([{"45", "22"},
                                            {"40","1"},
                                            {"3","5"},
                                            {"9","0"},
                                            {"8","0"},
                                            {"7","0"},
                                            {"6","2"},
                                            {"1","5"},
                                            {"0","2"},
                                            {"61","1"},
                                            {"60","0"},
                                            {"35","4"},
                                            {"39","0"},
                                            {"38","2"},
                                            {"37","2"},
                                            {"36","3"},
                                            {"32","24"},
                                            {"30","0"},
                                            {"19","1"},
                                            {"18","0"},
                                            {"17","2"},
                                            {"16","0"},
                                            {"15","0"},
                                            {"14","1"},
                                            {"13","0"},
                                            {"12","1"},
                                            {"11","0"},
                                            {"10","1"},
                                            {"59","0"},
                                            {"58","1"},
                                            {"57","0"},
                                            {"56","0"},
                                            {"55","4"},
                                            {"29","2"},
                                            {"27","2"},
                                            {"26","0"},
                                            {"25","5"},
                                            {"24","3"},
                                            {"23","1"},
                                            {"22","3"},
                                            {"21","2"},
                                            {"20","0"}])),
    ?assertMatch(ExpectedResult, lists:sort(Data)).

log_382cfe5b_test() ->
    {ok, Data} =
        run_log(fix_rebar_brokenness("log-382cfe5b-0ac2-48b8-83d1-717cb4620990.txt")),
    ExpectedResult = lists:sort(versionify([{"18","0"},
                                            {"17","0"},
                                            {"15","1"},
                                            {"14","0"},
                                            {"10","0"},
                                            {"7","0"},
                                            {"6","0"},
                                            {"5","0"},
                                            {"4","0"},
                                            {"3","0"},
                                            {"2","1"},
                                            {"1","0"},
                                            {"0","0"}])),
    ?assertMatch(ExpectedResult, lists:sort(Data)).

log_d3564ef6_test() ->
    {ok, Data} = run_log(fix_rebar_brokenness("log-d3564ef6-6437-41e7-90b6-dbdb849551a6_mod.txt")),
    ExpectedResult = lists:sort(versionify([{"57","5"},
                                            {"56","3"},
                                            {"55","4"},
                                            {"54","0"},
                                            {"53","1"},
                                            {"82","0"},
                                            {"81","0"},
                                            {"80","1"},
                                            {"29","0"},
                                            {"28","5"},
                                            {"27","3"},
                                            {"26","1"},
                                            {"25","3"},
                                            {"24","2"},
                                            {"23","0"},
                                            {"22","1"},
                                            {"21","0"},
                                            {"20","2"},
                                            {"75","32"},
                                            {"79","2"},
                                            {"78","4"},
                                            {"74","7"},
                                            {"73","11"},
                                            {"72","0"},
                                            {"70","1"},
                                            {"47","4"},
                                            {"45","1"},
                                            {"44","1"},
                                            {"43","7"},
                                            {"42","1"},
                                            {"41","2"},
                                            {"40","2"},
                                            {"19","0"},
                                            {"18","0"},
                                            {"17","1"},
                                            {"16","0"},
                                            {"15","1"},
                                            {"14","0"},
                                            {"13","1"},
                                            {"12","0"},
                                            {"11","0"},
                                            {"10","0"},
                                            {"9","2"},
                                            {"4","5"},
                                            {"3","2"},
                                            {"0","3"},
                                            {"69","0"},
                                            {"68","1"},
                                            {"67","7"},
                                            {"39","3"},
                                            {"35","24"},
                                            {"33","0"},
                                            {"32","2"},
                                            {"30","2"}])),
    ?assertMatch(ExpectedResult, lists:sort(Data)).

log_ea2d264b_test() ->
    {ok, Data} = run_log(fix_rebar_brokenness("log-ea2d264b-003e-4611-94ed-14efc7732083.txt")),
    ExpectedResult = lists:sort(versionify([{"18","1"},
                                            {"17","0"},
                                            {"16","0"},
                                            {"15","0"},
                                            {"14","0"},
                                            {"13","1"},
                                            {"10","1"},
                                            {"9","1"},
                                            {"8","2"},
                                            {"6","0"},
                                            {"5","0"},
                                            {"4","0"},
                                            {"3","0"},
                                            {"2","0"},
                                            {"1","0"},
                                            {"0","1"}])),
    ?assertMatch(ExpectedResult, lists:sort(Data)).

%%============================================================================
%% Internal Functions
%%============================================================================
versionify(X) when erlang:is_list(X) ->
    lists:map(fun versionify/1, X);
versionify({K, V}) ->
    {erlang:list_to_binary(K), rlx_depsolver:parse_version(V)}.

fix_rebar_brokenness(Filename) ->
    Alt1 = filename:join(["./test", "data", Filename]),
    Alt2 = filename:join(["../test", "data", Filename]),
    case filelib:is_regular(Alt1) of
        true ->
            Alt1;
        false ->
            case filelib:is_regular(Alt2) of
                true ->
                    Alt2;
                false ->
                    erlang:throw(unable_to_find_data_files)
            end
    end.

run_data_file(Device) ->
    Constraints = get_constraints(io:get_line(Device, "")),
    rlx_depsolver:solve(process_packages(read_packages(Device)), Constraints).

goble_lines(_Device, eof, Acc) ->
    lists:reverse(Acc);
goble_lines(_Device, {error, Err}, _Acc) ->
    erlang:throw(Err);
goble_lines(Device, ValidVal, Acc) ->
    goble_lines(Device, io:get_line(Device, ""), [ValidVal | Acc]).

goble_lines(Device) ->
    goble_lines(Device, io:get_line(Device, ""), []).

run_log_file(Device) ->
    State0 = rlx_depsolver:new_graph(),
    {Goals, State2} =
        lists:foldl(fun(Line, Data) ->
                            process_add_goal(Line,
                                             process_add_constraint(Line,
                                                                    process_add_package(Line, Data)))
                    end, {[], State0}, goble_lines(Device)),
    rlx_depsolver:solve(State2, Goals).

read_packages(Device) ->
    process_line(Device, io:get_line(Device, ""), []).

process_line(Device, eof, Acc) ->
    file:close(Device),
    Acc;
process_line(Device, [], Acc) ->
    process_line(Device, io:get_line(Device, ""),
                 Acc);
process_line(Device, "\n", Acc) ->
    process_line(Device, io:get_line(Device, ""),
                 Acc);
process_line(Device, [$\s | Rest], [{Pkg, Vsn, Deps} | Acc]) ->
    [DepPackage, Type,  DepVsn] = rlx_string:lexemes(Rest, " \n"),
    Dep =
        case Type of
            "=" ->
                {DepPackage, DepVsn};
            ">=" ->
                {DepPackage, DepVsn, gte}
        end,
    process_line(Device, io:get_line(Device, ""),
                 [{Pkg, Vsn, [Dep | Deps]} | Acc]);
process_line(Device, Pkg, Acc) ->
    [Package, Vsn] = rlx_string:lexemes(Pkg, " \n"),
    process_line(Device, io:get_line(Device, ""),
                 [{Package, Vsn, []} | Acc]).

process_packages(Pkgs) ->
    lists:foldl(fun({Pkg, Vsn, Constraints}, Dom0) ->
                        rlx_depsolver:add_package_version(Dom0, Pkg, Vsn, Constraints)
                end, rlx_depsolver:new_graph(), Pkgs).

get_constraints(ConLine) ->
    AppVsns = rlx_string:lexemes(ConLine, " \n"),
    lists:map(fun(AppCon) ->
                      parse_app(AppCon, [])
              end, AppVsns).
parse_app([$= | Rest], Acc) ->
    {lists:reverse(Acc), Rest};
parse_app([$>, $= | Rest], Acc) ->
    {lists:reverse(Acc), Rest, gte};
parse_app([Else | Rest], Acc) ->
    parse_app(Rest, [Else | Acc]);
parse_app([], Acc) ->
    lists:reverse(Acc).

process_add_package(Line, {Goals, State0}) ->
    case re:run(Line, ?ADD_PKG, [{capture, all, list}]) of
        {match, [_All, _InstNumber, PkgName, _PkgCount, VersionCount]} ->
            {Goals,
             lists:foldl(fun(PkgVsn, State1) ->
                                 rlx_depsolver:add_package_version(State1,
                                                               PkgName,
                                                               erlang:integer_to_list(PkgVsn),
                                                               [])
                         end, State0, lists:seq(0,
                                                erlang:list_to_integer(VersionCount)))};
        _ ->
            {Goals, State0}
    end.

process_add_constraint(Line, {Goals, State0}) ->
    case re:run(Line, ?ADD_VC, [{capture, all, list}]) of
        {match, [_All, _InstNumber, Pkg, Vsn, Dep, _Ignore, DepVsn]} ->
            {Goals,
             rlx_depsolver:add_package_version(State0, Pkg, Vsn, [{Dep, DepVsn}])};
        _ ->
            {Goals, State0}
    end.

process_add_goal(Line, {Goals, State0}) ->
    case re:run(Line, ?ADD_GOAL, [{capture, all, list}]) of
        {match,[_All, _InstNumber, NewGoal]} ->
            {[NewGoal | Goals], State0};
        _ ->
            {Goals, State0}
    end.