File: test094.cxx

package info (click to toggle)
libpqxx 4.0.1%2Bdfsg3-8
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 16,012 kB
  • ctags: 9,469
  • sloc: sh: 11,289; cpp: 10,801; xml: 1,256; makefile: 287; ansic: 195; python: 159
file content (132 lines) | stat: -rw-r--r-- 3,016 bytes parent folder | download | duplicates (3)
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
#include <iostream>

#include "test_helpers.hxx"

using namespace PGSTD;
using namespace pqxx;


// Test program for libpqxx.  Simulate "in-doubt" transaction failure.
namespace
{
// Transaction class that simulates connection failure during commit.
class basic_flakytransaction : public dbtransaction
{
public:
  bool simulate_failure;

protected:
  basic_flakytransaction(connection_base &C, const string &I) :
    namedclass("flakytransaction"),
    dbtransaction(C, I),
    simulate_failure(false)
	{}

private:
  virtual void do_commit()
  {
    if (simulate_failure) conn().simulate_failure();

    try
    {
      DirectExec("COMMIT");
    }
    catch (const exception &e)
    {
      if (conn().is_open())
      {
        PQXX_CHECK(!simulate_failure, "Connection did not simulate failure.");
	cerr << "Unexpected exception (connection still open)" << endl;
	throw;
      }

      process_notice(e.what() + string("\n"));

      const string Msg =
	(simulate_failure ?
		"Simulating commit failure" :
		"UNEXPECTED COMMIT FAILURE");

      process_notice(Msg + "\n");
      throw in_doubt_error(Msg);
    }
  }
};


template<isolation_level ISOLATIONLEVEL=read_committed>
class flakytransaction : public basic_flakytransaction
{
public:
  typedef isolation_traits<ISOLATIONLEVEL> isolation_tag;

  explicit flakytransaction(connection_base &C, const string &TName) :
    namedclass(fullname("transaction",isolation_tag::name()), TName),
    basic_flakytransaction(C, isolation_tag::name())
	{ Begin(); }

  explicit flakytransaction(connection_base &C) :
    namedclass(fullname("transaction",isolation_tag::name())),
    basic_flakytransaction(C, isolation_tag::name())
	{ Begin(); }

  virtual ~flakytransaction() throw () { End(); }
};


// A transactor build to fail, at least for the first m_failcount commits
class FlakyTransactor : public transactor<flakytransaction<> >
{
  int m_failcount;
public:
  explicit FlakyTransactor(int failcount=0) : 
    transactor<flakytransaction<> >("FlakyTransactor"),
    m_failcount(failcount)
	{}

  void operator()(argument_type &T)
  {
    T.simulate_failure = (m_failcount > 0);

    T.exec("SELECT count(*) FROM pg_tables");
  }

  void on_doubt() throw ()
  {
    try
    {
      if (m_failcount > 0)
      {
        --m_failcount;
        pqxx::test::expected_exception("Transactor outcome in doubt.");
      }
      else
      {
        cerr << "Transactor outcome in doubt!" << endl;
      }
    }
    catch (const exception &)
    {
    }
  }
};


void test_094(transaction_base &orgT)
{
  connection_base &C(orgT.conn());
  orgT.abort();

  // Run without simulating failure
  C.perform(FlakyTransactor(0), 1);

  // Simulate one failure.  The transactor will succeed on a second attempt, but
  // since this is an in-doubt error, the framework does not retry.
  PQXX_CHECK_THROWS(
	C.perform(FlakyTransactor(1), 2),
	in_doubt_error,
	"Simulated failure did not lead to in-doubt error.");
}
} // namespace

PQXX_REGISTER_TEST_T(test_094, nontransaction)