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
24#include <xrpl/protocol/jss.h>
25
26#include <boost/container/static_vector.hpp>
27
28#include <algorithm>
29
30namespace ripple {
31
33{
34 void
36 {
37 testcase("Invalid request params");
38 using namespace test::jtx;
39 Env env{*this, envconfig(no_admin)};
40
41 {
42 // no params
43 auto const result =
44 env.client().invoke("tx_history", {})[jss::result];
45 BEAST_EXPECT(result[jss::error] == "invalidParams");
46 BEAST_EXPECT(result[jss::status] == "error");
47 }
48
49 {
50 // test at 1 greater than the allowed non-admin limit
52 params[jss::start] = 10001; // limited to <= 10000 for non admin
53 auto const result =
54 env.client().invoke("tx_history", params)[jss::result];
55 BEAST_EXPECT(result[jss::error] == "noPermission");
56 BEAST_EXPECT(result[jss::status] == "error");
57 }
58 }
59
60 void
62 {
63 testcase("Command retired from API v2");
64 using namespace test::jtx;
65 Env env{*this, envconfig(no_admin)};
66
68 params[jss::api_version] = 2;
69 auto const result =
70 env.client().invoke("tx_history", params)[jss::result];
71 BEAST_EXPECT(result[jss::error] == "unknownCmd");
72 BEAST_EXPECT(result[jss::status] == "error");
73 }
74
75 void
77 {
78 testcase("Basic request");
79 using namespace test::jtx;
80 Env env{*this};
81
82 // create enough transactions to provide some
83 // history...
84 size_t const numAccounts = 20;
85 boost::container::static_vector<Account, numAccounts> accounts;
86 for (size_t i = 0; i < numAccounts; ++i)
87 {
88 accounts.emplace_back("A" + std::to_string(i));
89 auto const& acct = accounts.back();
90 env.fund(XRP(10000), acct);
91 env.close();
92 if (i > 0)
93 {
94 auto const& prev = accounts[i - 1];
95 env.trust(acct["USD"](1000), prev);
96 env(pay(acct, prev, acct["USD"](5)));
97 }
98 env(offer(acct, XRP(100), acct["USD"](1)));
99 env.close();
100
101 // verify the latest transaction in env (offer)
102 // is available in tx_history.
104 params[jss::start] = 0;
105 auto result =
106 env.client().invoke("tx_history", params)[jss::result];
107 if (!BEAST_EXPECT(
108 result[jss::txs].isArray() && result[jss::txs].size() > 0))
109 return;
110
111 // search for a tx in history matching the last offer
112 bool const txFound = [&] {
113 auto const toFind = env.tx()->getJson(JsonOptions::none);
114 for (auto tx : result[jss::txs])
115 {
116 tx.removeMember(jss::inLedger);
117 tx.removeMember(jss::ledger_index);
118 if (toFind == tx)
119 return true;
120 }
121 return false;
122 }();
123 BEAST_EXPECT(txFound);
124 }
125
126 unsigned int start = 0;
127 unsigned int total = 0;
128 // also summarize the transaction types in this map
130 while (start < 120)
131 {
133 params[jss::start] = start;
134 auto result =
135 env.client().invoke("tx_history", params)[jss::result];
136 if (!BEAST_EXPECT(
137 result[jss::txs].isArray() && result[jss::txs].size() > 0))
138 break;
139 total += result[jss::txs].size();
140 start += 20;
141 for (auto const& t : result[jss::txs])
142 {
143 typeCounts[t[sfTransactionType.fieldName].asString()]++;
144 }
145 }
146 BEAST_EXPECT(total == 117);
147 BEAST_EXPECT(typeCounts[jss::AccountSet.c_str()] == 20);
148 BEAST_EXPECT(typeCounts[jss::TrustSet.c_str()] == 19);
149 BEAST_EXPECT(typeCounts[jss::Payment.c_str()] == 58);
150 BEAST_EXPECT(typeCounts[jss::OfferCreate.c_str()] == 20);
151
152 // also, try a request with max non-admin start value
153 {
155 params[jss::start] = 10000; // limited to <= 10000 for non admin
156 auto const result =
157 env.client().invoke("tx_history", params)[jss::result];
158 BEAST_EXPECT(result[jss::status] == "success");
159 BEAST_EXPECT(result[jss::index] == 10000);
160 }
161 }
162
163public:
164 void
165 run() override
166 {
167 testBadInput();
168 testRequest();
170 }
171};
172
173BEAST_DEFINE_TESTSUITE(TransactionHistory, rpc, ripple);
174
175} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
UInt size() const
Number of values in array or object.
Value removeMember(char const *key)
Remove and return the named member.
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
void run() override
Runs the suite.
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:45
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
T to_string(T... args)