Skip to content

Commit eb13e71

Browse files
authored
Merge pull request #1047 from oxarbitrage/elasticsearch_tests
ElasticSearch test cases framework
2 parents 27064bb + 6ffb88c commit eb13e71

File tree

7 files changed

+180
-107
lines changed

7 files changed

+180
-107
lines changed

libraries/plugins/elasticsearch/elasticsearch_plugin.cpp

+27-96
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include <boost/algorithm/string.hpp>
4545
#include <regex>
4646

47+
#include <graphene/utilities/elasticsearch.hpp>
48+
4749
namespace graphene { namespace elasticsearch {
4850

4951
namespace detail
@@ -74,10 +76,9 @@ class elasticsearch_plugin_impl
7476
bool _elasticsearch_visitor = false;
7577
CURL *curl; // curl handler
7678
vector <string> bulk; // vector of op lines
77-
private:
79+
vector<std::string> prepare;
80+
private:
7881
void add_elasticsearch( const account_id_type account_id, const optional<operation_history_object>& oho, const signed_block& b );
79-
void createBulkLine(account_transaction_history_object ath, operation_history_struct os, int op_type, block_struct bs, visitor_struct vs);
80-
void sendBulk(std::string _elasticsearch_node_url, bool _elasticsearch_logs);
8182

8283
};
8384

@@ -211,10 +212,28 @@ void elasticsearch_plugin_impl::add_elasticsearch( const account_id_type account
211212
else
212213
limit_documents = _elasticsearch_bulk_replay;
213214

214-
createBulkLine(ath, os, op_type, bs, vs); // we have everything, creating bulk line
215+
// we have everything, creating bulk line
216+
bulk_struct bulks;
217+
bulks.account_history = ath;
218+
bulks.operation_history = os;
219+
bulks.operation_type = op_type;
220+
bulks.block_data = bs;
221+
bulks.additional_data = vs;
222+
223+
std::string data = fc::json::to_string(bulks);
224+
225+
auto block_date = bulks.block_data.block_time.to_iso_string();
226+
std::vector<std::string> parts;
227+
boost::split(parts, block_date, boost::is_any_of("-"));
228+
std::string index_name = "graphene-" + parts[0] + "-" + parts[1]; // index name
229+
std::string _id = fc::json::to_string(ath.id);
230+
231+
prepare = graphene::utilities::createBulk(index_name, data, _id, 0);
232+
bulk.insert(bulk.end(), prepare.begin(), prepare.end());
215233

216234
if (curl && bulk.size() >= limit_documents) { // we are in bulk time, ready to add data to elasticsearech
217-
sendBulk(_elasticsearch_node_url, _elasticsearch_logs);
235+
prepare.clear();
236+
graphene::utilities::SendBulk(curl, bulk, _elasticsearch_node_url, _elasticsearch_logs, "logs-account-history");
218237
}
219238

220239
// remove everything except current object from ath
@@ -243,97 +262,6 @@ void elasticsearch_plugin_impl::add_elasticsearch( const account_id_type account
243262
}
244263
}
245264

246-
void elasticsearch_plugin_impl::createBulkLine(account_transaction_history_object ath, operation_history_struct os, int op_type, block_struct bs, visitor_struct vs)
247-
{
248-
bulk_struct bulks;
249-
bulks.account_history = ath;
250-
bulks.operation_history = os;
251-
bulks.operation_type = op_type;
252-
bulks.block_data = bs;
253-
bulks.additional_data = vs;
254-
255-
std::string alltogether = fc::json::to_string(bulks);
256-
257-
auto block_date = bulks.block_data.block_time.to_iso_string();
258-
std::vector<std::string> parts;
259-
boost::split(parts, block_date, boost::is_any_of("-"));
260-
std::string index_name = "graphene-" + parts[0] + "-" + parts[1];
261-
262-
// bulk header before each line, op_type = create to avoid dups, index id will be ath id(2.9.X).
263-
std::string _id = fc::json::to_string(ath.id);
264-
bulk.push_back("{ \"index\" : { \"_index\" : \""+index_name+"\", \"_type\" : \"data\", \"op_type\" : \"create\", \"_id\" : "+_id+" } }"); // header
265-
bulk.push_back(alltogether);
266-
}
267-
268-
void elasticsearch_plugin_impl::sendBulk(std::string _elasticsearch_node_url, bool _elasticsearch_logs)
269-
{
270-
271-
// curl buffers to read
272-
std::string readBuffer;
273-
std::string readBuffer_logs;
274-
275-
std::string bulking = "";
276-
277-
bulking = boost::algorithm::join(bulk, "\n");
278-
bulking = bulking + "\n";
279-
bulk.clear();
280-
281-
//wlog((bulking));
282-
283-
struct curl_slist *headers = NULL;
284-
headers = curl_slist_append(headers, "Content-Type: application/json");
285-
std::string url = _elasticsearch_node_url + "_bulk";
286-
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
287-
curl_easy_setopt(curl, CURLOPT_POST, true);
288-
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
289-
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bulking.c_str());
290-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
291-
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&readBuffer);
292-
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
293-
//curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
294-
curl_easy_perform(curl);
295-
296-
long http_code = 0;
297-
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
298-
if(http_code == 200) {
299-
// all good, do nothing
300-
}
301-
else if(http_code == 429) {
302-
// repeat request?
303-
}
304-
else {
305-
// exit everything ?
306-
}
307-
308-
if(_elasticsearch_logs) {
309-
auto logs = readBuffer;
310-
// do logs
311-
std::string url_logs = _elasticsearch_node_url + "logs/data/";
312-
curl_easy_setopt(curl, CURLOPT_URL, url_logs.c_str());
313-
curl_easy_setopt(curl, CURLOPT_POST, true);
314-
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
315-
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, logs.c_str());
316-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
317-
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &readBuffer_logs);
318-
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
319-
//curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
320-
//ilog("log here curl: ${output}", ("output", readBuffer_logs));
321-
curl_easy_perform(curl);
322-
323-
http_code = 0;
324-
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
325-
if(http_code == 200) {
326-
// all good, do nothing
327-
}
328-
else if(http_code == 429) {
329-
// repeat request?
330-
}
331-
else {
332-
// exit everything ?
333-
}
334-
}
335-
}
336-
337265
} // end namespace detail
338266

339267
elasticsearch_plugin::elasticsearch_plugin() :
@@ -394,6 +322,9 @@ void elasticsearch_plugin::plugin_initialize(const boost::program_options::varia
394322

395323
void elasticsearch_plugin::plugin_startup()
396324
{
325+
if(!graphene::utilities::checkES(my->curl, my->_elasticsearch_node_url))
326+
FC_THROW_EXCEPTION(fc::exception, "ES database is not up in url ${url}", ("url", my->_elasticsearch_node_url));
327+
ilog("elasticsearch ACCOUNT HISTORY: plugin_startup() begin");
397328
}
398329

399330
} }

libraries/plugins/es_objects/es_objects.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,9 @@ void es_objects_plugin::plugin_initialize(const boost::program_options::variable
392392

393393
void es_objects_plugin::plugin_startup()
394394
{
395-
ilog("elasticsearch objects: plugin_startup() begin");
395+
if(!graphene::utilities::checkES(my->curl, my->_es_objects_elasticsearch_url))
396+
FC_THROW_EXCEPTION(fc::exception, "ES database is not up in url ${url}", ("url", my->_es_objects_elasticsearch_url));
397+
ilog("elasticsearch OBJECTS: plugin_startup() begin");
396398
}
397399

398400
} }

libraries/utilities/elasticsearch.cpp

+37
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,46 @@
2525

2626
#include <boost/algorithm/string/join.hpp>
2727
#include <fc/log/logger.hpp>
28+
#include <fc/io/json.hpp>
2829

2930
namespace graphene { namespace utilities {
3031

32+
33+
bool checkES(CURL *curl, std::string elasticsearch_url)
34+
{
35+
std::string readBuffer;
36+
std::string url = elasticsearch_url + "_nodes";
37+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
38+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
39+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&readBuffer);
40+
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
41+
curl_easy_perform(curl);
42+
if(readBuffer.empty())
43+
return false;
44+
else
45+
return true;
46+
}
47+
std::string simpleQuery(CURL *curl, std::string elasticsearch_url, std::string endpoint, std::string query)
48+
{
49+
std::string readBuffer;
50+
struct curl_slist *headers = NULL;
51+
headers = curl_slist_append(headers, "Content-Type: application/json");
52+
std::string url = elasticsearch_url + endpoint;
53+
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
54+
curl_easy_setopt(curl, CURLOPT_POST, true);
55+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
56+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, query.c_str());
57+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
58+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&readBuffer);
59+
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
60+
curl_easy_perform(curl);
61+
62+
if(!readBuffer.empty())
63+
return readBuffer;
64+
return "";
65+
66+
}
67+
3168
bool SendBulk(CURL *curl, std::vector<std::string>& bulk, std::string elasticsearch_url, bool do_logs, std::string logs_index)
3269
{
3370
// curl buffers to read

libraries/utilities/include/graphene/utilities/elasticsearch.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,7 @@ namespace graphene { namespace utilities {
3838

3939
bool SendBulk(CURL *curl, std::vector <std::string>& bulk, std::string elasticsearch_url, bool do_logs, std::string logs_index);
4040
std::vector<std::string> createBulk(std::string type, std::string data, std::string id, bool onlycreate);
41+
bool checkES(CURL *curl, std::string elasticsearch_url);
42+
std::string simpleQuery(CURL *curl, std::string elasticsearch_url, std::string endpoint, std::string query);
4143

4244
} } // end namespace graphene::utilities

tests/CMakeLists.txt

+10-6
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ if( GPERFTOOLS_FOUND )
77
endif()
88

99
file(GLOB UNIT_TESTS "tests/*.cpp")
10-
add_executable( chain_test ${COMMON_SOURCES} ${UNIT_TESTS} )
11-
target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} )
10+
add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} )
11+
target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} )
1212
if(MSVC)
1313
set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
1414
endif(MSVC)
1515

1616
file(GLOB PERFORMANCE_TESTS "performance/*.cpp")
17-
add_executable( performance_test ${COMMON_SOURCES} ${PERFORMANCE_TESTS} )
18-
target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
17+
add_executable( performance_test ${PERFORMANCE_TESTS} ${COMMON_SOURCES} )
18+
target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
1919

2020
file(GLOB BENCH_MARKS "benchmarks/*.cpp")
21-
add_executable( chain_bench ${COMMON_SOURCES} ${BENCH_MARKS} )
22-
target_link_libraries( chain_bench graphene_chain graphene_app graphene_account_history graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
21+
add_executable( chain_bench ${BENCH_MARKS} ${COMMON_SOURCES} )
22+
target_link_libraries( chain_bench graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
2323

2424
file(GLOB APP_SOURCES "app/*.cpp")
2525
add_executable( app_test ${APP_SOURCES} )
@@ -29,4 +29,8 @@ file(GLOB CLI_SOURCES "cli/*.cpp")
2929
add_executable( cli_test ${CLI_SOURCES} )
3030
target_link_libraries( cli_test graphene_app graphene_wallet graphene_witness graphene_account_history graphene_net graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
3131

32+
file(GLOB ES_SOURCES "elasticsearch/*.cpp")
33+
add_executable( es_test ${ES_SOURCES} ${COMMON_SOURCES} )
34+
target_link_libraries( es_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
35+
3236
add_subdirectory( generate_empty_blocks )

tests/common/database_fixture.cpp

+18-4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <graphene/account_history/account_history_plugin.hpp>
2828
#include <graphene/market_history/market_history_plugin.hpp>
2929
#include <graphene/grouped_orders/grouped_orders_plugin.hpp>
30+
#include <graphene/elasticsearch/elasticsearch_plugin.hpp>
3031

3132
#include <graphene/db/simple_index.hpp>
3233

@@ -73,7 +74,6 @@ database_fixture::database_fixture()
7374
if( arg == "--show-test-names" )
7475
std::cout << "running test " << boost::unit_test::framework::current_test_case().p_name << std::endl;
7576
}
76-
auto ahplugin = app.register_plugin<graphene::account_history::account_history_plugin>();
7777
auto mhplugin = app.register_plugin<graphene::market_history::market_history_plugin>();
7878
auto goplugin = app.register_plugin<graphene::grouped_orders::grouped_orders_plugin>();
7979
init_account_pub_key = init_account_priv_key.get_public_key();
@@ -126,8 +126,23 @@ database_fixture::database_fixture()
126126
options.insert(std::make_pair("track-account", boost::program_options::variable_value(track_account, false)));
127127
}
128128

129-
ahplugin->plugin_set_app(&app);
130-
ahplugin->plugin_initialize(options);
129+
if(boost::unit_test::framework::current_test_case().p_name.value == "es1") {
130+
auto esplugin = app.register_plugin<graphene::elasticsearch::elasticsearch_plugin>();
131+
esplugin->plugin_set_app(&app);
132+
133+
options.insert(std::make_pair("elasticsearch-node-url", boost::program_options::variable_value(string("http://localhost:9200/"), false)));
134+
options.insert(std::make_pair("elasticsearch-bulk-replay", boost::program_options::variable_value(uint32_t(2), false)));
135+
options.insert(std::make_pair("elasticsearch-bulk-sync", boost::program_options::variable_value(uint32_t(2), false)));
136+
137+
esplugin->plugin_initialize(options);
138+
esplugin->plugin_startup();
139+
}
140+
else {
141+
auto ahplugin = app.register_plugin<graphene::account_history::account_history_plugin>();
142+
ahplugin->plugin_set_app(&app);
143+
ahplugin->plugin_initialize(options);
144+
ahplugin->plugin_startup();
145+
}
131146

132147
options.insert(std::make_pair("bucket-size", boost::program_options::variable_value(string("[15]"),false)));
133148
mhplugin->plugin_set_app(&app);
@@ -136,7 +151,6 @@ database_fixture::database_fixture()
136151
goplugin->plugin_set_app(&app);
137152
goplugin->plugin_initialize(options);
138153

139-
ahplugin->plugin_startup();
140154
mhplugin->plugin_startup();
141155
goplugin->plugin_startup();
142156

tests/elasticsearch/main.cpp

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2018 oxarbitrage and contributors.
3+
*
4+
* The MIT License
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#include <graphene/app/api.hpp>
26+
#include <graphene/utilities/tempdir.hpp>
27+
#include <fc/crypto/digest.hpp>
28+
#include <fc/io/json.hpp>
29+
30+
#include <graphene/utilities/elasticsearch.hpp>
31+
32+
#include "../common/database_fixture.hpp"
33+
34+
#define BOOST_TEST_MODULE Elastic Search Database Tests
35+
#include <boost/test/included/unit_test.hpp>
36+
37+
using namespace graphene::chain;
38+
using namespace graphene::chain::test;
39+
using namespace graphene::app;
40+
41+
BOOST_FIXTURE_TEST_SUITE( elasticsearch_tests, database_fixture )
42+
43+
BOOST_AUTO_TEST_CASE(es1) {
44+
try {
45+
//account_id_type() do 3 ops
46+
create_bitasset("USD", account_id_type());
47+
create_account("dan");
48+
create_account("bob");
49+
50+
// generate a few blocks
51+
generate_block();
52+
generate_block();
53+
54+
fc::usleep(fc::milliseconds(2000));
55+
56+
// for later use
57+
//int asset_create_op_id = operation::tag<asset_create_operation>::value;
58+
//int account_create_op_id = operation::tag<account_create_operation>::value;
59+
60+
string query = "{ \"query\" : { \"bool\" : { \"must\" : [{\"match_all\": {}}] } } }";
61+
62+
CURL *curl; // curl handler
63+
curl = curl_easy_init();
64+
auto res = graphene::utilities::simpleQuery(curl, "http://localhost:9200/", "graphene-*/data/_count", query);
65+
variant j = fc::json::from_string(res);
66+
67+
auto total = j["_shards"]["total"].as_string();
68+
BOOST_CHECK_EQUAL(total, "5");
69+
70+
res = graphene::utilities::simpleQuery(curl, "http://localhost:9200/", "graphene-*/data/_search", query);
71+
j = fc::json::from_string(res);
72+
73+
auto first_id = j["hits"]["hits"][size_t(0)]["_id"].as_string() ;
74+
BOOST_CHECK_EQUAL(first_id, "2.9.1"); // this should be 0? are they inserted in the right order?
75+
76+
}
77+
catch (fc::exception &e) {
78+
edump((e.to_detail_string()));
79+
throw;
80+
}
81+
}
82+
83+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)