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

# 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

| Command Option | Type | Description | Required |
|--|--|--|--|
| --writeKey | String | Segment Write Key | Yes |
| --apiHost | String | Custom Host | No |
| --payload | JSON | Event Payload | Yes |

### Example: Passing Multiple Events as JSON Array

```bash
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --apiHost='' --payload='"[{\"anonymousId\":\"507f191e810c89729de960ea\",\"channel\":\"browser\",\"context\":{\"app\":\"ecommerce\"},\"integrations\":{\"All\":false,\"Mixpanel\":true,\"Salesforce\":true},\"messageId\":\"022ty90c-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\":\"AiUGstSDIg\",\"version\":\"2.0\"},{\"messageId\":\"122bb9ui-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/\"}},\"integrations\":{},\"properties\":{\"title\":\"Intro to Analytics\"}}]"'
```

### Example: Passing Individual Events

#### 1. Identify

``` bash
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"anonymousId\":\"507f191e810c89729de960ea\",\"channel\":\"browser\",\"context\":{\"app\":\"ecommerce\"},\"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/\"}},\"integrations\":{},\"properties\":{\"title\":\"Intro to Analytics\"}}"'
```

#### 3. Page

``` bash
$ e2e-test:run --writeKey='YOUR_WRITE_KEY' --payload='"{\"anonymousId\":\"507f191e810c19729de860ea\",\"channel\":\"browser\",\"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\",\"integrations\":{\"All\":true,\"Mixpanel\":false,\"Salesforce\":false},\"messageId\":\"022bb90c-bbac-11e8-8dfc-aa07a5b090ol\",\"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\",\"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='"{\"anonymousId\":\"507f191e810c19729de800ea\",\"channel\":\"browser\",\"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\"}"'
```

## 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.
102 changes: 102 additions & 0 deletions e2e-test/src/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import click
from dotenv import load_dotenv
import os
import sys
import logging
import json
from collections.abc import Iterable

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')
Copy link
Contributor

Choose a reason for hiding this comment

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

We'd also like to have an --apihost option

Copy link
Author

Choose a reason for hiding this comment

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

Done

@click.option('--apiHost', type=str, help='Custom host')
@click.option('--payload', type=str, help='A JSON string that specifies the event payload.')
def run(writekey, payload, apihost=None):
analytics.write_key = writekey

if apihost is not None:
analytics.host = apihost # Set custom host

analytics.debug = os.getenv('DEBUG_MODE')
analytics.send = os.getenv('SEND_EVENTS')
logger = log_config()

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

# To ensure for loop do not raise exception when individual JSON is passed
# we are converting the payload to a List having a single Dictionary as its item

if not isinstance(dataObject, Iterable): # Check if dataObject is non-iterable
dataObject = [dataObject]
elif isinstance(dataObject, dict): # Check if dataObject is a dictionary
dataObject = [dataObject]

# Iterate over each item in the payload JSON
for data in dataObject:

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)

handler = logging.StreamHandler()
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()