Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ build
.vscode/
.idea/
.python-version
.venv
6 changes: 6 additions & 0 deletions e2e-test/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
APP_NAME='e2e-test'
DEBUG_MODE = False
SEND_EVENTS = True
LOG_DIRECTORY='logs'
LOG_FILENAME_SUFFIX='e2e-test'
LOG_FORMAT='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
88 changes: 88 additions & 0 deletions e2e-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@

# Analytics Python CLI

This tool is created for the purpose of E2E Testing.

## Dependencies

| Module | Version |
|--|--|
| python | 3.9 |
| click | 8.1.8 |
| python-dotenv | 1.0.1 |
| python-dateutil | 2.8.2 |
| requests | 2.32.3 |
| PyJWT | 2.10.1 |
| backoff | 2.2.1 |

## Installation

1. Change the working directory
```bash
$ cd e2e-test
```
2. Create a virtual environment inside the working directory
```bash
$ python3 -m venv .venv
```
3. Enable the virtual environment
```bash
$ source .venv/bin/activate
```
4. Install dependencies
```bash
$ pip install -r requirements.txt
```
5. Install the script as a module
```bash
$ pip install --editable .
```

## Usage Examples with Sample Payloads

### 1. Identify

``` bash
$ 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\"}"'
```

### 2. Track

``` bash
$ 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\"}}"'
```

### 3. Page

``` bash
$ 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\"}"'
```

### 4. Screen

``` bash
$ 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\"}"'
```

### 5. Alias

``` bash
$ 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\"}"'
```

### 6. Group

``` bash
% 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}}"'
```

## Error Logs

1. Errors logs are written under ```logs```directory.
2. Each day, a new log directory is created under ```logs``` in ```YearMonthDay``` format.
3. Log files are named as ```e2e-test_<hour-of-the-day>.log```
4. Log file is rotated is maximum allowed file size is reached.

## Configuration Options

A few configuration options are available in the ```.env``` file.
Empty file added e2e-test/__init__.py
Empty file.
1 change: 1 addition & 0 deletions e2e-test/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

6 changes: 6 additions & 0 deletions e2e-test/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
click==8.1.8
python-dotenv==1.0.1
python-dateutil==2.8.2
requests==2.32.3
PyJWT==2.10.1
backoff==2.2.1
15 changes: 15 additions & 0 deletions e2e-test/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from setuptools import setup

setup(
name='e2e-test',
version='0.1.0',
py_modules=['e2e-test'],
install_requires=[
'click', 'python-dotenv', 'python-dateutil', 'requests', 'PyJWT', 'backoff'
],
entry_points={
'console_scripts': [
'e2e-test:run = src.cli:run',
],
},
)
Empty file added e2e-test/src/__init__.py
Empty file.
93 changes: 93 additions & 0 deletions e2e-test/src/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import click
from dotenv import load_dotenv
import os
import sys
import logging
from logging.handlers import RotatingFileHandler
import json
from datetime import datetime

load_dotenv()

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")))

import segment.analytics as analytics # noqa: E402 (ignore autopep8)


@click.command()
@click.option('--writeKey', type=str, help='Segment write key')
@click.option('--payload', type=str, help='A JSON string that specifies the event payload.')
def run(writekey, payload):
analytics.write_key = writekey
analytics.debug = os.getenv('DEBUG_MODE')
analytics.send = os.getenv('SEND_EVENTS')
logger = log_config()

try:
# Decode the JSON payload
decodedJson = json.loads(payload)
data = json.loads(decodedJson)

specType = data.get('type') if data.get('type') is not None else None
messageId = data.get('messageId') if data.get('messageId') is not None else None
userId = data.get('userId') if data.get('userId') is not None else ''
eventName = data.get('event') if data.get('event') is not None else None
traits = data.get('traits') if data.get('traits') is not None else None
properties = data.get('properties') if data.get('properties') is not None else None
context = data.get('context') if data.get('context') is not None else None
integrations = data.get('integrations') if data.get('integrations') is not None else None
groupId = data.get('groupId') if data.get('groupId') is not None else None
pageOrScreenName = data.get('name') if data.get('name') is not None else None
pageOrScreenCategory = data.get('category') if data.get('category') is not None else None
timestamp = data.get('timestamp') if data.get('timestamp') is not None else None
anonymousId = data.get('anonymousId') if data.get('anonymousId') is not None else ''
previousId = data.get('previousId') if data.get('previousId') is not None else None
if specType == 'identify':
analytics.identify(userId, traits, context, timestamp, anonymousId, integrations, messageId)
elif specType == 'track':
analytics.track(userId, eventName, properties, context, timestamp, anonymousId, integrations, messageId)
elif specType == 'page':
analytics.page(userId, pageOrScreenCategory, pageOrScreenName, properties,
context, timestamp, anonymousId, integrations, messageId)
elif specType == 'screen':
analytics.screen(userId, pageOrScreenCategory, pageOrScreenName, properties,
context, timestamp, anonymousId, integrations, messageId)
elif specType == 'alias':
analytics.alias(previousId, userId, context, timestamp, integrations, messageId)
elif specType == 'group':
analytics.group(userId, groupId, traits, context, timestamp, anonymousId, integrations, messageId)
else:
raise Exception
except Exception as e:
logger.exception(e)
finally:
analytics.flush()


def log_config():
# Create a logger object
logger = logging.getLogger(os.getenv('APP_NAME'))
logger.setLevel(logging.DEBUG)

# Create a file handler to log messages to a file
log_directory = f"{os.getenv('LOG_DIRECTORY')}/{datetime.now().strftime('%Y%m%d')}"
os.makedirs(log_directory, exist_ok=True)
log_filename = f"{os.getenv('LOG_FILENAME_SUFFIX')}_{datetime.now().strftime('%H')}00.log"

# Create a rotating file handler
handler = RotatingFileHandler(os.path.join(log_directory, log_filename),
mode='a', maxBytes=1024*1024, backupCount=100)
handler.setLevel(logging.DEBUG)

# Define the log message format
formatter = logging.Formatter(os.getenv('LOG_FORMAT'))
handler.setFormatter(formatter)

# Attach the handler to the logger
logger.addHandler(handler)

return logger


if __name__ == '__main__':
run()