Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding pymongo functional tests #340

Merged
merged 14 commits into from
Feb 7, 2020
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ python:
# allow_failures:
# - python: '3.8-dev'

services:
- docker

install:
- pip install tox-travis

Expand Down
7 changes: 7 additions & 0 deletions ext/opentelemetry-ext-docker-tests/tests/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: '3'

services:
otmongo:
ports:
- "27017:27017"
image: mongo:latest
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Copyright 2020, OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import typing
import unittest

from pymongo import MongoClient

from opentelemetry import trace as trace_api
from opentelemetry.ext.pymongo import trace_integration
from opentelemetry.sdk.trace import Span, Tracer, TracerSource
from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor
from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
InMemorySpanExporter,
)

MONGODB_HOST = os.getenv("MONGODB_HOST ", "localhost")
MONGODB_PORT = int(os.getenv("MONGODB_PORT ", "27017"))
MONGODB_DB_NAME = os.getenv("MONGODB_DB_NAME ", "opentelemetry-tests")
MONGODB_COLLECTION_NAME = "test"


class TestFunctionalPymongo(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._tracer_source = TracerSource()
cls._tracer = Tracer(cls._tracer_source, None)
cls._span_exporter = InMemorySpanExporter()
cls._span_processor = SimpleExportSpanProcessor(cls._span_exporter)
cls._tracer_source.add_span_processor(cls._span_processor)
trace_integration(cls._tracer)
client = MongoClient(
MONGODB_HOST, MONGODB_PORT, serverSelectionTimeoutMS=2000
)
db = client[MONGODB_DB_NAME]
cls._collection = db[MONGODB_COLLECTION_NAME]

def setUp(self):
self._span_exporter.clear()

def validate_spans(self):
spans = self._span_exporter.get_finished_spans()
self.assertEqual(len(spans), 2)
for span in spans:
if span.name == "rootSpan":
root_span = span
else:
pymongo_span = span
self.assertIsInstance(span.start_time, int)
self.assertIsInstance(span.end_time, int)
self.assertIsNot(root_span, None)
self.assertIsNot(pymongo_span, None)
self.assertIsNotNone(pymongo_span.parent)
self.assertEqual(pymongo_span.parent.name, root_span.name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By this point you require pymongo_span and root_span to be defined. They may not be if spans only includes 2 spans whose name attribute is "rootSpan" or if it includes 2 spans whose name is not. If any of those happen, you'll get a NameError in a test case when you want to get only AssertionErrors. Instead for looping through spans looking for spans whose name attribute matches, it should be asserted that spans actually contains one span whose name attribute is "rootSpan" and another one whose name attribute is not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual test I wanted to include is that rootSpan is parent of other spans created, that is why I'm saving the reference for it so I can assert later, the check of an extra span being created in pymongo is already taken care in self.assertEqual(len(spans), 2) because all tests start with a rootSpan only, are you suggesting to add more check regarding these spans?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, what I am pointing out is that your test case requires self._span_exporter.get_finished_spans() to deliver you 2 spans, one named "rootSpan" and other not, and since it requires that, it is probably something that you want to specifically test.

self.assertIs(pymongo_span.kind, trace_api.SpanKind.CLIENT)
self.assertEqual(
pymongo_span.attributes["db.instance"], MONGODB_DB_NAME
)
self.assertEqual(
pymongo_span.attributes["net.peer.name"], MONGODB_HOST
)
self.assertEqual(
pymongo_span.attributes["net.peer.port"], MONGODB_PORT
)

def test_insert(self):
"""Should create a child span for insert
"""
with self._tracer.start_as_current_span("rootSpan"):
self._collection.insert_one(
{"name": "testName", "value": "testValue"}
)
self.validate_spans()

def test_update(self):
"""Should create a child span for update
"""
with self._tracer.start_as_current_span("rootSpan"):
self._collection.update_one(
{"name": "testName"}, {"$set": {"value": "someOtherValue"}}
)
self.validate_spans()

def test_find(self):
"""Should create a child span for find
"""
with self._tracer.start_as_current_span("rootSpan"):
self._collection.find_one()
self.validate_spans()

def test_delete(self):
"""Should create a child span for delete
"""
with self._tracer.start_as_current_span("rootSpan"):
self._collection.delete_one({"name": "testName"})
self.validate_spans()
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from opentelemetry.util import time_ns


class TestPymongoIntegration(unittest.TestCase):
class TestPymongo(unittest.TestCase):
def test_trace_integration(self):
mock_register = mock.Mock()
patch = mock.patch(
Expand Down
23 changes: 22 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ envlist =
py37-tracecontext
py37-{mypy,mypyinstalled}
docs
docker-tests

[travis]
python =
3.7: py37, lint, docs
3.7: py37, lint, docs, docker-tests

[testenv]
deps =
Expand Down Expand Up @@ -152,3 +153,23 @@ commands_pre =

commands =
{toxinidir}/scripts/tracecontext-integration-test.sh

[testenv:docker-tests]
deps =
pytest
docker-compose >= 1.25.2
pymongo ~= 3.1

changedir =
ext/opentelemetry-ext-docker-tests/tests

commands_pre =
pip install -e {toxinidir}/opentelemetry-api \
-e {toxinidir}/opentelemetry-sdk \
-e {toxinidir}/ext/opentelemetry-ext-pymongo
- docker-compose up -d
commands =
pytest {posargs}

commands_post =
docker-compose down