File: test-manual.cpp

package info (click to toggle)
soci 4.1.2-2~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 17,968 kB
  • sloc: ansic: 169,887; cpp: 54,198; javascript: 12,258; ada: 1,973; sh: 36; makefile: 12; xml: 2
file content (203 lines) | stat: -rw-r--r-- 5,699 bytes parent folder | download | duplicates (2)
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
//
// Copyright (C) 2004-2024 Maciej Sobczak, Stephen Hutton
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//

#include "soci/soci.h"

#include "soci/callbacks.h"

#include <catch.hpp>

#include <iostream>

#include "test-context.h"

namespace soci
{

namespace tests
{

// This variable is referenced from test-common.cpp to force linking this file.
volatile bool soci_use_test_manual = false;

// These tests are disabled by default, as they require manual intevention, but
// can be run by explicitly giving their names on the command line.

// Check if reconnecting to the database after losing connection to it works.
TEST_CASE_METHOD(common_tests, "Reconnect", "[keep-alive][.]")
{
    soci::session sql(backEndFactory_, connectString_);
    auto_table_creator tableCreator(tc_.table_creator_1(sql));

    int id = 17;
    sql << "insert into soci_test (id) values (:id)", use(id);

    REQUIRE_NOTHROW( sql.commit() );
    CHECK( sql.is_connected() );

    std::cout << "Please break connection to the database "
                 "(stop the server, unplug the network cable, ...) "
                 "and press Enter" << std::endl;
    std::cin.get();

    try
    {
        CHECK( !sql.is_connected() );

        int id2;
        sql << "select id from soci_test", into(id2);

        FAIL("Connection to the database still available");
        return;
    }
    catch (soci_error const& e)
    {
        if ( sql.get_backend_name() == "odbc" ||
                e.get_error_category() == soci_error::unknown )
        {
            WARN( "Skipping error check because ODBC driver returned "
                  "unknown error: " << e.what() );
        }
        else
        {
            INFO( "Exception message: " << e.what() );
            CHECK( e.get_error_category() == soci_error::connection_error );
        }
    }

    std::cout << "Please undo the previous action "
                 "(restart the server, plug the cable back, ...) "
                 "and press Enter" << std::endl;
    std::cin.get();

    REQUIRE_NOTHROW( sql.reconnect() );
    CHECK( sql.is_connected() );

    int id2 = 1234;
    sql << "select id from soci_test", into(id2);
    CHECK( id2 == id );
}

// Check if automatically reconnecting to the database works.
//
// Note: this test doesn't work at all, failover doesn't happen neither with
// Oracle nor with PostgreSQL (which are the only backends for which it's
// implemented at all) and it's not clear how is it even supposed to work.
TEST_CASE_METHOD(common_tests, "Failover", "[keep-alive][.]")
{
    soci::session sql(backEndFactory_, connectString_);

    class MyCallback : public soci::failover_callback
    {
    public:
        MyCallback() : attempted_(false), reconnected_(false)
        {
        }

        bool did_reconnect() const { return reconnected_; }

        void started() override
        {
            std::cout << "Please undo the previous action "
                         "(restart the server, plug the cable back, ...) "
                         "and press Enter" << std::endl;
            std::cin.get();
        }

        void failed(bool& retry, std::string&) override
        {
            // We only retry once.
            retry = !attempted_;
            attempted_ = true;
        }

        void finished(soci::session&) override
        {
            reconnected_ = true;
        }

        void aborted() override
        {
            FAIL( "Failover aborted" );
        }

    private:
        bool attempted_;
        bool reconnected_;
    } myCallback;

    sql.set_failover_callback(myCallback);

    auto_table_creator tableCreator(tc_.table_creator_1(sql));

    int id = 17;
    sql << "insert into soci_test (id) values (:id)", use(id);
    REQUIRE_NOTHROW( sql.commit() );

    std::cout << "Please break connection to the database "
                 "(stop the server, unplug the network cable, ...) "
                 "and press Enter" << std::endl;
    std::cin.get();

    int id2;
    sql << "select id from soci_test", into(id2);
    CHECK( id2 == id );

    CHECK( myCallback.did_reconnect() );
}

// This pseudo-test allows to execute an arbitrary SQL query by defining
// SOCI_TEST_SQL environment variable and examine the resulting error.
TEST_CASE_METHOD(common_tests, "Execute", "[.]")
{
    auto const text = std::getenv("SOCI_TEST_SQL");
    if (!text)
    {
        FAIL( "SOCI_TEST_SQL environment variable must be set." );
    }

    soci::session sql(backEndFactory_, connectString_);
    try
    {
        sql << text;

        WARN("Statement executed successfully.");
    }
    catch (soci_error const& e)
    {
        char const* const categories[] =
        {
            "connection_error",
            "invalid_statement",
            "no_privilege",
            "no_data",
            "constraint_violation",
            "unknown_transaction_state",
            "system_error",
            "unknown"
        };

        unsigned const cat = e.get_error_category();
        REQUIRE(cat < sizeof(categories) / sizeof(categories[0]));

        WARN("Statement execution failed: " << e.what() << "\n"
             "Error category: " << categories[cat] << "\n");

        auto const& backend = e.get_backend_name();
        if ( !backend.empty() )
        {
            if ( e.get_backend_error_code() )
                WARN(backend << " error " << e.get_backend_error_code() << "\n");
            if ( !e.get_sqlstate().empty() )
                WARN(backend << " SQL state " << e.get_sqlstate() << "\n");
        }
    }
}

} // namespace tests

} // namespace soci