1/* Part of LogicMOO Base Logicmoo Path Setups
    2% ===================================================================
    3    File:         'logicmoo_util_library.pl'
    4    Purpose:       To load the logicmoo libraries as needed
    5    Contact:       $Author: dmiles $@users.sourceforge.net ;
    6    Version:       'logicmoo_util_library.pl' 1.0.0
    7    Revision:      $Revision: 1.7 $
    8    Revised At:    $Date: 2002/07/11 21:57:28 $
    9    Author:        Douglas R. Miles
   10    Maintainers:   logicmoo
   11    E-mail:        logicmoo@gmail.com
   12    WWW:           http://www.logicmoo.org
   13    SCM:           https://github.com/logicmoo/PrologMUD/tree/master/pack/logicmoo_base
   14    Copyleft:      1999-2015, LogicMOO Prolog Extensions
   15    License:       Lesser GNU Public License
   16% ===================================================================
   17*/
   18
   19:- module(logicmoo_remote,
   20          [ test_pengines/0,
   21            pengine_server/0                    % start server
   22          ]).   23
   24:- debug(pengine(delay)).   25% run pengine server for remote tests in a separate process.
   26% :- debug(pengine(external_server)).
   27
   28% the regular things we need for testing.
   29:- use_module(library(plunit)).   30%:- use_module(library(lists)).
   31:- use_module(library(debug)).   32:- use_module(library(pengines)).   33:- use_module(library(pengines_sandbox)).   34:- use_module(library(option)).   35:- use_module(library(http/thread_httpd)).   36:- use_module(library(http/http_dispatch)).   37:- use_module(library(http/http_files)).

Test suite for pengines

*/

   42test_pengines :-
   43    run_tests([ local_pengines,
   44                remote_pengines,
   45                application
   46              ]).
   47
   48% :- debug(pengine(_)).
   49
   50:- begin_tests(local_pengines).   51
   52test(simple, Results = [a,b,c]) :-
   53    pengine_create(
   54        [ src_text("p(a). p(b). p(c).")
   55        ]),
   56    collect(X, p(X), Results, []),
   57    assertion(no_more_pengines).
   58test(chunk, Results = [a,b,c]) :-
   59    pengine_create(
   60        [ src_text("p(a). p(b). p(c).")
   61        ]),
   62    collect(X, p(X), Results, [chunk(2)]),
   63    assertion(no_more_pengines).
   64test(chunk2, Results = [a,b,c]) :-
   65    pengine_create(
   66        [ src_text("p(a). p(b). p(c).")
   67        ]),
   68    collect_state(X, p(X), State, [chunk(2), next(2)]),
   69    Results = State.results,
   70    assertion(State.replies = 2),
   71    assertion(no_more_pengines).
   72test(stop, Results = [a,b]) :-
   73    pengine_create(
   74        [ src_text("p(a). p(b). p(c).")
   75        ]),
   76    collect(X, p(X), Results, [stop_after(2)]),
   77    assertion(no_more_pengines).
   78test(two, Sorted = [a,b,c,d,e,f]) :-
   79    pengine_create(
   80        [ src_text("p(a). p(b). p(c).")
   81        ]),
   82    pengine_create(
   83        [ src_text("p(d). p(e). p(f).")
   84        ]),
   85    collect(X, p(X), Results, []),
   86    msort(Results, Sorted),
   87    assertion(no_more_pengines).
   88test(alias, Name == pippi) :-
   89    pengine_create(
   90        [ alias(pippi),
   91          id(Id)
   92        ]),
   93    pengine_property(Id, alias(Name)),
   94    assertion(( pengine_property(Id, thread(Thread)),
   95                (   thread_property(Thread, alias(ThreadAlias))
   96                ->  ThreadAlias \== Name
   97                ;   true
   98                ))),
   99    collect(_, fail, Results, []),
  100    assertion(Results == []),
  101    assertion(no_more_pengines).
  102test(ask_simple, Results = [a,b,c]) :-
  103    pengine_create(
  104        [ ask(p(X)),
  105          template(X),
  106          src_text("p(a). p(b). p(c).")
  107        ]),
  108    collect(Results, []),
  109    assertion(no_more_pengines).
  110test(ask_fail, Results = []) :-
  111    pengine_create(
  112        [ ask(p(X)),
  113          template(X),
  114          src_text("p(_) :- fail.")
  115        ]),
  116    collect(Results, []),
  117    assertion(no_more_pengines).
  118
  119:- end_tests(local_pengines).  120
  121:- begin_tests(remote_pengines,
  122               [ setup(pengine_server(_URL)),
  123                 cleanup(stop_pengine_server)
  124               ]).  125
  126test(simple, Results = [a,b,c]) :-
  127    pengine_server(Server),
  128    pengine_create(
  129        [ server(Server),
  130          src_text("p(a). p(b). p(c).")
  131        ]),
  132    collect(X, p(X), Results, []),
  133    assertion(no_more_pengines).
  134test(chunk, Results = [a,b,c]) :-
  135    pengine_server(Server),
  136    pengine_create(
  137        [ server(Server),
  138          src_text("p(a). p(b). p(c).")
  139        ]),
  140    collect(X, p(X), Results, [chunk(2)]),
  141    assertion(no_more_pengines).
  142test(stop, Results = [a,b]) :-
  143    pengine_server(Server),
  144    pengine_create(
  145        [ server(Server),
  146          src_text("p(a). p(b). p(c).")
  147        ]),
  148    collect(X, p(X), Results, [stop_after(2)]),
  149    assertion(no_more_pengines).
  150test(two, Sorted = [a,b,c,d,e,f]) :-
  151    pengine_server(Server),
  152    pengine_create(
  153        [ server(Server),
  154          src_text("p(a). p(b). p(c).")
  155        ]),
  156    pengine_create(
  157        [ server(Server),
  158          src_text("p(d). p(e). p(f).")
  159        ]),
  160    collect(X, p(X), Results, []),
  161    msort(Results, Sorted),
  162    assertion(no_more_pengines).
  163test(rpc_det, Xs == [1]) :-
  164    pengine_server(Server),
  165    findall(X, pengine_rpc(Server,
  166                           X = 1,
  167                           []),
  168            Xs),
  169    assertion(no_more_pengines).
  170test(rpc_all, Xs == [1,2,3]) :-
  171    pengine_server(Server),
  172    findall(X, pengine_rpc(Server,
  173                           member(X, [1,2,3]),
  174                           []),
  175            Xs),
  176    assertion(no_more_pengines).
  177test(rpc_first, X == 1) :-
  178    pengine_server(Server),
  179    pengine_rpc(Server,
  180                member(X, [1,2,3]),
  181                []),
  182    !,
  183    assertion(no_more_pengines).
  184test(rpc_fail, true) :-
  185    pengine_server(Server),
  186    \+ pengine_rpc(Server,
  187                   fail,
  188                   []),
  189    assertion(no_more_pengines).
  190test(pengine_and_rpc, Results = [a,b,c]) :-
  191    pengine_server(Server),
  192    pengine_create(
  193        [ server(Server),
  194          src_text("p(a). p(b). p(c).")
  195        ]),
  196    findall(R, pengine_rpc(Server, member(R, [1,2,3]), []), Rs),
  197    assertion(Rs == [1,2,3]),
  198    collect(X, p(X), Results, []),
  199    assertion(no_more_pengines).
  200test(simple_app, Results = [a,b,c]) :-
  201    pengine_server(Server),
  202    pengine_create(
  203        [ server(Server),
  204          application(papp)
  205        ]),
  206    collect(X, p1(X), Results, []),
  207    assertion(no_more_pengines).
  208test(noapp, error(existence_error(pengine_application, nopapp))) :-
  209    pengine_server(Server),
  210    pengine_create(
  211        [ server(Server),
  212          application(nopapp)
  213        ]),
  214    collect(X, p1(X), _Results, []),
  215    assertion(no_more_pengines).
  216test(ask_simple, Results = [a,b,c]) :-
  217    pengine_server(Server),
  218    pengine_create(
  219        [ ask(p(X)),
  220          template(X),
  221          server(Server),
  222          src_text("p(a). p(b). p(c).")
  223        ]),
  224    collect(Results, []),
  225    assertion(no_more_pengines).
  226test(ask_simple_no_template, Results = [p(a),p(b),p(c)]) :-
  227    pengine_server(Server),
  228    pengine_create(
  229        [ ask(p(_X)),
  230          server(Server),
  231          src_text("p(a). p(b). p(c).")
  232        ]),
  233    collect(Results, []),
  234    assertion(no_more_pengines).
  235test(rpc_nested, Xs == [1,2,3]) :-
  236    pengine_server(Server),
  237    findall(X, pengine_rpc(Server,
  238                           pengine_rpc(Server,
  239                                       member(X, [1,2,3]),
  240                                       []),
  241                           []),
  242            Xs),
  243    assertion(no_more_pengines).
  244
  245:- end_tests(remote_pengines).  246
  247:- begin_tests(application).  248
  249test(simple, Results = [a,b,c]) :-
  250    pengine_create(
  251        [ application(papp)
  252        ]),
  253    collect(X, p1(X), Results, []),
  254    assertion(no_more_pengines).
  255test(self, true) :-
  256    pengine_create([ application(papp)
  257                   ]),
  258    collect(X, pengine_self(X), Results, []),
  259    Results = [Self],
  260    assertion(atom(Self)),
  261    assertion(no_more_pengines).
  262test(noapp, error(existence_error(pengine_application, nopapp))) :-
  263    pengine_create(
  264        [ application(nopapp)
  265        ]),
  266    collect(X, p1(X), _Results, []),
  267    assertion(no_more_pengines).
  268
  269:- end_tests(application).  270
  271
  272                 /*******************************
  273                 *          APPLICATION         *
  274                 *******************************/
  275
  276:- pengine_application(papp).  277:- use_module(papp:library(pengines)).  278
  279papp:p1(a).
  280papp:p1(b).
  281papp:p1(c).
  282
  283
  284                 /*******************************
  285                 *           UTILITIES          *
  286                 *******************************/
 collect(+Template, :Goal, -Results, +Options)
Collect answers from all pengines in Results. Options:
stop_after(N)
Stop collecting results after N answers
next(N)
Passed to pengine_next/2

Other options are passed to pengine_ask/3.

  299collect(Results, Options) :-
  300    collect(-, -, Results, Options).
  301
  302collect(Template, Goal, Results, Options) :-
  303    collect_state(Template, Goal, State, Options),
  304    Results = State.results.
  305
  306collect_state(Template, Goal, State, Options) :-
  307    partition(next_option, Options, NextOptions, Options1),
  308    partition(state_option, Options1, StateOptions, AskOptions),
  309    dict_create(State, state,
  310                [ results([]),
  311                  replies(0),
  312                  options(_{ask:AskOptions, next:NextOptions})
  313                | StateOptions
  314                ]),
  315    pengine_event_loop(collect_handler(Template, Goal, State), []).
  316
  317state_option(stop_after(_)).
  318next_option(next(_)).
  319
  320collect_handler(Template, Goal, State, create(Id, _)) :-
  321    Goal \== (-),
  322    pengine_ask(Id, Goal, [template(Template)|State.options.ask]).
  323collect_handler(_, _, State, success(Id, Values, More)) :-
  324    append(State.results, Values, R1),
  325    b_set_dict(results, State, R1),
  326    Replies1 is State.replies+1,
  327    b_set_dict(replies, State, Replies1),
  328    (   StopAfter = State.get(stop_after),
  329        length(R1, Collected),
  330        Collected >= StopAfter
  331    ->  pengine_destroy(Id)
  332    ;   More == true
  333    ->  pengine_next(Id, State.options.next)
  334    ;   true
  335    ).
 no_more_pengines is semidet
True if there are no more living pengines. Need to wait a little because they die asynchronously.
  342no_more_pengines :-
  343    (   true
  344    ;   between(1, 10, _),
  345        sleep(0.01)
  346    ),
  347    \+ pengines:current_pengine(_,_,_,_,_,_),
  348    \+ pengines:child(_,_),
  349    !.
  350
  351
  352                 /*******************************
  353                 *          HTTP SERVER         *
  354                 *******************************/
  355
  356:- pengine_sandbox:use_module(library(pengines)).  357:- http_handler(/, http_reply_from_files(web, []), [prefix]).  358
  359:- dynamic
  360    pengine_server_port/1.  361
  362pengine_server(URL) :-
  363    debugging(pengine(external_server)),
  364    !,
  365    start_external_server(URL).
  366pengine_server(URL) :-
  367    local_server(URL).
  368
  369local_server(URL) :-
  370    (   pengine_server_port(Port)
  371    ->  true
  372    ;   http_server(http_dispatch, [port(Port)]),
  373        asserta(pengine_server_port(Port))
  374    ),
  375    format(atom(URL), 'http://localhost:~d', [Port]).
  376
  377stop_pengine_server :-
  378    pengine_server_pid(PID),
  379    !,
  380    process_kill(PID, hup),
  381    process_wait(PID, _Status).             % getting status 2??
  382%       assertion(Status == exit(0)).
  383stop_pengine_server :-
  384    retract(pengine_server_port(Port)),
  385    !,
  386    http_stop_server(Port, []).
  387stop_pengine_server.
  388
  389
  390                 /*******************************
  391                 *       EXTERNAL SERVER                *
  392                 *******************************/
  393
  394:- dynamic pengine_server_pid/1.  395
  396start_external_server(URL) :-
  397    current_prolog_flag(executable, SWIPL),
  398    process_create(SWIPL,
  399                   [ '-q', '-f', 'test_pengines.pl',
  400                     '-g', 'pengine_server'
  401                   ],
  402                   [ stdout(pipe(Out)),
  403                     process(PID)
  404                   ]),
  405    read_line_to_string(Out, URL),
  406    assertion(string_concat('http://', _, URL)),
  407    asserta(pengine_server_pid(PID)),
  408    on_signal(hup, _, hangup).
  409
  410hangup(_Signal) :-
  411    format(user_error, 'Got hangup~n', []),
  412    thread_send_message(main, done).
  413
  414pengine_server :-
  415    local_server(URL),
  416    writeln(URL),
  417    thread_get_message(Done),
  418    format(user_error, 'Got ~p', [Done]).
  419
  420%:- discontiguous(logicmoo_utils:'$exported_op'/3).
  421%:- logicmoo_utils:use_module(library(logicmoo_common)).
  422:- reexport(library(logicmoo_common)).  423:- reexport(library(logicmoo_startup)).  424
  425:- use_module(library(pengines)).  426
  427test_remote_swi :-
  428    pengine_create([
  429        server('http://pengines.swi-prolog.org'),
  430        src_text("
  431            q(X) :- p(X).
  432            p(a). p(b). p(c).
  433        ")
  434    ]),
  435    pengine_event_loop(handle, []).
  436
  437test_remote_logicmoo :-
  438    pengine_create([
  439        server('http://logicmoo.org'),
  440        src_text("
  441            q(X) :- p(X).
  442            p(a). p(b). p(c).
  443        ")
  444    ]),
  445    pengine_event_loop(handle, []).
  446
  447test_remote_logicmoo :-
  448    pengine_create([
  449        server('http://logicmoo.org'),
  450        src_text("
  451            q(X) :- p(X),assert(r(X)).
  452            p(a). p(b). p(c).
  453        ")
  454    ]),
  455    pengine_event_loop(handle, []).
  456
  457handle(create(ID, _)) :-
  458    pengine_ask(ID, q(_X), []).
  459handle(success(ID, [X], false)) :-
  460    writeln(X),
  461    pengine_destroy(ID, []).
  462
  463handle(success(ID, [X], true)) :-
  464    writeln(X),
  465    pengine_next(ID, []).
  466
  467
  468test_remote_logicmoo2 :- 
  469  ask_remote_logicmoo(member(X,[1,2,3])).
  470
  471ask_remote_logicmoo(Goal) :-
  472    pengine_create([
  473        server('http://logicmoo.org'),
  474        src_text("
  475            q(X) :- p(X),assert(r(X)).
  476            p(a). p(b). p(c).
  477        ")
  478    ]),
  479   term_variables(Goal,Vs),
  480   HND = handle_goal(Goal,Vs),
  481   pengine_event_loop(HND, []).
  482
  483handle_goal(_,_,Event):- dmsg(Event),fail.
  484handle_goal(Goal,_,create(ID, _)) :-
  485    pengine_ask(ID, Goal, []).
  486handle_goal(Goal,Vs,success(ID, Vs, true)) :-
  487    writeln(Goal),
  488    pengine_next(ID, []).
  489handle_goal(Goal,Vs,success(ID, Vs, false)) :-
  490    writeln(Goal),
  491    pengine_destroy(ID, []).
  492
  493:- test_remote_logicmoo2.