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

Create custom contact properties and verify replication of those properties #244

Merged
merged 13 commits into from
Jan 25, 2024
Merged
111 changes: 111 additions & 0 deletions tests/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import requests
from base import HubspotBaseTest
from tap_tester import LOGGER
from copy import deepcopy

DEBUG = False
BASE_URL = "https://api.hubapi.com"
Expand Down Expand Up @@ -37,6 +38,7 @@ def giveup(exc):
jitter=None,
giveup=giveup,
interval=10)

def get(self, url, params=dict()):
"""Perform a GET using the standard requests method and logs the action"""
response = requests.get(url, params=params, headers=self.HEADERS)
Expand Down Expand Up @@ -833,6 +835,107 @@ def create(self, stream, company_ids=[], subscriptions=[], times=1):
else:
raise NotImplementedError(f"There is no create_{stream} method in this dipatch!")

def create_custom_contact_properties(self):
"""Create custom contact properties of all the types"""

url = f"{BASE_URL}/properties/v1/contacts/properties"
data = []
property = {
"name": "custom_string",
"label": "A New String Custom Property",
"description": "A new string property for you",
"groupName": "contactinformation",
"type": "string",
"fieldType": "text",
"formField": True,
"displayOrder": 6,
"options": [
]
}
data.append(deepcopy(property))

property = {
"name": "custom_number",
"label": "A New Number Custom Property",
"description": "A new number property for you",
"groupName": "contactinformation",
"type": "number",
"fieldType": "text",
"formField": True,
"displayOrder": 7,
"options": [
]
}
data.append(deepcopy(property))

property = {
"name": "custom_date",
"label": "A New Date Custom Property",
"description": "A new date property for you",
"groupName": "contactinformation",
"type": "date",
"fieldType": "text",
"formField": True,
"displayOrder": 9,
"options": [
]
}
data.append(deepcopy(property))

property = {
"name": "custom_datetime",
"label": "A New Datetime Custom Property",
"description": "A new datetime property for you",
"groupName": "contactinformation",
"type": "datetime",
"fieldType": "text",
"formField": True,
"displayOrder": 10,
"options": [
]
}
data.append(deepcopy(property))

property = {
"name": "multi_pick",
"label": "multi pick",
"description": "multi select picklist test",
"groupName": "contactinformation",
"type": "enumeration",
"fieldType": "checkbox",
"hidden": False,
"options": [
{
"label": "Option A",
"value": "option_a"
},
{
"label": "Option B",
"value": "option_b"
},
{
"label": "Option C",
"value": "option_c"
}
],
"formField": True
}
data.append(deepcopy(property))
Comment on lines +880 to +932
Copy link
Contributor

Choose a reason for hiding this comment

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

It is great that you are creating a variety of data types in the custom fields. Since you went through the pain of creating them we should also use them all when creating a contact - instead of just the first two - to make sure that we support all of the types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

:) was expecting this comment.. The other types seems complicated, I'll need more time to figure out how to do. Can I write a separate card for that ?

Copy link
Contributor

Choose a reason for hiding this comment

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

sure.

# generate a contacts record

for current_data in data:
try:
response = self.post(url, current_data)
LOGGER.info("response is %s", response)
# Setting up the property is a one time task, If exception occurs because, it already exists, ignore
except Exception as DataAlreadyExistsExcp:
LOGGER.info("Data already exists for %s", current_data)
if '409' in str(DataAlreadyExistsExcp):
pass
else:
response.raise_for_status()
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think I"m communicating well enough. doing except Exception is a no-no as this is a very broad exception. We need to figure out the specific exception that is being thrown and catch that. To determine what exception is being thrown you can remove the try/except and run the test to see what exception is raised. Catch that one.

Copy link
Contributor

Choose a reason for hiding this comment

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

Exception can be used as a wildcard that catches (almost) everything. However, it is good practice to be as specific as possible with the types of exceptions that we intend to handle, and to allow any unexpected exceptions to propagate on.

https://docs.python.org/3/tutorial/errors.html

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry Harrison - I think I got it right now :) Now handling it as requests.exceptions.HTTPError



def create_contacts(self):
"""
Generate a single contacts record.
Expand All @@ -843,6 +946,14 @@ def create_contacts(self):
url = f"{BASE_URL}/contacts/v1/contact"
data = {
"properties": [
{
"property": "custom_string",
"value": "custom_string_value"
},
{
"property": "custom_number",
"value": 1567
},
Comment on lines +958 to +965
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we are setting custom properties for every call of create_contacts we need the create_custom_contact_properties to be called prior to calling the create_contacts. I see you are doing this in the test, but what about other tests that would need to add contacts, those would probably break if the custom properties were not present. I believe we should call create_custom_contact_properties in the __init__ of the client so that we call it once when it starts up instead of depending on the tester to know about this or remember to add it in each test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, creating the custom contact property is a one time task. After my first successful run of the test, it never creates and gives a 409, that's why I am skipping it. Probably doing it in init is a good idea. Will try that

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you moved it to setup. I meant the init of the client so anyone using the client makes sure it is in good shape, vs just for your test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, moved it to init

{
"property": "email",
"value": f"{record_uuid}@stitchdata.com"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_hubspot_all_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ def test_run(self):
# to our test data. We have determined that the filtering of these fields is an expected behavior.

# deals workaround for 'property_hs_date_entered_<property>' fields
bad_key_prefixes = {'property_hs_date_entered_', 'property_hs_date_exited_',
bad_key_prefixes = {'property_hs_date_entered_', 'property_hs_v2_date_entered', 'property_hs_date_exited_',
'property_hs_time_in'}
bad_keys = set()
for key in expected_keys_adjusted:
Expand Down
2 changes: 2 additions & 0 deletions tests/test_hubspot_bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ def setUp(self):
self.maxDiff = None # see all output in failure

self.test_client = TestClient(self.get_properties()['start_date'])
# Create custom properties for contacts
self.test_client.create_custom_contact_properties()

def create_test_data(self, expected_streams):
"""
Expand Down