Skip to content

Commit

Permalink
[DEVX:176] setup automated tests (#138)
Browse files Browse the repository at this point in the history
* setup automated tests
  • Loading branch information
sainivedh authored Aug 2, 2023
1 parent 7b2ad6b commit 502b6df
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
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

0 comments on commit 502b6df

Please sign in to comment.