Skip to content

Commit

Permalink
test stability once more, after completely refactoring tests base cla…
Browse files Browse the repository at this point in the history
…sses
  • Loading branch information
Paul Philion committed Mar 5, 2024
1 parent 59caf17 commit a7f5cab
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 150 deletions.
1 change: 1 addition & 0 deletions cog_tickets.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ async def thread_ticket(self, ctx: discord.ApplicationContext, ticket_id:int):
# TODO message templates
note = f"Created Discord thread: {thread.name}: {thread.jump_url}"
user = self.redmine.user_mgr.find_discord_user(ctx.user.name)
log.debug(f">>> found {user} for {ctx.user.name}")
self.redmine.enable_discord_sync(ticket.id, user, note)

await ctx.respond(f"Created new thread for {ticket.id}: {thread}") # todo add some fancy formatting
Expand Down
17 changes: 7 additions & 10 deletions imap.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def set_token(self, token):

class Message():
"""email message"""
from_address: str
subject:str
attachments: list[Attachment]
note: str

def __init__(self, from_addr:str, subject:str):
self.from_address = from_addr
self.subject = subject
Expand Down Expand Up @@ -251,16 +256,8 @@ def handle_message(self, msg_id:str, message:Message):
log.info(f"Updated ticket #{ticket.id} with message from {user.login} and {len(message.attachments)} attachments")
else:
# no open tickets, create new ticket for the email message
self.redmine.create_ticket(user, subject, message.note, message.attachments)
log.info(f"Created new ticket for: {user.login}, {subject}, with {len(message.attachments)} attachments")

"""
# check status
if self.user_mgr.is_blocked(user):
log.debug(f"Rejecting ticket #{ticket.id} based on blocked user {user.login}")
self.reject_ticket(ticket.id)
refresh.
"""
ticket = self.redmine.create_ticket(user, subject, message.note, message.attachments)
log.info(f"Created new ticket for: {ticket}, with {len(message.attachments)} attachments")


def synchronize(self):
Expand Down
35 changes: 19 additions & 16 deletions redmine.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,15 @@

class RedmineException(Exception):
"""redmine exception"""
def __init__(self, message: str, request_id: str) -> None:
def __init__(self, message: str, request_id: str = "-") -> None:
super().__init__(message + ", req_id=" + request_id)
self.request_id = request_id


class Client(): ## redmine.Client
class Client():
"""redmine client"""
def __init__(self, url: str, token: str):
self.url = url
if self.url is None:
raise RedmineException("Unable to load REDMINE_URL", "[n/a]")

self.token = token
if self.url is None:
raise RedmineException("Unable to load REDMINE_TOKEN", "__init__")

session:RedmineSession = RedmineSession(url, token)
def __init__(self, session:RedmineSession):
self.url = session.url
self.user_mgr:UserManager = UserManager(session)
self.ticket_mgr:TicketManager = TicketManager(session)

Expand All @@ -54,15 +46,26 @@ def __init__(self, url: str, token: str):
@classmethod
def fromenv(cls):
url = os.getenv('REDMINE_URL')
if url is None:
raise RedmineException("Unable to load REDMINE_URL")

token = os.getenv('REDMINE_TOKEN')
return cls(url, token)
if token is None:
raise RedmineException("Unable to load REDMINE_TOKEN")

return cls(RedmineSession(url, token))


def create_ticket(self, user, subject, body, attachments=None):
return self.ticket_mgr.create(user, subject, body, attachments)
def create_ticket(self, user, subject, body, attachments=None) -> Ticket:
ticket = self.ticket_mgr.create(user, subject, body, attachments)
# check user status, reject the ticket if blocked
if self.user_mgr.is_blocked(user):
log.debug(f"Rejecting ticket #{ticket.id} based on blocked user {user.login}")
ticket = self.ticket_mgr.reject_ticket(ticket.id)
return ticket


def update_ticket(self, ticket_id:int, fields:dict, user_login:str=None):
def update_ticket(self, ticket_id:int, fields:dict, user_login:str|None=None):
return self.ticket_mgr.update(ticket_id, fields, user_login)


Expand Down
26 changes: 14 additions & 12 deletions session.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import logging
from urllib3.exceptions import ConnectTimeoutError
import requests
from requests.exceptions import ConnectTimeout, ConnectionError
from requests.exceptions import ConnectTimeout

import dotenv

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -47,8 +48,12 @@ def fromenv(cls):

return cls(url, token)

@classmethod
def fromenvfile(cls):
dotenv.load_dotenv()
return cls.fromenv()

def get_headers(self, impersonate_id:str=None):
def get_headers(self, impersonate_id:str|None=None):
headers = {
'User-Agent': 'netbot/0.0.1', # TODO update to project version, and add version management
'Content-Type': 'application/json',
Expand All @@ -62,11 +67,9 @@ def get_headers(self, impersonate_id:str=None):
return headers


def get(self, query_str:str, user:str=None):
def get(self, query_str:str, impersonate_id:str|None=None):
"""run a query against a redmine instance"""

headers = self.get_headers(user)

headers = self.get_headers(impersonate_id)
try:
r = self.session.get(f"{self.url}{query_str}", headers=headers, timeout=TIMEOUT)

Expand All @@ -83,19 +86,18 @@ def get(self, query_str:str, user:str=None):
return None


# data=json.dumps(data),
def put(self, resource: str, data:dict, user_login: str = None) -> None:
def put(self, resource: str, data:str, impersonate_id:str|None=None) -> None:
r = self.session.put(f"{self.url}{resource}",
data=data,
timeout=TIMEOUT,
headers=self.get_headers(user_login))
headers=self.get_headers(impersonate_id))
if r.ok:
log.debug(f"PUT {resource}: {data} - {r}")
log.debug(f"PUT {resource}: {data}")
else:
raise RedmineException(f"POST {resource} by {user_login} failed, status=[{r.status_code}] {r.reason}", r.headers['X-Request-Id'])
raise RedmineException(f"POST {resource} by {impersonate_id} failed, status=[{r.status_code}] {r.reason}", r.headers['X-Request-Id'])


def post(self, resource: str, data:dict = None, user_login: str = None, files = None) -> dict:
def post(self, resource: str, data:str, user_login: str|None = None, files: list|None = None) -> dict|None:
r = self.session.post(f"{self.url}{resource}",
data=data,
files=files,
Expand Down
14 changes: 7 additions & 7 deletions test_cog_scn.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async def test_team_join_leave(self):

# check add result
#ctx.respond.assert_called_with(
# f"Discord user: {self.discord_user} has been paired with redmine user: {self.user.login}")
# f"Discord user: {self.user.discord_id} has been paired with redmine user: {self.user.login}")

# reindex using cog
ctx = self.build_context()
Expand All @@ -52,7 +52,7 @@ async def test_team_join_leave(self):
# 4.5 check reindex result, and lookup based on login and discord id
ctx.respond.assert_called_with("Rebuilt redmine indices.")
self.assertIsNotNone(self.redmine.user_mgr.find(self.user.login))
self.assertIsNotNone(self.redmine.user_mgr.find(self.discord_user))
self.assertIsNotNone(self.redmine.user_mgr.find(self.user.discord_id))

# join team users
ctx = self.build_context()
Expand All @@ -63,13 +63,13 @@ async def test_team_join_leave(self):

# confirm via mock callback and API
#ctx.respond.assert_called_with(f"Unknown team name: {test_team_name}") # unknown team response!
ctx.respond.assert_called_with(f"**{self.discord_user}** has joined *{test_team_name}*")
ctx.respond.assert_called_with(f"**{self.user.discord_id}** has joined *{test_team_name}*")
self.assertTrue(self.redmine.user_mgr.is_user_in_team(self.user, test_team_name), f"{self.user.login} not in team {test_team_name}")

# confirm in team via cog teams response
ctx = self.build_context()
await self.cog.teams(ctx, test_team_name)
self.assertIn(self.full_name, str(ctx.respond.call_args))
self.assertIn(self.user.full_name(), str(ctx.respond.call_args))

# leave team users
ctx = self.build_context()
Expand All @@ -78,12 +78,12 @@ async def test_team_join_leave(self):

# confirm via API and callback
self.assertFalse(self.redmine.user_mgr.is_user_in_team(self.user, test_team_name), f"{self.user.login} *in* team {test_team_name}")
ctx.respond.assert_called_with(f"**{self.discord_user}** has left *{test_team_name}*")
ctx.respond.assert_called_with(f"**{self.user.discord_id}** has left *{test_team_name}*")

# confirm not in team via cog teams response
ctx = self.build_context()
await self.cog.teams(ctx, test_team_name)
self.assertNotIn(self.full_name, str(ctx.respond.call_args))
self.assertNotIn(self.user.full_name(), str(ctx.respond.call_args))


async def test_thread_sync(self):
Expand Down Expand Up @@ -148,7 +148,7 @@ async def test_locked_during_sync_ticket(self):
message = unittest.mock.AsyncMock(discord.Message)
message.content = f"This is a new note about ticket #{ticket.id} for test {self.tag}"
message.author = unittest.mock.AsyncMock(discord.Member)
message.author.name = self.discord_user
message.author.name = self.user.discord_id

thread = unittest.mock.AsyncMock(discord.Thread)
thread.name = f"Ticket #{ticket.id}: {ticket.subject}"
Expand Down
2 changes: 1 addition & 1 deletion test_cog_tickets.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async def test_thread_sync(self):
thread.name = f"Ticket #{ticket.id}: {subject}"

member = unittest.mock.AsyncMock(discord.Member)
member.name=self.discord_user
member.name=self.user.discord_id

message = unittest.mock.AsyncMock(discord.Message)
message.channel = ctx.channel
Expand Down
7 changes: 3 additions & 4 deletions test_netbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"""NetBot Test Suite"""

import unittest
from unittest import mock
import logging

import discord
Expand Down Expand Up @@ -48,7 +47,7 @@ async def test_synchronize_ticket(self):
message = unittest.mock.AsyncMock(discord.Message)
message.content = f"This is a new note about ticket #{ticket.id} for test {self.tag}"
message.author = unittest.mock.AsyncMock(discord.Member)
message.author.name = self.discord_user
message.author.name = self.user.discord_id

thread = unittest.mock.AsyncMock(discord.Thread)
thread.name = f"Ticket #{ticket.id}"
Expand All @@ -62,7 +61,7 @@ async def test_synchronize_ticket(self):

# assert method send called on mock thread, with the correct values
self.assertIn(self.tag, thread.send.call_args.args[0])
self.assertIn(self.full_name, thread.send.call_args.args[0])
self.assertIn(self.user.full_name(), thread.send.call_args.args[0])
self.assertIn(body, thread.send.call_args.args[0])

# get notes from redmine, assert tags in most recent
Expand All @@ -85,7 +84,7 @@ async def test_sync_ticket_long_message(self):
message = unittest.mock.AsyncMock(discord.Message)
message.content = f"This is a new note about ticket #{ticket.id} for test {self.tag}"
message.author = unittest.mock.AsyncMock(discord.Member)
message.author.name = self.discord_user
message.author.name = self.user.discord_id

thread = unittest.mock.AsyncMock(discord.Thread)
thread.name = f"Ticket #{ticket.id}"
Expand Down
28 changes: 15 additions & 13 deletions test_redmine.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from dotenv import load_dotenv

import redmine
import session
import test_utils


Expand All @@ -29,27 +30,28 @@ def test_block_user(self):
self.user_mgr.unblock(self.user)
self.assertFalse(self.user_mgr.is_blocked(self.user))

"""

def test_blocked_create_ticket(self):
try:
# block
self.user_mgr.block(self.user)
self.assertTrue(self.redmine.user_mgr.is_blocked(self.user))
# block
self.user_mgr.block(self.user)
self.assertTrue(self.user_mgr.is_blocked(self.user))

# create ticket for blocked
ticket = self.create_ticket(self.user, "subject", "body")
self.assertEqual("Reject", ticket.status.name)
# create ticket for blocked
ticket = self.create_test_ticket()
self.assertIsNotNone(ticket)
self.assertEqual("Reject", ticket.status.name)

finally:
# remove the test user
self.redmine.user_mgr.remove(user)
"""
# remove the ticket and unbluck the user
self.tickets_mgr.remove(ticket.id)
self.user_mgr.unblock(self.user)
self.assertFalse(self.user_mgr.is_blocked(self.user))


def test_client_timeout(self):
# construct an invalid client to try to get a timeout
try:
client = redmine.Client("http://192.168.1.42/", "bad-token")
bad_session = session.RedmineSession("http://192.168.1.42/", "bad-token")
client = redmine.Client(bad_session)
self.assertIsNotNone(client)
#log.info(client)
except Exception:
Expand Down
Loading

0 comments on commit a7f5cab

Please sign in to comment.