Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-nbxmpp for openSUSE:Factory 
checked in at 2023-06-05 18:06:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-nbxmpp (Old)
 and      /work/SRC/openSUSE:Factory/.python-nbxmpp.new.15902 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-nbxmpp"

Mon Jun  5 18:06:13 2023 rev:42 rq:1089734 version:4.3.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-nbxmpp/python-nbxmpp.changes      
2023-03-27 18:15:40.878916975 +0200
+++ /work/SRC/openSUSE:Factory/.python-nbxmpp.new.15902/python-nbxmpp.changes   
2023-06-05 18:06:15.603010476 +0200
@@ -1,0 +2,18 @@
+Sun May 28 21:40:08 UTC 2023 - Alexei Sorokin <sor.ale...@meowr.ru>
+
+- Update to version 4.3.1:
+  * HTTP: Abort correctly on content overflow.
+  * Websocket: Always set peer certificate.
+
+-------------------------------------------------------------------
+Fri May 26 19:23:13 UTC 2023 - Alexei Sorokin <sor.ale...@meowr.ru>
+
+- Update to version 4.3.0:
+  * Add option to force http1.
+  * Add method to generate XMPP IRIs.
+  * Lower log level for missing GSSAPI dependency.
+  * OMEMO: Add device id and namespace to OMEMOBundle.
+  * Don’t delete session object in cleanup().
+  * HTTP: Don’t accept content encoding.
+
+-------------------------------------------------------------------

Old:
----
  python-nbxmpp-4.2.2.tar.bz2

New:
----
  python-nbxmpp-4.3.1.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-nbxmpp.spec ++++++
--- /var/tmp/diff_new_pack.nDPoPr/_old  2023-06-05 18:06:16.671016783 +0200
+++ /var/tmp/diff_new_pack.nDPoPr/_new  2023-06-05 18:06:16.679016830 +0200
@@ -24,7 +24,7 @@
 %endif
 %define _name   nbxmpp
 Name:           python-nbxmpp
-Version:        4.2.2
+Version:        4.3.1
 Release:        0
 Summary:        XMPP library by Gajim team
 License:        GPL-3.0-or-later

++++++ python-nbxmpp-4.2.2.tar.bz2 -> python-nbxmpp-4.3.1.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/.gitlab-ci.yml 
new/python-nbxmpp-4.3.1/.gitlab-ci.yml
--- old/python-nbxmpp-4.2.2/.gitlab-ci.yml      2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/.gitlab-ci.yml      2023-05-28 23:18:18.000000000 
+0200
@@ -4,6 +4,7 @@
   - test
   - build
   - deploy
+  - publish
 
 test-pylint:
   stage: test
@@ -58,7 +59,11 @@
     exit_codes:
       - 100
   script:
-    - release-helper nightly-check
+    - |
+      if [ "$FORCE_DEB_DEPLOY" != "true" ]
+      then
+        release-helper nightly-check
+      fi
     - >
       release-helper deploy-to-ftp \
         --host=$FTP_HOST \
@@ -66,3 +71,17 @@
         --password=$FTP_PASS \
         --directory=debian/nbxmpp/"$(date +'%Y%m%d')" \
         debian_build
+
+publish-release:
+  image: nbxmpp-publish:latest
+  stage: publish
+  dependencies: []
+  rules:
+    - if: '$CI_COMMIT_TAG'
+  script:
+    - >
+      release-helper create-release \
+        $CI_PROJECT_ID \
+        $CI_RELEASE_TOKEN \
+        --version=$CI_COMMIT_TAG \
+        --tag=$CI_COMMIT_TAG
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/ChangeLog 
new/python-nbxmpp-4.3.1/ChangeLog
--- old/python-nbxmpp-4.2.2/ChangeLog   2023-03-25 17:33:26.000000000 +0100
+++ new/python-nbxmpp-4.3.1/ChangeLog   2023-05-28 23:18:18.000000000 +0200
@@ -1,3 +1,30 @@
+nbxmpp 4.3.1 (28 May 2023)
+
+  Bug Fixes
+
+  * HTTP: Abort correctly on content overflow
+  * Websocket: Always set peer certificate
+
+nbxmpp 4.3.0 (21 May 2023)
+
+  New
+
+  * Add option to force http1
+  * Add method to generate XMPP IRIs
+
+  Improvements
+
+  * Lower log level for missing GSSAPI dependency
+
+  Change
+
+  * OMEMO: Add device id and namespace to OMEMOBundle
+
+  Bug Fixes
+
+  * Don’t delete session object in cleanup()
+  * HTTP: Don’t accept content encoding (#143)
+
 nbxmpp 4.2.2 (25 Mar 2023)
 
   Bug Fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/__init__.py 
new/python-nbxmpp-4.3.1/nbxmpp/__init__.py
--- old/python-nbxmpp-4.2.2/nbxmpp/__init__.py  2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/__init__.py  2023-05-28 23:18:18.000000000 
+0200
@@ -3,4 +3,4 @@
 
 from .protocol import *  # pylint: disable=wrong-import-position
 
-__version__: str = '4.2.2'
+__version__: str = '4.3.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/const.py 
new/python-nbxmpp-4.3.1/nbxmpp/const.py
--- old/python-nbxmpp-4.2.2/nbxmpp/const.py     2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/const.py     2023-05-28 23:18:18.000000000 
+0200
@@ -462,6 +462,9 @@
     CONTENT_OVERFLOW = 4
     TIMEOUT = 5
 
+    def __str__(self) -> str:
+        return self.name
+
 
 MOODS = [
     'afraid',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/http.py 
new/python-nbxmpp-4.3.1/nbxmpp/http.py
--- old/python-nbxmpp-4.2.2/nbxmpp/http.py      2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/http.py      2023-05-28 23:18:18.000000000 
+0200
@@ -50,6 +50,7 @@
 CHUNK_SIZE = 32768
 DEFAULT_USER_AGENT = f'nbxmpp/{nbxmpp.__version__}'
 SIGNAL_ACTIONS = GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION
+MIN_SOUP_3_3_0 = Soup.check_version(3, 3, 0)
 
 
 class HTTPLogAdapter(logging.LoggerAdapter):
@@ -59,10 +60,10 @@
 
 class HTTPSession:
     def __init__(self, user_agent: str = DEFAULT_USER_AGENT) -> None:
-
         self._session = Soup.Session()
         self._session.set_user_agent(user_agent)
         self._session.add_feature_by_type(Soup.ContentSniffer)
+        self._session.remove_feature_by_type(Soup.ContentDecoder)
 
     def get_soup_session(self) -> Soup.Session:
         return self._session
@@ -73,8 +74,8 @@
 
         self._session.set_proxy_resolver(resolver)
 
-    def create_request(self) -> HTTPRequest:
-        return HTTPRequest(self)
+    def create_request(self, force_http1: bool = False) -> HTTPRequest:
+        return HTTPRequest(self, force_http1=force_http1)
 
 
 class HTTPRequest(GObject.GObject):
@@ -90,7 +91,10 @@
         'destroy': (SIGNAL_ACTIONS, None, ()),
     }
 
-    def __init__(self, session: HTTPSession) -> None:
+    def __init__(self,
+                 session: HTTPSession,
+                 force_http1: bool = False
+                 ) -> None:
         GObject.GObject.__init__(self)
 
         self._log = HTTPLogAdapter(log, extra={'request': self})
@@ -126,6 +130,8 @@
         self._emit_response_progress = False
 
         self._message = Soup.Message()
+        if MIN_SOUP_3_3_0:
+            self._message.set_force_http1(force_http1)
         self._user_data = None
 
         self._log.info('Created')
@@ -278,6 +284,7 @@
         self._message.connect('got-body', self._on_got_body)
         self._message.connect('restarted', self._on_restarted)
         self._message.connect('finished', self._on_finished)
+        self._message.connect('got-headers', self._on_got_headers)
 
         soup_session = self._session.get_soup_session()
         soup_session.send_async(self._message,
@@ -301,6 +308,8 @@
 
     def _on_timeout(self) -> None:
         self._timeout_reached = True
+        self._timeout_id = None
+        self._set_error(HTTPRequestError.TIMEOUT)
         self.cancel()
 
     def _on_response(self,
@@ -308,6 +317,8 @@
                      result: Gio.AsyncResult
                      ) -> None:
 
+        self._log.info('HTTP version: %s',
+                       self._message.get_http_version().value_name)
         self._log.info('Request response received')
         try:
             self._input_stream = session.send_finish(result)
@@ -343,6 +354,7 @@
     def _on_bytes_read_result(self,
                               input_stream: Gio.InputStream,
                               result: Gio.AsyncResult) -> None:
+
         try:
             data = input_stream.read_bytes_finish(result)
         except GLib.Error as error:
@@ -360,10 +372,8 @@
             self._finish_read()
             return
 
-        length = len(bytes_)
-        self._received_size += length
-        if self._received_size > self._response_content_length:
-            self._finish_read(HTTPRequestError.CONTENT_OVERFLOW)
+        self._received_size += len(bytes_)
+        if self._check_content_overflow():
             return
 
         if self._output_stream is None:
@@ -382,12 +392,7 @@
                 return
 
         self._read_async()
-
-        if (self._emit_response_progress and
-                self._message.get_method() == 'GET'):
-            self.emit('response-progress',
-                      self._received_size / self._response_content_length)
-
+        self._emit_progress()
 
     def _finish_read(self, error: Optional[HTTPRequestError] = None) -> None:
         self._log.info('Finished reading')
@@ -404,11 +409,7 @@
                             ) -> None:
 
         # Signal is only raised when there is content in the response
-
         headers = message.get_response_headers()
-
-        self._response_content_length = headers.get_content_length()
-
         if content_type is None:
             # According to the docs, content_type is None when the sniffer
             # decides to trust the content-type sent by the server.
@@ -416,14 +417,19 @@
 
         self._response_content_type = content_type or ''
 
-        self._log.info('Sniffed: content-type: %s, content-length: %s',
-                       self._response_content_type,
-                       self._response_content_length)
+        self._log.info('Sniffed: content-type: %s',
+                       self._response_content_type)
 
         self.emit('content-sniffed',
                   self._response_content_length,
                   self._response_content_type)
 
+    def _on_got_headers(self, message: Soup.Message) -> None:
+        headers = message.get_response_headers()
+        self._response_content_length = headers.get_content_length()
+        self._log.info('Got Headers: content-length: %s',
+                       self._response_content_length)
+
     def _on_got_body(self, _message: Soup.Message) -> None:
         # This signal tells us that the full body was received.
         # The `finished` signal is not a sure indicator if the message body
@@ -432,11 +438,28 @@
         self._log.info('Body received')
         self._body_received = True
 
+    def _emit_progress(self) -> None:
+        if not self._emit_response_progress:
+            return
+
+        if not self._message.get_method() == 'GET':
+            return
+
+        self.emit('response-progress',
+                  self._received_size / self._response_content_length)
+
+    def _check_content_overflow(self) -> bool:
+        if self._received_size > self._response_content_length:
+            self._finish_read(HTTPRequestError.CONTENT_OVERFLOW)
+            return True
+        return False
+
     def _on_restarted(self, _message: Soup.Message) -> None:
         self._log.info('Restarted')
         self._body_received = False
         self._response_content_type = ''
         self._response_content_length = 0
+        self._received_size = 0
 
     def _on_finished(self, _message: Soup.Message) -> None:
         self._log.info('Message finished')
@@ -469,14 +492,17 @@
 
         self._set_complete()
 
+    def _set_error(self, error: HTTPRequestError) -> None:
+        self._log.info('Set Error: %s', error)
+        self._error = error
+
     def _set_failed(self, error: HTTPRequestError) -> None:
         self._log.info('Set Failed: %s', error)
         self._is_finished = True
-        if self._timeout_reached:
-            self._timeout_id = None
-            self._error = HTTPRequestError.TIMEOUT
-        else:
-            self._error = error
+
+        if self._error is None:
+            self._set_error(error)
+
         self._close_all_streams()
         self.emit('finished')
         self._cleanup()
@@ -516,7 +542,6 @@
         self._message.run_dispose()
 
         del self._cancellable
-        del self._session
         del self._user_data
 
         if self._timeout_id is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/modules/omemo.py 
new/python-nbxmpp-4.3.1/nbxmpp/modules/omemo.py
--- old/python-nbxmpp-4.2.2/nbxmpp/modules/omemo.py     2023-03-25 
17:33:26.000000000 +0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/modules/omemo.py     2023-05-28 
23:18:18.000000000 +0200
@@ -161,7 +161,7 @@
         if not items:
             yield task.set_result(None)
 
-        yield _parse_bundle(items[0])
+        yield _parse_bundle(items[0], device_id)
 
 
 def _parse_omemo_message(stanza):
@@ -235,7 +235,7 @@
     return OMEMOMessage(sid=sid, iv=iv, keys=keys, payload=payload)
 
 
-def _parse_bundle(item):
+def _parse_bundle(item, device_id):
     '''
     <item id='current'>
       <bundle xmlns='eu.siacs.conversations.axolotl'>
@@ -317,7 +317,9 @@
 
         result['otpks'].append({'key': key, 'id': id_})
 
-    return OMEMOBundle(**result)
+    return OMEMOBundle(**result,
+                       device_id=device_id,
+                       namespace=Namespace.OMEMO_TEMP)
 
 
 def _make_bundle(bundle):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/protocol.py 
new/python-nbxmpp-4.3.1/nbxmpp/protocol.py
--- old/python-nbxmpp-4.2.2/nbxmpp/protocol.py  2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/protocol.py  2023-05-28 23:18:18.000000000 
+0200
@@ -38,6 +38,12 @@
 from gi.repository import GLib
 
 import idna
+from nbxmpp.xmppiri import escape_ifragment
+from nbxmpp.xmppiri import escape_inode
+from nbxmpp.xmppiri import escape_ires
+from nbxmpp.xmppiri import escape_ivalue
+from nbxmpp.xmppiri import validate_ikey
+from nbxmpp.xmppiri import validate_querytype
 from nbxmpp.simplexml import Node
 from nbxmpp.namespaces import Namespace
 from nbxmpp.stringprep import nodeprep
@@ -315,6 +321,7 @@
 STREAM_UNSUPPORTED_STANZA_TYPE = 'urn:ietf:params:xml:ns:xmpp-streams 
unsupported-stanza-type'
 ERR_FORBIDDEN = 'urn:ietf:params:xml:ns:xmpp-stanzas forbidden'
 
+
 def isResultNode(node):
     """
     Return true if the node is a positive reply
@@ -768,6 +775,45 @@
             return f'{localpart}@{self.domain}{domain_encoded}'
         return f'{localpart}@{self.domain}/{self.resource}{domain_encoded}'
 
+    def to_iri(self,
+               query: Optional[str | tuple[str, list[tuple[str, str]]]] = None,
+               fragment: Optional[str] = None
+               ) -> str:
+
+        if self.localpart:
+            inode = escape_inode(self.localpart)
+            ipathxmpp = f'{inode}@{self.domain}'
+        else:
+            ipathxmpp = f'{self.domain}'
+
+        if self.resource is not None:
+            ires = escape_ires(self.resource)
+            ipathxmpp = f'{ipathxmpp}/{ires}'
+
+        iri = f'xmpp:{ipathxmpp}'
+
+        if query is not None:
+            if isinstance(query, str):
+                querytype = query
+                queryparams = None
+            else:
+                querytype, queryparams = query
+
+            iquerytype = validate_querytype(querytype)
+            iri += f'?{iquerytype}'
+
+            if queryparams is not None:
+                for ikey, ivalue in queryparams:
+                    ivalue = escape_ivalue(ivalue)
+                    ikey = validate_ikey(ikey)
+                    iri += f';{ikey}={ivalue}'
+
+        if fragment is not None:
+            ifragment = escape_ifragment(fragment)
+            iri += f'#{ifragment}'
+
+        return iri
+
     def copy(self) -> JID:
         deprecation_warning('copy() is not needed, JID is immutable')
         return self
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/sasl.py 
new/python-nbxmpp-4.3.1/nbxmpp/sasl.py
--- old/python-nbxmpp-4.2.2/nbxmpp/sasl.py      2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/sasl.py      2023-05-28 23:18:18.000000000 
+0200
@@ -41,7 +41,7 @@
     gssapi = __import__('gssapi')
     GSSAPI_AVAILABLE = True
 except (ImportError, OSError) as error:
-    log.warning('GSSAPI not available: %s', error)
+    log.info('GSSAPI not available: %s', error)
     GSSAPI_AVAILABLE = False
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/structs.py 
new/python-nbxmpp-4.3.1/nbxmpp/structs.py
--- old/python-nbxmpp-4.2.2/nbxmpp/structs.py   2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/structs.py   2023-05-28 23:18:18.000000000 
+0200
@@ -732,6 +732,8 @@
     spk_signature: bytes
     ik: bytes
     otpks: list[dict[str, str]]
+    device_id: int = -1
+    namespace: str = Namespace.OMEMO_TEMP
 
     def pick_prekey(self) -> dict[str, str]:
         return random.SystemRandom().choice(self.otpks)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/websocket.py 
new/python-nbxmpp-4.3.1/nbxmpp/websocket.py
--- old/python-nbxmpp-4.2.2/nbxmpp/websocket.py 2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/websocket.py 2023-05-28 23:18:18.000000000 
+0200
@@ -52,6 +52,8 @@
 
         message = Soup.Message.new('GET', self._address.uri)
         message.connect('accept-certificate', self._check_certificate)
+        message.connect('notify::tls-peer-certificate',
+                        self._on_certificate_set)
         message.set_flags(Soup.MessageFlags.NO_REDIRECT)
         self._session.websocket_connect_async(message,
                                               None,
@@ -105,6 +107,15 @@
         self._cancellable.cancel()
         return False
 
+    def _on_certificate_set(self, message, _param):
+        if self._peer_certificate is not None:
+            return
+
+        # If the cert has errors _check_certificate() will set the cert.
+        self._peer_certificate = message.props.tls_peer_certificate
+        self._peer_certificate_errors = convert_tls_error_flags(
+            message.props.tls_peer_certificate_errors)
+
     def _on_websocket_message(self, _websocket, _type, message):
         data = message.get_data().decode()
         self._log_stanza(data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/nbxmpp/xmppiri.py 
new/python-nbxmpp-4.3.1/nbxmpp/xmppiri.py
--- old/python-nbxmpp-4.2.2/nbxmpp/xmppiri.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/nbxmpp/xmppiri.py   2023-05-28 23:18:18.000000000 
+0200
@@ -0,0 +1,57 @@
+
+import re
+from gi.repository import GLib
+
+
+# https://www.rfc-editor.org/rfc/rfc3987
+
+ucschar        = r'\xA0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF'\
+    r'\U00010000-\U0001FFFD\U00020000-\U0002FFFD\U00030000-\U0003FFFD'\
+    r'\U00040000-\U0004FFFD\U00050000-\U0005FFFD\U00060000-\U0006FFFD'\
+    r'\U00070000-\U0007FFFD\U00080000-\U0008FFFD\U00090000-\U0009FFFD'\
+    r'\U000A0000-\U000AFFFD\U000B0000-\U000BFFFD\U000C0000-\U000CFFFD'\
+    r'\U000D0000-\U000DFFFD\U000E1000-\U000EFFFD'
+unreserved     = r'A-Za-z0-9\-._~'
+iunreserved    = fr'{unreserved}{ucschar}'
+subdelims = r"!$&'()*+,;="
+
+# https://www.rfc-editor.org/rfc/rfc5122.html#section-2.2
+nodeallow  = r"!$()*+,;="
+resallow   = r"!$&'()*+,:;="
+
+# ifragment without iunreserved and pct-encoded
+reserved_chars_allowed_in_ifragment = subdelims + ":@" + "/?"
+
+rx_ikey        = f'[{iunreserved}]*'
+rx_iquerytype  = f'[{iunreserved}]*'
+
+
+def validate_ikey(ikey: str) -> str:
+    res = re.fullmatch(rx_ikey, ikey)
+    if res is None:
+        raise ValueError('Not allowed characters in key')
+    return ikey
+
+
+def validate_querytype(querytype: str) -> str:
+    res = re.fullmatch(rx_iquerytype, querytype)
+    if res is None:
+        raise ValueError('Not allowed characters in querytype')
+    return querytype
+
+
+def escape_ifragment(ifragment: str) -> str:
+    return GLib.Uri.escape_string(
+        ifragment, reserved_chars_allowed_in_ifragment, True)
+
+
+def escape_ivalue(ivalue: str) -> str:
+    return GLib.Uri.escape_string(ivalue, None, True)
+
+
+def escape_inode(inode: str) -> str:
+    return GLib.Uri.escape_string(inode, nodeallow, True)
+
+
+def escape_ires(ires: str) -> str:
+    return GLib.Uri.escape_string(ires, resallow, True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/test/lib/util.py 
new/python-nbxmpp-4.3.1/test/lib/util.py
--- old/python-nbxmpp-4.2.2/test/lib/util.py    2023-03-25 17:33:26.000000000 
+0100
+++ new/python-nbxmpp-4.3.1/test/lib/util.py    2023-05-28 23:18:18.000000000 
+0200
@@ -1,3 +1,4 @@
+import sys
 import unittest
 from unittest.mock import Mock
 
@@ -18,3 +19,29 @@
 
         self.dispatcher.reset_parser()
         self.dispatcher.process_data(STREAM_START)
+
+
+def raise_all_exceptions(func):
+    # Exceptions which are raised from async callbacks
+    # in GLib or GTK do not bubble up to the unittest
+    # This decorator catches all exceptions and raises them
+    # after the unittest
+    def func_wrapper(self, *args, **kwargs):
+
+        exceptions = []
+
+        def on_hook(type_, value, tback):
+            exceptions.append((type_, value, tback))
+
+        orig_excepthook = sys.excepthook
+        sys.excepthook = on_hook
+        try:
+            result = func(self)
+        finally:
+            sys.excepthook = orig_excepthook
+            if exceptions:
+                tp, value, tb = exceptions[0]
+                raise tp(value).with_traceback(tb)
+
+        return result
+    return func_wrapper
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/test/unit/test_http.py 
new/python-nbxmpp-4.3.1/test/unit/test_http.py
--- old/python-nbxmpp-4.2.2/test/unit/test_http.py      2023-03-25 
17:33:26.000000000 +0100
+++ new/python-nbxmpp-4.3.1/test/unit/test_http.py      2023-05-28 
23:18:18.000000000 +0200
@@ -1,9 +1,6 @@
-from time import time
 import tempfile
 import unittest
-from unittest.mock import call
 from unittest.mock import Mock
-from unittest.mock import patch
 import os
 from pathlib import Path
 
@@ -12,6 +9,7 @@
 
 from nbxmpp.const import HTTPRequestError
 from nbxmpp.http import HTTPSession
+from test.lib.util import raise_all_exceptions
 
 
 SMALL_FILE_URL = 'https://gajim.org/downloads/ci/unittest_small_file'  # 200 KB
@@ -124,13 +122,11 @@
         session = HTTPSession()
         request = session.create_request()
 
-        def _on_progress(req, progress):
-            self.assertIsInstance(progress, float)
+        def _on_start(req):
             req.cancel()
 
         callback_mock = Mock()
-        request.connect('starting-response-body', callback_mock.starting)
-        request.connect('response-progress', _on_progress)
+        request.connect('starting-response-body', _on_start)
         request.connect('finished', callback_mock.finished)
         request.connect('destroy', lambda *args: mainloop.quit())
         request.send('GET', LARGE_FILE_URL, timeout=10)
@@ -141,7 +137,6 @@
         self.assertTrue(request.is_finished())
         self.assertEqual(request.get_error(), HTTPRequestError.CANCELLED)
 
-        callback_mock.starting.assert_called()
         callback_mock.finished.assert_called()
 
     def test_download_failed_404(self):
@@ -242,6 +237,30 @@
         self.assertTrue(request4.is_finished())
         self.assertTrue(request4.is_complete())
 
+    @raise_all_exceptions
+    def test_content_overflow(self):
+
+        mainloop = GLib.MainLoop()
+
+        session = HTTPSession()
+        request = session.create_request()
+
+        def _on_starting(req) -> None:
+            req._received_size = 100000000000
+
+        callback_mock = Mock()
+        request.connect('starting-response-body', _on_starting)
+        request.connect('finished', callback_mock.finished)
+        request.connect('destroy', lambda *args: mainloop.quit())
+        request.send('GET', SMALL_FILE_URL, timeout=10)
+
+        mainloop.run()
+
+        self.assertTrue(request.is_finished())
+        self.assertFalse(request.is_complete())
+        self.assertEqual(request.get_error(), 
HTTPRequestError.CONTENT_OVERFLOW)
+
+        callback_mock.finished.assert_called()
 
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-nbxmpp-4.2.2/test/unit/test_jid_parsing.py 
new/python-nbxmpp-4.3.1/test/unit/test_jid_parsing.py
--- old/python-nbxmpp-4.2.2/test/unit/test_jid_parsing.py       2023-03-25 
17:33:26.000000000 +0100
+++ new/python-nbxmpp-4.3.1/test/unit/test_jid_parsing.py       2023-05-28 
23:18:18.000000000 +0200
@@ -189,3 +189,26 @@
             # from_user_input does only support bare jids
             with self.assertRaises(Exception):
                 JID.from_user_input(user_input)
+
+    def test_jid_to_iri(self):
+        tests = [
+            ('nasty!#$%()*+,-.;=?[\\]^_`{|}~n...@example.com', 
'xmpp:nasty!%23$%25()*+,-.;=%3F%5B%5C%5D%5E_%60%7B%7C%7D~n...@example.com'),
+            ('n...@example.com/repulsive 
!#"$%&\'()*+,-./:;<=>?@[\\]^_`{|}~resource', 
'xmpp:n...@example.com/repulsive%20!%23%22$%25&\'()*+,-.%2F:;%3C=%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~resource'),
+        ]
+
+        for jid, iri in tests:
+            jid = JID.from_string(jid)
+            self.assertEqual(jid.to_iri(), iri)
+
+        jid = JID.from_string('example-n...@example.com')
+        iri = jid.to_iri(('message', [('subject', 'Hello World')]), 'frag')
+        self.assertEqual(iri, 
'xmpp:example-n...@example.com?message;subject=Hello%20World#frag')
+
+        iri = jid.to_iri('message')
+        self.assertEqual(iri, 'xmpp:example-n...@example.com?message')
+
+        iri = jid.to_iri(fragment='onlyfragment')
+        self.assertEqual(iri, 'xmpp:example-n...@example.com#onlyfragment')
+
+        jid = JID.from_user_input('call me "ishmael"@example.com')
+        self.assertEqual(jid.to_iri(), 
'xmpp:call%5c20me%5c20%5c22ishmael%5...@example.com')

Reply via email to