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

Word cloud generator 2 #125

Closed
wants to merge 12 commits into from
Closed
5 changes: 5 additions & 0 deletions .github/workflows/black.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ jobs:
with:
src: "dns_entry_checker"

- name: Word Cloud Generator
uses: psf/black@stable
with:
src: "word_cloud_generator"

- name: JSM Metric Collection
uses: psf/black@stable
with:
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/word_cloud_generator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Word Cloud Generator Unittest

on:
push:
branches:
- master
pull_request:
paths:
- "word_cloud_generator/**"
- ".github/workflows/word_cloud_generator.yaml"

jobs:
test_with_unit_test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r word_cloud_generator/requirements.txt
- name: Test with unittest
run: |
cd word_cloud_generator
python3 -m unittest test_word_cloud_generator.py
Empty file.
29 changes: 29 additions & 0 deletions word_cloud_generator/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Word Cloud Generator

## General Info

This is a Python script that when run, creates a filter word cloud from the summary of tickets over a time period.

The script takes ~10 seconds to complete on a month of tickets

Unit tests exist which test the logic of the methods the script uses, and the tests should be run whenever changes are made to the code.

## Requirements

requests: 2.31.0
parameterized: 0.9.0
python-dateutil: 2.8.2
wordcloud: 1.9.2

## Setup
Running the script:
```
$ cd ../word_cloud_generator
$ pip install -r requirements.txt
$ python3 word_cloud_generator.py
```

Running the unit tests:
```
$ python3 -m unittest discover -s ./test -p "test_*.py"
```
5 changes: 5 additions & 0 deletions word_cloud_generator/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
requests
parameterized
python-dateutil
wordcloud
mashumaro
283 changes: 283 additions & 0 deletions word_cloud_generator/test_word_cloud_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
from unittest import mock
from unittest.mock import MagicMock, patch
from parameterized import parameterized
from datetime import datetime

import requests
import requests.auth
import word_cloud_generator
import unittest


class ChangingJson:
"""
Class to represent a json object which changes value when it's called.
"""

def __init__(self, values):
"""
Constructs the attributes for the ChangingJson object
:param values: The values for the ChangingJson to change through (list)
"""
self.values = values
self.current_index = 0

def get(self, get_value):
"""
Function to emulate the Json "Get" function while cycling through the values
:param get_value: The value to requested (any)
:return: The next value currently stored in the list (any)
"""
return_value = self.values[self.current_index].get(get_value)
if get_value == "size":
self.current_index = (self.current_index + 1) % len(self.values)
return return_value


auth = requests.auth.HTTPBasicAuth("test_username", "test_password")
headers = {
"Accept": "application/json",
}
host = "https://test.com"


class WorldCloudGeneratorTests(unittest.TestCase):
"""
Class for the test to be run against the functions from word_cloud_generator.py
"""

@parameterized.expand(
[
("check found", "something-else", True),
("check not found", b'{"status":"RUNNING"}', False),
]
)
def test_get_response_json(self, __, session_response_return_value, expected_out):
"""
Function to test the functionality of get_response_json by asserting that the function
calls a specific function or raises a Timeout error
:param __: The name of the parameter, which is thrown away (string)
:param session_response_return_value: The mocked return value for the
session response (string)
:param expected_out: The expected output of the function (bool)
"""
with mock.patch("word_cloud_generator.requests") and patch(
"word_cloud_generator.json"
):
word_cloud_generator.requests.session = MagicMock()
word_cloud_generator.requests.session.return_value.get.return_value.content = (
session_response_return_value
)

word_cloud_generator.json = MagicMock()

if expected_out:
word_cloud_generator.get_response_json(auth, headers, host)

word_cloud_generator.json.loads.assert_called_once()
else:
self.assertRaises(
requests.exceptions.Timeout,
word_cloud_generator.get_response_json,
auth,
headers,
host,
)

@parameterized.expand(
[
("dates valid", "2022-01-01", ["test1", "test2", "test3", "test4"]),
("dates invalid", "2024-01-01", []),
]
)
def test_get_issues_contents_after_time(self, __, filter_date, expected_out):
"""
Function to test the functionality of get_issues_contents_after_time by asserting
that the value returned is expected
:param __: The name of the parameter, which is thrown away (string)
:param filter_date: The mocked date to filter after (list)
:param expected_out: The expected output of the function (bool)
"""
with mock.patch("word_cloud_generator.get_response_json"), mock.patch(
"word_cloud_generator.filter_issue"
):
issue_filter = word_cloud_generator.from_user_inputs(
**{
"output": None,
"start_date": None,
"end_date": filter_date,
"word_cloud": None,
}
)
values = ChangingJson(
(
{
"values": (
{
"fields": {
"summary": "test1",
"created": "2023-01-01T00:00:00",
}
},
{
"fields": {
"summary": "test2",
"created": "2023-01-01T00:00:00",
}
},
),
"size": 50,
},
{
"values": (
{
"fields": {
"summary": "test3",
"created": "2023-01-01T00:00:00",
}
},
{
"fields": {
"summary": "test4",
"created": "2023-01-01T00:00:00",
}
},
),
"size": 32,
},
)
)
word_cloud_generator.get_response_json.return_value = values
word_cloud_generator.filter_issue.return_value = True
self.assertEqual(
word_cloud_generator.get_issues_contents_after_time(
auth,
headers,
host,
issue_filter,
),
expected_out,
)

@parameterized.expand(
[
(
"dates valid",
{
"output": None,
"end_date": None,
"word_cloud": None,
"start_date": "2024-01-01",
"assigned": "test",
},
True,
),
(
"dates invalid",
{
"output": None,
"end_date": None,
"word_cloud": None,
"start_date": "2022-01-01",
"assigned": "test",
},
False,
),
(
"assigned valid",
{
"output": None,
"end_date": None,
"word_cloud": None,
"start_date": "2024-01-01",
"assigned": "test",
},
True,
),
(
"assigned invalid",
{
"output": None,
"end_date": None,
"word_cloud": None,
"start_date": "2024-01-01",
"assigned": "test failed",
},
False,
),
]
)
def test_filter_issue(self, __, issue_filter, expected_out):
"""
Function to test the functionality of filter_issue by asserting
that the value returned is expected
:param __: The name of the parameter, which is thrown away (string)
:param issue_filter: The issue filter (dict)
:param expected_out: The expected output of the function (bool)
"""
issue = {"fields": {"assignee": {"displayName": "test"}}}
issue_date = datetime.strptime("2023-01-01", "%Y-%m-%d")
issue_filter = word_cloud_generator.from_user_inputs(**issue_filter)
self.assertEqual(
word_cloud_generator.filter_issue(
issue,
issue_filter,
issue_date,
),
expected_out,
)

def test_generate_word_cloud(self):
"""
Function to test the functionality of generate_word_cloud by asserting that the function
is called with specific inputs
"""
with mock.patch("word_cloud_generator.filter_word_cloud"), mock.patch(
"word_cloud_generator.WordCloud"
):
issues_contents = "test data"
issue_filter = ""
word_cloud_output_location = "test"
word_cloud_parameters = {
"width": 2000,
"height": 1000,
"min_font_size": 25,
"max_words": 10000,
}
word_cloud_generator.generate_word_cloud(
issues_contents,
issue_filter,
word_cloud_output_location,
**word_cloud_parameters,
)
word_cloud_generator.WordCloud.return_value.generate.assert_called_with(
word_cloud_generator.filter_word_cloud.return_value
)
word_cloud_generator.WordCloud.return_value.to_file.assert_called_with(
"test"
)

def test_filter_word_cloud(self):
"""
Function to test the functionality of generate_word_cloud by asserting that the function
returns an expected value
"""
issue_filter = word_cloud_generator.from_user_inputs(
**{
"output": None,
"start_date": None,
"end_date": None,
"word_cloud": None,
"filter_not": "delete|this",
"filter_for": "data|test|this|here|delete|not",
}
)
issues_contents = "test data delete this not here"
self.assertEqual(
word_cloud_generator.filter_word_cloud(issue_filter, issues_contents),
"test data not here",
)


if __name__ == "__main__":
unittest.main()
Loading