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

Implement Contract Test for Psychopg2 #72

Merged
merged 143 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 119 commits
Commits
Show all changes
143 commits
Select commit Hold shift + click to select a range
a6297d0
Test application
XinRanZhAWS Feb 23, 2024
34bbba7
test-app and basic test
XinRanZhAWS Feb 23, 2024
54dfb0b
Test application
XinRanZhAWS Feb 23, 2024
375632d
minor fix for docker
Feb 23, 2024
5d277c0
docker compose related minor fix
Feb 23, 2024
320a020
Merge branch 'main' into psychopg2-contract-test
Feb 23, 2024
7bfd827
add debug info
Feb 23, 2024
767c1e7
remove debug information
Feb 27, 2024
b2377d4
temp comment out bug line
Feb 27, 2024
a9407be
connect db network
Feb 27, 2024
4303261
connect db network
Feb 27, 2024
31e0496
connect db network
Feb 27, 2024
6a20033
connect db network
Feb 27, 2024
179dd1f
connect db network
Feb 27, 2024
5d2c04f
connect db network
Feb 27, 2024
05ebea6
connect db network
Feb 27, 2024
60cf592
connect db network
Feb 27, 2024
06bd0ca
adjust test env
Feb 27, 2024
941c621
adjust test env
Feb 27, 2024
7a48bb9
debug line
Feb 27, 2024
2c207bf
debug line
Feb 27, 2024
fc05a6b
Debug to see whats wrong
Feb 27, 2024
04a5934
Debug to see whats wrong
Feb 27, 2024
20c127b
Debug to see whats wrong
Feb 27, 2024
eecbd5c
Debug to see whats wrong
Feb 27, 2024
abdd708
Debug to see whats wrong
Feb 27, 2024
4cacb92
Debug to see whats wrong
Feb 27, 2024
6f77f8f
Debug to see whats wrong
Feb 27, 2024
195443a
Fix an issue that broke the run
Feb 28, 2024
5029ba7
Fix an issue that broke the run
Feb 28, 2024
4487d38
Fix an issue that broke the run
Feb 28, 2024
3ccffd5
init, functional
Feb 28, 2024
7d4a98f
Checkstyle fix
Feb 28, 2024
651b677
remove un-used print and local bypass
Feb 28, 2024
d08362f
Check style fix
Feb 28, 2024
f903367
Check style fix && clean resource after use
Feb 28, 2024
3ae303d
Checkstyle fix
Feb 28, 2024
0b465e9
Checkstyle fix
Feb 28, 2024
1eacd82
Checkstyle fix
Feb 28, 2024
7440369
Checkstyle fix
Feb 28, 2024
71a74d4
drop unneeded requests
Feb 29, 2024
1b6d3bc
local bypass for ec2 issue
Feb 29, 2024
8e3ecb9
try to avoid psycopg2-binary
Feb 29, 2024
abce245
use official python try to get through psychopg2 problem
Feb 29, 2024
64fcaa9
Fix issue related to test
Feb 29, 2024
2bda077
Fix issue related to test
Feb 29, 2024
04f5e0f
Fix issue related to test
Feb 29, 2024
7401b56
Fix test
Feb 29, 2024
1b80e6d
Fix test
Feb 29, 2024
622b5fb
Fix test
Feb 29, 2024
63e7bf3
Fix test
Mar 1, 2024
d8e7bd6
Fix test
Mar 1, 2024
f0a1077
Fix test
Mar 1, 2024
ccf94a2
Fix test
Mar 1, 2024
a775ca8
Fix test
Mar 1, 2024
5ba7196
Fix test
Mar 1, 2024
82d9c11
Fix test
Mar 1, 2024
3e3573d
Fix test
Mar 1, 2024
d6122ab
Fix test
Mar 1, 2024
5ed5f36
Fix test
Mar 1, 2024
1abf1d1
Fix test
Mar 1, 2024
933f2e5
Fix test
Mar 1, 2024
7390503
Fix test
Mar 1, 2024
dab6d28
Checkstyle and naming
Mar 1, 2024
83e984f
Checkstyle
Mar 1, 2024
8ce89e0
Checkstyle and naming
Mar 1, 2024
7e8a5f8
Remove unneeded debug message
Mar 1, 2024
ac74f38
Remove unneeded debug message, naming and env
Mar 1, 2024
a76d9cd
Checkstyle and
Mar 1, 2024
cfbcd94
Reflect to comment
Mar 1, 2024
a057cab
Merge branch 'main' into psychopg2-contract-test
XinRanZhAWS Mar 1, 2024
83608cf
Local bypass
Mar 1, 2024
2248bad
Remove local bypass
Mar 1, 2024
a6c29b8
Solve an issue cause non-stable workflow run
Mar 1, 2024
0699982
Merge branch 'main' into psychopg2-contract-test
Mar 1, 2024
448ed99
Solve an issue cause non-stable workflow run
Mar 1, 2024
e37fd13
use testcontainers to create postgres container
Mar 1, 2024
1d1da66
use testcontainers to create postgres container
Mar 1, 2024
9115e51
use testcontainers to create postgres container
Mar 1, 2024
5d9a3df
use testcontainers to create postgres container
Mar 1, 2024
33c0ae5
use testcontainers to create postgres container
Mar 1, 2024
088b8a5
use testcontainers to create postgres container
Mar 1, 2024
eb359fa
use testcontainers to create postgres container
Mar 1, 2024
ebfafb4
checkstyle
Mar 1, 2024
16abdb6
install dependency
Mar 1, 2024
db933f3
install dependency
Mar 1, 2024
8051291
reflect comment part 1
Mar 1, 2024
1c581fe
Clear signals after done with db setup to avoid issue
Mar 1, 2024
4a904b0
Clear signals after done with db setup to avoid issue
Mar 1, 2024
aea8b68
Clear signals after done with db setup to avoid issue
Mar 2, 2024
401230d
fix tests
Mar 2, 2024
d0c03b6
fix tests
Mar 2, 2024
1155c8d
fix tests
Mar 2, 2024
9408e48
fix tests
Mar 2, 2024
e8d7233
Adjust test behaviour
Mar 4, 2024
f560f81
Adjust test behaviour
Mar 4, 2024
df0699d
Adjust test behaviour
Mar 4, 2024
e57bceb
fix a typo
Mar 4, 2024
c04278a
Change the way test implemented
Mar 4, 2024
377e9a6
Change the way test implemented
Mar 4, 2024
1b86274
Change the way test implemented && Checkstyle
Mar 4, 2024
e2c74fb
checkstyle
XinRanZhAWS Mar 4, 2024
4b90f51
Change the way to do test
Mar 4, 2024
9db1e03
Change the way to do test
Mar 4, 2024
c69a07e
Change the way to do test
Mar 4, 2024
214c5e5
Move request test do_request to above level
Mar 4, 2024
a55a48d
Move request test do_request to above level
Mar 4, 2024
f184656
Improve integration
Mar 4, 2024
7b9cd39
Improve integration
Mar 4, 2024
1aae385
checkstyle
XinRanZhAWS Mar 4, 2024
fd52a06
checkstyle
Mar 4, 2024
7edd191
checkstyle fix
Mar 4, 2024
7ae1699
checkstyle fix
Mar 4, 2024
822d53a
checkstyle fix
Mar 4, 2024
a004c74
checkstyle
XinRanZhAWS Mar 4, 2024
b352d65
fix based on comment
Mar 4, 2024
39f298a
Merge remote-tracking branch 'origin/psychopg2-contract-test' into ps…
Mar 4, 2024
4ac6d27
fix a typo
Mar 4, 2024
b262f18
fix an issue
Mar 4, 2024
14dff5b
Update contract-tests/tests/test/amazon/psycopg2/psycopg2_test.py
XinRanZhAWS Mar 4, 2024
ecd4e3f
Update contract-tests/tests/test/amazon/psycopg2/psycopg2_test.py
XinRanZhAWS Mar 4, 2024
d8011c1
Adjust based on comments
Mar 4, 2024
1d4901c
Adjust based on comments
Mar 4, 2024
c279ff8
fix a typo
Mar 4, 2024
5835dde
move some tests based on comments
Mar 4, 2024
3c01bcf
typo fix
Mar 4, 2024
ebfa375
typo fix
Mar 4, 2024
9edafde
fix the way some test implemented
Mar 4, 2024
8fa68e2
checkstyle
XinRanZhAWS Mar 4, 2024
5c9cc13
checkstyle
Mar 4, 2024
1790ccb
debug msg
Mar 4, 2024
89333a3
add test for status_code
Mar 4, 2024
ec0f028
add test for status_code
Mar 4, 2024
d6b3b88
debug print
Mar 4, 2024
0f39d66
change behaviour for test
Mar 4, 2024
e4fbb7c
change the way test implemented
Mar 4, 2024
eb13fb8
change the way test implemented
Mar 4, 2024
7b89f5e
change the way test implemented
Mar 4, 2024
c30284e
change the way test implemented
Mar 4, 2024
d8ea43b
Pythonic
Mar 4, 2024
10bcc44
checktyle
XinRanZhAWS Mar 4, 2024
88312d0
Merge branch 'main' into psychopg2-contract-test
XinRanZhAWS Mar 4, 2024
03af765
remove a debug msg
Mar 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions contract-tests/images/applications/psycopg2/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Meant to be run from aws-otel-python-instrumentation/contract-tests.
# Assumes existence of dist/aws_opentelemetry_distro-<pkg_version>-py3-none-any.whl.
# Assumes filename of aws_opentelemetry_distro-<pkg_version>-py3-none-any.whl is passed in as "DISTRO" arg.
FROM python:3.10
thpierce marked this conversation as resolved.
Show resolved Hide resolved
WORKDIR /psycopg2
COPY ./dist/$DISTRO /psycopg2
COPY ./contract-tests/images/applications/psycopg2 /psycopg2

ENV PIP_ROOT_USER_ACTION=ignore
ARG DISTRO
RUN pip install --upgrade pip && pip install -r requirements.txt && pip install ${DISTRO} --force-reinstall
RUN opentelemetry-bootstrap -a install

# Without `-u`, logs will be buffered and `wait_for_logs` will never return.
CMD ["opentelemetry-instrument", "python", "-u", "./psycopg2_server.py"]
96 changes: 96 additions & 0 deletions contract-tests/images/applications/psycopg2/psycopg2_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
import atexit
import os
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from threading import Thread
from typing import Tuple

import psycopg2
from typing_extensions import override

_PORT: int = 8080
_SUCCESS: str = "success"
_ERROR: str = "error"
_FAULT: str = "fault"

_DB_HOST = os.getenv("DB_HOST")
_DB_USER = os.getenv("DB_USER")
_DB_PASS = os.getenv("DB_PASS")
_DB_NAME = os.getenv("DB_NAME")


def prepare_database() -> None:
conn = psycopg2.connect(dbname=_DB_NAME, user=_DB_USER, password=_DB_PASS, host=_DB_HOST)
cur = conn.cursor()
cur.execute("DROP TABLE IF EXISTS test_table")
cur.execute(
"""
CREATE TABLE test_table (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
)
"""
)

cur.execute("INSERT INTO test_table (name) VALUES (%s)", ("Alice",))
cur.execute("INSERT INTO test_table (name) VALUES (%s)", ("Bob",))

conn.commit()

cur.close()
conn.close()


class RequestHandler(BaseHTTPRequestHandler):
@override
# pylint: disable=invalid-name
def do_GET(self):
status_code: int = 200
conn = psycopg2.connect(dbname=_DB_NAME, user=_DB_USER, password=_DB_PASS, host=_DB_HOST)
if self.in_path(_SUCCESS):
cur = conn.cursor()
cur.execute("SELECT id, name FROM test_table")
rows = cur.fetchall()
cur.close()
if len(rows) == 2:
status_code = 200
else:
status_code = 400
elif self.in_path(_FAULT):
cur = conn.cursor()
try:
cur.execute("SELECT DISTINCT id, name FROM invalid_table")
except psycopg2.ProgrammingError as exception:
print("Expected Exception with Invalid SQL occurred:", exception)
status_code = 500
except Exception as exception: # pylint: disable=broad-except
print("Exception Occurred:", exception)
else:
status_code = 200
finally:
cur.close()
else:
status_code = 404
conn.close()
self.send_response_only(status_code)
self.end_headers()

def in_path(self, sub_path: str):
return sub_path in self.path


def main() -> None:
prepare_database()
server_address: Tuple[str, int] = ("0.0.0.0", _PORT)
request_handler_class: type = RequestHandler
requests_server: ThreadingHTTPServer = ThreadingHTTPServer(server_address, request_handler_class)
atexit.register(requests_server.shutdown)
server_thread: Thread = Thread(target=requests_server.serve_forever)
server_thread.start()
print("Ready")
server_thread.join()


if __name__ == "__main__":
main()
6 changes: 6 additions & 0 deletions contract-tests/images/applications/psycopg2/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
name = "psycopg2-server"
description = "Simple server that relies on psycopg2 library"
version = "1.0.0"
license = "Apache-2.0"
requires-python = ">=3.8"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
opentelemetry-distro==0.43b0
opentelemetry-exporter-otlp-proto-grpc==1.22.0
typing-extensions==4.9.0
psycopg2==2.9.9
2 changes: 1 addition & 1 deletion contract-tests/images/applications/requests/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Meant to be run from aws-otel-python-instrumentation/contract-tests.
# Assumes existence of dist/aws_opentelemetry_distro-<pkg_version>-py3-none-any.whl.
# Assumes filename of aws_opentelemetry_distro-<pkg_version>-py3-none-any.whl is passed in as "DISTRO" arg.
FROM public.ecr.aws/docker/library/python:3.11-slim
FROM python:3.10
WORKDIR /requests
COPY ./dist/$DISTRO /requests
COPY ./contract-tests/images/applications/requests /requests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def handle_request(self, method: str):
url: str = f"http://{_NETWORK_ALIAS}:{_PORT}/{_NETWORK_ALIAS}{self.path}"
response: Response = request(method, url, timeout=20)
status_code = response.status_code
print("received a " + method + " request")
thpierce marked this conversation as resolved.
Show resolved Hide resolved
self.send_response_only(status_code)
self.end_headers()

Expand Down
2 changes: 1 addition & 1 deletion contract-tests/images/mock-collector/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM public.ecr.aws/docker/library/python:3.11-slim
FROM python:3.10
WORKDIR /mock-collector
COPY . /mock-collector

Expand Down
52 changes: 51 additions & 1 deletion contract-tests/tests/test/amazon/base/contract_test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
from docker import DockerClient
from docker.models.networks import Network, NetworkCollection
from docker.types import EndpointConfig
from mock_collector_client import MockCollectorClient
from mock_collector_client import MockCollectorClient, ResourceScopeMetric, ResourceScopeSpan
from requests import Response, request
from testcontainers.core.container import DockerContainer
from testcontainers.core.waiting_utils import wait_for_logs
from typing_extensions import override

from amazon.utils.app_signals_constants import ERROR_METRIC, FAULT_METRIC, LATENCY_METRIC
from opentelemetry.proto.common.v1.common_pb2 import AnyValue

NETWORK_NAME: str = "aws-appsignals-network"

_logger: Logger = getLogger(__name__)
Expand Down Expand Up @@ -115,6 +119,39 @@ def tear_down(self) -> None:

self.mock_collector_client.clear_signals()

def do_test_requests(
self, path: str, method: str, status_code: int, expected_error: int, expected_fault: int, **kwargs
) -> None:
address: str = self.application.get_container_host_ip()
port: str = self.application.get_exposed_port(self.get_application_port())
url: str = f"http://{address}:{port}/{path}"
response: Response = request(method, url, timeout=20)

self.assertEqual(status_code, response.status_code)

resource_scope_spans: List[ResourceScopeSpan] = self.mock_collector_client.get_traces()
self._assert_aws_span_attributes(resource_scope_spans, path, **kwargs)
self._assert_semantic_conventions_span_attributes(resource_scope_spans, method, path, status_code, **kwargs)

metrics: List[ResourceScopeMetric] = self.mock_collector_client.get_metrics(
{LATENCY_METRIC, ERROR_METRIC, FAULT_METRIC}
)
self._assert_metric_attribute(metrics, LATENCY_METRIC, 5000, **kwargs)
self._assert_metric_attribute(metrics, ERROR_METRIC, expected_error, **kwargs)
self._assert_metric_attribute(metrics, FAULT_METRIC, expected_fault, **kwargs)

def _assert_str_attribute(self, attributes_dict: Dict[str, AnyValue], key: str, expected_value: str):
self.assertIn(key, attributes_dict)
actual_value: AnyValue = attributes_dict[key]
self.assertIsNotNone(actual_value)
self.assertEqual(expected_value, actual_value.string_value)

def _assert_int_attribute(self, attributes_dict: Dict[str, AnyValue], key: str, expected_value: int) -> None:
self.assertIn(key, attributes_dict)
actual_value: AnyValue = attributes_dict[key]
self.assertIsNotNone(actual_value)
self.assertEqual(expected_value, actual_value.int_value)

# pylint: disable=no-self-use
# Methods that should be overridden in subclasses
@classmethod
Expand Down Expand Up @@ -145,3 +182,16 @@ def get_application_otel_service_name(self) -> str:

def get_application_otel_resource_attributes(self) -> str:
return "service.name=" + self.get_application_otel_service_name()

def _assert_aws_span_attributes(self, resource_scope_spans: List[ResourceScopeSpan], path: str, **kwargs):
pass
thpierce marked this conversation as resolved.
Show resolved Hide resolved

def _assert_semantic_conventions_span_attributes(
self, resource_scope_spans: List[ResourceScopeSpan], method: str, path: str, status_code: int, **kwargs
):
pass

def _assert_metric_attribute(
self, resource_scope_metrics: List[ResourceScopeMetric], metric_name: str, expected_sum: int, **kwargs
):
pass
145 changes: 145 additions & 0 deletions contract-tests/tests/test/amazon/psycopg2/psycopg2_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
from typing import Dict, List

from mock_collector_client import ResourceScopeMetric, ResourceScopeSpan
from testcontainers.postgres import PostgresContainer
from typing_extensions import override

from amazon.base.contract_test_base import NETWORK_NAME, ContractTestBase
from amazon.utils.app_signals_constants import (
AWS_LOCAL_OPERATION,
AWS_LOCAL_SERVICE,
AWS_REMOTE_OPERATION,
AWS_REMOTE_SERVICE,
AWS_SPAN_KIND,
LATENCY_METRIC,
)
from opentelemetry.proto.common.v1.common_pb2 import AnyValue, KeyValue
from opentelemetry.proto.metrics.v1.metrics_pb2 import ExponentialHistogramDataPoint, Metric
from opentelemetry.proto.trace.v1.trace_pb2 import Span


class Psycopg2Test(ContractTestBase):
@override
@classmethod
def set_up_dependency_container(cls) -> None:
cls.container = (
PostgresContainer(user="dbuser", password="example", dbname="postgres")
.with_kwargs(network=NETWORK_NAME)
.with_name("mydb")
)
cls.container.start()

@override
@classmethod
def tear_down_dependency_container(cls) -> None:
cls.container.stop()

@override
def get_application_extra_environment_variables(self) -> Dict[str, str]:
return {
"DB_HOST": "mydb",
"DB_USER": "dbuser",
"DB_PASS": "example",
"DB_NAME": "postgres",
thpierce marked this conversation as resolved.
Show resolved Hide resolved
}

@override
def get_application_image_name(self) -> str:
return "aws-appsignals-tests-psycopg2-app"

def test_success(self) -> None:
self.mock_collector_client.clear_signals()
self.do_test_requests("success", "GET", 200, 0, 0, sql_command="SELECT")

def test_fault(self) -> None:
self.mock_collector_client.clear_signals()
self.do_test_requests("fault", "GET", 500, 0, 1, sql_command="SELECT DISTINCT")

@override
def _assert_aws_span_attributes(self, resource_scope_spans: List[ResourceScopeSpan], path: str, **kwargs) -> None:
target_spans: List[Span] = []
for resource_scope_span in resource_scope_spans:
# pylint: disable=no-member
if resource_scope_span.span.kind == Span.SPAN_KIND_CLIENT:
target_spans.append(resource_scope_span.span)

self.assertEqual(len(target_spans), 1)
self._assert_aws_attributes(target_spans[0].attributes, **kwargs)

@override
def _assert_aws_attributes(self, attributes_list: List[KeyValue], **kwargs) -> None:
attributes_dict: Dict[str, AnyValue] = self._get_attributes_dict(attributes_list)
self._assert_str_attribute(attributes_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
# InternalOperation as OTEL does not instrument the basic server we are using, so the client span is a local
# root.
self._assert_str_attribute(attributes_dict, AWS_LOCAL_OPERATION, "InternalOperation")
self._assert_str_attribute(attributes_dict, AWS_REMOTE_SERVICE, "postgresql")
command: str = kwargs.get("sql_command")
self._assert_str_attribute(attributes_dict, AWS_REMOTE_OPERATION, f"{command}")
# See comment above AWS_LOCAL_OPERATION
self._assert_str_attribute(attributes_dict, AWS_SPAN_KIND, "LOCAL_ROOT")

def _get_attributes_dict(self, attributes_list: List[KeyValue]) -> Dict[str, AnyValue]:
attributes_dict: Dict[str, AnyValue] = {}
for attribute in attributes_list:
key: str = attribute.key
value: AnyValue = attribute.value
if key in attributes_dict:
old_value: AnyValue = attributes_dict[key]
self.fail(f"Attribute {key} unexpectedly duplicated. Value 1: {old_value} Value 2: {value}")
attributes_dict[key] = value
return attributes_dict

@override
def _assert_semantic_conventions_span_attributes(
thpierce marked this conversation as resolved.
Show resolved Hide resolved
self, resource_scope_spans: List[ResourceScopeSpan], method: str, path: str, status_code: int, **kwargs
thpierce marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
target_spans: List[Span] = []
for resource_scope_span in resource_scope_spans:
# pylint: disable=no-member
if resource_scope_span.span.kind == Span.SPAN_KIND_CLIENT:
target_spans.append(resource_scope_span.span)

self.assertEqual(len(target_spans), 1)
self.assertEqual(target_spans[0].name, kwargs.get("sql_command").split()[0])
self._assert_semantic_conventions_attributes(target_spans[0].attributes, kwargs.get("sql_command"))

def _assert_semantic_conventions_attributes(self, attributes_list: List[KeyValue], command: str) -> None:
thpierce marked this conversation as resolved.
Show resolved Hide resolved
attributes_dict: Dict[str, AnyValue] = self._get_attributes_dict(attributes_list)
self.assertTrue(attributes_dict.get("db.statement").string_value.startswith(command))
self._assert_str_attribute(attributes_dict, "db.system", "postgresql")
self._assert_str_attribute(attributes_dict, "db.name", "postgres")

@override
def _assert_metric_attribute(
self, resource_scope_metrics: List[ResourceScopeMetric], metric_name: str, expected_sum: int, **kwargs
) -> None:
target_metrics: List[Metric] = []
for resource_scope_metric in resource_scope_metrics:
if resource_scope_metric.metric.name.lower() == metric_name.lower():
target_metrics.append(resource_scope_metric.metric)

self.assertEqual(len(target_metrics), 1)
target_metric: Metric = target_metrics[0]
dp_list: List[ExponentialHistogramDataPoint] = target_metric.exponential_histogram.data_points

self.assertEqual(len(dp_list), 2)
dp: ExponentialHistogramDataPoint = dp_list[0]
if len(dp_list[1].attributes) > len(dp_list[0].attributes):
dp = dp_list[1]
thpierce marked this conversation as resolved.
Show resolved Hide resolved
attribute_dict: Dict[str, AnyValue] = self._get_attributes_dict(dp.attributes)
self._assert_str_attribute(attribute_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
# See comment on AWS_LOCAL_OPERATION in _assert_aws_attributes
self._assert_str_attribute(attribute_dict, AWS_LOCAL_OPERATION, "InternalOperation")
self._assert_str_attribute(attribute_dict, AWS_REMOTE_SERVICE, "postgresql")
self._assert_str_attribute(attribute_dict, AWS_REMOTE_OPERATION, kwargs.get("sql_command"))
self._assert_str_attribute(attribute_dict, AWS_SPAN_KIND, "CLIENT")
self._assert_str_attribute(attribute_dict, AWS_LOCAL_SERVICE, self.get_application_otel_service_name())
XinRanZhAWS marked this conversation as resolved.
Show resolved Hide resolved

actual_sum: float = dp.sum
if metric_name is LATENCY_METRIC:
self.assertTrue(0 < actual_sum < expected_sum)
else:
self.assertEqual(actual_sum, expected_sum)
thpierce marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading