Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
b4b0a49
wip
octavian-ionescu Jan 19, 2024
e18ebe2
wip
octavian-ionescu Jan 19, 2024
91a7b36
wip
octavian-ionescu Jan 19, 2024
635aed2
xfailed / fixed unit test failures
octavian-ionescu Feb 1, 2024
637f755
skipped most of test_location.py for now (projectable relationship is…
octavian-ionescu Feb 1, 2024
86c6074
sequential run of unit tests
octavian-ionescu Feb 5, 2024
34c0fae
2 in parallel test
octavian-ionescu Feb 6, 2024
4d5d37d
2 in parallel
octavian-ionescu Feb 6, 2024
542c9e4
3 in parallel
octavian-ionescu Feb 6, 2024
4ffa722
heartbeat and publish marked as flaky, 2 runs
octavian-ionescu Feb 6, 2024
9c3eace
increased max_runs on publish multiple replies test + xfailed heartbe…
octavian-ionescu Feb 6, 2024
1239119
4 in parallel + flaky hub test
octavian-ionescu Feb 6, 2024
7780f00
increased flaky allowance for publish tests to 5 runs
octavian-ionescu Feb 6, 2024
4725faf
increased flaky allowance for publish tests to max 10 runs
octavian-ionescu Feb 6, 2024
adcd562
bogus_000
octavian-ionescu Feb 6, 2024
e0127a2
all in parallel - retry
octavian-ionescu Feb 6, 2024
b8fa0ed
skipped some hub tests, all run in parallel
octavian-ionescu Feb 6, 2024
38e1924
skipped some more hub tests, all run in parallel
octavian-ionescu Feb 6, 2024
5311681
skipped some more hub tests, all run in parallel
octavian-ionescu Feb 6, 2024
075b49e
all run in parallel
octavian-ionescu Feb 6, 2024
d3a714b
flaky test in component
octavian-ionescu Feb 6, 2024
3564a56
more flaky tests
octavian-ionescu Feb 6, 2024
5380029
more flaky and xfailed tests
octavian-ionescu Feb 6, 2024
f9dcda3
reinstated hub tests
octavian-ionescu Feb 6, 2024
c55de48
xfailed some assert tests
octavian-ionescu Feb 6, 2024
cc97ef5
flaky-ed some tests
octavian-ionescu Feb 6, 2024
98285c4
flaky-ed some tests
octavian-ionescu Feb 6, 2024
3173b17
flaky-ed some tests
octavian-ionescu Feb 6, 2024
b5aca93
timer test - reverted
octavian-ionescu Feb 7, 2024
90ac8a3
timer test - flaky
octavian-ionescu Feb 7, 2024
92f4529
timer test - xfail
octavian-ionescu Feb 7, 2024
4a8ad2f
wip_test_timer.py
octavian-ionescu Feb 7, 2024
7a6ba52
wip_generate_unique_name
octavian-ionescu Feb 7, 2024
42dd116
wip_reverted test timer
octavian-ionescu Feb 7, 2024
fcab79a
typo
octavian-ionescu Feb 7, 2024
9670c6f
fixed test_timer.py
octavian-ionescu Feb 7, 2024
6ebcb60
fixed test_timer.py
octavian-ionescu Feb 7, 2024
9eef3b7
fixed test_timer.py
octavian-ionescu Feb 7, 2024
398d781
wip: fixing test_custom_attribute.py
octavian-ionescu Feb 7, 2024
ff19494
wip: fixing test_custom_attribute.py
octavian-ionescu Feb 7, 2024
34c11d5
wip: fixing test_custom_attribute.py
octavian-ionescu Feb 7, 2024
7e820b6
wip: fixing test_custom_attribute.py
octavian-ionescu Feb 7, 2024
4278a68
wip: fixed test_custom_attribute.py
octavian-ionescu Feb 7, 2024
64ae93c
wip: fixing test_asset_version.py
octavian-ionescu Feb 7, 2024
64b59e5
wip: fixing test_asset_version.py
octavian-ionescu Feb 7, 2024
ccdbe13
wip: fixing test_asset_version.py
octavian-ionescu Feb 7, 2024
137da96
fixed test_asset_version
octavian-ionescu Feb 7, 2024
8334f58
fixed test_asset_version
octavian-ionescu Feb 7, 2024
3e6fbac
fixed test_collection.py
octavian-ionescu Feb 7, 2024
b9e1933
fixing test_component.py
octavian-ionescu Feb 7, 2024
206267a
fixing test_component.py
octavian-ionescu Feb 7, 2024
d49c436
fixing test_session.py
octavian-ionescu Feb 7, 2024
54b8219
fixed test_user.py
octavian-ionescu Feb 7, 2024
78950aa
fixing test_session.py
octavian-ionescu Feb 7, 2024
8c5896f
fixed test_user.py
octavian-ionescu Feb 7, 2024
f8eb0b5
fixing test_session.py
octavian-ionescu Feb 7, 2024
b1375fc
fixing test_session.py
octavian-ionescu Feb 7, 2024
4879e46
fixed test_location.py
octavian-ionescu Feb 8, 2024
356f580
fixed test_location.py
octavian-ionescu Feb 8, 2024
7e184dc
fixed test_location.py
octavian-ionescu Feb 8, 2024
48744e4
fixed test_session.py
octavian-ionescu Feb 8, 2024
c6ebb25
fixed test_session.py
octavian-ionescu Feb 8, 2024
ab1376a
wip: fixing test_hub.py
octavian-ionescu Feb 9, 2024
7e2341f
wip: fixed test_hub.py
octavian-ionescu Feb 9, 2024
3e43cd2
wip: fixed test_hub.py
octavian-ionescu Feb 9, 2024
18d6486
wip: fixing test_hub.py
octavian-ionescu Feb 9, 2024
1491316
wip: fixing test_session and test_collection.py
octavian-ionescu Feb 9, 2024
739ce42
wip: fixing test_session.py
octavian-ionescu Feb 9, 2024
4c0c093
wip: fixing test_session.py
octavian-ionescu Feb 9, 2024
97a3955
wip: fixing test_session.py
octavian-ionescu Feb 9, 2024
c500fcf
wip: fixing test_session.py
octavian-ionescu Feb 9, 2024
89dfdf4
wip: fixing test_component.py
octavian-ionescu Feb 9, 2024
0e20049
wip: fixing fixtures
octavian-ionescu Feb 9, 2024
6e79f7e
wip: fixing test_location.py
octavian-ionescu Feb 9, 2024
6d0b0c1
simplified timer duplicate error handling
octavian-ionescu Feb 13, 2024
cf34b7e
server path configurable via secrets
octavian-ionescu Feb 16, 2024
cf9f038
cicd - style
octavian-ionescu Feb 16, 2024
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
13 changes: 3 additions & 10 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- main
tags:
- "v*"

pull_request:

jobs:
Expand All @@ -16,24 +17,16 @@ jobs:
matrix:
python-version: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
runs-on: ubuntu-latest
container: python:${{ matrix.python-version }}
services:
ftrack:
image: ftrackdocker/test-server:latest
credentials:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
ports:
- 80:80
steps:
- uses: actions/checkout@v3
- name: Run pytest
run: |
python setup.py test
env:
FTRACK_SERVER: http://ftrack:80
FTRACK_SERVER: ${{ secrets.FTRACK_SERVER }}
FTRACK_API_USER: ${{ secrets.FTRACK_API_USER }}
FTRACK_API_KEY: ${{ secrets.FTRACK_API_KEY_UNITTEST }}

build:
runs-on: ubuntu-latest
name: Build package distribution
Expand Down
2 changes: 1 addition & 1 deletion source/ftrack_api/entity/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def start_timer(self, context=None, comment='', name=None, force=False):
try:
self.session.commit()
except ftrack_api.exception.ServerError as error:
if 'IntegrityError' in str(error):
if 'DuplicateEntryError' in str(error):
raise ftrack_api.exception.NotUniqueError(
('Failed to start a timelog for user with id: {0}, it is '
'likely that a timer is already running. Either use '
Expand Down
Binary file modified test/fixture/media/image-resized-10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 53 additions & 4 deletions test/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,15 +384,64 @@ def cleanup():


@pytest.fixture()
def new_asset_version(request, session):
def new_asset_version_with_component(request, session, new_task, unique_name):
'''Return a new asset version with one component attached.'''
asset_parent = new_task['parent']
asset_type = session.query('AssetType').first()

asset = session.create('Asset', {
'name': unique_name,
'type': asset_type,
'parent': asset_parent
})
asset_version = session.create('AssetVersion', {
'asset_id': asset['id'],
'asset': asset,
'task': new_task
})
component = session.create('Component', {
'name': unique_name,
'version_id': asset_version['id'],
})
session.commit()

def cleanup():
'''Remove created entities.'''
session.delete(component)
session.delete(asset_version)
session.delete(asset)
session.commit()

request.addfinalizer(cleanup)

return asset_version


@pytest.fixture()
def new_asset_version(request, session, new_task, unique_name):
'''Return a new asset version.'''
asset_parent = new_task['parent']
asset_type = session.query('AssetType').first()

asset = session.create('Asset', {
'name': unique_name,
'type': asset_type,
'parent': asset_parent
})
asset_version = session.create('AssetVersion', {
'asset_id': 'dd9a7e2e-c5eb-11e1-9885-f23c91df25eb'
'asset_id': asset['id'],
'asset': asset,
'task': new_task
})
session.commit()

# Do not cleanup the version as that will sometimes result in a deadlock
# database error.
def cleanup():
'''Remove created entities.'''
session.delete(asset_version)
session.delete(asset)
session.commit()

request.addfinalizer(cleanup)

return asset_version

Expand Down
6 changes: 3 additions & 3 deletions test/unit/entity/test_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ def image_path():

return image_path

def test_create_task_thumbnail(task, image_path):
def test_create_task_thumbnail(new_task, image_path):
'''Successfully create thumbnail component and set as task thumbnail.'''
component = task.create_thumbnail(image_path)
component = new_task.create_thumbnail(image_path)
component.session.commit()
assert component['id'] == task['thumbnail_id']
assert component['id'] == new_task['thumbnail_id']


def test_create_thumbnail_with_data(task, image_path, unique_name):
Expand Down
26 changes: 19 additions & 7 deletions test/unit/entity/test_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,8 @@ def decode(self, resource_identifier, context=None):
def new_location(request, session, unique_name, temporary_directory):
'''Return new managed location.'''

from builtins import str

location = session.create(str('Location'), {
str('name'): str('test-location-{}'.format(unique_name))
location = session.create('Location', {
'name': 'test-location-{}'.format(unique_name)
})


Expand All @@ -72,8 +70,15 @@ def new_location(request, session, unique_name, temporary_directory):

def cleanup():
'''Remove created entity.'''

location_components = session.query(
'ComponentLocation where location_id is {0}'.format(
location['id']
)
).all()

# First auto-remove all components in location.
for location_component in location['location_components']:
for location_component in location_components:
session.delete(location_component)

# At present, need this intermediate commit otherwise server errors
Expand Down Expand Up @@ -108,8 +113,14 @@ def new_unmanaged_location(request, session, unique_name):

def cleanup():
'''Remove created entity.'''
location_components = session.query(
'ComponentLocation where location_id is {0}'.format(
location['id']
)
).all()

# First auto-remove all components in location.
for location_component in location['location_components']:
for location_component in location_components:
session.delete(location_component)

# At present, need this intermediate commit otherwise server errors
Expand Down Expand Up @@ -547,4 +558,5 @@ def test_transfer_component_from_server(
assert (
multi_location.get_component_availability(server_image_component)
== 100.0
)
)

6 changes: 3 additions & 3 deletions test/unit/event/event_hub_server_heartbeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from ftrack_api.event.base import Event


TOPIC = 'test_event_hub_server_heartbeat'
RECEIVED = []


Expand All @@ -25,6 +24,7 @@ def main(arguments=None):
'''Publish and receive heartbeat test.'''
parser = argparse.ArgumentParser()
parser.add_argument('mode', choices=['publish', 'subscribe'])
parser.add_argument('topic')

namespace = parser.parse_args(arguments)
logging.basicConfig(level=logging.INFO)
Expand Down Expand Up @@ -56,15 +56,15 @@ def main(arguments=None):

for counter in range(1, message_count + 1):
session.event_hub.publish(
Event(topic=TOPIC, data=dict(counter=counter))
Event(topic=namespace.topic, data=dict(counter=counter))
)
print('Sent message {0}'.format(counter))

if counter < message_count:
time.sleep(sleep_time_per_message)

elif namespace.mode == 'subscribe':
session.event_hub.subscribe('topic={0}'.format(TOPIC), callback)
session.event_hub.subscribe('topic={0}'.format(namespace.topic), callback)
session.event_hub.wait(
duration=(
((message_count - 1) * sleep_time_per_message) + 15
Expand Down
19 changes: 12 additions & 7 deletions test/unit/event/test_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import sys
import requests
import logging
import uuid

import pytest
from flaky import flaky
Expand Down Expand Up @@ -676,14 +677,15 @@ def replier(event):
'''Replier.'''
return 'Replied'

event_hub.subscribe('topic=test', replier)
topic_name = 'test_{0}'.format(uuid.uuid4())
event_hub.subscribe('topic={0}'.format(topic_name), replier)

called = {'callback': None}

def on_reply(event):
called['callback'] = event['data']

event_hub.publish(Event(topic='test'), on_reply=on_reply)
event_hub.publish(Event(topic=topic_name), on_reply=on_reply)
event_hub.wait(2)

assert called['callback'] == 'Replied'
Expand All @@ -700,15 +702,16 @@ def replier_two(event):
'''Replier.'''
return 'Two'

event_hub.subscribe('topic=test', replier_one)
event_hub.subscribe('topic=test', replier_two)
topic_name = 'test_{0}'.format(uuid.uuid4())
event_hub.subscribe('topic={0}'.format(topic_name), replier_one)
event_hub.subscribe('topic={0}'.format(topic_name), replier_two)

called = {'callback': []}

def on_reply(event):
called['callback'].append(event['data'])

event_hub.publish(Event(topic='test'), on_reply=on_reply)
event_hub.publish(Event(topic=topic_name), on_reply=on_reply)
event_hub.wait(2)

assert sorted(called['callback']) == ['One', 'Two']
Expand All @@ -719,15 +722,17 @@ def test_server_heartbeat_response():
test_script = os.path.join(
os.path.dirname(__file__), 'event_hub_server_heartbeat.py'
)
# set the topic name to something unique
topic = 'test_event_hub_server_heartbeat_{0}'.format(uuid.uuid4())

# Start subscriber that will listen for all three messages.
subscriber = subprocess.Popen([sys.executable, test_script, 'subscribe'])
subscriber = subprocess.Popen([sys.executable, test_script, 'subscribe', topic])

# Give subscriber time to connect to server.
time.sleep(10)

# Start publisher to publish three messages.
publisher = subprocess.Popen([sys.executable, test_script, 'publish'])
publisher = subprocess.Popen([sys.executable, test_script, 'publish', topic])

publisher.wait()
subscriber.wait()
Expand Down
26 changes: 8 additions & 18 deletions test/unit/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ def test_ensure_entity_with_non_string_data_types(session, mocker):
datetime = arrow.get()

task = session.query('Task').first()
# if session.api_user contained '@', we'd need to work some more on queries.
user = session.query(
'User where username is {}'.format(session.api_user)
).first()
Expand Down Expand Up @@ -1328,7 +1329,7 @@ def get_versions(sessions):
)


def test_query_nested(session):
def test_query_nested(session, new_asset_version_with_component):
'''Query components nested and update a value and query again.

This test will query components via 2 relations, then update the
Expand All @@ -1343,19 +1344,13 @@ def test_query_nested(session):

query = (
'select versions.components.name from Asset where id is '
'"12939d0c-6766-11e1-8104-f23c91df25eb"'
'{0}'.format(new_asset_version_with_component['asset_id'])
)

def get_version(session):
'''Return the test version from *session*.'''
asset = session.query(query).first()
asset_version = None
for version in asset['versions']:
if version['version'] == 8:
asset_version = version
break

return asset_version
return asset['versions'][0]

asset_version = get_version(session_one)
asset_version2 = get_version(session_two)
Expand Down Expand Up @@ -1400,7 +1395,7 @@ def test_merge_iterations(session, mocker, project):
pytest.param(lambda component, asset_version, asset: asset['versions'], id='from_asset')
]
)
def test_query_nested2(session, get_versions):
def test_query_nested2(session, new_asset_version_with_component, get_versions):
'''Query version.asset.versions from component and then add new version.

This test will query versions via multiple relations and ensure a new
Expand All @@ -1413,15 +1408,10 @@ def test_query_nested2(session, get_versions):
auto_connect_event_hub=False
)

# Get a random component that is linked to a version and asset.
component_id = session_two.query(
'FileComponent where version.asset_id != None'
).first()['id']

# Get a component that is linked to a version and asset.
component_id = new_asset_version_with_component['components'][0]['id']
query = (
'select version.asset.versions from Component where id is "{}"'.format(
component_id
)
'select version.asset.versions from Component where id is "{}"'.format(component_id)
)

component = session_one.query(query).one()
Expand Down