31
31
from robotframework_reportportal .variables import Variables
32
32
33
33
logger = logging .getLogger (__name__ )
34
- VARIABLE_PATTERN = r'^\s*\${[^}]*}\s*=\s*'
34
+ VARIABLE_PATTERN = re .compile (r'^\s*\${[^}]*}\s*=\s*' )
35
+ IMAGE_PATTERN = re .compile (
36
+ r'</td></tr><tr><td colspan="\d+"><a href="[^"]+"(?: target="_blank")?>'
37
+ r'<img src="([^"]+)" width="\d+(?:px|pt)?"/?></a>' )
38
+
39
+ DEFAULT_BINARY_FILE_TYPE = 'application/octet-stream'
35
40
TRUNCATION_SIGN = "...'"
36
41
37
42
@@ -98,7 +103,7 @@ def __init__(self) -> None:
98
103
self ._service = None
99
104
self ._variables = None
100
105
101
- def _build_msg_struct (self , message : Dict ) -> LogMessage :
106
+ def _build_msg_struct (self , message : Dict [ str , Any ] ) -> LogMessage :
102
107
"""Check if the given message comes from our custom logger or not.
103
108
104
109
:param message: Message passed by the Robot Framework
@@ -110,6 +115,44 @@ def _build_msg_struct(self, message: Dict) -> LogMessage:
110
115
msg .level = message ['level' ]
111
116
if not msg .launch_log :
112
117
msg .item_id = getattr (self .current_item , 'rp_item_id' , None )
118
+
119
+ message_str = msg .message
120
+ if is_binary (message_str ):
121
+ variable_match = VARIABLE_PATTERN .search (message_str )
122
+ if variable_match :
123
+ # Treat as partial binary data
124
+ msg_content = message_str [variable_match .end ():]
125
+ # remove trailing `'"...`, add `...'`
126
+ msg .message = (message_str [variable_match .start ():variable_match .end ()]
127
+ + str (msg_content .encode ('utf-8' ))[:- 5 ] + TRUNCATION_SIGN )
128
+ else :
129
+ # Do not log full binary data, since it's usually corrupted
130
+ content_type = guess_content_type_from_bytes (_unescape (message_str , 128 ))
131
+ msg .message = (f'Binary data of type "{ content_type } " logging skipped, as it was processed as text and'
132
+ ' hence corrupted.' )
133
+ msg .level = 'WARN'
134
+ elif message .get ('html' , 'no' ) == 'yes' :
135
+ image_match = IMAGE_PATTERN .match (message_str )
136
+ if image_match :
137
+ image_path = image_match .group (1 )
138
+ msg .message = f'Image attached: { image_path } '
139
+ if os .path .exists (image_path ):
140
+ image_type_by_name = guess_type (image_path )[0 ]
141
+ with open (image_path , 'rb' ) as fh :
142
+ image_data = fh .read ()
143
+ image_type_by_data = guess_content_type_from_bytes (image_data )
144
+ if image_type_by_name and image_type_by_data and image_type_by_name != image_type_by_data :
145
+ logger .warning (
146
+ f'Image type mismatch: type by file name "{ image_type_by_name } " '
147
+ f'!= type by file content "{ image_type_by_data } "' )
148
+ mime_type = DEFAULT_BINARY_FILE_TYPE
149
+ else :
150
+ mime_type = image_type_by_name or image_type_by_data or DEFAULT_BINARY_FILE_TYPE
151
+ msg .attachment = {
152
+ 'name' : os .path .basename (image_path ),
153
+ 'data' : image_data ,
154
+ 'mime' : mime_type
155
+ }
113
156
return msg
114
157
115
158
def _add_current_item (self , item : Union [Keyword , Launch , Suite , Test ]) -> None :
@@ -132,20 +175,6 @@ def log_message(self, message: Dict) -> None:
132
175
:param message: Message passed by the Robot Framework
133
176
"""
134
177
msg = self ._build_msg_struct (message )
135
- if is_binary (msg .message ):
136
- variable_match = re .search (VARIABLE_PATTERN , msg .message )
137
- if variable_match :
138
- # Treat as partial binary data
139
- msg_content = msg .message [variable_match .end ():]
140
- # remove trailing `'"...`, add `...'`
141
- msg .message = (msg .message [variable_match .start ():variable_match .end ()]
142
- + str (msg_content .encode ('utf-8' ))[:- 5 ] + TRUNCATION_SIGN )
143
- else :
144
- # Do not log full binary data, since it's usually corrupted
145
- content_type = guess_content_type_from_bytes (_unescape (msg .message , 128 ))
146
- msg .message = (f'Binary data of type "{ content_type } " logging skipped, as it was processed as text and'
147
- ' hence corrupted.' )
148
- msg .level = 'WARN'
149
178
logger .debug (f'ReportPortal - Log Message: { message } ' )
150
179
self .service .log (message = msg )
151
180
@@ -161,7 +190,7 @@ def log_message_with_image(self, msg: Dict, image: str):
161
190
mes .attachment = {
162
191
'name' : os .path .basename (image ),
163
192
'data' : fh .read (),
164
- 'mime' : guess_type (image )[0 ] or 'application/octet-stream'
193
+ 'mime' : guess_type (image )[0 ] or DEFAULT_BINARY_FILE_TYPE
165
194
}
166
195
logger .debug (f'ReportPortal - Log Message with Image: { mes } { image } ' )
167
196
self .service .log (message = mes )
0 commit comments