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

Add tests #17

Merged
merged 17 commits into from
Mar 7, 2024
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
10 changes: 5 additions & 5 deletions .github/workflows/check-code-formatting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jobs:

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

- name: Set up Python 3.11
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: "3.11"

Expand All @@ -35,14 +35,14 @@ jobs:
strategy:
fail-fast: false
matrix:
python: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python: ["3.8", "3.9", "3.10", "3.11", "3.12"]

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

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

Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/test-coverage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Test coverage

on: [pull_request]

jobs:
test-coverage:
name: Test coverage
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os: ["macos-latest", "ubuntu-latest"]
python: ["3.8", "3.9", "3.10", "3.11", "3.12"]

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

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

- name: Install poetry
run: pip install poetry

- name: Install shui dependencies
run: poetry install

- name: Run unit tests
run: poetry run coverage run -m pytest -v

- name: Generate coverage report
run: poetry run coverage report -m
6 changes: 3 additions & 3 deletions .github/workflows/test-functionality.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ jobs:
fail-fast: false
matrix:
os: ["macos-latest", "ubuntu-latest"]
python: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python: ["3.8", "3.9", "3.10", "3.11", "3.12"]

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

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

Expand Down
8 changes: 6 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ classifiers = [
]

[tool.poetry.dependencies]
python = "^3.7"
python = "^3.8"
beautifulsoup4 = ">=4.12"
cleo = ">=2.0"
importlib-metadata = { version = ">=6.7", python = "<3.8" }
packaging = ">=23.0"
pathlib3x = ">=2.0"
requests = ">=2.31"
Expand All @@ -29,9 +30,12 @@ url-normalize = ">=1.4"
urllib3 = ">=2.0"

[tool.poetry.dev-dependencies]
black = ">=23.0"
black = ">=24.0"
coverage = ">=7.2"
mypy = ">=1.4"
pylint = ">=2.13"
pytest = ">=7.4"
requests-mock = ">=1.11"
types-beautifulsoup4 = ">=4.12"
types-requests = ">=2.31"
types-setuptools = ">=68.0"
Expand Down
5 changes: 3 additions & 2 deletions shui/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Base include for shui (Spark-Hadoop Unix Installer)"""
import pkg_resources

__version__ = pkg_resources.get_distribution("shui").version
from importlib import metadata

__version__ = metadata.version("shui")
1 change: 1 addition & 0 deletions shui/classes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module containing shui classes"""

from .file_with_hash import FileWithHash
from .fileinfo import FileInfo
from .version import Version
Expand Down
1 change: 1 addition & 0 deletions shui/classes/file_with_hash.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Class to contain file information for a file and its associated hash file"""

import hashlib
from typing import Iterator

Expand Down
5 changes: 4 additions & 1 deletion shui/classes/fileinfo.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Class to relate local and remote information about a Spark/Hadoop file"""

import pathlib3x as pathlib
import requests
import tqdm
Expand All @@ -23,7 +24,9 @@ def is_hashfile(self) -> bool:

def download(self) -> None:
"""Download this Spark/Hadoop version from a remote URL to a local path"""
response = requests.get(self.url, stream=True, allow_redirects=True)
response = requests.get(
self.url, stream=True, allow_redirects=True, timeout=600
)
content_length = response.headers.get("content-length")
total_bytes = int(content_length) if content_length else None
with open(self.path, "wb") as output_file:
Expand Down
1 change: 1 addition & 0 deletions shui/classes/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Class to contain information about a Spark/Hadoop version"""

import re

from packaging.version import parse as version_parse
Expand Down
1 change: 1 addition & 0 deletions shui/cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Command line entrypoint for shui application"""

from cleo.application import Application

from shui import __version__
Expand Down
1 change: 1 addition & 0 deletions shui/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Command-line applications"""

from .install_command import InstallCommand
from .versions_command import VersionsCommand

Expand Down
1 change: 1 addition & 0 deletions shui/commands/install_command.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Command-line application for installing a particular Spark/Hadoop version"""

from contextlib import suppress

import pathlib3x as pathlib
Expand Down
1 change: 1 addition & 0 deletions shui/commands/versions_command.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Command-line application for getting available Spark/Hadoop versions"""

from cleo.commands.command import Command
from cleo.helpers import option

Expand Down
1 change: 1 addition & 0 deletions shui/functions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module for functions that interact with the remote Apache server"""

from .file_details import get_file_details
from .install import extract_tarball
from .versions import get_versions
Expand Down
1 change: 1 addition & 0 deletions shui/functions/file_details.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Functions for downloading a particular version from the remote repository"""

import pathlib3x as pathlib

from shui.classes import FileInfo, FileWithHash, Version
Expand Down
1 change: 1 addition & 0 deletions shui/functions/install.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Functions for installing a particular version from a local tarball"""

import tarfile

import pathlib3x as pathlib
Expand Down
1 change: 1 addition & 0 deletions shui/functions/response.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Request with built-in retry"""

from typing import Collection

from requests import Response, Session
Expand Down
1 change: 1 addition & 0 deletions shui/functions/versions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Functions for interacting with the available versions on the remote repository"""

import re
from typing import List, Pattern

Expand Down
54 changes: 54 additions & 0 deletions tests/classes/test_file_with_hash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import pytest
from pathlib3x import Path

from shui.classes import FileInfo, FileWithHash


@pytest.fixture
def testfile(tmp_path: Path) -> FileInfo:
file_path = tmp_path / "testfile"
file_info = FileInfo("https://example.com", file_path)
with open(file_info.path, "w") as f_out:
f_out.write("content\n")
return file_info


@pytest.fixture
def testhashfile(tmp_path: Path) -> FileInfo:
file_path = tmp_path / "testfile.sha512"
file_info = FileInfo("https://example.com", file_path)
return file_info


@pytest.fixture
def filewithhash(testfile: FileInfo, testhashfile: FileInfo) -> FileWithHash:
return FileWithHash(testfile, testhashfile)


class TestFileWithHash:
def test_init(self, testfile: FileInfo) -> None:
with pytest.raises(ValueError):
FileWithHash(testfile, testfile)

def test_iter(
self, filewithhash: FileWithHash, testfile: FileInfo, testhashfile: FileInfo
) -> None:
objects = list(filewithhash)
assert len(objects) == 2
assert objects[0] == testfile
assert objects[1] == testhashfile

def test_remove(self, filewithhash: FileWithHash) -> None:
filewithhash.remove()
assert filewithhash.file.path.is_file() == False
assert filewithhash.hashfile.path.is_file() == False

def test_verify(self, filewithhash: FileWithHash) -> None:
with open(filewithhash.hashfile.path, "w") as f_out:
f_out.write(
"90eecf7b3db9ea38dda020755b28405c5267c8865e76bd9847f4f2f8c95a7ebfbe1e2c81ab9766573535389264178eda6ca951287471840115bd403668a4ec37\n"
)
assert filewithhash.verify() == True
with open(filewithhash.hashfile.path, "w") as f_out:
f_out.write("incorrect_hash")
assert filewithhash.verify() == False
40 changes: 40 additions & 0 deletions tests/classes/test_fileinfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import pytest
import requests_mock

from shui.classes import FileInfo


@pytest.fixture
def testfile(tmp_path) -> FileInfo:
file_path = tmp_path / "testfile"
return FileInfo("https://example.com", file_path)


@pytest.fixture
def testhashfile(tmp_path) -> FileInfo:
file_path = tmp_path / "testfile.sha512"
return FileInfo("https://example.com", file_path)


class TestFileInfo:
def test_download(self, testfile: FileInfo) -> None:
with requests_mock.Mocker() as request:
request.get("https://example.com", text="content")
testfile.download()
with open(testfile.path, "rb") as f_test:
content = f_test.readlines()
assert content == [b"content"]

def test_is_hashfile(self, testfile: FileInfo, testhashfile: FileInfo) -> None:
assert testfile.is_hashfile == False
assert testhashfile.is_hashfile == True

def test_is_hash_for(self, testfile: FileInfo, testhashfile: FileInfo) -> None:
assert testhashfile.is_hash_for(testfile) == True

def test_name(self, testfile: FileInfo) -> None:
assert testfile.name == "testfile"

def test_remove(self, testfile: FileInfo) -> None:
testfile.remove()
assert testfile.path.is_file() == False
29 changes: 29 additions & 0 deletions tests/classes/test_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from shui.classes import Version


class TestVersion:
version_350 = Version("spark-3.5.0-bin-hadoop3.tgz", "https://example.com")
version_351 = Version("spark-3.5.1-bin-hadoop3.tgz", "https://example.com")
version_352 = Version("spark-3.5.2-bin-hadoop3.tgz", "https://example.com")

def test_hadoop(self) -> None:
assert self.version_351.hadoop == "3"

def test_spark(self) -> None:
assert self.version_351.spark == "3.5.1"

def test_str(self) -> None:
assert (
str(self.version_351)
== "<comment>Spark</comment> (<info>3.5.1</info>) <comment>Hadoop</comment> (<info>3</info>)"
)

def test_repr(self) -> None:
assert (
repr(self.version_351)
== "<Version spark-3.5.1-bin-hadoop3.tgz https://example.com>"
)

def test_ordering(self) -> None:
ordered = sorted([self.version_351, self.version_352, self.version_350])
assert ordered == [self.version_350, self.version_351, self.version_352]
Loading