diff --git a/.circleci/config.yml b/.circleci/config.yml index ca024bf5..95f93b1c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,6 +15,7 @@ jobs: - image: circleci/mariadb:10.1-ram - image: circleci/redis:5.0.4 - image: rabbitmq:3.5.4 + - image: couchbase/server-sandbox:5.5.0 working_directory: ~/repo @@ -31,6 +32,12 @@ jobs: - run: name: install dependencies command: | + sudo apt-get update + sudo apt install lsb-release -y + curl -O https://packages.couchbase.com/releases/couchbase-release/couchbase-release-1.0-6-amd64.deb + sudo dpkg -i ./couchbase-release-1.0-6-amd64.deb + sudo apt-get update + sudo apt install libcouchbase-dev -y rm -rf venv export PATH=/home/circleci/.local/bin:$PATH pip install --user -U pip setuptools virtualenv @@ -66,6 +73,7 @@ jobs: - image: circleci/mariadb:10-ram - image: circleci/redis:5.0.4 - image: rabbitmq:3.5.4 + - image: couchbase/server-sandbox:5.5.0 working_directory: ~/repo @@ -82,6 +90,12 @@ jobs: - run: name: install dependencies command: | + sudo apt-get update + sudo apt install lsb-release -y + curl -O https://packages.couchbase.com/releases/couchbase-release/couchbase-release-1.0-6-amd64.deb + sudo dpkg -i ./couchbase-release-1.0-6-amd64.deb + sudo apt-get update + sudo apt install libcouchbase-dev -y python -m venv venv . venv/bin/activate pip install -U pip @@ -115,6 +129,7 @@ jobs: - image: circleci/mariadb:10-ram - image: circleci/redis:5.0.4 - image: rabbitmq:3.5.4 + - image: couchbase/server-sandbox:5.5.0 working_directory: ~/repo @@ -131,6 +146,12 @@ jobs: - run: name: install dependencies command: | + sudo apt-get update + sudo apt install lsb-release -y + curl -O https://packages.couchbase.com/releases/couchbase-release/couchbase-release-1.0-6-amd64.deb + sudo dpkg -i ./couchbase-release-1.0-6-amd64.deb + sudo apt-get update + sudo apt install libcouchbase-dev -y python -m venv venv . venv/bin/activate pip install -U pip diff --git a/instana/__init__.py b/instana/__init__.py index de4e484a..476e0df0 100644 --- a/instana/__init__.py +++ b/instana/__init__.py @@ -67,6 +67,7 @@ def boot_agent(): else: from .instrumentation import mysqlclient + from .instrumentation import couchbase_inst from .instrumentation import flask from .instrumentation import grpcio from .instrumentation.tornado import client diff --git a/instana/instrumentation/couchbase_inst.py b/instana/instrumentation/couchbase_inst.py new file mode 100644 index 00000000..387147ae --- /dev/null +++ b/instana/instrumentation/couchbase_inst.py @@ -0,0 +1,89 @@ +""" +couchbase instrumentation - This instrumentation supports the Python CouchBase 2.3.4 --> 2.5.x SDK currently: +https://docs.couchbase.com/python-sdk/2.5/start-using-sdk.html +""" +from __future__ import absolute_import + +from distutils.version import LooseVersion +import wrapt + +from ..log import logger +from ..singletons import tracer + +try: + import couchbase + from couchbase.n1ql import N1QLQuery + + # List of operations to instrument + # incr, incr_multi, decr, decr_multi, retrieve_in are wrappers around operations above + operations = ['upsert', 'insert', 'replace', 'append', 'prepend', 'get', 'rget', + 'touch', 'lock', 'unlock', 'remove', 'counter', 'mutate_in', 'lookup_in', + 'stats', 'ping', 'diagnostics', 'observe', + + 'upsert_multi', 'insert_multi', 'replace_multi', 'append_multi', + 'prepend_multi', 'get_multi', 'touch_multi', 'lock_multi', 'unlock_multi', + 'observe_multi', 'endure_multi', 'remove_multi', 'counter_multi'] + + def capture_kvs(scope, instance, query_arg, op): + try: + scope.span.set_tag('couchbase.hostname', instance.server_nodes[0]) + scope.span.set_tag('couchbase.bucket', instance.bucket) + scope.span.set_tag('couchbase.type', op) + + if query_arg is not None: + query = None + if type(query_arg) is N1QLQuery: + query = query_arg.statement + else: + query = query_arg + + scope.span.set_tag('couchbase.sql', query) + except: + # No fail on key capture - best effort + pass + + def make_wrapper(op): + def wrapper(wrapped, instance, args, kwargs): + parent_span = tracer.active_span + + # If we're not tracing, just return + if parent_span is None: + return wrapped(*args, **kwargs) + + with tracer.start_active_span("couchbase", child_of=parent_span) as scope: + capture_kvs(scope, instance, None, op) + try: + return wrapped(*args, **kwargs) + except Exception as e: + scope.span.log_exception(e) + scope.span.set_tag('couchbase.error', repr(e)) + raise + return wrapper + + def query_with_instana(wrapped, instance, args, kwargs): + parent_span = tracer.active_span + + # If we're not tracing, just return + if parent_span is None: + return wrapped(*args, **kwargs) + + with tracer.start_active_span("couchbase", child_of=parent_span) as scope: + capture_kvs(scope, instance, args[0], 'n1ql_query') + try: + return wrapped(*args, **kwargs) + except Exception as e: + scope.span.log_exception(e) + scope.span.set_tag('couchbase.error', repr(e)) + raise + + if hasattr(couchbase, '__version__') \ + and (LooseVersion(couchbase.__version__) >= LooseVersion('2.3.4')) \ + and (LooseVersion(couchbase.__version__) < LooseVersion('3.0.0')): + logger.debug("Instrumenting couchbase") + wrapt.wrap_function_wrapper('couchbase.bucket', 'Bucket.n1ql_query', query_with_instana) + for op in operations: + f = make_wrapper(op) + wrapt.wrap_function_wrapper('couchbase.bucket', 'Bucket.%s' % op, f) + +except ImportError: + pass \ No newline at end of file diff --git a/instana/json_span.py b/instana/json_span.py index 628c1986..fab4154b 100644 --- a/instana/json_span.py +++ b/instana/json_span.py @@ -48,6 +48,15 @@ class Data(BaseSpan): log = None +class CouchbaseData(BaseSpan): + hostname = None + bucket = None + type = None + error = None + error_code = None + sql = None + + class HttpData(BaseSpan): host = None url = None diff --git a/instana/recorder.py b/instana/recorder.py index 8c4471e0..238d3892 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -9,7 +9,7 @@ import instana.singletons -from .json_span import (CustomData, Data, HttpData, JsonSpan, LogData, MySQLData, PostgresData, +from .json_span import (CouchbaseData, CustomData, Data, HttpData, JsonSpan, LogData, MySQLData, PostgresData, RabbitmqData, RedisData, RenderData, RPCData, SDKData, SoapData, SQLAlchemyData) from .log import logger @@ -23,15 +23,18 @@ class InstanaRecorder(SpanRecorder): THREAD_NAME = "Instana Span Reporting" - registered_spans = ("aiohttp-client", "aiohttp-server", "django", "log", "memcache", "mysql", + registered_spans = ("aiohttp-client", "aiohttp-server", "couchbase", "django", "log", "memcache", "mysql", "postgres", "rabbitmq", "redis", "render", "rpc-client", "rpc-server", "sqlalchemy", "soap", "tornado-client", "tornado-server", "urllib3", "wsgi") + http_spans = ("aiohttp-client", "aiohttp-server", "django", "http", "soap", "tornado-client", "tornado-server", "urllib3", "wsgi") - exit_spans = ("aiohttp-client", "log", "memcache", "mysql", "postgres", "rabbitmq", "redis", "rpc-client", + exit_spans = ("aiohttp-client", "couchbase", "log", "memcache", "mysql", "postgres", "rabbitmq", "redis", "rpc-client", "sqlalchemy", "soap", "tornado-client", "urllib3") + entry_spans = ("aiohttp-server", "django", "wsgi", "rabbitmq", "rpc-server", "tornado-server") + local_spans = ("log", "render") entry_kind = ["entry", "server", "consumer"] @@ -161,6 +164,14 @@ def build_registered_span(self, span): if data.rabbitmq.sort == 'consume': kind = 1 # entry + if span.operation_name == "couchbase": + data.couchbase = CouchbaseData(hostname=span.tags.pop('couchbase.hostname', None), + bucket=span.tags.pop('couchbase.bucket', None), + type=span.tags.pop('couchbase.type', None), + error=span.tags.pop('couchbase.error', None), + error_type=span.tags.pop('couchbase.error_type', None), + sql=span.tags.pop('couchbase.sql', None)) + if span.operation_name == "redis": data.redis = RedisData(connection=span.tags.pop('connection', None), driver=span.tags.pop('driver', None), diff --git a/setup.py b/setup.py index 5ba3cdc2..670bd28c 100644 --- a/setup.py +++ b/setup.py @@ -69,6 +69,7 @@ def check_setuptools(): 'test': [ 'aiohttp>=3.5.4;python_version>="3.5"', 'asynqp>=0.4;python_version>="3.5"', + 'couchbase==2.5.9', 'django>=1.11,<2.2', 'nose>=1.0', 'flask>=0.12.2', diff --git a/tests/helpers.py b/tests/helpers.py index a48de128..a6956b36 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -2,6 +2,13 @@ testenv = {} +""" +CouchDB Environment +""" +testenv['couchdb_host'] = os.environ.get('COUCHDB_HOST', '127.0.0.1') +testenv['couchdb_username'] = os.environ.get('COUCHDB_USERNAME', 'Administrator') +testenv['couchdb_password'] = os.environ.get('COUCHDB_PASSWORD', 'password') + """ MySQL Environment """ diff --git a/tests/test_couchbase.py b/tests/test_couchbase.py new file mode 100644 index 00000000..ba3a6793 --- /dev/null +++ b/tests/test_couchbase.py @@ -0,0 +1,1271 @@ +from __future__ import absolute_import + +import unittest + +from instana.singletons import tracer +from .helpers import testenv, get_first_span_by_name, get_span_by_filter + +from couchbase.admin import Admin +from couchbase.cluster import Cluster +from couchbase.bucket import Bucket +from couchbase.exceptions import CouchbaseTransientError, HTTPError, KeyExistsError, NotFoundError +import couchbase.subdocument as SD +from couchbase.n1ql import N1QLQuery + +# Delete any pre-existing buckets. Create new. +cb_adm = Admin(testenv['couchdb_username'], testenv['couchdb_password'], host=testenv['couchdb_host'], port=8091) + +# Make sure a test bucket exists +try: + cb_adm.bucket_create('travel-sample') + cb_adm.wait_ready('travel-sample', timeout=30) +except HTTPError: + pass + + +class TestStandardCouchDB(unittest.TestCase): + def setUp(self): + """ Clear all spans before a test run """ + self.recorder = tracer.recorder + self.recorder.clear_spans() + self.cluster = Cluster('couchbase://%s' % testenv['couchdb_host']) + self.bucket = Bucket('couchbase://%s/travel-sample' % testenv['couchdb_host'], + username=testenv['couchdb_username'], password=testenv['couchdb_password']) + # self.bucket = self.cluster.open_bucket('travel-sample') + self.bucket.upsert('test-key', 1) + + def tearDown(self): + """ Do nothing for now """ + return None + + def test_vanilla_get(self): + res = self.bucket.get("test-key") + self.assertIsNotNone(res) + + def test_pipeline(self): + pass + + def test_upsert(self): + res = None + with tracer.start_active_span('test'): + res = self.bucket.upsert("test_upsert", 1) + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'upsert') + + def test_upsert_multi(self): + res = None + + kvs = dict() + kvs['first_test_upsert_multi'] = 1 + kvs['second_test_upsert_multi'] = 1 + + with tracer.start_active_span('test'): + res = self.bucket.upsert_multi(kvs) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_upsert_multi'].success) + self.assertTrue(res['second_test_upsert_multi'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'upsert_multi') + + def test_insert_new(self): + res = None + try: + self.bucket.remove('test_insert_new') + except NotFoundError: + pass + + with tracer.start_active_span('test'): + res = self.bucket.insert("test_insert_new", 1) + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'insert') + + def test_insert_existing(self): + res = None + try: + self.bucket.insert("test_insert", 1) + except KeyExistsError: + pass + + try: + with tracer.start_active_span('test'): + res = self.bucket.insert("test_insert", 1) + except KeyExistsError: + pass + + self.assertIsNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertTrue(cb_span.error) + self.assertEqual(cb_span.ec, 1) + # Just search for the substring of the exception class + found = cb_span.data.couchbase.error.find("_KeyExistsError") + self.assertFalse(found == -1, "Error substring not found.") + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'insert') + + def test_insert_multi(self): + res = None + + kvs = dict() + kvs['first_test_upsert_multi'] = 1 + kvs['second_test_upsert_multi'] = 1 + + try: + self.bucket.remove('first_test_upsert_multi') + self.bucket.remove('second_test_upsert_multi') + except NotFoundError: + pass + + with tracer.start_active_span('test'): + res = self.bucket.insert_multi(kvs) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_upsert_multi'].success) + self.assertTrue(res['second_test_upsert_multi'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'insert_multi') + + def test_replace(self): + res = None + try: + self.bucket.insert("test_replace", 1) + except KeyExistsError: + pass + + with tracer.start_active_span('test'): + res = self.bucket.replace("test_replace", 2) + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'replace') + + def test_replace_non_existent(self): + res = None + + try: + self.bucket.remove("test_replace") + except NotFoundError: + pass + + try: + with tracer.start_active_span('test'): + res = self.bucket.replace("test_replace", 2) + except NotFoundError: + pass + + self.assertIsNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertTrue(cb_span.error) + self.assertEqual(cb_span.ec, 1) + # Just search for the substring of the exception class + found = cb_span.data.couchbase.error.find("NotFoundError") + self.assertFalse(found == -1, "Error substring not found.") + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'replace') + + def test_replace_multi(self): + res = None + + kvs = dict() + kvs['first_test_replace_multi'] = 1 + kvs['second_test_replace_multi'] = 1 + + self.bucket.upsert('first_test_replace_multi', "one") + self.bucket.upsert('second_test_replace_multi', "two") + + with tracer.start_active_span('test'): + res = self.bucket.replace_multi(kvs) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_replace_multi'].success) + self.assertTrue(res['second_test_replace_multi'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'replace_multi') + + def test_append(self): + self.bucket.upsert("test_append", "one") + + res = None + with tracer.start_active_span('test'): + res = self.bucket.append("test_append", "two") + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'append') + + def test_append_multi(self): + res = None + + kvs = dict() + kvs['first_test_append_multi'] = "ok1" + kvs['second_test_append_multi'] = "ok2" + + self.bucket.upsert('first_test_append_multi', "one") + self.bucket.upsert('second_test_append_multi', "two") + + with tracer.start_active_span('test'): + res = self.bucket.append_multi(kvs) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_append_multi'].success) + self.assertTrue(res['second_test_append_multi'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'append_multi') + + def test_prepend(self): + self.bucket.upsert("test_prepend", "one") + + res = None + with tracer.start_active_span('test'): + res = self.bucket.prepend("test_prepend", "two") + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'prepend') + + def test_prepend_multi(self): + res = None + + kvs = dict() + kvs['first_test_prepend_multi'] = "ok1" + kvs['second_test_prepend_multi'] = "ok2" + + self.bucket.upsert('first_test_prepend_multi', "one") + self.bucket.upsert('second_test_prepend_multi', "two") + + with tracer.start_active_span('test'): + res = self.bucket.prepend_multi(kvs) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_prepend_multi'].success) + self.assertTrue(res['second_test_prepend_multi'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'prepend_multi') + + def test_get(self): + res = None + + with tracer.start_active_span('test'): + res = self.bucket.get("test-key") + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'get') + + def test_rget(self): + res = None + + try: + with tracer.start_active_span('test'): + res = self.bucket.rget("test-key", replica_index=None) + except CouchbaseTransientError: + pass + + self.assertIsNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertTrue(cb_span.error) + self.assertEqual(cb_span.ec, 1) + # Just search for the substring of the exception class + found = cb_span.data.couchbase.error.find("CouchbaseTransientError") + self.assertFalse(found == -1, "Error substring not found.") + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'rget') + + def test_get_not_found(self): + res = None + try: + self.bucket.remove('test_get_not_found') + except NotFoundError: + pass + + try: + with tracer.start_active_span('test'): + res = self.bucket.get("test_get_not_found") + except NotFoundError: + pass + + self.assertIsNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertTrue(cb_span.error) + self.assertEqual(cb_span.ec, 1) + # Just search for the substring of the exception class + found = cb_span.data.couchbase.error.find("NotFoundError") + self.assertFalse(found == -1, "Error substring not found.") + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'get') + + def test_get_multi(self): + res = None + + self.bucket.upsert('first_test_get_multi', "one") + self.bucket.upsert('second_test_get_multi', "two") + + with tracer.start_active_span('test'): + res = self.bucket.get_multi(['first_test_get_multi', 'second_test_get_multi']) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_get_multi'].success) + self.assertTrue(res['second_test_get_multi'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'get_multi') + + def test_touch(self): + res = None + self.bucket.upsert("test_touch", 1) + + with tracer.start_active_span('test'): + res = self.bucket.touch("test_touch") + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'touch') + + def test_touch_multi(self): + res = None + + self.bucket.upsert('first_test_touch_multi', "one") + self.bucket.upsert('second_test_touch_multi', "two") + + with tracer.start_active_span('test'): + res = self.bucket.touch_multi(['first_test_touch_multi', 'second_test_touch_multi']) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_touch_multi'].success) + self.assertTrue(res['second_test_touch_multi'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'touch_multi') + + def test_lock(self): + res = None + self.bucket.upsert("test_lock_unlock", "lock_this") + + with tracer.start_active_span('test'): + rv = self.bucket.lock("test_lock_unlock", ttl=5) + self.assertIsNotNone(rv) + self.assertTrue(rv.success) + + # upsert automatically unlocks the key + res = self.bucket.upsert("test_lock_unlock", "updated", rv.cas) + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(3, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "lock" + cb_lock_span = get_span_by_filter(spans, filter) + self.assertIsNotNone(cb_lock_span) + + filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "upsert" + cb_upsert_span = get_span_by_filter(spans, filter) + self.assertIsNotNone(cb_upsert_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_lock_span.t) + self.assertEqual(test_span.t, cb_upsert_span.t) + + self.assertEqual(cb_lock_span.p, test_span.s) + self.assertEqual(cb_upsert_span.p, test_span.s) + + self.assertIsNotNone(cb_lock_span.stack) + self.assertFalse(cb_lock_span.error) + self.assertIsNone(cb_lock_span.ec) + self.assertIsNotNone(cb_upsert_span.stack) + self.assertFalse(cb_upsert_span.error) + self.assertIsNone(cb_upsert_span.ec) + + self.assertEqual(cb_lock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_lock_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_lock_span.data.couchbase.type, 'lock') + self.assertEqual(cb_upsert_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_upsert_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_upsert_span.data.couchbase.type, 'upsert') + + def test_lock_unlock(self): + res = None + self.bucket.upsert("test_lock_unlock", "lock_this") + + with tracer.start_active_span('test'): + rv = self.bucket.lock("test_lock_unlock", ttl=5) + self.assertIsNotNone(rv) + self.assertTrue(rv.success) + + # upsert automatically unlocks the key + res = self.bucket.unlock("test_lock_unlock", rv.cas) + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(3, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "lock" + cb_lock_span = get_span_by_filter(spans, filter) + self.assertIsNotNone(cb_lock_span) + + filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "unlock" + cb_unlock_span = get_span_by_filter(spans, filter) + self.assertIsNotNone(cb_unlock_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_lock_span.t) + self.assertEqual(test_span.t, cb_unlock_span.t) + + self.assertEqual(cb_lock_span.p, test_span.s) + self.assertEqual(cb_unlock_span.p, test_span.s) + + self.assertIsNotNone(cb_lock_span.stack) + self.assertFalse(cb_lock_span.error) + self.assertIsNone(cb_lock_span.ec) + self.assertIsNotNone(cb_unlock_span.stack) + self.assertFalse(cb_unlock_span.error) + self.assertIsNone(cb_unlock_span.ec) + + self.assertEqual(cb_lock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_lock_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_lock_span.data.couchbase.type, 'lock') + self.assertEqual(cb_unlock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_unlock_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_unlock_span.data.couchbase.type, 'unlock') + + def test_lock_unlock_muilti(self): + res = None + self.bucket.upsert("test_lock_unlock_multi_1", "lock_this") + self.bucket.upsert("test_lock_unlock_multi_2", "lock_this") + + keys_to_lock = ("test_lock_unlock_multi_1", "test_lock_unlock_multi_2") + + with tracer.start_active_span('test'): + rv = self.bucket.lock_multi(keys_to_lock, ttl=5) + self.assertIsNotNone(rv) + self.assertTrue(rv['test_lock_unlock_multi_1'].success) + self.assertTrue(rv['test_lock_unlock_multi_2'].success) + + res = self.bucket.unlock_multi(rv) + self.assertIsNotNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(3, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "lock_multi" + cb_lock_span = get_span_by_filter(spans, filter) + self.assertIsNotNone(cb_lock_span) + + filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "unlock_multi" + cb_unlock_span = get_span_by_filter(spans, filter) + self.assertIsNotNone(cb_unlock_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_lock_span.t) + self.assertEqual(test_span.t, cb_unlock_span.t) + + self.assertEqual(cb_lock_span.p, test_span.s) + self.assertEqual(cb_unlock_span.p, test_span.s) + + self.assertIsNotNone(cb_lock_span.stack) + self.assertFalse(cb_lock_span.error) + self.assertIsNone(cb_lock_span.ec) + self.assertIsNotNone(cb_unlock_span.stack) + self.assertFalse(cb_unlock_span.error) + self.assertIsNone(cb_unlock_span.ec) + + self.assertEqual(cb_lock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_lock_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_lock_span.data.couchbase.type, 'lock_multi') + self.assertEqual(cb_unlock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_unlock_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_unlock_span.data.couchbase.type, 'unlock_multi') + + def test_remove(self): + res = None + self.bucket.upsert("test_remove", 1) + + with tracer.start_active_span('test'): + res = self.bucket.remove("test_remove") + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'remove') + + def test_remove_multi(self): + res = None + self.bucket.upsert("test_remove_multi_1", 1) + self.bucket.upsert("test_remove_multi_2", 1) + + keys_to_remove = ("test_remove_multi_1", "test_remove_multi_2") + + with tracer.start_active_span('test'): + res = self.bucket.remove_multi(keys_to_remove) + + self.assertIsNotNone(res) + self.assertTrue(res['test_remove_multi_1'].success) + self.assertTrue(res['test_remove_multi_2'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'remove_multi') + + def test_counter(self): + res = None + self.bucket.upsert("test_counter", 1) + + with tracer.start_active_span('test'): + res = self.bucket.counter("test_counter", delta=10) + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'counter') + + def test_counter_multi(self): + res = None + self.bucket.upsert("first_test_counter", 1) + self.bucket.upsert("second_test_counter", 1) + + with tracer.start_active_span('test'): + res = self.bucket.counter_multi(("first_test_counter", "second_test_counter")) + + self.assertIsNotNone(res) + self.assertTrue(res['first_test_counter'].success) + self.assertTrue(res['second_test_counter'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'counter_multi') + + def test_mutate_in(self): + res = None + self.bucket.upsert('king_arthur', {'name': 'Arthur', 'email': 'kingarthur@couchbase.com', + 'interests': ['Holy Grail', 'African Swallows']}) + + with tracer.start_active_span('test'): + res = self.bucket.mutate_in('king_arthur', + SD.array_addunique('interests', 'Cats'), + SD.counter('updates', 1)) + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'mutate_in') + + def test_lookup_in(self): + res = None + self.bucket.upsert('king_arthur', {'name': 'Arthur', 'email': 'kingarthur@couchbase.com', + 'interests': ['Holy Grail', 'African Swallows']}) + + with tracer.start_active_span('test'): + res = self.bucket.lookup_in('king_arthur', + SD.get('email'), + SD.get('interests')) + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'lookup_in') + + def test_stats(self): + res = None + + with tracer.start_active_span('test'): + res = self.bucket.stats() + + self.assertIsNotNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'stats') + + def test_ping(self): + res = None + + with tracer.start_active_span('test'): + res = self.bucket.ping() + + self.assertIsNotNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'ping') + + def test_diagnostics(self): + res = None + + with tracer.start_active_span('test'): + res = self.bucket.diagnostics() + + self.assertIsNotNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'diagnostics') + + def test_observe(self): + res = None + self.bucket.upsert('test_observe', 1) + + with tracer.start_active_span('test'): + res = self.bucket.observe('test_observe') + + self.assertIsNotNone(res) + self.assertTrue(res.success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'observe') + + def test_observe_multi(self): + res = None + self.bucket.upsert('test_observe_multi_1', 1) + self.bucket.upsert('test_observe_multi_2', 1) + + keys_to_observe = ('test_observe_multi_1', 'test_observe_multi_2') + + with tracer.start_active_span('test'): + res = self.bucket.observe_multi(keys_to_observe) + + self.assertIsNotNone(res) + self.assertTrue(res['test_observe_multi_1'].success) + self.assertTrue(res['test_observe_multi_2'].success) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'observe_multi') + + def test_raw_n1ql_query(self): + res = None + + with tracer.start_active_span('test'): + res = self.bucket.n1ql_query("SELECT 1") + + self.assertIsNotNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'n1ql_query') + self.assertEqual(cb_span.data.couchbase.sql, 'SELECT 1') + + def test_n1ql_query(self): + res = None + + with tracer.start_active_span('test'): + res = self.bucket.n1ql_query(N1QLQuery('SELECT name FROM `travel-sample` WHERE brewery_id ="mishawaka_brewing"')) + + self.assertIsNotNone(res) + + spans = self.recorder.queued_spans() + self.assertEqual(2, len(spans)) + + test_span = get_first_span_by_name(spans, 'sdk') + self.assertIsNotNone(test_span) + self.assertEqual(test_span.data.sdk.name, 'test') + + cb_span = get_first_span_by_name(spans, 'couchbase') + self.assertIsNotNone(cb_span) + + # Same traceId and parent relationship + self.assertEqual(test_span.t, cb_span.t) + self.assertEqual(cb_span.p, test_span.s) + + self.assertIsNotNone(cb_span.stack) + self.assertFalse(cb_span.error) + self.assertIsNone(cb_span.ec) + + self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') + self.assertEqual(cb_span.data.couchbase.type, 'n1ql_query') + self.assertEqual(cb_span.data.couchbase.sql, 'SELECT name FROM `travel-sample` WHERE brewery_id ="mishawaka_brewing"')