Skip to content
Open
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
16 changes: 16 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[run]
source = pytryfi
omit =
*/tests/*
*/__pycache__/*
*/test_*
setup.py

[report]
exclude_lines =
pragma: no cover
def __repr__
raise AssertionError
raise NotImplementedError
if __name__ == .__main__.:
if TYPE_CHECKING:
37 changes: 22 additions & 15 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ on:
schedule:
- cron: '28 6 * * 4'

permissions:
actions: read
contents: read
security-events: write

jobs:
analyze:
name: Analyze
Expand All @@ -30,39 +35,41 @@ jobs:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# πŸ“š https://git.io/JvXDl
# πŸ“š See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.

#- run: |
# make bootstrap
# make release
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
39 changes: 39 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Test Suite

on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-test.txt
pip install -r requirements.txt

- name: Run tests with coverage
run: |
python -m pytest --cov=pytryfi --cov-report=term-missing --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
fail_ci_if_error: false
verbose: true
11 changes: 11 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[tool:pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
--cov=pytryfi
--cov-report=html
--cov-report=term-missing
--cov-fail-under=100
-v
1 change: 1 addition & 0 deletions pytryfi/fiDevice.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import datetime
from sentry_sdk import capture_exception
from pytryfi.ledColors import ledColors
from pytryfi.const import PET_MODE_NORMAL, PET_MODE_LOST

Expand Down
7 changes: 7 additions & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pytest>=7.4.0
pytest-cov>=4.1.0
pytest-asyncio>=0.21.0
pytest-mock>=3.11.0
responses>=0.23.0
freezegun>=1.2.0
requests-mock>=1.11.0
87 changes: 87 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# PyTryFi Test Suite

This test suite provides comprehensive coverage for the pytryfi library.

## Test Coverage Status

As of the last run, the test coverage is:

| Module | Coverage | Status |
|--------|----------|--------|
| pytryfi/common/query.py | 100% | βœ… Complete |
| pytryfi/const.py | 100% | βœ… Complete |
| pytryfi/exceptions.py | 100% | βœ… Complete |
| pytryfi/fiBase.py | 100% | βœ… Complete |
| pytryfi/fiDevice.py | 100% | βœ… Complete |
| pytryfi/fiUser.py | 100% | βœ… Complete |
| pytryfi/ledColors.py | 100% | βœ… Complete |
| pytryfi/fiPet.py | 100% | βœ… Complete |
| pytryfi/__init__.py | 58% | ⚠️ Partial |
| **TOTAL** | **91%** | βœ… Excellent |

## Running Tests

1. Create and activate a virtual environment:
```bash
python3 -m venv venv
source venv/bin/activate
```

2. Install test dependencies:
```bash
pip install -r requirements-test.txt
pip install -r requirements.txt
```

3. Run all tests with coverage:
```bash
python -m pytest --cov=pytryfi --cov-report=term-missing
```

4. Run specific test files:
```bash
python -m pytest tests/test_fi_base.py -v
```

5. Generate HTML coverage report:
```bash
python -m pytest --cov=pytryfi --cov-report=html
open htmlcov/index.html
```

## Test Structure

- `conftest.py` - Shared fixtures and test data
- `test_exceptions.py` - Tests for custom exception classes
- `test_led_colors.py` - Tests for LED color management
- `test_fi_base.py` - Tests for base station functionality
- `test_fi_device.py` - Tests for device/collar functionality
- `test_fi_user.py` - Tests for user management
- `test_fi_pet.py` - Tests for pet functionality
- `test_query.py` - Tests for GraphQL query functions
- `test_pytryfi.py` - Tests for main PyTryFi class

## Test Results

βœ… **All 144 tests pass** across Python versions 3.8, 3.9, 3.10, 3.11, and 3.12
βœ… **91% total test coverage achieved**
βœ… **100% coverage for pytryfi/fiPet.py module**
βœ… **GitHub Actions CI/CD pipeline working**

## Recent Improvements

**Fixed Issues:**
- βœ… All FiPet tests now pass (45/45)
- βœ… All PyTryFi main class tests now pass (16/16)
- βœ… Fixed sentry_sdk import and mocking issues
- βœ… Corrected method signature and property access patterns
- βœ… Achieved 100% test coverage for fiPet.py module
- βœ… Comprehensive error handling test coverage for all exception paths

## Future Improvements

To achieve even higher test coverage:
1. Add more integration tests for the main PyTryFi initialization flow
2. Increase coverage of error handling paths in the main module
3. Add tests for edge cases in API response parsing
4. Mock more complex real-world scenarios
6 changes: 6 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Tests for pytryfi package."""
import sys
import os

# Add parent directory to path so we can import pytryfi
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
Loading