Skip to content

Commit f960f6c

Browse files
authored
Implement sending events to GA
1 parent a2ce003 commit f960f6c

File tree

7 files changed

+200
-2
lines changed

7 files changed

+200
-2
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""This package contains handles connections with external services.
2+
3+
Copyright (c) 2020 http://reportportal.io .
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""This module contains constants for the external services.
2+
3+
Copyright (c) 2020 http://reportportal.io .
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
17+
18+
import base64
19+
20+
21+
def _decode_string(text):
22+
"""Decode value of the given string.
23+
24+
:param text: Encoded string
25+
:return: Decoded value
26+
"""
27+
base64_bytes = text.encode('ascii')
28+
message_bytes = base64.b64decode(base64_bytes)
29+
return message_bytes.decode('ascii')
30+
31+
32+
GA_INSTANCE = _decode_string('VUEtMTczNDU2ODA5LTE=')
33+
GA_ENDPOINT = 'https://www.google-analytics.com/collect'
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from typing import Text
2+
3+
def _decode_string(text: Text) -> Text: ...
4+
5+
GA_INSTANCE: Text
6+
GA_ENDPOINT: Text
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""This modules contains interfaces for communications with GA.
2+
3+
Copyright (c) 2020 http://reportportal.io .
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
17+
18+
import logging
19+
from pkg_resources import get_distribution
20+
import requests
21+
from uuid import uuid4
22+
23+
from .constants import GA_INSTANCE, GA_ENDPOINT
24+
25+
logger = logging.getLogger(__name__)
26+
27+
28+
def _get_client_info():
29+
"""Get name of the client and its version.
30+
31+
:return: ('reportportal-client', '5.0.4')
32+
"""
33+
client = get_distribution('reportportal-client')
34+
return client.project_name, client.version
35+
36+
37+
def send_event(agent_name, agent_version):
38+
"""Send an event to GA about client and agent versions with their names.
39+
40+
:param agent_name: Name of the agent that uses the client
41+
:param agent_version: Version of the agent
42+
"""
43+
client_name, client_version = _get_client_info()
44+
payload = {
45+
'v': '1',
46+
'tid': GA_INSTANCE,
47+
'aip': '1',
48+
'cid': str(uuid4()),
49+
't': 'event',
50+
'ec': 'Client name "{}", version "{}"'.format(
51+
client_name, client_version
52+
),
53+
'ea': 'Start launch',
54+
'el': 'Agent name "{}", version "{}"'.format(
55+
agent_name, agent_version
56+
)
57+
}
58+
headers = {'User-Agent': 'Universal Analytics'}
59+
try:
60+
return requests.post(url=GA_ENDPOINT, data=payload, headers=headers)
61+
except requests.exceptions.RequestException as err:
62+
logger.debug('Failed to send data to Google Analytics: %s',
63+
str(err))
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from logging import Logger
2+
import requests
3+
from .constants import GA_ENDPOINT as GA_ENDPOINT, GA_INSTANCE as GA_INSTANCE
4+
from typing import Text
5+
6+
logger: Logger
7+
8+
def _get_client_info() -> tuple: ...
9+
10+
def send_event(agent_name: Text, agent_version: Text) -> requests.Response: ...

tests/test_analytics.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""This module contains unit tests for analytics used in the project.
2+
3+
Copyright (c) 2020 http://reportportal.io .
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
17+
18+
from requests.exceptions import RequestException
19+
20+
from six.moves import mock
21+
22+
from reportportal_client.external.constants import GA_ENDPOINT, GA_INSTANCE
23+
from reportportal_client.external.google_analytics import send_event
24+
25+
26+
@mock.patch('reportportal_client.external.google_analytics.uuid4',
27+
mock.Mock(return_value=555))
28+
@mock.patch('reportportal_client.external.google_analytics.requests.post')
29+
@mock.patch('reportportal_client.external.google_analytics.get_distribution')
30+
def test_send_event(mocked_distribution, mocked_requests):
31+
"""Test functionality of the send_event() function.
32+
33+
:param mocked_distribution: Mocked get_distribution() function
34+
:param mocked_requests: Mocked requests module
35+
"""
36+
expected_cl_version, expected_cl_name = '5.0.4', 'reportportal-client'
37+
agent_version, agent_name = '5.0.5', 'pytest-reportportal'
38+
mocked_distribution.return_value.version = expected_cl_version
39+
mocked_distribution.return_value.project_name = expected_cl_name
40+
41+
expected_headers = {'User-Agent': 'Universal Analytics'}
42+
43+
expected_data = {
44+
'v': '1',
45+
'tid': GA_INSTANCE,
46+
'aip': '1',
47+
'cid': '555',
48+
't': 'event',
49+
'ec': 'Client name "{}", version "{}"'.format(
50+
expected_cl_name, expected_cl_version
51+
),
52+
'ea': 'Start launch',
53+
'el': 'Agent name "{}", version "{}"'.format(
54+
agent_name, agent_version
55+
)
56+
}
57+
send_event(agent_name, agent_version)
58+
mocked_requests.assert_called_with(
59+
url=GA_ENDPOINT, data=expected_data, headers=expected_headers)
60+
61+
62+
@mock.patch('reportportal_client.external.google_analytics.uuid4',
63+
mock.Mock(return_value=555))
64+
@mock.patch('reportportal_client.external.google_analytics.requests.post',
65+
mock.Mock(side_effect=RequestException))
66+
@mock.patch('reportportal_client.external.google_analytics.get_distribution',
67+
mock.Mock())
68+
def test_send_event_raises():
69+
"""Test that the send_event() does not raise exceptions."""
70+
send_event('pytest-reportportal', '5.0.5')

tests/test_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"""This modules includes unit tests for the service.py module."""
22

33
from datetime import datetime
4+
from pkg_resources import DistributionNotFound
45

5-
import pytest
66
from delayed_assert import assert_expectations, expect
7-
from pkg_resources import DistributionNotFound
7+
import pytest
88
from six.moves import mock
99

1010
from reportportal_client.service import (

0 commit comments

Comments
 (0)