Skip to content

Commit 870b89c

Browse files
This commit contains code for Analytics Python CLI E2E Testing Tool - LIBRARIES-2434
1 parent cb3e7ff commit 870b89c

File tree

9 files changed

+210
-0
lines changed

9 files changed

+210
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ build
1010
.vscode/
1111
.idea/
1212
.python-version
13+
.venv

e2e-test/.env

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
APP_NAME='e2e-test'
2+
DEBUG_MODE = False
3+
SEND_EVENTS = True
4+
LOG_DIRECTORY='logs'
5+
LOG_FILENAME_SUFFIX='e2e-test'
6+
LOG_FORMAT='%(asctime)s - %(name)s - %(levelname)s - %(message)s'

e2e-test/README.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
2+
# Analytics Python CLI
3+
4+
This tool is created for the purpose of E2E Testing.
5+
6+
## Dependencies
7+
8+
| Module | Version |
9+
|--|--|
10+
| python | 3.9 |
11+
| click | 8.1.8 |
12+
| python-dotenv | 1.0.1 |
13+
| python-dateutil | 2.8.2 |
14+
| requests | 2.32.3 |
15+
| PyJWT | 2.10.1 |
16+
| backoff | 2.2.1 |
17+
18+
## Installation
19+
20+
1. Change the working directory
21+
```bash
22+
$ cd e2e-test
23+
```
24+
2. Create a virtual environment inside the working directory
25+
```bash
26+
$ python3 -m venv .venv
27+
```
28+
3. Enable the virtual environment
29+
```bash
30+
$ source .venv/bin/activate
31+
```
32+
4. Install dependencies
33+
```bash
34+
$ pip install -r requirements.txt
35+
```
36+
5. Install the script as a module
37+
```bash
38+
$ pip install --editable .
39+
```
40+
41+
## Usage Examples with Sample Payloads
42+
43+
### 1. Identify
44+
45+
``` bash
46+
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"anonymousId\":\"507f191e810c89729de960ea\",\"channel\":\"browser\",\"context\":{\"ip\":\"8.8.8.8\",\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36\"},\"integrations\":{\"All\":false,\"Mixpanel\":true,\"Salesforce\":true},\"messageId\":\"022bb90c-bbac-11e4-8dfc-aa07a5b093q8\",\"traits\":{\"name\":\"Clark Kent\",\"email\":\"[email protected]\",\"plan\":\"premium\",\"logins\":5,\"address\":{\"street\":\"6th St\",\"city\":\"San Francisco\",\"state\":\"CA\",\"postalCode\":\"94103\",\"country\":\"USA\"}},\"type\":\"identify\",\"userId\":\"97980cfea0062\",\"version\":\"2.0\"}"'
47+
```
48+
49+
### 2. Track
50+
51+
``` bash
52+
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"messageId\":\"122bb90c-bbac-11e4-8dfc-aa07z5b098ip\",\"userId\":\"AiUGstSDIg\",\"type\":\"track\",\"event\":\"Course Clicked\",\"context\":{\"page\":{\"path\":\"/academy/\",\"referrer\":\"\",\"search\":\"\",\"title\":\"Analytics Academy\",\"url\":\"https://segment.com/academy/\"},\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"ip\":\"108.0.78.21\"},\"integrations\":{},\"properties\":{\"title\":\"Intro to Analytics\"}}"'
53+
```
54+
55+
### 3. Page
56+
57+
``` bash
58+
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"anonymousId\":\"507f191e810c19729de860ea\",\"channel\":\"browser\",\"context\":{\"ip\":\"8.8.8.8\",\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36\"},\"integrations\":{\"All\":true,\"Mixpanel\":false,\"Salesforce\":false},\"messageId\":\"022bb90c-bbac-11e8-8dfc-aa07a5b090ol\",\"name\":\"Home\",\"properties\":{\"title\":\"Welcome | Initech\",\"url\":\"http://www.example.com\"},\"type\":\"page\",\"userId\":\"97980cfea0067\"}"'
59+
```
60+
61+
### 4. Screen
62+
63+
``` bash
64+
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"anonymousId\":\"507f191e810c19729de860ea\",\"channel\":\"browser\",\"context\":{\"ip\":\"8.8.8.8\",\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36\"},\"integrations\":{\"All\":true,\"Mixpanel\":false,\"Salesforce\":false},\"messageId\":\"022bb90c-bbac-11e4-8dfc-aa07a5b090op\",\"name\":\"Registration\",\"properties\":{\"title\":\"Welcome | Initech\",\"url\":\"http://www.example.com\"},\"type\":\"screen\",\"userId\":\"97980cfea0067\"}"'
65+
```
66+
67+
### 5. Alias
68+
69+
``` bash
70+
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"anonymousId\":\"507f191e810c19729de800ea\",\"channel\":\"browser\",\"context\":{\"ip\":\"8.8.8.8\",\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36\"},\"integrations\":{\"All\":true,\"Mixpanel\":false,\"Salesforce\":false},\"messageId\":\"022bb90c-bbac-11e4-8dfc-aa07u5b093lk\",\"previousId\":\"12345-239239-239239-23923\",\"type\":\"alias\",\"userId\":\"507f191e81\",\"version\":\"1.9\"}"'
71+
```
72+
73+
### 6. Group
74+
75+
``` bash
76+
% e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"type\":\"group\",\"groupId\":\"0e8c78ea9d97a7b8185e8632\",\"userId\":\"EMP12345\",\"traits\":{\"name\":\"Initech\",\"industry\":\"Technology\",\"employees\":329,\"plan\":\"enterprise\",\"total billed\":830}}"'
77+
```
78+
79+
## Error Logs
80+
81+
1. Errors logs are written under ```logs```directory.
82+
2. Each day, a new log directory is created under ```logs``` in ```YearMonthDay``` format.
83+
3. Log files are named as ```e2e-test_<hour-of-the-day>.log```
84+
4. Log file is rotated is maximum allowed file size is reached.
85+
86+
## Configuration Options
87+
88+
A few configuration options are available in the ```.env``` file.

e2e-test/__init__.py

Whitespace-only changes.

e2e-test/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

e2e-test/requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
click==8.1.8
2+
python-dotenv==1.0.1
3+
python-dateutil==2.8.2
4+
requests==2.32.3
5+
PyJWT==2.10.1
6+
backoff==2.2.1

e2e-test/setup.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from setuptools import setup
2+
3+
setup(
4+
name='e2e-test',
5+
version='0.1.0',
6+
py_modules=['e2e-test'],
7+
install_requires=[
8+
'click', 'python-dotenv', 'python-dateutil', 'requests', 'PyJWT', 'backoff'
9+
],
10+
entry_points={
11+
'console_scripts': [
12+
'e2e-test:run = src.cli:run',
13+
],
14+
},
15+
)

e2e-test/src/__init__.py

Whitespace-only changes.

e2e-test/src/cli.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import click
2+
from dotenv import load_dotenv
3+
import os
4+
import sys
5+
import logging
6+
from logging.handlers import RotatingFileHandler
7+
import json
8+
from datetime import datetime
9+
10+
load_dotenv()
11+
12+
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")))
13+
14+
import segment.analytics as analytics # noqa: E402 (ignore autopep8)
15+
16+
17+
@click.command()
18+
@click.option('--writeKey', type=str, help='Segment write key')
19+
@click.option('--payload', type=str, help='A JSON string that specifies the event payload.')
20+
def run(writekey, payload):
21+
analytics.write_key = writekey
22+
analytics.debug = os.getenv('DEBUG_MODE')
23+
analytics.send = os.getenv('SEND_EVENTS')
24+
logger = log_config()
25+
26+
try:
27+
# Decode the JSON payload
28+
decodedJson = json.loads(payload)
29+
data = json.loads(decodedJson)
30+
31+
specType = data.get('type') if data.get('type') is not None else None
32+
messageId = data.get('messageId') if data.get('messageId') is not None else None
33+
userId = data.get('userId') if data.get('userId') is not None else ''
34+
eventName = data.get('event') if data.get('event') is not None else None
35+
traits = data.get('traits') if data.get('traits') is not None else None
36+
properties = data.get('properties') if data.get('properties') is not None else None
37+
context = data.get('context') if data.get('context') is not None else None
38+
integrations = data.get('integrations') if data.get('integrations') is not None else None
39+
groupId = data.get('groupId') if data.get('groupId') is not None else None
40+
pageOrScreenName = data.get('name') if data.get('name') is not None else None
41+
pageOrScreenCategory = data.get('category') if data.get('category') is not None else None
42+
timestamp = data.get('timestamp') if data.get('timestamp') is not None else None
43+
anonymousId = data.get('anonymousId') if data.get('anonymousId') is not None else ''
44+
previousId = data.get('previousId') if data.get('previousId') is not None else None
45+
if specType == 'identify':
46+
analytics.identify(userId, traits, context, timestamp, anonymousId, integrations, messageId)
47+
elif specType == 'track':
48+
analytics.track(userId, eventName, properties, context, timestamp, anonymousId, integrations, messageId)
49+
elif specType == 'page':
50+
analytics.page(userId, pageOrScreenCategory, pageOrScreenName, properties,
51+
context, timestamp, anonymousId, integrations, messageId)
52+
elif specType == 'screen':
53+
analytics.screen(userId, pageOrScreenCategory, pageOrScreenName, properties,
54+
context, timestamp, anonymousId, integrations, messageId)
55+
elif specType == 'alias':
56+
analytics.alias(previousId, userId, context, timestamp, integrations, messageId)
57+
elif specType == 'group':
58+
analytics.group(userId, groupId, traits, context, timestamp, anonymousId, integrations, messageId)
59+
else:
60+
raise Exception
61+
except Exception as e:
62+
logger.exception(e)
63+
finally:
64+
analytics.flush()
65+
66+
67+
def log_config():
68+
# Create a logger object
69+
logger = logging.getLogger(os.getenv('APP_NAME'))
70+
logger.setLevel(logging.DEBUG)
71+
72+
# Create a file handler to log messages to a file
73+
log_directory = f"{os.getenv('LOG_DIRECTORY')}/{datetime.now().strftime('%Y%m%d')}"
74+
os.makedirs(log_directory, exist_ok=True)
75+
log_filename = f"{os.getenv('LOG_FILENAME_SUFFIX')}_{datetime.now().strftime('%H')}00.log"
76+
77+
# Create a rotating file handler
78+
handler = RotatingFileHandler(os.path.join(log_directory, log_filename),
79+
mode='a', maxBytes=1024*1024, backupCount=100)
80+
handler.setLevel(logging.DEBUG)
81+
82+
# Define the log message format
83+
formatter = logging.Formatter(os.getenv('LOG_FORMAT'))
84+
handler.setFormatter(formatter)
85+
86+
# Attach the handler to the logger
87+
logger.addHandler(handler)
88+
89+
return logger
90+
91+
92+
if __name__ == '__main__':
93+
run()

0 commit comments

Comments
 (0)