couchbase 3.2.3 → 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/deps/lcb/CMakeLists.txt +1 -1
  2. package/deps/lcb/CONTRIBUTING.md +1 -1
  3. package/deps/lcb/README.markdown +2 -2
  4. package/deps/lcb/RELEASE_NOTES.markdown +72 -17
  5. package/deps/lcb/cmake/Modules/GetVersionInfo.cmake +1 -1
  6. package/deps/lcb/contrib/cbsasl/src/scram-sha/scram_utils.cc +22 -26
  7. package/deps/lcb/contrib/lcb-jsoncpp/lcb-jsoncpp.cpp +20 -6
  8. package/deps/lcb/doc/Doxyfile +1 -1
  9. package/deps/lcb/example/minimal/query.c +9 -7
  10. package/deps/lcb/gyp_config/common/libcouchbase/configuration.h +3 -3
  11. package/deps/lcb/include/libcouchbase/couchbase.h +3 -1
  12. package/deps/lcb/include/libcouchbase/error.h +2 -0
  13. package/deps/lcb/include/libcouchbase/ixmgmt.h +15 -10
  14. package/deps/lcb/include/libcouchbase/tracing.h +2 -2
  15. package/deps/lcb/include/memcached/protocol_binary.h +21 -0
  16. package/deps/lcb/libcouchbase.gyp +347 -349
  17. package/deps/lcb/packaging/deb/control +1 -1
  18. package/deps/lcb/src/analytics/analytics_handle.cc +7 -5
  19. package/deps/lcb/src/analytics/analytics_handle.hh +28 -0
  20. package/deps/lcb/src/capi/cmd_counter.hh +6 -0
  21. package/deps/lcb/src/capi/cmd_exists.hh +6 -0
  22. package/deps/lcb/src/capi/cmd_get.hh +5 -0
  23. package/deps/lcb/src/capi/cmd_get_replica.hh +6 -0
  24. package/deps/lcb/src/capi/cmd_remove.hh +6 -0
  25. package/deps/lcb/src/capi/cmd_search.hh +6 -0
  26. package/deps/lcb/src/capi/cmd_store.hh +16 -21
  27. package/deps/lcb/src/capi/cmd_subdoc.hh +18 -0
  28. package/deps/lcb/src/capi/cmd_touch.hh +6 -0
  29. package/deps/lcb/src/capi/cmd_unlock.hh +6 -0
  30. package/deps/lcb/src/capi/cmd_view.hh +6 -0
  31. package/deps/lcb/src/capi/collection_qualifier.hh +2 -2
  32. package/deps/lcb/src/cntl.cc +42 -8
  33. package/deps/lcb/src/dns-srv.cc +5 -3
  34. package/deps/lcb/src/errmap.cc +5 -9
  35. package/deps/lcb/src/errmap.h +7 -3
  36. package/deps/lcb/src/handler.cc +24 -18
  37. package/deps/lcb/src/lcbio/ctx.cc +4 -2
  38. package/deps/lcb/src/mcserver/mcserver.cc +8 -5
  39. package/deps/lcb/src/mcserver/negotiate.cc +39 -17
  40. package/deps/lcb/src/n1ql/ixmgmt.cc +1 -2
  41. package/deps/lcb/src/n1ql/query_handle.cc +27 -16
  42. package/deps/lcb/src/n1ql/query_handle.hh +27 -1
  43. package/deps/lcb/src/operations/counter.cc +1 -1
  44. package/deps/lcb/src/operations/exists.cc +2 -2
  45. package/deps/lcb/src/operations/get.cc +2 -2
  46. package/deps/lcb/src/operations/observe.cc +1 -1
  47. package/deps/lcb/src/operations/remove.cc +1 -1
  48. package/deps/lcb/src/operations/store.cc +1 -1
  49. package/deps/lcb/src/operations/subdoc.cc +1 -2
  50. package/deps/lcb/src/operations/touch.cc +2 -2
  51. package/deps/lcb/src/operations/unlock.cc +2 -2
  52. package/deps/lcb/src/search/search_handle.cc +27 -8
  53. package/deps/lcb/src/search/search_handle.hh +29 -0
  54. package/deps/lcb/src/ssl/ssl_common.c +6 -7
  55. package/deps/lcb/src/tracing/span.cc +43 -10
  56. package/deps/lcb/src/tracing/tracing-internal.h +105 -93
  57. package/deps/lcb/src/views/view_handle.cc +13 -5
  58. package/deps/lcb/src/views/view_handle.hh +29 -0
  59. package/deps/lcb/tests/CMakeLists.txt +21 -0
  60. package/deps/lcb/tests/basic/t_ctlcodes.cc +24 -3
  61. package/deps/lcb/tests/basic/t_jsparse.cc +8 -0
  62. package/deps/lcb/tests/iotests/mock-environment.cc +15 -0
  63. package/deps/lcb/tests/iotests/mock-environment.h +47 -0
  64. package/deps/lcb/tests/iotests/mock-unit-test.cc +96 -5
  65. package/deps/lcb/tests/iotests/mock-unit-test.h +32 -0
  66. package/deps/lcb/tests/iotests/t_collections.cc +1 -1
  67. package/deps/lcb/tests/iotests/t_confmon.cc +4 -2
  68. package/deps/lcb/tests/iotests/t_get.cc +14 -4
  69. package/deps/lcb/tests/iotests/t_n1ql.cc +17 -1
  70. package/deps/lcb/tests/iotests/t_views.cc +1 -0
  71. package/deps/lcb/tests/iotests/testutil.cc +168 -0
  72. package/deps/lcb/tests/iotests/testutil.h +111 -0
  73. package/deps/lcb/tests/mocksupport/procutil.c +32 -28
  74. package/deps/lcb/tests/mocksupport/server.c +0 -1
  75. package/deps/lcb/tools/cbc.cc +7 -0
  76. package/dist/analyticsindexmanager.js +3 -3
  77. package/dist/binding.d.ts +2 -0
  78. package/dist/bindingutilities.js +4 -0
  79. package/dist/bucketmanager.d.ts +31 -1
  80. package/dist/bucketmanager.js +28 -2
  81. package/dist/collection.js +2 -2
  82. package/dist/collectionmanager.js +2 -2
  83. package/dist/connection.js +3 -0
  84. package/dist/errors.d.ts +18 -0
  85. package/dist/errors.js +26 -2
  86. package/dist/eventingfunctionmanager.js +6 -6
  87. package/dist/queryindexmanager.js +3 -3
  88. package/dist/searchexecutor.js +3 -0
  89. package/dist/searchindexmanager.js +1 -1
  90. package/dist/searchquery.d.ts +17 -0
  91. package/dist/searchquery.js +22 -1
  92. package/dist/searchtypes.d.ts +7 -2
  93. package/dist/searchtypes.js +2 -2
  94. package/dist/usermanager.js +1 -1
  95. package/dist/viewindexmanager.js +1 -1
  96. package/package.json +1 -1
  97. package/src/connection.cpp +2 -0
  98. package/src/constants.cpp +2 -0
  99. package/src/instance.cpp +8 -1
  100. package/src/instance.h +1 -0
@@ -20,7 +20,7 @@
20
20
 
21
21
  #include "internal.h" /* vbucket_* things from lcb_INSTANCE **/
22
22
  #include <lcbio/iotable.h>
23
- #include "bucketconfig/bc_http.h"
23
+ #include "libcouchbase/couchbase.h"
24
24
 
25
25
  #define LOGARGS(instance, lvl) instance->settings, "tests-MUT", LCB_LOG_##lvl, __FILE__, __LINE__
26
26
 
@@ -29,7 +29,7 @@
29
29
  */
30
30
  void MockUnitTest::SetUp()
31
31
  {
32
- srand(time(NULL));
32
+ srand(time(nullptr));
33
33
  MockEnvironment::Reset();
34
34
  }
35
35
 
@@ -42,8 +42,8 @@ void checkConnectCommon(lcb_INSTANCE *instance)
42
42
 
43
43
  void MockUnitTest::createClusterConnection(HandleWrap &handle, lcb_INSTANCE **instance)
44
44
  {
45
- lcb_CREATEOPTS *options = NULL;
46
- MockEnvironment::getInstance()->makeConnectParams(options, NULL, LCB_TYPE_CLUSTER);
45
+ lcb_CREATEOPTS *options = nullptr;
46
+ MockEnvironment::getInstance()->makeConnectParams(options, nullptr, LCB_TYPE_CLUSTER);
47
47
  MockEnvironment::getInstance()->createConnection(handle, instance, options);
48
48
  checkConnectCommon(handle.getLcb());
49
49
  lcb_createopts_destroy(options);
@@ -70,7 +70,7 @@ void MockUnitTest::createConnection(lcb_INSTANCE **instance)
70
70
 
71
71
  void MockUnitTest::createConnection(HandleWrap &handle)
72
72
  {
73
- lcb_INSTANCE *instance = NULL;
73
+ lcb_INSTANCE *instance = nullptr;
74
74
  createConnection(handle, &instance);
75
75
  }
76
76
 
@@ -81,3 +81,94 @@ lcb_STATUS MockUnitTest::tryCreateConnection(HandleWrap &hw, lcb_INSTANCE **inst
81
81
  lcb_wait(*instance, LCB_WAIT_DEFAULT);
82
82
  return lcb_get_bootstrap_status(*instance);
83
83
  }
84
+
85
+ void MockUnitTest::assert_kv_span(const std::shared_ptr<TestSpan> &span, const std::string &expectedName,
86
+ const KVSpanAssertions &assertions)
87
+ {
88
+ auto bucket = MockEnvironment::getInstance()->getBucket();
89
+ ASSERT_EQ(expectedName, span->name);
90
+ ASSERT_EQ("couchbase", span->str_tags["db.system"]);
91
+ ASSERT_TRUE(span->int_tags.find("db.couchbase.server_duration") != span->int_tags.end());
92
+ ASSERT_EQ(bucket, span->str_tags["db.name"]);
93
+ ASSERT_EQ(assertions.scope, span->str_tags["db.couchbase.scope"]);
94
+ ASSERT_EQ(assertions.collection, span->str_tags["db.couchbase.collection"]);
95
+ ASSERT_EQ("kv", span->str_tags["db.couchbase.service"]);
96
+ ASSERT_EQ(expectedName, span->str_tags["db.operation"]);
97
+ ASSERT_EQ("IP.TCP", span->str_tags["net.transport"]);
98
+ ASSERT_TRUE(span->str_tags.count("db.couchbase.operation_id") > 0);
99
+ ASSERT_TRUE(span->str_tags.count("db.couchbase.local_id") > 0);
100
+ ASSERT_TRUE(span->str_tags.count("net.host.name") > 0);
101
+ ASSERT_TRUE(span->str_tags.count("net.host.port") > 0);
102
+ ASSERT_TRUE(span->str_tags.count("net.peer.name") > 0);
103
+ ASSERT_TRUE(span->str_tags.count("net.peer.port") > 0);
104
+ ASSERT_TRUE(span->int_tags.count("db.couchbase.retries") > 0);
105
+ if (assertions.durability_level == LCB_DURABILITYLEVEL_NONE) {
106
+ ASSERT_TRUE(span->str_tags.count("db.couchbase.durability") == 0);
107
+ } else {
108
+ ASSERT_EQ(dur_level_to_string(assertions.durability_level), span->str_tags["db.couchbase.durability"]);
109
+ }
110
+ ASSERT_TRUE(span->finished);
111
+ }
112
+
113
+ void MockUnitTest::assert_http_span(const std::shared_ptr<TestSpan> &span, const std::string &expectedName,
114
+ const HTTPSpanAssertions &assertions)
115
+ {
116
+ ASSERT_EQ(expectedName, span->name);
117
+ ASSERT_EQ("couchbase", span->str_tags["db.system"]);
118
+ if (!assertions.bucket.empty()) {
119
+ ASSERT_EQ(assertions.bucket, span->str_tags["db.name"]);
120
+ }
121
+ if (!assertions.scope.empty()) {
122
+ ASSERT_EQ(assertions.scope, span->str_tags["db.couchbase.scope"]);
123
+ }
124
+ if (!assertions.collection.empty()) {
125
+ ASSERT_EQ(assertions.collection, span->str_tags["db.couchbase.collection"]);
126
+ }
127
+ if (!assertions.service.empty()) {
128
+ ASSERT_EQ(assertions.service, span->str_tags["db.couchbase.service"]);
129
+ }
130
+ if (!assertions.op.empty()) {
131
+ ASSERT_EQ(assertions.op, span->str_tags["db.operation"]);
132
+ }
133
+ ASSERT_EQ("IP.TCP", span->str_tags["net.transport"]);
134
+ if (assertions.operation_id.empty()) {
135
+ ASSERT_TRUE(span->str_tags.find("db.couchbase.operation_id") == span->str_tags.end());
136
+ } else if (assertions.operation_id == "any") {
137
+ ASSERT_TRUE(span->str_tags.find("db.couchbase.operation_id") != span->str_tags.end());
138
+ } else {
139
+ ASSERT_EQ(assertions.operation_id, span->str_tags["db.couchbase.operation_id"]);
140
+ }
141
+ ASSERT_TRUE(span->str_tags.find("net.host.name") != span->str_tags.end());
142
+ ASSERT_TRUE(span->str_tags.find("net.host.port") != span->str_tags.end());
143
+ ASSERT_TRUE(span->str_tags.find("net.peer.name") != span->str_tags.end());
144
+ ASSERT_TRUE(span->str_tags.find("net.peer.port") != span->str_tags.end());
145
+ ASSERT_TRUE(span->int_tags.find("db.couchbase.retries") != span->int_tags.end());
146
+ if (!assertions.statement.empty()) {
147
+ ASSERT_EQ(assertions.statement, span->str_tags["db.statement"]);
148
+ }
149
+ ASSERT_TRUE(span->finished);
150
+ }
151
+
152
+ void MockUnitTest::assert_kv_metrics(const std::string &metric_name, const std::string &op, uint32_t length,
153
+ bool at_least_len)
154
+ {
155
+ std::string key = metric_name + ":kv";
156
+ if (op != "") {
157
+ key = key + ":" + op;
158
+ }
159
+ assert_metrics(key, length, at_least_len);
160
+ }
161
+
162
+ void MockUnitTest::assert_metrics(const std::string &key, uint32_t length, bool at_least_len)
163
+ {
164
+ auto meter = MockEnvironment::getInstance()->getMeter();
165
+ ASSERT_TRUE(meter.recorders.find(key) != meter.recorders.end());
166
+ if (at_least_len) {
167
+ ASSERT_TRUE(meter.recorders[key]->values.size() >= length);
168
+ } else {
169
+ ASSERT_TRUE(meter.recorders[key]->values.size() == length);
170
+ }
171
+ for (const auto value : meter.recorders[key]->values) {
172
+ ASSERT_NE(0, value);
173
+ }
174
+ }
@@ -21,6 +21,7 @@
21
21
  #include <gtest/gtest.h>
22
22
  #include <libcouchbase/couchbase.h>
23
23
  #include "mock-environment.h"
24
+ #include "testutil.h"
24
25
 
25
26
  class HandleWrap;
26
27
 
@@ -44,6 +45,22 @@ class HandleWrap;
44
45
  return; \
45
46
  }
46
47
 
48
+ struct KVSpanAssertions {
49
+ lcb_DURABILITY_LEVEL durability_level{LCB_DURABILITYLEVEL_NONE};
50
+ std::string scope{"_default"};
51
+ std::string collection{"_default"};
52
+ };
53
+
54
+ struct HTTPSpanAssertions {
55
+ std::string statement{};
56
+ std::string scope{};
57
+ std::string collection{};
58
+ std::string bucket{};
59
+ std::string op{};
60
+ std::string operation_id{};
61
+ std::string service{};
62
+ };
63
+
47
64
  class MockUnitTest : public ::testing::Test
48
65
  {
49
66
  protected:
@@ -56,6 +73,13 @@ class MockUnitTest : public ::testing::Test
56
73
  virtual void createClusterConnection(HandleWrap &handle, lcb_INSTANCE **instance);
57
74
  virtual lcb_STATUS tryCreateConnection(HandleWrap &hw, lcb_INSTANCE **instance, lcb_CREATEOPTS *&crparams);
58
75
 
76
+ static void assert_kv_span(const std::shared_ptr<TestSpan> &span, const std::string &expectedName,
77
+ const KVSpanAssertions &assertions);
78
+ static void assert_http_span(const std::shared_ptr<TestSpan> &span, const std::string &expectedName,
79
+ const HTTPSpanAssertions &assertions);
80
+ void assert_kv_metrics(const std::string &metric_name, const std::string &op, uint32_t length, bool at_least_len);
81
+ void assert_metrics(const std::string &key, uint32_t length, bool at_least_len);
82
+
59
83
  // A mock "Transaction"
60
84
  void doMockTxn(MockCommand &cmd)
61
85
  {
@@ -66,4 +90,12 @@ class MockUnitTest : public ::testing::Test
66
90
  }
67
91
  };
68
92
 
93
+ /*
94
+ * This test class groups tests that might be problematic when executed together with all other tests.
95
+ * Every test case in this suite must start with Jira ticket number for future.
96
+ */
97
+ class ContaminatingUnitTest : public MockUnitTest
98
+ {
99
+ };
100
+
69
101
  #endif
@@ -572,7 +572,7 @@ TEST_F(CollectionUnitTest, testDroppedScope)
572
572
  *
573
573
  * Collection creations are successful
574
574
  */
575
- TEST_F(CollectionUnitTest, testMaxCollectionsPerScope)
575
+ TEST_F(ContaminatingUnitTest, test_CCBC_1483_MaxCollectionsPerScope)
576
576
  {
577
577
  SKIP_IF_MOCK()
578
578
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_70)
@@ -24,6 +24,9 @@ struct evstop_listener : Listener {
24
24
 
25
25
  void clconfig_lsn(EventType event, ConfigInfo *)
26
26
  {
27
+ if (event == CLCONFIG_EVENT_PROVIDERS_CYCLED) {
28
+ return IOT_STOP(io);
29
+ }
27
30
  if (event != CLCONFIG_EVENT_GOT_NEW_CONFIG) {
28
31
  return;
29
32
  }
@@ -40,7 +43,6 @@ static void listen_callback1(Listener *lsn, EventType event, ConfigInfo *info) {
40
43
 
41
44
  TEST_F(ConfmonTest, testBasic)
42
45
  {
43
- SKIP_UNLESS_MOCK();
44
46
  HandleWrap hw;
45
47
  lcb_INSTANCE *instance;
46
48
  MockEnvironment::getInstance()->createConnection(hw, &instance);
@@ -68,8 +70,8 @@ TEST_F(ConfmonTest, testBasic)
68
70
  mon->start();
69
71
 
70
72
  IOT_START(instance->iotable);
71
- ASSERT_NE(0, listener.called);
72
73
  delete mon;
74
+ ASSERT_NE(0, listener.called);
73
75
  }
74
76
 
75
77
  struct listener2 : Listener {
@@ -21,6 +21,7 @@
21
21
  #include "iotests.h"
22
22
  #include "logging.h"
23
23
  #include "internal.h"
24
+ #include "testutil.h"
24
25
 
25
26
  #define LOGARGS(instance, lvl) instance->settings, "tests-GET", LCB_LOG_##lvl, __FILE__, __LINE__
26
27
 
@@ -106,6 +107,9 @@ static void testGetHitGetCallback(lcb_INSTANCE *, lcb_CALLBACK_TYPE, const lcb_R
106
107
  */
107
108
  TEST_F(GetUnitTest, testGetHit)
108
109
  {
110
+ MockEnvironment *mock = MockEnvironment::getInstance();
111
+ tracing_guard use_tracing;
112
+ metrics_guard use_metrics;
109
113
  HandleWrap hw;
110
114
  lcb_INSTANCE *instance;
111
115
  createConnection(hw, &instance);
@@ -129,6 +133,16 @@ TEST_F(GetUnitTest, testGetHit)
129
133
 
130
134
  lcb_wait(instance, LCB_WAIT_DEFAULT);
131
135
  EXPECT_EQ(2, numcallbacks);
136
+
137
+ auto spans = mock->getTracer().spans;
138
+ ASSERT_EQ(4, spans.size());
139
+ auto span = spans[0];
140
+ assert_kv_span(span, "upsert", {});
141
+ span = spans[2];
142
+ assert_kv_span(span, "get", {});
143
+
144
+ assert_kv_metrics(METRICS_OPS_METER_NAME, "get", 2, false);
145
+ assert_kv_metrics(METRICS_OPS_METER_NAME, "upsert", 2, false);
132
146
  }
133
147
 
134
148
  extern "C" {
@@ -1097,10 +1111,6 @@ TEST_F(GetUnitTest, testChangePassword)
1097
1111
  createConnection(hwHttp, &instanceHttp);
1098
1112
  (void)lcb_install_callback(instanceHttp, LCB_CALLBACK_HTTP, (lcb_RESPCALLBACK)change_password_http_callback);
1099
1113
 
1100
- // Set short timeout
1101
- lcb_uint32_t tmoval = 100000;
1102
- lcb_cntl(instance, LCB_CNTL_SET, LCB_CNTL_OP_TIMEOUT, &tmoval);
1103
-
1104
1114
  // store keys
1105
1115
  // run one set to connect to only one node
1106
1116
  // the goal is to change the password then try to connect others nodes
@@ -165,6 +165,8 @@ class QueryUnitTest : public MockUnitTest
165
165
 
166
166
  TEST_F(QueryUnitTest, testSimple)
167
167
  {
168
+ MockEnvironment *mock = MockEnvironment::getInstance();
169
+ tracing_guard use_tracing;
168
170
  lcb_INSTANCE *instance;
169
171
  HandleWrap hw;
170
172
  if (!createQueryConnection(hw, &instance)) {
@@ -172,12 +174,26 @@ TEST_F(QueryUnitTest, testSimple)
172
174
  }
173
175
 
174
176
  N1QLResult res;
175
- makeCommand("SELECT mockrow");
177
+ const char *query = "SELECT mockrow";
178
+ makeCommand(query);
179
+
180
+ const char *context_id = "context_id";
181
+ lcb_cmdquery_client_context_id(cmd, context_id, strlen(context_id));
182
+
176
183
  lcb_STATUS rc = lcb_query(instance, &res, cmd);
177
184
  ASSERT_STATUS_EQ(LCB_SUCCESS, rc);
178
185
  lcb_wait(instance, LCB_WAIT_DEFAULT);
179
186
  ASSERT_STATUS_EQ(LCB_SUCCESS, res.rc);
180
187
  ASSERT_EQ(1, res.rows.size());
188
+
189
+ auto spans = mock->getTracer().spans;
190
+ ASSERT_EQ(1, spans.size());
191
+ auto span = spans[0];
192
+ HTTPSpanAssertions assertions;
193
+ assertions.statement = query;
194
+ assertions.operation_id = context_id;
195
+ assertions.service = "query";
196
+ assert_http_span(span, "query", assertions);
181
197
  }
182
198
 
183
199
  TEST_F(QueryUnitTest, testQueryError)
@@ -243,6 +243,7 @@ TEST_F(ViewsUnitTest, testSimpleView)
243
243
  {
244
244
  SKIP_UNLESS_MOCK();
245
245
  // Requires beer-sample
246
+ MockEnvironment *mock = MockEnvironment::getInstance();
246
247
  HandleWrap hw;
247
248
  lcb_INSTANCE *instance;
248
249
  connectBeerSample(hw, &instance);
@@ -316,6 +316,10 @@ static std::uint64_t get_manifest_id(lcb_INSTANCE *instance)
316
316
  lcb_cmdgetmanifest_destroy(cmd);
317
317
  lcb_wait(instance, LCB_WAIT_DEFAULT);
318
318
 
319
+ if (result.rc == LCB_ERR_TIMEOUT) {
320
+ return 0;
321
+ }
322
+
319
323
  Json::Value payload;
320
324
  EXPECT_EQ(LCB_SUCCESS, result.rc);
321
325
  EXPECT_FALSE(result.value.empty());
@@ -461,3 +465,167 @@ std::string unique_name(const std::string &prefix)
461
465
  ss << prefix << lcb_next_rand32();
462
466
  return ss.str();
463
467
  }
468
+
469
+ void TestSpan::SetAttribute(std::string key, uint64_t value)
470
+ {
471
+ int_tags[std::move(key)] = value;
472
+ }
473
+
474
+ void TestSpan::SetAttribute(std::string key, std::string value)
475
+ {
476
+ str_tags[std::move(key)] = std::move(value);
477
+ }
478
+
479
+ void TestSpan::End()
480
+ {
481
+ finished = true;
482
+ }
483
+
484
+ TestSpan::TestSpan(std::string span_name)
485
+ {
486
+ name = std::move(span_name);
487
+ }
488
+
489
+ std::shared_ptr<TestSpan> TestTracer::StartSpan(std::string name)
490
+ {
491
+ auto t_span = std::make_shared<TestSpan>(name);
492
+ spans.push_back(t_span);
493
+ return t_span;
494
+ }
495
+
496
+ void TestTracer::reset()
497
+ {
498
+ spans.clear();
499
+ }
500
+
501
+ static void *start_span(lcbtrace_TRACER *tracer, const char *name, void *parent)
502
+ {
503
+ auto test_tracer = static_cast<TestTracer *>(tracer->cookie);
504
+ if (!test_tracer->enabled()) {
505
+ return nullptr;
506
+ }
507
+ auto test_span = test_tracer->StartSpan(std::string(name));
508
+ return test_span.get();
509
+ }
510
+
511
+ static void end_span(void *span)
512
+ {
513
+ if (span == nullptr) {
514
+ return;
515
+ }
516
+ static_cast<TestSpan *>(span)->End();
517
+ }
518
+
519
+ static void add_tag_string(void *span, const char *name, const char *value, size_t value_len)
520
+ {
521
+ if (span == nullptr) {
522
+ return;
523
+ }
524
+ std::string val;
525
+ val.append(value, value_len);
526
+ static_cast<TestSpan *>(span)->SetAttribute(std::string(name), val);
527
+ }
528
+
529
+ static void add_tag_uint64(void *span, const char *name, uint64_t value)
530
+ {
531
+ if (span == nullptr) {
532
+ return;
533
+ }
534
+ static_cast<TestSpan *>(span)->SetAttribute(name, value);
535
+ }
536
+
537
+ void TestTracer::create_lcb_tracer()
538
+ {
539
+ lcbtracer_ = lcbtrace_new(nullptr, LCBTRACE_F_EXTERNAL);
540
+ lcbtracer_->version = 1;
541
+ lcbtracer_->v.v1.start_span = start_span;
542
+ lcbtracer_->v.v1.end_span = end_span;
543
+ lcbtracer_->v.v1.add_tag_string = add_tag_string;
544
+ lcbtracer_->v.v1.add_tag_uint64 = add_tag_uint64;
545
+ lcbtracer_->cookie = static_cast<void *>(this);
546
+ }
547
+
548
+ void TestTracer::destroy_lcb_tracer()
549
+ {
550
+ if (lcbtracer_ != nullptr) {
551
+ lcbtrace_destroy(lcbtracer_);
552
+ delete lcbtracer_;
553
+ lcbtracer_ = nullptr;
554
+ }
555
+ }
556
+
557
+ TestTracer::~TestTracer()
558
+ {
559
+ destroy_lcb_tracer();
560
+ }
561
+
562
+ TestMeter::TestMeter() = default;
563
+
564
+ void TestMeter::reset()
565
+ {
566
+ recorders.clear();
567
+ }
568
+
569
+ void TestValueRecorder::RecordValue(uint64_t value)
570
+ {
571
+ values.push_back(value);
572
+ }
573
+
574
+ std::shared_ptr<TestValueRecorder> TestMeter::ValueRecorder(std::string name,
575
+ std::unordered_map<std::string, std::string> tags)
576
+ {
577
+ auto key = name + ":" + tags["db.couchbase.service"];
578
+ auto op = tags["db.operation"];
579
+ if (!op.empty()) {
580
+ key = key + ":" + op;
581
+ }
582
+ std::shared_ptr<TestValueRecorder> test_recorder;
583
+ if (recorders.find(key) == recorders.end()) {
584
+ test_recorder = std::make_shared<TestValueRecorder>();
585
+ recorders[key] = test_recorder;
586
+ } else {
587
+ test_recorder = recorders[key];
588
+ }
589
+ return test_recorder;
590
+ }
591
+
592
+ static void record_callback(const lcbmetrics_VALUERECORDER *recorder, uint64_t value)
593
+ {
594
+ void *test_recorder;
595
+ lcbmetrics_valuerecorder_cookie(recorder, &test_recorder);
596
+ static_cast<TestValueRecorder *>(test_recorder)->RecordValue(value);
597
+ }
598
+
599
+ static const lcbmetrics_VALUERECORDER *new_recorder(const lcbmetrics_METER *meter, const char *name,
600
+ const lcbmetrics_TAG *tags, size_t ntags)
601
+ {
602
+ std::unordered_map<std::string, std::string> recorder_tags;
603
+ for (int i = 0; i < ntags; i++) {
604
+ recorder_tags[tags[i].key] = tags[i].value;
605
+ }
606
+
607
+ void *test_meter_;
608
+ lcbmetrics_meter_cookie(meter, &test_meter_);
609
+ auto test_meter = static_cast<TestMeter *>(test_meter_);
610
+ auto test_value_recorder = test_meter->ValueRecorder(std::string(name), recorder_tags);
611
+
612
+ lcbmetrics_VALUERECORDER *recorder;
613
+ lcbmetrics_valuerecorder_create(&recorder, test_value_recorder.get());
614
+ lcbmetrics_valuerecorder_record_value_callback(recorder, record_callback);
615
+
616
+ return recorder;
617
+ }
618
+
619
+ void TestMeter::create_lcb_meter()
620
+ {
621
+ lcbmetrics_meter_create(&lcbmeter_, static_cast<void *>(this));
622
+ lcbmetrics_meter_value_recorder_callback(lcbmeter_, new_recorder);
623
+ }
624
+
625
+ void TestMeter::destroy_lcb_meter()
626
+ {
627
+ if (lcbmeter_ != nullptr) {
628
+ lcbmetrics_meter_destroy(lcbmeter_);
629
+ lcbmeter_ = nullptr;
630
+ }
631
+ }
@@ -20,6 +20,8 @@
20
20
  #include <libcouchbase/couchbase.h>
21
21
  #include <libcouchbase/vbucket.h>
22
22
  #include <string>
23
+ #include <memory>
24
+ #include <unordered_map>
23
25
 
24
26
  #define ASSERT_STATUS_EQ(expected, actual) \
25
27
  lcb_STATUS GTEST_CONCAT_TOKEN_(actual_code__, __LINE__) = (actual); \
@@ -212,4 +214,113 @@ void drop_scope(lcb_INSTANCE *instance, const std::string &scope, bool wait = tr
212
214
  void drop_collection(lcb_INSTANCE *instance, const std::string &scope, const std::string &collection, bool wait = true);
213
215
 
214
216
  std::string unique_name(const std::string &);
217
+
218
+ class TestSpan
219
+ {
220
+ public:
221
+ explicit TestSpan(std::string name);
222
+ void SetAttribute(std::string key, std::string value);
223
+ void SetAttribute(std::string key, uint64_t value);
224
+ void End();
225
+
226
+ std::unordered_map<std::string, std::string> str_tags{};
227
+ std::unordered_map<std::string, uint64_t> int_tags{};
228
+ bool finished{false};
229
+ std::string name{};
230
+
231
+ TestSpan *parent{nullptr};
232
+ };
233
+
234
+ class TestTracer
235
+ {
236
+ public:
237
+ TestTracer() = default;
238
+ ~TestTracer();
239
+ std::shared_ptr<TestSpan> StartSpan(std::string name);
240
+
241
+ std::vector<std::shared_ptr<TestSpan>> spans{};
242
+
243
+ void reset();
244
+
245
+ bool set_enabled(bool new_value)
246
+ {
247
+ bool old_value = enabled_;
248
+ enabled_ = new_value;
249
+
250
+ reset();
251
+ destroy_lcb_tracer();
252
+ if (new_value) {
253
+ create_lcb_tracer();
254
+ }
255
+ return old_value;
256
+ }
257
+
258
+ bool enabled() const
259
+ {
260
+ return enabled_;
261
+ }
262
+
263
+ lcbtrace_TRACER *lcb_tracer()
264
+ {
265
+ return lcbtracer_;
266
+ }
267
+
268
+ private:
269
+ void create_lcb_tracer();
270
+ void destroy_lcb_tracer();
271
+
272
+ lcbtrace_TRACER *lcbtracer_{nullptr};
273
+ bool enabled_{false};
274
+ };
275
+
276
+ class TestValueRecorder
277
+ {
278
+ public:
279
+ TestValueRecorder() = default;
280
+ void RecordValue(uint64_t value);
281
+
282
+ std::vector<uint64_t> values{};
283
+ };
284
+
285
+ class TestMeter
286
+ {
287
+ public:
288
+ TestMeter();
289
+ void reset();
290
+ std::shared_ptr<TestValueRecorder> ValueRecorder(std::string name,
291
+ std::unordered_map<std::string, std::string> tags);
292
+
293
+ std::unordered_map<std::string, std::shared_ptr<TestValueRecorder>> recorders{};
294
+
295
+ bool set_enabled(bool new_value)
296
+ {
297
+ bool old_value = enabled_;
298
+ enabled_ = new_value;
299
+
300
+ reset();
301
+ destroy_lcb_meter();
302
+ if (new_value) {
303
+ create_lcb_meter();
304
+ }
305
+ return old_value;
306
+ }
307
+
308
+ bool enabled() const
309
+ {
310
+ return enabled_;
311
+ }
312
+
313
+ lcbmetrics_METER *lcb_meter()
314
+ {
315
+ return lcbmeter_;
316
+ }
317
+
318
+ private:
319
+ void create_lcb_meter();
320
+ void destroy_lcb_meter();
321
+
322
+ lcbmetrics_METER *lcbmeter_{nullptr};
323
+ bool enabled_{false};
324
+ };
325
+
215
326
  #endif