rippled
Loading...
Searching...
No Matches
TransactionHistory_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2017 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx.h>
21#include <test/jtx/Env.h>
22#include <test/jtx/envconfig.h>
23#include <xrpl/protocol/jss.h>
24#include <boost/container/static_vector.hpp>
25#include <algorithm>
26
27namespace ripple {
28
30{
31 void
33 {
34 testcase("Invalid request params");
35 using namespace test::jtx;
36 Env env{*this, envconfig(no_admin)};
37
38 {
39 // no params
40 auto const result =
41 env.client().invoke("tx_history", {})[jss::result];
42 BEAST_EXPECT(result[jss::error] == "invalidParams");
43 BEAST_EXPECT(result[jss::status] == "error");
44 }
45
46 {
47 // test at 1 greater than the allowed non-admin limit
49 params[jss::start] = 10001; // limited to <= 10000 for non admin
50 auto const result =
51 env.client().invoke("tx_history", params)[jss::result];
52 BEAST_EXPECT(result[jss::error] == "noPermission");
53 BEAST_EXPECT(result[jss::status] == "error");
54 }
55 }
56
57 void
59 {
60 testcase("Command retired from API v2");
61 using namespace test::jtx;
62 Env env{*this, envconfig(no_admin)};
63
65 params[jss::api_version] = 2;
66 auto const result =
67 env.client().invoke("tx_history", params)[jss::result];
68 BEAST_EXPECT(result[jss::error] == "unknownCmd");
69 BEAST_EXPECT(result[jss::status] == "error");
70 }
71
72 void
74 {
75 testcase("Basic request");
76 using namespace test::jtx;
77 Env env{*this};
78
79 // create enough transactions to provide some
80 // history...
81 size_t const numAccounts = 20;
82 boost::container::static_vector<Account, numAccounts> accounts;
83 for (size_t i = 0; i < numAccounts; ++i)
84 {
85 accounts.emplace_back("A" + std::to_string(i));
86 auto const& acct = accounts.back();
87 env.fund(XRP(10000), acct);
88 env.close();
89 if (i > 0)
90 {
91 auto const& prev = accounts[i - 1];
92 env.trust(acct["USD"](1000), prev);
93 env(pay(acct, prev, acct["USD"](5)));
94 }
95 env(offer(acct, XRP(100), acct["USD"](1)));
96 env.close();
97
98 // verify the latest transaction in env (offer)
99 // is available in tx_history.
101 params[jss::start] = 0;
102 auto result =
103 env.client().invoke("tx_history", params)[jss::result];
104 if (!BEAST_EXPECT(
105 result[jss::txs].isArray() && result[jss::txs].size() > 0))
106 return;
107
108 // search for a tx in history matching the last offer
109 bool const txFound = [&] {
110 auto const toFind = env.tx()->getJson(JsonOptions::none);
111 for (auto tx : result[jss::txs])
112 {
113 tx.removeMember(jss::inLedger);
114 tx.removeMember(jss::ledger_index);
115 if (toFind == tx)
116 return true;
117 }
118 return false;
119 }();
120 BEAST_EXPECT(txFound);
121 }
122
123 unsigned int start = 0;
124 unsigned int total = 0;
125 // also summarize the transaction types in this map
127 while (start < 120)
128 {
130 params[jss::start] = start;
131 auto result =
132 env.client().invoke("tx_history", params)[jss::result];
133 if (!BEAST_EXPECT(
134 result[jss::txs].isArray() && result[jss::txs].size() > 0))
135 break;
136 total += result[jss::txs].size();
137 start += 20;
138 for (auto const& t : result[jss::txs])
139 {
140 typeCounts[t[sfTransactionType.fieldName].asString()]++;
141 }
142 }
143 BEAST_EXPECT(total == 117);
144 BEAST_EXPECT(typeCounts[jss::AccountSet.c_str()] == 20);
145 BEAST_EXPECT(typeCounts[jss::TrustSet.c_str()] == 19);
146 BEAST_EXPECT(typeCounts[jss::Payment.c_str()] == 58);
147 BEAST_EXPECT(typeCounts[jss::OfferCreate.c_str()] == 20);
148
149 // also, try a request with max non-admin start value
150 {
152 params[jss::start] = 10000; // limited to <= 10000 for non admin
153 auto const result =
154 env.client().invoke("tx_history", params)[jss::result];
155 BEAST_EXPECT(result[jss::status] == "success");
156 BEAST_EXPECT(result[jss::index] == 10000);
157 }
158 }
159
160public:
161 void
162 run() override
163 {
164 testBadInput();
165 testRequest();
167 }
168};
169
170BEAST_DEFINE_TESTSUITE(TransactionHistory, rpc, ripple);
171
172} // namespace ripple
Represents a JSON value.
Definition: json_value.h:147
A testsuite class.
Definition: suite.h:53
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
void run() override
Runs the suite.
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
T to_string(T... args)