-
Notifications
You must be signed in to change notification settings - Fork 7
/
psicash_tester.cpp
146 lines (119 loc) · 5.04 KB
/
psicash_tester.cpp
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
/*
* Copyright (c) 2018, Psiphon Inc.
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NDEBUG
#include <string>
#include <thread>
#include <iostream>
#include "psicash_tester.hpp"
#include "utils.hpp"
#include "http_status_codes.h"
using namespace std;
using namespace psicash;
namespace testing {
#define TEST_HEADER "X-PsiCash-Test"
// Making this a global rather than PsiCashTester member, because it needs to be modified
// inside a const method. (Tests are not multithreaded, so this is okay. But still ugly.)
static std::vector<std::string> g_request_mutators;
PsiCashTester::PsiCashTester()
: PsiCash() {
g_request_mutators.clear();
}
PsiCashTester::~PsiCashTester() {
}
error::Error PsiCashTester::Init(const string& user_agent, const string& file_store_root,
MakeHTTPRequestFn make_http_request_fn, bool force_reset) {
return Init(user_agent, file_store_root, make_http_request_fn, force_reset, DEV_ENV);
}
error::Error PsiCashTester::Init(const string& user_agent, const string& file_store_root,
MakeHTTPRequestFn make_http_request_fn, bool force_reset, bool test) {
return PsiCash::Init(user_agent, file_store_root, make_http_request_fn, force_reset, test);
}
UserData& PsiCashTester::user_data() {
return *user_data_;
}
error::Error PsiCashTester::MakeRewardRequests(const std::string& transaction_class,
const std::string& distinguisher,
int repeat) {
for (int i = 0; i < repeat; ++i) {
if (i != 0) {
// Sleep a bit to avoid server DB transaction conflicts
this_thread::sleep_for(chrono::milliseconds(100));
}
auto result = MakeHTTPRequestWithRetry(
"POST", "/transaction", true,
{{"class", transaction_class},
{"distinguisher", distinguisher}},
nonstd::nullopt);
if (!result) {
return WrapError(result.error(), "MakeHTTPRequestWithRetry failed");
} else if (result->code != kHTTPStatusOK) {
return error::MakeNoncriticalError(utils::Stringer(
"1T reward request failed: ", result->code, "; ", result->error, "; ", result->body));
}
}
return error::nullerr;
}
error::Result<HTTPParams>
PsiCashTester::BuildRequestParams(const std::string& method, const std::string& path,
bool include_auth_tokens,
const std::vector<std::pair<std::string, std::string>>& query_params,
int attempt,
const std::map<std::string, std::string>& additional_headers,
const std::string& body) const {
auto bonus_headers = additional_headers;
if (!g_request_mutators.empty()) {
auto mutator = g_request_mutators.back();
if (!mutator.empty()) {
bonus_headers[TEST_HEADER] = mutator;
}
g_request_mutators.pop_back();
}
return PsiCash::BuildRequestParams(
method, path, include_auth_tokens, query_params, attempt, bonus_headers, body);
}
bool PsiCashTester::MutatorsEnabled() {
static bool checked = false, mutators_enabled = false;
if (checked) {
return mutators_enabled;
}
checked = true;
SetRequestMutators({"CheckEnabled"});
auto result = MakeHTTPRequestWithRetry(
"GET", "/refresh-state", false, {}, nonstd::nullopt);
if (!result) {
throw std::runtime_error("MUTATOR CHECK FAILED: "s + result.error().ToString());
}
mutators_enabled = (result->code == kHTTPStatusAccepted);
if (!mutators_enabled) {
std::cout << "SKIPPING MUTATOR TESTS; code: " << result->code << std::endl;
}
return mutators_enabled;
}
void PsiCashTester::SetRequestMutators(const std::vector<std::string>& mutators) {
// We're going to store it reversed so we can pop off the end.
g_request_mutators.assign(mutators.crbegin(), mutators.crend());
}
psicash::error::Result<psicash::Purchase> PsiCashTester::PurchaseFromJSON(const nlohmann::json& j, const std::string& expected_type) const {
return PsiCash::PurchaseFromJSON(j, expected_type);
}
std::string PsiCashTester::CommaDelimitTokens(const std::vector<std::string>& types) const {
return PsiCash::CommaDelimitTokens(types);
}
} // namespace psicash
#endif // NDEBUG