xquery version "3.1";

(:~
 : Providing an API endpoint for triggering test execution.
 : This endpoint has been established instead of the text execution in post-install.xq
 : since at this point the RESTXQ API isn't fired up yet which causes the tests to throw errors.
 : 
 : @author Michelle Weidling
 : @since 0.4.0
 :)

module namespace testtrigger="http://ahiqar.uni-goettingen.de/ns/testtrigger";

import module namespace functx="http://www.functx.com";
import module namespace rest="http://exquery.org/ns/restxq";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

import module namespace at="http://ahiqar.uni-goettingen.de/ns/annotations/tests" at "../tests/annotation-tests.xqm";
import module namespace commons="http://ahiqar.uni-goettingen.de/ns/commons" at "commons.xqm";
import module namespace ct="http://ahiqar.uni-goettingen.de/ns/commons-tests" at "../tests/commons-tests.xqm";
import module namespace dbt="http://ahiqar.uni-goettingen.de/ns/database-triggers" at "../triggers/trigger.xqm";
import module namespace et="http://ahiqar.uni-goettingen.de/ns/annotations/editorial/tests" at "../tests/editorial-tests.xqm";
import module namespace tct="http://ahiqar.uni-goettingen.de/ns/tapi/collection/tests" at "../tests/tapi-collection-tests.xqm";
import module namespace thtmlt="http://ahiqar.uni-goettingen.de/ns/tapi/html/tests" at "../tests/tapi-html-tests.xqm";
import module namespace timgt="http://ahiqar.uni-goettingen.de/ns/tapi/images/tests" at "../tests/tapi-img-tests.xqm";
import module namespace titemt="http://ahiqar.uni-goettingen.de/ns/tapi/item/tests" at "../tests/tapi-item-tests.xqm";
import module namespace tmt="http://ahiqar.uni-goettingen.de/ns/tapi/manifest/tests" at "../tests/tapi-manifest-tests.xqm";
import module namespace ttnt="http://ahiqar.uni-goettingen.de/ns/tapi/txt/normalization/tests" at "../tests/tapi-txt-normalization-tests.xqm";
import module namespace t2ht="http://ahiqar.uni-goettingen.de/ns/tei2html-tests" at "../tests/tei2html-tests.xqm";
import module namespace t2jt="http://ahiqar.uni-goettingen.de/ns/tei2json/tests" at "../tests/tei2json-tests.xqm";
import module namespace t2htextt="http://ahiqar.uni-goettingen.de/ns/tei2html-textprocessing-tests" at "../tests/tei2html-textprocessing-tests.xqm";
import module namespace tokt="http://ahiqar.uni-goettingen.de/ns/tokenize/tests" at "../tests/tokenize-tests.xqm";
import module namespace st="http://ahiqar.uni-goettingen.de/ns/search/tests" at "../tests/search-tests.xqm";
import module namespace met="http://ahiqar.uni-goettingen.de/ns/motifs-expansion/tests" at "../tests/motifs-expansion-tests.xqm";



(: modules that need credentials for the tests to work :)
import module namespace titemtc="http://ahiqar.uni-goettingen.de/ns/tapi/item/tests/credentials" at "../tests/tapi-item-tests-credentials-needed.xqm";
import module namespace ttc="http://ahiqar.uni-goettingen.de/ns/tapi/tests/credentials" at "../tests/tapi-tests-credentials-needed.xqm";
import module namespace ctc="http://ahiqar.uni-goettingen.de/ns/commons-tests/credentials" at "../tests/commons-tests-credentials-needed.xqm";

(:~
 : Triggers the tests for the Ahiqar backend. Called by the CI.
 : 
 : @param $token A CI token
 : @return item() A log message to std out. In the Docker environment, this goes to exist.log.
 : @error The deploy token provided is incorrect
 :)
declare
  %rest:GET
  %rest:HEAD
  %rest:path("/trigger-unit-tests")
  %rest:query-param("token", "{$token}", "1234")
  %rest:query-param("return", "{$return}", "false")
function testtrigger:trigger($token, $return)
as item()? {
  if( $token ne commons:get-secret("APP_DEPLOY_TOKEN"))
    then error(QName("error://1", "deploy"), "Deploy token incorrect.")
  else
    let $sysout := util:log-system-out("TextAPI and package installation done. Preparing tests…")
    let $preparation-uris := testtrigger:prepare-tests()
    
    let $sysout := util:log-system-out("Preparation of unit tests done. Running tests …")
    let $tests := testtrigger:execute-tests()
    
    let $fileSeparator := util:system-property("file.separator")
    let $system-path := system:get-exist-home() || $fileSeparator
    
    let $testWrap := <tests time="{current-dateTime()}">{ $tests }</tests>
    
    let $filename := $system-path || "ahiqar-test-results.xml"
    let $file := file:serialize($testWrap, $filename, ())
    
    let $sysout := util:log-system-out("Removing test data.")
    let $tear-down := testtrigger:tear-down()
    
    return
    (   util:log-system-out("Tests complete. See " || $filename),
        if ($return eq "true") then $testWrap else ()
    )
};

declare function testtrigger:prepare-tests()
as item()+ {
    dbt:prepare-collections-for-triggers(),
    let $uris :=
        for $uri in xmldb:get-child-resources($commons:data)[starts-with(., "sample_")] return
            $commons:data || $uri

    for $uri in $uris return
        dbt:process-triggers($uri)
};

declare function testtrigger:tear-down()
as item()* {
    let $uris := (xmldb:get-child-resources($commons:json)[contains(., "sample") or contains(., "wo_tile")], xmldb:get-child-resources($commons:html)[contains(., "sample")])
    for $uri in $uris return 
        (
            if (ends-with($uri, "json")) then
                xmldb:remove($commons:json, $uri)
            else
                xmldb:remove($commons:html, $uri),
            util:log-system-out(concat("Removed ", $uri))
        )
};

declare function testtrigger:execute-tests()
as element()+ {
    let $test-results :=
    (
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/collection/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/commons-tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/manifest/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/item/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/html/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tei2html-tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tei2html-textprocessing-tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/annotations/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/annotations/editorial/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/txt/normalization/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/images/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tokenize/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tei2json/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/search/tests")),
        test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/motifs-expansion/tests")),

        (: tests with credentials needed :)
        if (commons:get-secret("TGLOGIN")) then
            (
                test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/item/tests/credentials")),
                test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/tapi/tests/credentials")),
                test:suite(util:list-functions("http://ahiqar.uni-goettingen.de/ns/commons-tests/credentials"))
            )
        else
            ()
    )

    let $results := for $result in $test-results return
        if ($result//@failures = 0
        and $result//@errors = 0) then
            <OK name="{testtrigger:get-package-name($result//@package)}" package="{$result//@package}"/>
        else
            <PROBLEM name="{testtrigger:get-package-name($result//@package)}"
                package="{$result//@package}"
                errors="{$result//@errors}"
                failures="{$result//@failures}">
                {$result//testcase[child::*[self::failure or self::error]]}
            </PROBLEM>
            
    for $result in $results
    order by $result/name() descending return
        $result
};

declare function testtrigger:get-package-name($package as xs:string)
as xs:string? {
    switch ($package)
        case "http://ahiqar.uni-goettingen.de/ns/commons-tests" return "Commons"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/collection/tests" return "TextAPI Collections"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/manifest/tests" return "TextAPI Manifests"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/item/tests" return "TextAPI Items"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/html/tests" return "HTML creation"
        case "http://ahiqar.uni-goettingen.de/ns/tei2html-tests" return "TEI2HTML transformation"
        case "http://ahiqar.uni-goettingen.de/ns/tei2json/tests" return "TEI2JSON transformation"
        case "http://ahiqar.uni-goettingen.de/ns/tei2html-textprocessing-tests" return "TEI2HTML text processing"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/txt/normalization/tests" return "TXT normalization"
        case "http://ahiqar.uni-goettingen.de/ns/annotations/tests" return "AnnotationAPI"
        case "http://ahiqar.uni-goettingen.de/ns/annotations/editorial/tests" return "Annotations: Editorial comments"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/images/tests" return "Image Sections"
        case "http://ahiqar.uni-goettingen.de/ns/tokenize/tests" return "Tokenize"
        case "http://ahiqar.uni-goettingen.de/ns/search/tests" return "Search"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/item/tests/credentials" return "TextAPI Items (credentials needed)"
        case "http://ahiqar.uni-goettingen.de/ns/tapi/tests/credentials" return "TextAPI general (credentials needed)"
        case "http://ahiqar.uni-goettingen.de/ns/commons-tests/credentials" return "Commons (credentials needed)"
        case "http://ahiqar.uni-goettingen.de/ns/motifs-expansion/tests" return "Motif Transformation"
        default return ()
};
