File: TestLoadDefsCmd.cpp

package info (click to toggle)
ecflow 5.15.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 51,868 kB
  • sloc: cpp: 269,341; python: 22,756; sh: 3,609; perl: 770; xml: 333; f90: 204; ansic: 141; makefile: 70
file content (172 lines) | stat: -rw-r--r-- 7,682 bytes parent folder | download
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
/*
 * Copyright 2009- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#include <iostream>
#include <stdexcept>
#include <string>

#include <boost/test/unit_test.hpp>

#include "InvokeServer.hpp"
#include "SCPort.hpp"
#include "ecflow/base/cts/user/LoadDefsCmd.hpp"
#include "ecflow/node/Defs.hpp"
#include "ecflow/node/Family.hpp"
#include "ecflow/node/Suite.hpp"
#include "ecflow/node/System.hpp"
#include "ecflow/node/Task.hpp"
#include "ecflow/test/scaffold/Naming.hpp"

using namespace std;
using namespace ecf;

BOOST_AUTO_TEST_SUITE(S_Client)

BOOST_AUTO_TEST_SUITE(T_LoadDefsCmd)

//=============================================================================
// This test the LoadDefsCmd. This command will merge/absorb a defs file
// Since we are merging 2 files. It will give us an opportunity to resolve
// the extern node paths in the trigger expressions.
//
// ********************************************************************
// In the real server, we dont store, externs
// *******************************************************************
BOOST_AUTO_TEST_CASE(test_load_defs_cmd_handleRequest) {
    ECF_NAME_THIS_TEST();

    TestLog test_log("test_load_defs_cmd_handleRequest.log"); // will create log file, and destroy log and remove file
                                                              // at end of scope

    std::string firstDef = File::test_data("libs/client/test/data/first.def", "libs/client");

    // Load the FIRST file with a set of unresolved extrens
    defs_ptr firstDefs = Defs::create();
    {
        std::string errorMsg, warningMsg;
        bool parse = firstDefs->restore(firstDef, errorMsg, warningMsg);
        BOOST_CHECK_MESSAGE(parse, "Parse failed. " << errorMsg);
        firstDefs->clear_externs(); // server defs should not have externs.
    }
    size_t noOfSuites = firstDefs->suiteVec().size();

    // load the SECOND file, which should resolve the externs
    std::string secondDef = File::test_data("libs/client/test/data/second.def", "libs/client");
    Defs secondDefs;
    {
        std::string errorMsg, warningMsg;
        bool parse = secondDefs.restore(secondDef, errorMsg, warningMsg);
        BOOST_CHECK_MESSAGE(parse, "Parse failed. " << errorMsg);
    }
    noOfSuites += secondDefs.suiteVec().size();

    // Create a LoadDefsCmd. This capable of merging defs files
    // Externs are NOT loaded into the server.
    LoadDefsCmd cmd(firstDefs);
    cmd.setup_user_authentification();

    // Calling handelRequest will absorb the first defs into second & server user variables
    // AND resolve any references to node paths in the trigger expressions
    //
    // Test that the merge was OK as well
    // Note: The firstDefs is recreated in the SERVER (via LoadDefsCmd), hence out of sync with this firstDefs
    MockServer mockServer(&secondDefs);
    STC_Cmd_ptr requestStatus = cmd.handleRequest(&mockServer);
    BOOST_CHECK_MESSAGE(requestStatus, "Handle Request " << cmd << " returned NULL\n");
    BOOST_CHECK_MESSAGE(requestStatus->error().empty(), requestStatus->error());
    BOOST_CHECK_MESSAGE(secondDefs.suiteVec().size() == noOfSuites, "Merge failed to add suites");

    // Modify the Defs file to add a task/trigger that references the undefined
    // extern path defined in file 'first.def' This should fail.
    task_ptr task = Task::create("AMadeUpName");
    task->add_trigger("/a/b/c/d/e/f/g/h/j == complete");
    secondDefs.suiteVec().back()->familyVec().back()->addTask(task);

    // we just added an expression, re-parse to create AST
    // This should also attempt to resolve the extern node path /a/b/c/d/e/f/g/h/j
    // The suite 'a' should exist. But the full path is non existent
    // hence we expect the PARSE to fail.
    std::string errormsg, warningMsg;
    BOOST_CHECK_MESSAGE(!secondDefs.check(errormsg, warningMsg), errormsg);
}

BOOST_AUTO_TEST_CASE(test_load_defs_check_only) {
    ECF_NAME_THIS_TEST();

    /// Test that when check only is called the definition is NOT loaded
    InvokeServer invokeServer("Client:: ...test_load_defs_check_only", SCPort::next());
    BOOST_REQUIRE_MESSAGE(invokeServer.server_started(),
                          "Server failed to start on " << invokeServer.host() << ":" << invokeServer.port());

    std::string path = File::test_data("libs/client/test/data/lifecycle.txt", "libs/client");

    // Do not load the defs do a check only
    ClientInvoker theClient(invokeServer.host(), invokeServer.port());
    {
        BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path, false, true /* check only*/) == 0,
                              "Expected load to succeed\n"
                                  << theClient.errorMsg());
        BOOST_REQUIRE_MESSAGE(theClient.sync_local() == 0, "Expected sync to succeed\n" << theClient.errorMsg());

        // Note: when running with ECF_HOST=localhost the defs may exist, but the number of suites should be empty
        BOOST_REQUIRE_MESSAGE(!theClient.defs() || theClient.defs()->suiteVec().empty(),
                              "Expected no defs, since nothing should have been loaded\n"
                                  << theClient.errorMsg());
    }
    {
        theClient.set_auto_sync(true);
        BOOST_REQUIRE_MESSAGE(theClient.loadDefs(path, false, true /* check only*/) == 0,
                              "Expected load to succeed\n"
                                  << theClient.errorMsg());
        BOOST_REQUIRE_MESSAGE(!theClient.defs() || theClient.defs()->suiteVec().empty(),
                              "Expected no defs, since nothing should have been loaded\n"
                                  << theClient.errorMsg());
    }
    // provide path to definition that should fail to parse
    std::string path_bad_def = File::test_data("libs/client/test/data/bad.def", "libs/client");
    BOOST_REQUIRE_THROW(theClient.loadDefs(path_bad_def, false, true /* check only*/), std::runtime_error);
}

BOOST_AUTO_TEST_CASE(test_load_defs) {
    ECF_NAME_THIS_TEST();

    /// Test that loading a defs a second time, with the same suite, throws a errors
    /// unless the -force option is used.
    InvokeServer invokeServer("Client:: ...test_load_defs", SCPort::next());
    BOOST_REQUIRE_MESSAGE(invokeServer.server_started(),
                          "Server failed to start on " << invokeServer.host() << ":" << invokeServer.port());

    // create a defs with a single suite 's1'
    defs_ptr theDefs = Defs::create();
    {
        suite_ptr suite = Suite::create("s1");
        theDefs->addSuite(suite);
    }

    // Load the defs into the server
    ClientInvoker theClient(invokeServer.host(), invokeServer.port());
    theClient.set_throw_on_error(false);
    BOOST_REQUIRE_MESSAGE(theClient.load(theDefs) == 0, "Expected load to succeed\n" << theClient.errorMsg());

    // load the defs again. This should fail. as it stops accidental overwrites
    BOOST_REQUIRE_MESSAGE(theClient.load(theDefs) == 1, "Expected load to fail\n" << theClient.errorMsg());

    // Try again but with force
    BOOST_REQUIRE_MESSAGE(theClient.load(theDefs, true /*force*/) == 0,
                          "Expected load to succeed\n"
                              << theClient.errorMsg());

    /// Destroy singleton's to avoid valgrind from complaining
    System::destroy();
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()