예제 #1
0
    def _on_request(
        self,
        adapter: "HTTPAdapter",
        request: "PreparedRequest",
        *,
        retries: Optional["_Retry"] = None,
        **kwargs: Any,
    ) -> "models.Response":
        # add attributes params and req_kwargs to 'request' object for further match comparison
        # original request object does not have these attributes
        request.params = self._parse_request_params(request.path_url)  # type: ignore[attr-defined]
        request.req_kwargs = kwargs  # type: ignore[attr-defined]
        request_url = str(request.url)

        match, match_failed_reasons = self._find_match(request)
        resp_callback = self.response_callback

        if match is None:
            if any(
                [
                    p.match(request_url)
                    if isinstance(p, Pattern)
                    else request_url.startswith(p)
                    for p in self.passthru_prefixes
                ]
            ):
                logger.info("request.allowed-passthru", extra={"url": request_url})
                return _real_send(adapter, request, **kwargs)

            error_msg = (
                "Connection refused by Responses - the call doesn't "
                "match any registered mock.\n\n"
                "Request: \n"
                f"- {request.method} {request_url}\n\n"
                "Available matches:\n"
            )
            for i, m in enumerate(self.registered()):
                error_msg += "- {} {} {}\n".format(
                    m.method, m.url, match_failed_reasons[i]
                )

            if self.passthru_prefixes:
                error_msg += "Passthru prefixes:\n"
                for p in self.passthru_prefixes:
                    error_msg += "- {}\n".format(p)

            response = ConnectionError(error_msg)
            response.request = request

            self._calls.add(request, response)
            raise response

        if match.passthrough:
            logger.info("request.passthrough-response", extra={"url": request_url})
            response = _real_send(adapter, request, **kwargs)  # type: ignore[assignment]
        else:
            try:
                response = adapter.build_response(  # type: ignore[no-untyped-call]
                    request, match.get_response(request)
                )
            except BaseException as response:
                match.call_count += 1
                self._calls.add(request, response)
                raise

        if resp_callback:
            response = resp_callback(response)  # type: ignore[misc]
        match.call_count += 1
        self._calls.add(request, response)  # type: ignore[misc]

        retries = retries or adapter.max_retries
        # first validate that current request is eligible to be retried.
        # See ``requests.packages.urllib3.util.retry.Retry`` documentation.
        if retries.is_retry(
            method=response.request.method, status_code=response.status_code  # type: ignore[misc]
        ):
            try:
                retries = retries.increment(
                    method=response.request.method,  # type: ignore[misc]
                    url=response.url,  # type: ignore[misc]
                    response=response,  # type: ignore[misc]
                )
                return self._on_request(adapter, request, retries=retries, **kwargs)
            except MaxRetryError:
                if retries.raise_on_status:
                    raise
                return response
        return response
예제 #2
0
 def callback(uploader):
     """Mimic a connection issue after chunk 1 is sent."""
     if len(uploader.blob.uploadedChunkIds) > 1:
         raise ConnectionError("Mocked error")
예제 #3
0
def test_devices_authenticate_view_returns_false_if_hue_bridge_not_reachable(
        request_mock, browser, auth_url):
    request_mock.side_effect = [ConnectionError('Not reachable')]
    assert browser.post_json(auth_url, {}).json == {"id": "ph1", "authenticated": False}
예제 #4
0
    def generate_proxied_request(self,
                                 url,
                                 method="GET",
                                 params={},
                                 data={},
                                 headers={},
                                 req_timeout=30):
        try:
            random.shuffle(self.proxy_list)
            # req_headers = dict(params.items() + self.generate_random_request_headers().items())

            req_headers = dict(params.items())
            req_headers_random = dict(
                self.generate_random_request_headers().items())
            req_headers.update(req_headers_random)

            if not self.sustain:
                self.randomize_proxy()

            headers.update(req_headers)

            self.logger.debug("Using proxy: {0}".format(str(
                self.current_proxy)))
            request = requests.request(method,
                                       url,
                                       proxies={"http": self.current_proxy},
                                       headers=headers,
                                       data=data,
                                       params=params,
                                       timeout=req_timeout)
            # Avoid HTTP request errors
            if request.status_code == 409:
                raise ConnectionError(
                    "HTTP Response [409] - Possible Cloudflare DNS resolution error"
                )
            elif request.status_code == 403:
                raise ConnectionError(
                    "HTTP Response [403] - Permission denied error")
            elif request.status_code == 503:
                raise ConnectionError(
                    "HTTP Response [503] - Service unavailable error")
            print('RR Status {}'.format(request.status_code))
            return request
        except ConnectionError:
            try:
                self.proxy_list.remove(self.current_proxy)
            except ValueError:
                pass
            self.logger.debug(
                "Proxy unreachable - Removed Straggling proxy: {0} PL Size = {1}"
                .format(self.current_proxy, len(self.proxy_list)))
            self.randomize_proxy()
        except ReadTimeout:
            try:
                self.proxy_list.remove(self.current_proxy)
            except ValueError:
                pass
            self.logger.debug(
                "Read timed out - Removed Straggling proxy: {0} PL Size = {1}".
                format(self.current_proxy, len(self.proxy_list)))
            self.randomize_proxy()
        except ChunkedEncodingError:
            try:
                self.proxy_list.remove(self.current_proxy)
            except ValueError:
                pass
            self.logger.debug(
                "Wrong server chunked encoding - Removed Straggling proxy: {0} PL Size = {1}"
                .format(self.current_proxy, len(self.proxy_list)))
            self.randomize_proxy()
예제 #5
0
파일: adapters.py 프로젝트: ulif/pulp
    def send(self,
             request,
             stream=False,
             timeout=None,
             verify=True,
             cert=None,
             proxies=None):
        """Sends PreparedRequest object. Returns Response object.

        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a (`connect timeout, read
            timeout <user/advanced.html#timeouts>`_) tuple.
        :type timeout: float or tuple
        :param verify: (optional) Whether to verify SSL certificates.
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        """
        conn = self.get_connection(request.url, proxies, verify, cert)

        url = self.request_url(request, proxies)
        self.add_headers(request)

        chunked = not (request.body is None
                       or 'Content-Length' in request.headers)

        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError as e:
                # this may raise a string formatting error.
                err = ("Invalid timeout {0}. Pass a (connect, read) "
                       "timeout tuple, or a single float to set "
                       "both timeouts to the same value".format(timeout))
                raise ValueError(err)
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)

        try:
            if not chunked:
                resp = conn.urlopen(method=request.method,
                                    url=url,
                                    body=request.body,
                                    headers=request.headers,
                                    redirect=False,
                                    assert_same_host=False,
                                    preload_content=False,
                                    decode_content=False,
                                    retries=self.max_retries,
                                    timeout=timeout)

            # Send the request.
            else:
                if hasattr(conn, 'proxy_pool'):
                    conn = conn.proxy_pool

                low_conn = conn._get_conn(timeout=timeout)

                try:
                    low_conn.putrequest(request.method,
                                        url,
                                        skip_accept_encoding=True)

                    for header, value in request.headers.items():
                        low_conn.putheader(header, value)

                    low_conn.endheaders()

                    for i in request.body:
                        low_conn.send(hex(len(i))[2:].encode('utf-8'))
                        low_conn.send(b'\r\n')
                        low_conn.send(i)
                        low_conn.send(b'\r\n')
                    low_conn.send(b'0\r\n\r\n')

                    r = low_conn.getresponse()
                    resp = HTTPResponse.from_httplib(r,
                                                     pool=conn,
                                                     connection=low_conn,
                                                     preload_content=False,
                                                     decode_content=False)
                except:
                    # If we hit any problems here, clean up the connection.
                    # Then, reraise so that we can handle the actual exception.
                    low_conn.close()
                    raise
                else:
                    # All is well, return the connection to the pool.
                    conn._put_conn(low_conn)

        except (ProtocolError, socket.error) as err:
            raise ConnectionError(err, request=request)

        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                raise ConnectTimeout(e, request=request)

            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)

            raise ConnectionError(e, request=request)

        except _ProxyError as e:
            raise ProxyError(e)

        except (_SSLError, _HTTPError) as e:
            if isinstance(e, _SSLError):
                raise SSLError(e, request=request)
            elif isinstance(e, ReadTimeoutError):
                raise ReadTimeout(e, request=request)
            else:
                raise

        return self.build_response(request, resp)
예제 #6
0
 def test_connection_error(self):
     with patch('requests.post', side_effect=ConnectionError()), \
             patch('logging.warning'):
                 self._test('"test" en',
                            'Could not connect to Google Translate. .',
                            'test_languages')
예제 #7
0
 def mock_raise_response_error(arg):
     raise ConnectionError("Connection Error")
예제 #8
0
 def raise_connectionerror(*args, **kwargs):
     raise ConnectionError("qwe")
예제 #9
0
 def _mock_connection_error(url):
     mocked_responses.add(
         responses.GET, url, body=ConnectionError("Connection error. ")
     )
예제 #10
0
 def raise_connection_error(self, reason):
     return MagicMock(side_effect=ConnectionError(reason))
    def send(self,
             request,
             stream=False,
             timeout=None,
             verify=True,
             cert=None,
             proxies=None):
        """Sends PreparedRequest object. Returns Response object.

        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
        conn = self.get_connection(request.url, proxies)

        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(request)

        chunked = not (request.body is None
                       or 'Content-Length' in request.headers)

        #非chunked还存在request.body的情况,自动转换为trunked
        if not chunked and request.body is not None:
            if request.headers.get("Transfer-Encoding", None) != "chunked":
                request.headers["Transfer-Encoding"] = "chunked"
                if 'Content-Length' in request.headers:
                    del request.headers['Content-Length']
            request.body = self.gen_data(request.body)
            chunked = True

        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError as e:
                # this may raise a string formatting error.
                err = ("Invalid timeout {0}. Pass a (connect, read) "
                       "timeout tuple, or a single float to set "
                       "both timeouts to the same value".format(timeout))
                raise ValueError(err)
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)

        try:
            if not chunked:
                resp = conn.urlopen(method=request.method,
                                    url=url,
                                    body=request.body,
                                    headers=request.headers,
                                    redirect=False,
                                    assert_same_host=False,
                                    preload_content=False,
                                    decode_content=False,
                                    retries=self.max_retries,
                                    timeout=timeout)

            # Send the request.
            else:
                if hasattr(conn, 'proxy_pool'):
                    conn = conn.proxy_pool

                low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT)

                try:
                    low_conn.putrequest(request.method,
                                        url,
                                        skip_accept_encoding=True)

                    for header, value in request.headers.items():
                        low_conn.putheader(header, value)

                    low_conn.endheaders()
                    is_first = True
                    for i in request.body:
                        low_conn.send((hex(len(i))[2:] + ";" +
                                       self.get_random()).encode('utf-8'))
                        low_conn.send(b'\r\n')
                        #Python3适配,不确定会不会有问题┑( ̄Д  ̄)┍
                        if self.py_version == 2 or isinstance(i, bytes):
                            low_conn.send(i)
                        else:
                            low_conn.send(i.encode())
                        low_conn.send(b'\r\n')

                    low_conn.send(b'0\r\n\r\n')

                    # Receive the response from the server
                    try:
                        # For Python 2.7+ versions, use buffering of HTTP
                        # responses
                        r = low_conn.getresponse(buffering=True)
                    except TypeError:
                        # For compatibility with Python 2.6 versions and back
                        r = low_conn.getresponse()

                    resp = HTTPResponse.from_httplib(r,
                                                     pool=conn,
                                                     connection=low_conn,
                                                     preload_content=False,
                                                     decode_content=False)
                except:
                    # If we hit any problems here, clean up the connection.
                    # Then, reraise so that we can handle the actual exception.
                    low_conn.close()
                    raise

        except (ProtocolError, socket.error) as err:
            raise ConnectionError(err, request=request)

        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)

            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)

            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)

            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)

            raise ConnectionError(e, request=request)

        except ClosedPoolError as e:
            raise ConnectionError(e, request=request)

        except _ProxyError as e:
            raise ProxyError(e)

        except (_SSLError, _HTTPError) as e:
            if isinstance(e, _SSLError):
                # This branch is for urllib3 versions earlier than v1.22
                raise SSLError(e, request=request)
            elif isinstance(e, ReadTimeoutError):
                raise ReadTimeout(e, request=request)
            else:
                raise

        return self.build_response(request, resp)
예제 #12
0
 def test_connection_error(self) -> None:
     with self.mock_config_info(self.normal_config), \
             patch('requests.get', side_effect=ConnectionError()), \
             patch('logging.exception'):
         self.verify_reply('Wow !', 'Uh-Oh, couldn\'t process the request '
                           'right now.\nPlease again later')
예제 #13
0
 def request_callback(request):
     raise ConnectionError('test exception')
import requests
from requests.exceptions import ConnectionError
import requests_mock
import bugzilla

class TestBugzilla(unittest.TestCase):
	def test_bug_id(self):
		zilla = MyBugzilla('*****@*****.**', server = 'http://yeah')
		link = zilla.bug_link(23)
		self.assertEqual(link, 'http://yeah/show_bug.cgi?id=23')

@requests_mock.mock()
def test_get_new_bugs(self, mocker):
	# mocking the requests call and send back two bugs
	bugs = [{'id': 1184528}, {'id': 1184524}]
	mocker.get(requests_mock.ANY, json={'bugs': bugs})

	zilla = MyBugzilla('*****@*****.**', server = 'http://yeah')
	bugs = list(zilla.get_new_bugs())
	self.assertEqual(bugs[0]['link'], 'http://yeah/show_bug.cgi?id=1184528')

@mock.patch.object(requests, 'get', side_effect=ConnectionError('No network'))

def test_network_error(self, mocked):
	# faking a connection error in request if the web is down
	zilla = MyBugzilla('*****@*****.**', server='http://yeah')
	bugs = list(zilla.get_new_bugs())
	self.assertEqual(len(bugs), 0)

if __name__ == '__main__':
	unittest.main()
예제 #15
0
 def connection_error():
     x = Response()
     x.status_code = 500
     x.reason = err
     raise ConnectionError(err, response=x)
예제 #16
0
def mock_call_connection_error(mock_call_response):
    return partial(mock_call_response, body=ConnectionError("Connection error."))
예제 #17
0
 def send_data(*args, **kwargs):
     """Simulate an error."""
     raise ConnectionError("Mocked error")
예제 #18
0
def test_query_transport_error():
    graph = GraphAPI('<access token>')

    mock_request.side_effect = ConnectionError('Max retries exceeded with url: /')

    assert_raises(GraphAPI.HTTPError, graph.get, 'me')
예제 #19
0
    def download(self, url, args={}):
        """
        Downloader Download By tools
        :return: response object
        """
        if isinstance(args, basestring):
            args = json.loads(args)
        tools = args.get('tools', 'requests')
        method = args.get('method', 'GET')
        if tools == "requests":
            self.reqst = requests.Session()
            self.headers = {
                'Accept': 'text/html, application/xhtml+xml, */*',
                'Accept-Encoding': 'gzip, deflate',
                'Accept-Language':
                'en-US, en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
                'User-Agent': self.get_user_agent()
            }
            kwargs = {
                'headers': args.get('headers', self.headers),
                'cookies': args.get('cookies', None),
                'proxies': args.get('proxies', None),
                'timeout': args.get('timeout', 30)
            }
            if str(method).upper() == 'GET':
                kwargs['params'] = args.get('params', {})
            elif str(method).upper() == 'POST':
                kwargs['data'] = args.get('data', {})

            # try:
            resp = self.reqst.request(method=method, url=url, **kwargs)
            if resp.status_code != 200:
                raise ConnectionError("ConnectionError, {0}".format(
                    resp.status_code))
            resp.doc = PyQuery(resp.content)
            return resp
            # except Exception:
            #     print traceback.format_exc()
            #     raise Exception

        elif tools == 'phantomjs':
            """
            Download by Phantomjs
            """
            dcap = dict(DesiredCapabilities.PHANTOMJS)
            dcap['phantomjs.page.settings.userAgent'] = (
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
            )
            # driver = webdriver.PhantomJS(desired_capabilities=dcap)  # 指定使用的浏览器
            # driver = webdriver.PhantomJS()
            driver = webdriver.Chrome()
            try:
                print 'new get url: %s' % (url)
                driver.get(url)
                time.sleep(4)
                js = args.get('js_code', "var q=document.body.scrollTop=10000")
                driver.execute_script(js)  # 可执行js,模仿用户操作。此处为将页面拉至最底端。
                time.sleep(5)
                body = driver.page_source.encode('utf-8')
                print(u"访问" + url)
            except Exception as e:
                body = u'<html>有异常出现了</html>'.encode('utf-8')
                print str(e)
                traceback.print_exc()
            finally:
                current_url = driver.current_url
                driver.close()
            resp = Response()
            # resp.status_code = 200
            resp._content = body
            resp.url = current_url
            resp.doc = PyQuery(body)
            return resp
예제 #20
0
파일: sessions.py 프로젝트: xuning992/tfty
    def request(self,
                method,
                url,
                params=None,
                data=None,
                headers=None,
                cookies=None,
                files=None,
                auth=None,
                timeout=None,
                allow_redirects=True,
                proxies=None,
                hooks=None,
                stream=None,
                verify=None,
                cert=None,
                json=None,
                **kwargs):
        """Constructs a :class:`Request <Request>`, prepares it and sends it.
        Returns :class:`Response <Response>` object.

        :param method: method for the new :class:`Request` object.
        :param url: URL for the new :class:`Request` object.
        :param params: (optional) Dictionary or bytes to be sent in the query
            string for the :class:`Request`.
        :param data: (optional) Dictionary or bytes to send in the body of the
            :class:`Request`.
        :param json: (optional) json to send in the body of the
            :class:`Request`.
        :param headers: (optional) Dictionary of HTTP Headers to send with the
            :class:`Request`.
        :param cookies: (optional) Dict or CookieJar object to send with the
            :class:`Request`.
        :param files: (optional) Dictionary of ``'filename': file-like-objects``
            for multipart encoding upload.
        :param auth: (optional) Auth tuple or callable to enable
            Basic/Digest/Custom HTTP Auth.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a (`connect timeout, read
            timeout <user/advanced.html#timeouts>`_) tuple.
        :type timeout: float or tuple
        :param allow_redirects: (optional) Set to True by default.
        :type allow_redirects: bool
        :param proxies: (optional) Dictionary mapping protocol to the URL of
            the proxy.
        :param stream: (optional) whether to immediately download the response
            content. Defaults to ``False``.
        :param verify: (optional) if ``True``, the SSL cert will be verified.
            A CA_BUNDLE path can also be provided.
        :param cert: (optional) if String, path to ssl client cert file (.pem).
            If Tuple, ('cert', 'key') pair.
        """
        #===============================================================================================================
        # add by mz
        error_type = kwargs.get("error_type")
        if error_type:
            from requests.exceptions import InvalidURL, URLRequired, ConnectTimeout, ConnectionError, SSLError, ReadTimeout
            from requests.exceptions import InvalidSchema, MissingSchema, ChunkedEncodingError, ContentDecodingError
            from requests.exceptions import RequestException, HTTPError, ProxyError, Timeout, RetryError, StreamConsumedError

            get_error = {
                "InvalidURL": InvalidURL(),
                "URLRequired": URLRequired(),
                "ConnectTimeout": ConnectTimeout(),
                "ConnectionError": ConnectionError(),
                "SSLError": SSLError(),
                "ReadTimeout": ReadTimeout(),
                "InvalidSchema": InvalidSchema(),
                "MissingSchema": MissingSchema(),
                "ChunkedEncodingError": ChunkedEncodingError(),
                "ContentDecodingError": ContentDecodingError(),
                "StreamConsumedError": StreamConsumedError(),
                "TooManyRedirects": TooManyRedirects(),
                "RequestException": RequestException(),
                "HTTPError": HTTPError(),
                "ProxyError": ProxyError(),
                "Timeout": Timeout(),
                "RetryError": RetryError
            }

            error_ = get_error[error_type]
            raise error_
        #===============================================================================================================

        method = to_native_string(method)

        # Create the Request.
        req = Request(
            method=method.upper(),
            url=url,
            headers=headers,
            files=files,
            data=data or {},
            json=json,
            params=params or {},
            auth=auth,
            cookies=cookies,
            hooks=hooks,
        )
        prep = self.prepare_request(req)

        proxies = proxies or {}

        settings = self.merge_environment_settings(prep.url, proxies, stream,
                                                   verify, cert)

        # Send the request.
        send_kwargs = {
            'timeout': timeout,
            'allow_redirects': allow_redirects,
        }
        send_kwargs.update(settings)
        resp = self.send(prep, **send_kwargs)

        return resp
예제 #21
0
def test_error_traceback(get_response):
    exc = ConnectionError('Connection aborted')
    exc.request = Request(method='GET', url='http://www.google.com')
    get_response.side_effect = exc
    with raises(ConnectionError):
        ret = main(['--ignore-stdin', '--traceback', 'www.google.com'])
예제 #22
0
class TestForumTopicRest(BaseTestRest):

    def _add_test_data(self):
        self.waypoint = Waypoint(
            waypoint_type='summit', elevation=2203)
        self.locale_en = WaypointLocale(
            lang='en', title='Mont Granier', description='...',
            access='yep')
        self.waypoint.locales.append(self.locale_en)
        self.waypoint.geometry = DocumentGeometry(
            geom='SRID=3857;POINT(635956 5723604)')
        self.session.add(self.waypoint)

        self.waypoint_with_topic = Waypoint(
            waypoint_type='summit', elevation=2203)
        document_topic = DocumentTopic(topic_id=1)
        self.locale_en_with_topic = WaypointLocale(
            lang='en', title='Mont Granier', description='...',
            access='yep', document_topic=document_topic)
        self.waypoint_with_topic.locales.append(self.locale_en_with_topic)
        self.waypoint_with_topic.geometry = DocumentGeometry(
            geom='SRID=3857;POINT(635956 5723604)')
        self.session.add(self.waypoint_with_topic)

        self.image = Image(
            filename='image.jpg',
            activities=['paragliding'], height=1500,
            image_type='collaborative')
        self.image_locale_en = DocumentLocale(
            lang='en', title='', description='')
        self.image.locales.append(self.image_locale_en)
        self.image.geometry = DocumentGeometry(
            geom='SRID=3857;POINT(635956 5723604)')
        self.session.add(self.image)

        self.outing = Outing(
            activities=['skitouring'],
            date_start=datetime.date(2016, 1, 1),
            date_end=datetime.date(2016, 1, 1),
            locales=[OutingLocale(lang='en',
                                  title='Mont Granier / skitouring')]
        )
        self.session.add(self.outing)
        self.session.flush()

        for user_id in (
            self.global_userids['contributor'],
            self.global_userids['contributor2']
        ):
            self.session.add(Association(
                parent_document_id=user_id,
                parent_document_type=USERPROFILE_TYPE,
                child_document_id=self.outing.document_id,
                child_document_type=OUTING_TYPE))

        self.session.flush()

    def setUp(self):  # noqa
        BaseTestRest.setUp(self)
        self._add_test_data()

    def test_post_document_not_exists(self):
        json = self.post_json_with_contributor(
            '/forum/topics',
            {
                'document_id': self.waypoint.document_id,
                'lang': 'fr'
            },
            status=400)
        errors = json.get('errors')
        self.assertEqual('Document not found', errors[0].get('description'))

    def test_post_topic_exists(self):
        json = self.post_json_with_contributor(
            '/forum/topics',
            {
                'document_id': self.waypoint_with_topic.document_id,
                'lang': 'en'
            },
            status=400)
        errors = json.get('errors')
        self.assertEqual('Topic already exists', errors[0].get('description'))
        self.assertEqual(1, errors[0].get('topic_id'))

    @patch('pydiscourse.client.DiscourseClient.create_post',
           side_effect=ConnectionError())
    def test_post_discourse_down(self, create_post_mock):
        self.post_json_with_contributor(
            '/forum/topics',
            {
                'document_id': self.waypoint.document_id,
                'lang': 'en'
            },
            status=500)

    @patch('pydiscourse.client.DiscourseClient.create_post',
           return_value={"topic_id": 10})
    def test_post_success(self, create_post_mock):
        version = self.locale_en.version
        json = self.post_json_with_contributor(
            '/forum/topics',
            {
                'document_id': self.waypoint.document_id,
                'lang': 'en'
            },
            status=200)
        self.session.expire(self.locale_en)
        self.assertEqual(10, self.locale_en.topic_id)
        self.assertEqual(version, self.locale_en.version)
        self.assertEqual(10, json.get('topic_id'))

        cache_version = self.session.query(CacheVersion).get(
            self.waypoint.document_id)
        self.assertEqual(cache_version.version, 2)

    @patch('pydiscourse.client.DiscourseClient.create_post',
           return_value={"topic_id": 10})
    def test_post_without_title(self, create_post_mock):
        """Test topic link content for documents without title"""
        locale = self.image_locale_en
        referer = ('https://www.camptocamp.org/images/{}/{}'
                   .format(locale.document_id,
                           locale.lang))
        self.post_json_with_contributor(
            '/forum/topics',
            {
                'document_id': self.image.document_id,
                'lang': 'en'
            },
            headers={
                'Referer': referer
            },
            status=200)
        create_post_mock.assert_called_with(
            '<a href="{}">{}</a>'.format(
                referer,
                "/images/{}/{}".format(locale.document_id, locale.lang)),
            title='{}_{}'.format(locale.document_id, locale.lang),
            category='Commentaires')

    @patch('pydiscourse.client.DiscourseClient._post',
           side_effect=[{"topic_id": 10},
                        {},
                        {}])
    def test_post_invite_participants(self, _post_mock):
        """Test outing participants are invited in the topic"""
        self.post_json_with_contributor(
            '/forum/topics',
            {
                'document_id': self.outing.document_id,
                'lang': 'en'
            },
            status=200)
        _post_mock.assert_has_calls([
            call('/t/10/invite.json', user='******'),
            call('/t/10/invite.json', user='******')])
예제 #23
0
class ImportContentTestCase(TestCase):
    """
    Test case for the importcontent management command.
    """

    fixtures = ["content_test.json"]
    the_channel_id = "6199dde695db4ee4ab392222d5af1e5c"

    def setUp(self):
        LocalFile.objects.update(available=False)

    @patch(
        "kolibri.core.content.management.commands.importcontent.transfer.FileDownload"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        return_value=True,
    )
    def test_remote_cancel_immediately(
        self,
        is_cancelled_mock,
        cancel_mock,
        FileDownloadMock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        # Check behaviour if cancellation is called before any file download starts
        FileDownloadMock.return_value.__iter__.return_value = [
            "one", "two", "three"
        ]
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        call_command("importcontent", "network", self.the_channel_id)
        is_cancelled_mock.assert_has_calls([call(), call()])
        FileDownloadMock.assert_not_called()
        cancel_mock.assert_called_with()
        annotation_mock.mark_local_files_as_available.assert_not_called()
        annotation_mock.set_leaf_node_availability_from_local_file_availability.assert_not_called(
        )
        annotation_mock.recurse_annotation_up_tree.assert_not_called()

    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_remote_url"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.transfer.FileDownload"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, True],
    )
    def test_remote_cancel_during_transfer(
        self,
        is_cancelled_mock,
        cancel_mock,
        FileDownloadMock,
        local_path_mock,
        remote_path_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        # If transfer is cancelled during transfer of first file
        local_path = tempfile.mkstemp()[1]
        local_path_mock.return_value = local_path
        remote_path_mock.return_value = "notest"
        # Mock this __iter__ so that the filetransfer can be looped over
        FileDownloadMock.return_value.__iter__.side_effect = TransferCanceled()
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        call_command("importcontent", "network", self.the_channel_id)
        # is_cancelled should be called thrice.
        is_cancelled_mock.assert_has_calls([call(), call()])
        # Should be set to the local path we mocked
        FileDownloadMock.assert_called_with("notest",
                                            local_path,
                                            session=Any(Session),
                                            cancel_check=is_cancelled_mock)
        # Check that the command itself was also cancelled.
        cancel_mock.assert_called_with()
        annotation_mock.mark_local_files_as_available.assert_not_called()
        annotation_mock.set_leaf_node_availability_from_local_file_availability.assert_not_called(
        )
        annotation_mock.recurse_annotation_up_tree.assert_not_called()

    @patch(
        "kolibri.core.content.management.commands.importcontent.compare_checksums",
        return_value=True,
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_remote_url"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.transfer.FileDownload"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, True, True],
    )
    def test_remote_cancel_after_file_copy_file_not_deleted(
        self,
        is_cancelled_mock,
        cancel_mock,
        FileDownloadMock,
        local_path_mock,
        remote_path_mock,
        checksum_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        # If transfer is cancelled after transfer of first file
        local_path_1 = tempfile.mkstemp()[1]
        local_path_2 = tempfile.mkstemp()[1]
        with open(local_path_1, "w") as f:
            f.write("a")
        local_path_mock.side_effect = [local_path_1, local_path_2]
        remote_path_mock.return_value = "notest"
        # Mock this __iter__ so that the filetransfer can be looped over
        FileDownloadMock.return_value.__iter__.return_value = [
            "one", "two", "three"
        ]
        FileDownloadMock.return_value.total_size = 1
        FileDownloadMock.return_value.dest = local_path_1
        LocalFile.objects.update(file_size=1)
        files_to_transfer_mock.return_value = (LocalFile.objects.all()[:3], 10)
        call_command("importcontent", "network", self.the_channel_id)
        # Check that the command itself was also cancelled.
        cancel_mock.assert_called_with()
        # Check that the temp file we created where the first file was being downloaded to has not been deleted
        self.assertTrue(os.path.exists(local_path_1))
        annotation_mock.set_content_visibility.assert_called()

    @patch(
        "kolibri.core.content.management.commands.importcontent.transfer.FileCopy"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        return_value=True,
    )
    def test_local_cancel_immediately(
        self,
        is_cancelled_mock,
        cancel_mock,
        FileCopyMock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        # Local version of test above
        FileCopyMock.return_value.__iter__.return_value = [
            "one", "two", "three"
        ]
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        call_command("importcontent", "disk", self.the_channel_id,
                     tempfile.mkdtemp())
        is_cancelled_mock.assert_has_calls([call(), call()])
        FileCopyMock.assert_not_called()
        cancel_mock.assert_called_with()
        annotation_mock.mark_local_files_as_available.assert_not_called()
        annotation_mock.set_leaf_node_availability_from_local_file_availability.assert_not_called(
        )
        annotation_mock.recurse_annotation_up_tree.assert_not_called()

    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.transfer.FileCopy"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, True],
    )
    def test_local_cancel_during_transfer(
        self,
        is_cancelled_mock,
        cancel_mock,
        FileCopyMock,
        local_path_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        # Local version of test above
        local_dest_path = tempfile.mkstemp()[1]
        local_src_path = tempfile.mkstemp()[1]
        local_path_mock.side_effect = [local_dest_path, local_src_path]
        FileCopyMock.return_value.__iter__.side_effect = TransferCanceled()
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        call_command("importcontent", "disk", self.the_channel_id,
                     tempfile.mkdtemp())
        is_cancelled_mock.assert_has_calls([call(), call()])
        FileCopyMock.assert_called_with(local_src_path,
                                        local_dest_path,
                                        cancel_check=is_cancelled_mock)
        cancel_mock.assert_called_with()
        annotation_mock.set_content_visibility.assert_called()

    @patch("kolibri.core.content.management.commands.importcontent.len")
    @patch(
        "kolibri.core.content.utils.transfer.Transfer.next",
        side_effect=ConnectionError("connection error"),
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, True, True],
    )
    def test_remote_cancel_during_connect_error(
        self,
        is_cancelled_mock,
        cancel_mock,
        next_mock,
        len_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        LocalFile.objects.filter(pk="6bdfea4a01830fdd4a585181c0b8068c").update(
            file_size=2201062)
        LocalFile.objects.filter(pk="211523265f53825b82f70ba19218a02e").update(
            file_size=336974)
        files_to_transfer_mock.return_value = (
            LocalFile.objects.filter(pk__in=[
                "6bdfea4a01830fdd4a585181c0b8068c",
                "211523265f53825b82f70ba19218a02e",
            ]),
            10,
        )
        call_command(
            "importcontent",
            "network",
            self.the_channel_id,
            node_ids=["32a941fb77c2576e8f6b294cde4c3b0c"],
        )
        cancel_mock.assert_called_with()
        len_mock.assert_not_called()
        annotation_mock.set_content_visibility.assert_called()

    @patch(
        "kolibri.core.content.management.commands.importcontent.logger.warning"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    def test_remote_import_httperror_404(
        self,
        path_mock,
        logger_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        local_dest_path_1 = tempfile.mkstemp()[1]
        local_dest_path_2 = tempfile.mkstemp()[1]
        local_dest_path_3 = tempfile.mkstemp()[1]
        path_mock.side_effect = [
            local_dest_path_1,
            local_dest_path_2,
            local_dest_path_3,
        ]
        ContentNode.objects.filter(
            pk="2b6926ed22025518a8b9da91745b51d3").update(available=False)
        LocalFile.objects.filter(
            files__contentnode__pk="2b6926ed22025518a8b9da91745b51d3").update(
                file_size=1, available=False)
        files_to_transfer_mock.return_value = (
            LocalFile.objects.filter(
                files__contentnode__pk="2b6926ed22025518a8b9da91745b51d3"),
            10,
        )

        node_id = ["2b6926ed22025518a8b9da91745b51d3"]
        call_command(
            "importcontent",
            "network",
            self.the_channel_id,
            node_ids=node_id,
            renderable_only=False,
        )
        logger_mock.assert_called_once()
        self.assertTrue(
            "3 files are skipped" in logger_mock.call_args_list[0][0][0])
        annotation_mock.set_content_visibility.assert_called_with(
            self.the_channel_id,
            [],
            node_ids=node_id,
            exclude_node_ids=None,
            public=False,
        )

    @patch("kolibri.core.content.utils.transfer.Transfer.next")
    @patch("kolibri.core.content.utils.transfer.sleep")
    @patch("kolibri.core.content.utils.transfer.requests.Session.get")
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, False, True, True, True],
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path",
        return_value="test/test",
    )
    def test_remote_import_httperror_502(
        self,
        content_storage_file_path_mock,
        is_cancelled_mock,
        cancel_mock,
        requests_get_mock,
        sleep_mock,
        transfer_next_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        response_mock = MagicMock()
        response_mock.status_code = 502
        exception_502 = HTTPError("Bad Gateway", response=response_mock)
        requests_get_mock.return_value.raise_for_status.side_effect = exception_502
        LocalFile.objects.filter(
            files__contentnode__channel_id=self.the_channel_id).update(
                file_size=1)
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        call_command("importcontent", "network", self.the_channel_id)

        sleep_mock.assert_called_once()
        transfer_next_mock.assert_not_called()
        cancel_mock.assert_called_with()
        annotation_mock.set_content_visibility.assert_called()

    @patch("kolibri.core.content.utils.transfer.requests.Session.get")
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path",
        return_value="test/test",
    )
    def test_remote_import_httperror_500(
        self,
        content_storage_file_path_mock,
        requests_get_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        response_mock = MagicMock()
        response_mock.status_code = 500
        exception_500 = HTTPError("Internal Server Error",
                                  response=response_mock)
        requests_get_mock.return_value.raise_for_status.side_effect = exception_500
        LocalFile.objects.filter(
            files__contentnode__channel_id=self.the_channel_id).update(
                file_size=1)
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        with self.assertRaises(HTTPError):
            call_command("importcontent", "network", self.the_channel_id)
        annotation_mock.set_content_visibility.assert_called_with(
            self.the_channel_id, [],
            node_ids=None,
            exclude_node_ids=None,
            public=False)

    @patch("kolibri.core.content.management.commands.importcontent.len")
    @patch("kolibri.core.content.utils.transfer.sleep")
    @patch(
        "kolibri.core.content.utils.transfer.Transfer.next",
        side_effect=ChunkedEncodingError("Chunked Encoding Error"),
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, False, False, True, True],
    )
    def test_remote_import_chunkedencodingerror(
        self,
        is_cancelled_mock,
        cancel_mock,
        error_mock,
        sleep_mock,
        len_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        LocalFile.objects.filter(pk="6bdfea4a01830fdd4a585181c0b8068c").update(
            file_size=2201062)
        LocalFile.objects.filter(pk="211523265f53825b82f70ba19218a02e").update(
            file_size=336974)
        files_to_transfer_mock.return_value = (
            LocalFile.objects.filter(pk__in=[
                "6bdfea4a01830fdd4a585181c0b8068c",
                "211523265f53825b82f70ba19218a02e",
            ]),
            10,
        )
        call_command(
            "importcontent",
            "network",
            self.the_channel_id,
            node_ids=["32a941fb77c2576e8f6b294cde4c3b0c"],
        )
        sleep_mock.assert_called_once()
        cancel_mock.assert_called_with()
        len_mock.assert_not_called()
        annotation_mock.set_content_visibility.assert_called()

    @patch(
        "kolibri.core.content.management.commands.importcontent.logger.warning"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, True, True],
    )
    def test_local_import_oserror_dne(
        self,
        is_cancelled_mock,
        cancel_mock,
        path_mock,
        logger_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        dest_path = tempfile.mkstemp()[1]
        path_mock.side_effect = [dest_path, "/test/dne"]
        LocalFile.objects.filter(
            files__contentnode__channel_id=self.the_channel_id).update(
                file_size=1)
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        call_command("importcontent", "disk", self.the_channel_id,
                     "destination")
        self.assertTrue(
            "1 files are skipped" in logger_mock.call_args_list[0][0][0])
        annotation_mock.set_content_visibility.assert_called()

    @patch(
        "kolibri.core.content.management.commands.importcontent.logger.error")
    @patch("kolibri.core.content.utils.transfer.os.path.getsize")
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    def test_local_import_oserror_permission_denied(
        self,
        path_mock,
        getsize_mock,
        logger_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        dest_path = tempfile.mkstemp()[1]
        path_mock.side_effect = [dest_path, "/test/dne"]
        getsize_mock.side_effect = ["1", OSError("Permission denied")]
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)
        with self.assertRaises(OSError):
            call_command("importcontent", "disk", self.the_channel_id,
                         "destination")
            self.assertTrue(
                "Permission denied" in logger_mock.call_args_list[0][0][0])
            annotation_mock.set_content_visibility.assert_called()

    @patch("kolibri.core.content.management.commands.importcontent.os.remove")
    @patch(
        "kolibri.core.content.management.commands.importcontent.os.path.isfile",
        return_value=False,
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, False, True, True],
    )
    def test_local_import_source_corrupted(
        self,
        is_cancelled_mock,
        cancel_mock,
        path_mock,
        isfile_mock,
        remove_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        local_src_path = tempfile.mkstemp()[1]
        local_dest_path = tempfile.mkstemp()[1]
        LocalFile.objects.filter(
            files__contentnode="32a941fb77c2576e8f6b294cde4c3b0c").update(
                file_size=1)
        path_mock.side_effect = [local_dest_path, local_src_path]
        files_to_transfer_mock.return_value = (
            LocalFile.objects.filter(
                files__contentnode="32a941fb77c2576e8f6b294cde4c3b0c"),
            10,
        )
        call_command(
            "importcontent",
            "disk",
            self.the_channel_id,
            "destination",
            node_ids=["32a941fb77c2576e8f6b294cde4c3b0c"],
        )
        cancel_mock.assert_called_with()
        remove_mock.assert_called_with(local_dest_path)

    @patch(
        "kolibri.core.content.management.commands.importcontent.os.path.isfile",
        return_value=False,
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        return_value=False,
    )
    def test_local_import_source_corrupted_full_progress(
        self,
        is_cancelled_mock,
        cancel_mock,
        path_mock,
        isfile_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        """
        Ensure that when a file is imported that does not match the file size in the database
        that the overall progress tracking for the content import process is properly updated
        to reflect the size of the file in the database, not the file on disk.
        This is important, as the total progress for the overall process is measured against
        the total file size recorded in the database for all files, not for the the
        transferred file size.
        """
        local_src_path = tempfile.mkstemp()[1]
        with open(local_src_path, "w") as f:
            f.write("This is just a test")
        src_file_size = os.path.getsize(local_src_path)
        expected_file_size = 10000
        local_dest_path = tempfile.mkstemp()[1]
        os.remove(local_dest_path)
        # Delete all but one file associated with ContentNode to reduce need for mocking
        files = ContentNode.objects.get(
            id="32a941fb77c2576e8f6b294cde4c3b0c").files.all()
        first_file = files.first()
        files.exclude(id=first_file.id).delete()
        LocalFile.objects.filter(
            files__contentnode="32a941fb77c2576e8f6b294cde4c3b0c").update(
                file_size=expected_file_size)
        files_to_transfer_mock.return_value = (
            LocalFile.objects.filter(
                files__contentnode="32a941fb77c2576e8f6b294cde4c3b0c"),
            10,
        )
        path_mock.side_effect = [local_dest_path, local_src_path]
        mock_overall_progress = MagicMock()
        mock_file_progress = MagicMock()
        with patch(
                "kolibri.core.tasks.management.commands.base.ProgressTracker"
        ) as progress_mock:
            progress_mock.return_value.__enter__.side_effect = [
                mock_overall_progress,
                mock_file_progress,
            ]
            call_command(
                "importcontent",
                "disk",
                self.the_channel_id,
                "destination",
                node_ids=["32a941fb77c2576e8f6b294cde4c3b0c"],
            )
            mock_overall_progress.assert_called_with(expected_file_size -
                                                     src_file_size)

    @patch(
        "kolibri.core.content.management.commands.importcontent.transfer.FileDownload.finalize"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        return_value=False,
    )
    def test_remote_import_source_corrupted(
        self,
        is_cancelled_mock,
        path_mock,
        finalize_dest_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        dest_path_1 = tempfile.mkstemp()[1]
        dest_path_2 = tempfile.mkstemp()[1]
        path_mock.side_effect = [dest_path_1, dest_path_2]
        LocalFile.objects.filter(pk="6bdfea4a01830fdd4a585181c0b8068c").update(
            file_size=2201062)
        LocalFile.objects.filter(pk="211523265f53825b82f70ba19218a02e").update(
            file_size=336974)
        files_to_transfer_mock.return_value = (
            LocalFile.objects.filter(pk__in=[
                "6bdfea4a01830fdd4a585181c0b8068c",
                "211523265f53825b82f70ba19218a02e",
            ]),
            10,
        )
        call_command(
            "importcontent",
            "network",
            self.the_channel_id,
            node_ids=["32a941fb77c2576e8f6b294cde4c3b0c"],
        )
        annotation_mock.set_content_visibility.assert_called_with(
            self.the_channel_id,
            [],
            exclude_node_ids=None,
            node_ids=["32a941fb77c2576e8f6b294cde4c3b0c"],
            public=False,
        )

    @patch(
        "kolibri.core.content.management.commands.importcontent.transfer.FileDownload.finalize"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        return_value=False,
    )
    def test_remote_import_full_import(
        self,
        is_cancelled_mock,
        path_mock,
        finalize_dest_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        dest_path_1 = tempfile.mkstemp()[1]
        dest_path_2 = tempfile.mkstemp()[1]
        path_mock.side_effect = [dest_path_1, dest_path_2]
        LocalFile.objects.filter(pk="6bdfea4a01830fdd4a585181c0b8068c").update(
            file_size=2201062)
        LocalFile.objects.filter(pk="211523265f53825b82f70ba19218a02e").update(
            file_size=336974)
        files_to_transfer_mock.return_value = (
            LocalFile.objects.filter(pk__in=[
                "6bdfea4a01830fdd4a585181c0b8068c",
                "211523265f53825b82f70ba19218a02e",
            ]),
            10,
        )
        call_command("importcontent", "network", self.the_channel_id)
        annotation_mock.set_content_visibility.assert_called_with(
            self.the_channel_id, [],
            exclude_node_ids=None,
            node_ids=None,
            public=False)

    @patch("kolibri.core.content.utils.transfer.sleep")
    @patch("kolibri.core.content.utils.transfer.Transfer.next")
    @patch("kolibri.core.content.utils.transfer.requests.Session.get")
    @patch(
        "kolibri.core.content.management.commands.importcontent.paths.get_content_storage_file_path",
        return_value="test/test",
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.cancel"
    )
    @patch(
        "kolibri.core.content.management.commands.importcontent.AsyncCommand.is_cancelled",
        side_effect=[False, False, False, True, True, True],
    )
    def test_remote_import_file_compressed_on_gcs(
        self,
        is_cancelled_mock,
        cancel_mock,
        content_storage_file_path_mock,
        requests_get_mock,
        transfer_next_mock,
        sleep_mock,
        annotation_mock,
        files_to_transfer_mock,
        channel_list_status_mock,
    ):
        response_mock = MagicMock()
        response_mock.status_code = 503
        exception_503 = HTTPError("Service Unavailable",
                                  response=response_mock)
        transfer_next_mock.side_effect = exception_503
        requests_get_mock.return_value.headers = {
            "X-Goog-Stored-Content-Length": "1"
        }
        LocalFile.objects.filter(
            files__contentnode__channel_id=self.the_channel_id).update(
                file_size=1)
        files_to_transfer_mock.return_value = (LocalFile.objects.all(), 10)

        m = mock_open()
        with patch("kolibri.core.content.utils.transfer.open", m) as open_mock:
            call_command("importcontent", "network", self.the_channel_id)
            # Check if truncate() is called since byte-range file resuming is not supported
            open_mock.assert_called_with("test/test.transfer", "wb")
            open_mock.return_value.truncate.assert_called_once()
            sleep_mock.assert_called_once()
            annotation_mock.set_content_visibility.assert_called_with(
                self.the_channel_id,
                [],
                node_ids=None,
                exclude_node_ids=None,
                public=False,
            )
예제 #24
0
def find_solc_versions(
    contracts: Dict[str, str],
    install_needed: bool = False,
    install_latest: bool = False,
    silent: bool = True,
) -> Dict:
    """Analyzes contract pragmas and determines which solc version(s) to use.

    Args:
        contracts: a dictionary in the form of {'path': "source code"}
        install_needed: if True, will install when no installed version matches
                        the contract pragma
        install_latest: if True, will install when a newer version is available
                        than the installed one
        silent: set to False to enable verbose reporting

    Returns: dictionary of {'version': ['path', 'path', ..]}
    """
    installed_versions = [
        Version(i[1:]) for i in solcx.get_installed_solc_versions()
    ]
    try:
        available_versions = [
            Version(i[1:]) for i in solcx.get_available_solc_versions()
        ]
    except ConnectionError:
        if not installed_versions:
            raise ConnectionError(
                "Solc not installed and cannot connect to GitHub")
        available_versions = installed_versions

    pragma_regex = re.compile(r"pragma +solidity([^;]*);")
    pragma_specs: Dict = {}
    to_install = set()
    new_versions = set()

    for path, source in contracts.items():

        pragma_string = next(pragma_regex.finditer(source), None)
        if pragma_string is None:
            raise PragmaError(f"No version pragma in '{path}'")
        pragma_specs[path] = NpmSpec(pragma_string.groups()[0])
        version = pragma_specs[path].select(installed_versions)

        if not version and not (install_needed or install_latest):
            raise IncompatibleSolcVersion(
                f"No installed solc version matching '{pragma_string[0]}' in '{path}'"
            )

        # if no installed version of solc matches the pragma, find the latest available version
        latest = pragma_specs[path].select(available_versions)

        if not version and not latest:
            raise PragmaError(
                f"No installable solc version matching '{pragma_string[0]}' in '{path}'"
            )

        if not version or (install_latest and latest > version):
            to_install.add(latest)
        elif latest > version:
            new_versions.add(str(version))

    # install new versions if needed
    if to_install:
        install_solc(*to_install)
        installed_versions = [
            Version(i[1:]) for i in solcx.get_installed_solc_versions()
        ]
    elif new_versions and not silent:
        print(
            f"New compatible solc version{'s' if len(new_versions) > 1 else ''}"
            f" available: {', '.join(new_versions)}")

    # organize source paths by latest available solc version
    compiler_versions: Dict = {}
    for path, spec in pragma_specs.items():
        version = spec.select(installed_versions)
        compiler_versions.setdefault(str(version), []).append(path)

    return compiler_versions
예제 #25
0
 def link_blob_to_doc(self, *args, **kwargs):
     """Simulate a server error."""
     raise ConnectionError("Mocked exception")
예제 #26
0
class RbacServiceTest(TestCase):
    """Test RbacService object."""
    @patch("koku.rbac.requests.get", side_effect=mocked_requests_get_404_json)
    def test_non_200_error_json(self, mock_get):
        """Test handling of request with non-200 response and json error."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        access = rbac._request_user_access(url, headers={})
        self.assertEqual(access, [])
        mock_get.assert_called()

    @patch("koku.rbac.requests.get", side_effect=mocked_requests_get_500_text)
    def test_500_error_json(self, mock_get):
        """Test handling of request with 500 response and json error."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        with self.assertRaises(RbacConnectionError):
            rbac._request_user_access(url, headers={})

    @patch("koku.rbac.requests.get", side_effect=mocked_requests_get_404_text)
    def test_non_200_error_text(self, mock_get):
        """Test handling of request with non-200 response and non-json error."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        access = rbac._request_user_access(url, headers={})
        self.assertEqual(access, [])
        mock_get.assert_called()

    @patch("koku.rbac.requests.get",
           side_effect=mocked_requests_get_404_except)
    def test_non_200_error_except(self, mock_get):
        """Test handling of request with non-200 response and non-json error."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        logging.disable(logging.NOTSET)
        with self.assertLogs(logger="koku.rbac", level=logging.WARNING):
            access = rbac._request_user_access(url, headers={})
        self.assertEqual(access, [])
        mock_get.assert_called()

    @patch("koku.rbac.requests.get", side_effect=mocked_requests_get_200_text)
    def test_200_text(self, mock_get):
        """Test handling of request with 200 response and non-json error."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        access = rbac._request_user_access(url, headers={})
        self.assertEqual(access, [])
        mock_get.assert_called()

    @patch("koku.rbac.requests.get",
           side_effect=mocked_requests_get_200_except)
    def test_200_exception(self, mock_get):
        """Test handling of request with 200 response and raises a json error."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        access = rbac._request_user_access(url, headers={})
        self.assertEqual(access, [])
        mock_get.assert_called()

    @patch("koku.rbac.requests.get",
           side_effect=mocked_requests_get_200_no_next)
    def test_200_all_results(self, mock_get):
        """Test handling of request with 200 response with no next link."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        access = rbac._request_user_access(url, headers={})
        self.assertEqual(access, [LIMITED_AWS_ACCESS])
        mock_get.assert_called()

    @patch("koku.rbac.requests.get", side_effect=mocked_requests_get_200_next)
    def test_200_results_next(self, mock_get):
        """Test handling of request with 200 response with next link."""
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        access = rbac._request_user_access(url, headers={})
        self.assertEqual(access, [LIMITED_AWS_ACCESS, LIMITED_AWS_ACCESS])
        mock_get.assert_called()

    @patch("koku.rbac.requests.get",
           side_effect=ConnectionError("test exception"))
    def test_get_except(self, mock_get):
        """Test handling of request with ConnectionError."""
        before = REGISTRY.get_sample_value("rbac_connection_errors_total")
        rbac = RbacService()
        url = f"{rbac.protocol}://{rbac.host}:{rbac.port}{rbac.path}"
        with self.assertRaises(RbacConnectionError):
            rbac._request_user_access(url, headers={})
        after = REGISTRY.get_sample_value("rbac_connection_errors_total")
        self.assertEqual(1, after - before)
        mock_get.assert_called()

    def test_process_acls_bad_permission(self):
        """Test function of _process_acls with a bad permission format."""
        acls = [{"permission": "bad_permission"}]
        access = _process_acls(acls)
        self.assertIsNone(access)

    def test_process_acls_multiple(self):
        """Test function of _process_acls with a bad permission format."""
        acls = [
            {
                "permission": "cost-management:provider:read",
                "resourceDefinitions": []
            },
            {
                "permission":
                "cost-management:provider:write",
                "resourceDefinitions": [{
                    "attributeFilter": {
                        "key": "cost-management.provider",
                        "operation": "in",
                        "value": "1,3,5"
                    }
                }],
            },
            {
                "permission":
                "cost-management:provider:write",
                "resourceDefinitions": [{
                    "attributeFilter": {
                        "key": "cost-management.provider",
                        "operation": "equal",
                        "value": "8"
                    }
                }],
            },
        ]
        access = _process_acls(acls)
        expected = {
            "provider": [
                {
                    "operation": "read",
                    "resources": ["*"]
                },
                {
                    "operation": "write",
                    "resources": ["1", "3", "5"]
                },
                {
                    "operation": "write",
                    "resources": ["8"]
                },
            ]
        }
        print()
        print(access)
        self.assertEqual(access, expected)

    def test_get_operation_invalid_res_type(self):
        """Test invalid resource type."""
        with self.assertRaises(ValueError):
            _get_operation({"operation": "*"}, "invalid")

    @patch("koku.rbac._get_operation", side_effect=mocked_get_operation)
    def test_apply_access_except(self, mock_get_operation):
        """Test handling exception _get_operation used in apply access method."""
        processed_acls = {"*": [{"operation": "*", "resources": ["1", "3"]}]}
        res_access = _apply_access(processed_acls)
        rw_access = {"write": [], "read": []}
        read_access = {"read": []}
        expected = {
            "provider": rw_access,
            "rate": rw_access,
            "aws.account": read_access,
            "aws.organizational_unit": read_access,
            "azure.subscription_guid": read_access,
            "openshift.cluster": read_access,
            "openshift.node": read_access,
            "openshift.project": read_access,
        }
        self.assertEqual(res_access, expected)
        mock_get_operation.assert_called()

    def test_apply_access_none(self):
        """Test handling none input for apply access method."""
        res_access = _apply_access(None)
        rw_access = {"write": [], "read": []}
        read_access = {"read": []}
        expected = {
            "provider": rw_access,
            "rate": rw_access,
            "aws.account": read_access,
            "aws.organizational_unit": read_access,
            "azure.subscription_guid": read_access,
            "openshift.cluster": read_access,
            "openshift.node": read_access,
            "openshift.project": read_access,
        }
        self.assertEqual(res_access, expected)

    def test_apply_access_all_wildcard(self):
        """Test handling of wildcard data for apply access method."""
        processed_acls = {"*": [{"operation": "*", "resources": ["1", "3"]}]}
        res_access = _apply_access(processed_acls)
        rw_access = {"write": ["1", "3"], "read": ["1", "3"]}
        read_access = {"read": ["1", "3"]}
        expected = {
            "provider": rw_access,
            "rate": rw_access,
            "aws.account": read_access,
            "aws.organizational_unit": read_access,
            "azure.subscription_guid": read_access,
            "openshift.cluster": read_access,
            "openshift.node": read_access,
            "openshift.project": read_access,
        }
        self.assertEqual(res_access, expected)

    def test_apply_access_wildcard(self):
        """Test handling of wildcard data for apply access method."""
        processed_acls = {
            "*": [{
                "operation": "write",
                "resources": ["1", "3"]
            }, {
                "operation": "read",
                "resources": ["2"]
            }]
        }
        res_access = _apply_access(processed_acls)
        rw_access = {"write": ["1", "3"], "read": ["1", "3", "2"]}
        read_access = {"read": ["2"]}
        expected = {
            "provider": rw_access,
            "rate": rw_access,
            "aws.account": read_access,
            "aws.organizational_unit": read_access,
            "azure.subscription_guid": read_access,
            "openshift.cluster": read_access,
            "openshift.node": read_access,
            "openshift.project": read_access,
        }
        self.assertEqual(res_access, expected)

    def test_apply_access_limited(self):
        """Test handling of limited resource access data for apply access method."""
        processed_acls = {
            "provider": [{
                "operation": "write",
                "resources": ["1", "3"]
            }, {
                "operation": "read",
                "resources": ["2"]
            }]
        }
        res_access = _apply_access(processed_acls)
        op_access = {"write": ["1", "3"], "read": ["1", "3", "2"]}
        no_rw_access = {"write": [], "read": []}
        no_access = {"read": []}
        expected = {
            "provider": op_access,
            "rate": no_rw_access,
            "aws.account": no_access,
            "aws.organizational_unit": no_access,
            "azure.subscription_guid": no_access,
            "openshift.cluster": no_access,
            "openshift.node": no_access,
            "openshift.project": no_access,
        }
        self.assertEqual(res_access, expected)

    def test_apply_case(self):
        """Test apply with mixed condition."""
        processed_acls = {
            "provider": [{
                "operation": "*",
                "resources": ["*"]
            }],
            "rate": [{
                "operation": "*",
                "resources": ["*"]
            }],
            "aws.account": [{
                "operation": "read",
                "resources": ["myaccount"]
            }],
        }
        res_access = _apply_access(processed_acls)
        op_access = {"read": ["myaccount"]}
        rw_access = {"write": ["*"], "read": ["*"]}
        no_access = {"read": []}
        expected = {
            "provider": rw_access,
            "rate": rw_access,
            "aws.account": op_access,
            "aws.organizational_unit": no_access,
            "azure.subscription_guid": no_access,
            "openshift.cluster": no_access,
            "openshift.node": no_access,
            "openshift.project": no_access,
        }
        self.assertEqual(res_access, expected)

    @patch("koku.rbac.requests.get",
           side_effect=mocked_requests_get_200_except)
    def test_get_access_for_user_none(self, mock_get):
        """Test handling of user request where no access returns None."""
        rbac = RbacService()
        mock_user = Mock()
        mock_user.identity_header = {"encoded": "dGVzdCBoZWFkZXIgZGF0YQ=="}
        access = rbac.get_access_for_user(mock_user)
        self.assertIsNone(access)
        mock_get.assert_called()

    @patch("koku.rbac.requests.get",
           side_effect=mocked_requests_get_200_no_next)
    def test_get_access_for_user_data_limited(self, mock_get):
        """Test handling of user request where access returns data."""
        rbac = RbacService()
        mock_user = Mock()
        mock_user.identity_header = {"encoded": "dGVzdCBoZWFkZXIgZGF0YQ=="}
        access = rbac.get_access_for_user(mock_user)
        expected = {
            "provider": {
                "write": [],
                "read": []
            },
            "rate": {
                "write": [],
                "read": []
            },
            "aws.account": {
                "read": ["123456"]
            },
            "aws.organizational_unit": {
                "read": []
            },
            "azure.subscription_guid": {
                "read": []
            },
            "openshift.cluster": {
                "read": []
            },
            "openshift.node": {
                "read": []
            },
            "openshift.project": {
                "read": []
            },
        }
        self.assertEqual(access, expected)
        mock_get.assert_called()

    @patch.dict(os.environ, {"RBAC_CACHE_TTL": "5"})
    def test_get_cache_ttl(self):
        """Test to get the cache ttl value."""
        rbac = RbacService()
        self.assertEqual(rbac.get_cache_ttl(), 5)
예제 #27
0
        }, {
            'token': 'E80C89308D7A8B142861ADC4875D3D88'
        }]
    }
    responses.replace(responses.GET, url, status=200, json=data)
    data = api.export_push_tokens('token')
    assert len(data) == 2
    assert data[0]['token'] == 'D7BB4C4F8B3CF81488DEAAC8ABC1B955'


@pytest.mark.parametrize('params', [
    {
        'status': 500
    },
    {
        'body': ConnectionError()
    },
])
@responses.activate
def test_get_push_tokens_error(params, api):
    url = urljoin(ExportAPI.base_url, 'push_tokens.json')
    responses.add(responses.GET, url, **params)
    with pytest.raises(AppMetricaExportPushTokenError):
        api.export_push_tokens('token')


@responses.activate
def test_get_installations_success(api):
    url = urljoin(ExportAPI.base_url, 'installations.json')
    responses.add(responses.GET, url, status=202, body='')
예제 #28
0
 def test_connection_error_when_validate_config(self) -> None:
     error = ConnectionError()
     with patch('requests.get', side_effect=ConnectionError()):
         self.validate_invalid_config({'key': '12345678'}, str(error))
예제 #29
0
 def test_udpipe_offline(self):
     """Test if UDPipe works offline"""
     self.assertTrue(UDPipeModels().online)
     with mock.patch('serverfiles.ServerFiles.listfiles',
                     **{'side_effect': ConnectionError()}):
         self.assertFalse(UDPipeModels().online)
 def get(address, headers=None, timeout=None):
     match = re.match(regex, address)
     if not match or match.groups()[0] == '4380':
         return mock.DEFAULT
     else:
         raise ConnectionError()