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

[DEVX:176] setup automated tests #138

Merged
merged 2 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
43 changes: 43 additions & 0 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Run tests

on:
push:
branches: [ clarifai-sdk-dev ]
pull_request:

jobs:
build:

runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: [3.8, 3.9]
exclude:
- os: macos-latest
python-version: 3.9
include:
- os: windows-latest
python-version: 3.8.10
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r tests/requirements.txt
- name: Run static analysis lint
uses: pre-commit/[email protected]
- name: Run pytest
shell: bash
run: |
pytest tests/ -n auto
2 changes: 2 additions & 0 deletions tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytest==7.1.2
pytest-xdist==2.5.0
71 changes: 71 additions & 0 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from unittest import mock
from unittest.mock import Mock

import pytest as pytest

from clarifai.client.auth.helper import ClarifaiAuthHelper, clear_cache


@pytest.fixture(autouse=True)
def clear_caches():
clear_cache()


def test_ui_default_url():
default = ClarifaiAuthHelper("clarifai", "main", "fake_pat")
assert default.ui == "https://clarifai.com"
assert default.pat == "fake_pat"


@pytest.mark.parametrize(("input_url", "expected_url"), (
("http://localhost:3002", "http://localhost:3002"),
("https://localhost:3002", "https://localhost:3002"),
("https://clarifai.com", "https://clarifai.com"),
))
def test_ui_urls(input_url, expected_url):
helper = ClarifaiAuthHelper("clarifai", "main", "fake_pat", ui=input_url)
assert helper.ui == expected_url


def test_passing_no_schema_url_use_https_when_server_is_running():

def raise_exception():
return Mock()

with mock.patch('urllib.request.urlopen', new_callable=raise_exception):
helper = ClarifaiAuthHelper("clarifai", "main", "fake_pat", ui="server")
assert helper.ui == "https://server"


def test_passing_no_schema_url_show_error_when_not_server_running():

def raise_exception():
return Mock(side_effect=Exception("http_exception"))

with mock.patch('urllib.request.urlopen', new_callable=raise_exception):
with pytest.raises(
Exception,
match="Could not get a valid response from url: localhost:3002, is the API running there?"
):
ClarifaiAuthHelper("clarifai", "main", "fake_pat", ui="localhost:3002")


def test_passing_no_schema_url_detect_http_when_SSL_in_error():

def raise_exception():
return Mock(side_effect=Exception("Has SSL in error"))

with mock.patch('urllib.request.urlopen', new_callable=raise_exception):
helper = ClarifaiAuthHelper("clarifai", "main", "fake_pat", ui="localhost:3002")
assert helper.ui == "http://localhost:3002"


def test_passing_no_schema_url_require_port():

def raise_exception():
return Mock(side_effect=Exception("Has SSL in error"))

with mock.patch('urllib.request.urlopen', new_callable=raise_exception):
with pytest.raises(
Exception, match="When providing an insecure url it must have both host:port format"):
ClarifaiAuthHelper("clarifai", "main", "fake_pat", ui="localhost")
97 changes: 97 additions & 0 deletions tests/test_stub.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from unittest import mock

import grpc
import pytest as pytest
from clarifai_grpc.grpc.api import service_pb2
from clarifai_grpc.grpc.api.status import status_code_pb2

from clarifai.client.auth.helper import ClarifaiAuthHelper, clear_cache
from clarifai.client.auth.stub import AuthorizedStub, RetryStub


class MockRpcError(grpc.RpcError):
pass


@pytest.fixture(autouse=True)
def clear_caches():
clear_cache()


def test_auth_unary_unary():
auth = ClarifaiAuthHelper("clarifai", "main", "fake_pat")
stub = AuthorizedStub(auth)
with mock.patch.object(stub.stub, 'ListInputs', spec=stub.stub.ListInputs) as mock_f:
req = service_pb2.ListInputsRequest()
req.user_app_id.app_id = 'test_auth_unary_unary'
stub.ListInputs(req)
mock_f.assert_called_with(req, metadata=auth.metadata)


def test_auth_unary_unary_future():
auth = ClarifaiAuthHelper("clarifai", "main", "fake_pat")
stub = AuthorizedStub(auth)
with mock.patch.object(stub.stub, 'ListInputs', spec=stub.stub.ListInputs) as mock_f:
req = service_pb2.ListInputsRequest()
req.user_app_id.app_id = 'test_auth_unary_unary_future'
stub.ListInputs.future(req)
mock_f.future.assert_called_with(req, metadata=auth.metadata)


def test_auth_unary_stream():
auth = ClarifaiAuthHelper("clarifai", "main", "fake_pat")
stub = AuthorizedStub(auth)
with mock.patch.object(stub.stub, 'StreamInputs', spec=stub.stub.StreamInputs) as mock_f:
req = service_pb2.StreamInputsRequest()
req.user_app_id.app_id = 'test_auth_unary_stream'
stub.StreamInputs(req)
mock_f.assert_called_with(req, metadata=auth.metadata)


def test_retry_unary_unary():
max_attempts = 5
auth = ClarifaiAuthHelper("clarifai", "main", "fake_pat")
stub = RetryStub(AuthorizedStub(auth), max_attempts=max_attempts, backoff_time=0.0001)
retry_response = service_pb2.MultiInputResponse()
retry_response.status.code = status_code_pb2.CONN_THROTTLED
success_response = service_pb2.MultiInputResponse()
success_response.status.code = status_code_pb2.SUCCESS
for nfailures in range(0, max_attempts + 1):
mock_resps = [retry_response] * nfailures + [success_response]
with mock.patch.object(
stub.stub, 'ListInputs', spec=stub.stub.stub.ListInputs, side_effect=mock_resps) as mock_f:
req = service_pb2.ListInputsRequest()
req.user_app_id.app_id = 'test_retry_unary_unary'
res = stub.ListInputs(req)
assert mock_f.call_count == min(max_attempts, len(mock_resps))
if nfailures < max_attempts:
assert res is success_response
else:
assert res is retry_response


def test_retry_grpcconn_unary_unary():
max_attempts = 5
auth = ClarifaiAuthHelper("clarifai", "main", "fake_pat")
stub = RetryStub(AuthorizedStub(auth), max_attempts=max_attempts, backoff_time=0.0001)
retry_response = service_pb2.MultiInputResponse()
retry_response.status.code = status_code_pb2.CONN_THROTTLED
success_response = service_pb2.MultiInputResponse()
success_response.status.code = status_code_pb2.SUCCESS
error = MockRpcError()
error.code = lambda: grpc.StatusCode.UNAVAILABLE
for nfailures in range(0, max_attempts + 1):
mock_resps = [error] * nfailures + [success_response]
with mock.patch.object(
stub.stub, 'ListInputs', spec=stub.stub.stub.ListInputs, side_effect=mock_resps) as mock_f:
req = service_pb2.ListInputsRequest()
req.user_app_id.app_id = 'test_retry_unary_unary'
try:
res = stub.ListInputs(req)
except Exception as e:
res = e
assert mock_f.call_count == min(max_attempts, len(mock_resps))
if nfailures < max_attempts:
assert res is success_response
else:
assert res is error
Loading