Coverage for testrail_api_reporter/publishers/slack_sender.py: 35%

1# -*- coding: utf-8 -*-

2""" Slack sender module """

3

4 import json

5

6 import requests

7

8 from ..utils.logger_config import setup_logger, DEFAULT_LOGGING_LEVEL

9 from ..utils.reporter_utils import format_error, check_captions_and_files

10

11

12 class SlackSender:

13 """Slack sender class, see for details https://api.slack.com/messaging/webhooks"""

14

15 def __init__(self, hook_url=None, timeout=5, verify=True, logger=None, log_level=DEFAULT_LOGGING_LEVEL):

16 """

17 General init

18

19 :param hook_url: url for Slack API hook, string, required

20 :param timeout: timeout for message send, integer, optional

21 :param verify: verification required, bool, optional

22 :param logger: logger object, optional

23 :param log_level: logging level, optional, by default, is 'logging.DEBUG'

24 """

25 if not logger:

26 self.___logger = setup_logger(name="SlackSender", log_file="SlackSender.log", level=log_level)

27 else:

28 self.___logger = logger

29 self.___logger.debug("Initializing Slack Sender")

30 if not hook_url:

31 raise ValueError("No Slack hook url provided, aborted!")

32 self.__hook_url = hook_url

33 self.__timeout = timeout

34 self.__verify = verify

35

36 @staticmethod

37 def __prepare_attachments(files, captions):

38 """

39 Prepares attachments

40

41 :param files: list of files (images)

42 :param captions: list of captions for files, list of strings, if not provided, no captions will be added

43 :return: list of dict with attachment info

44 """

45 legacy_attachments = []

46 for j, file in enumerate(files):

47 legacy_attachments.append(

48 {

49 "pretext": "----",

50 "text": captions[j] if captions else "",

51 "mrkdwn_in": ["text", "pretext"],

52 "image_url": file,

53 }

54 )

55 return legacy_attachments

56

57 @staticmethod

58 def __prepare_blocks(title):

59 """

60 Prepares blocks

61

62 :param title: header message title

63 :return: list of dict with blocks info

64 """

65 return [{"type": "header", "text": {"type": "plain_text", "text": title, "emoji": True}}]

66

67 def __prepare_payload(self, title, files, captions):

68 """

69 Prepares whole payload

70

71 :param title: header message title

72 :param files: list of files (images)

73 :param captions: list of captions for files, list of strings, if not provided, no captions will be added to

74 :return: json with payload

75 """

76 return json.dumps(

77 {

78 "attachments": self.__prepare_attachments(files=files, captions=captions),

79 "blocks": self.__prepare_blocks(title=title),

80 }

81 )

82

83 @staticmethod

84 def __prepare_headers():

85 """

86 Prepares headers for request itself

87

88 :return: json with headers

89 """

90 return {"Content-type": "application/json", "Accept": "text/plain"}

91

92 def send_message(self, files=None, captions=None, title="Test development & automation coverage report"):

93 """

94 Send a message to Slack

95

96 :param files: list of urls of images

97 :param captions: list of captions for files, list of strings, if not provided, no captions will be added

98 :param title: header title of message

99 :return: none

100 """

101 # check params

102 if not isinstance(files, list):

103 raise ValueError("No file list for report provided, aborted!")

104 captions = check_captions_and_files(

105 captions=captions,

106 files=files,

107 debug=self.___logger.level == DEFAULT_LOGGING_LEVEL,

108 logger=self.___logger,

109 )

110 # Send to slack

111 try:

112 response = requests.post(

113 url=self.__hook_url,

114 data=self.__prepare_payload(title=title, files=files, captions=captions),

115 timeout=self.__timeout,

116 verify=self.__verify,

117 headers=self.__prepare_headers(),

118 )

119 if response.status_code != 200:

120 raise ValueError(

121 f"Message can't be sent! Error {response.status_code}: {response.text}: "

122 f"{response.raise_for_status()}"

123 )

124 self.___logger.debug("Message sent!")

125 except Exception as error:

126 raise ValueError(f"Message can't be sent!\nError{format_error(error)}") from error