def _make_url(base_url, value):
    # type: (Text, Text) -> Text
    if is_absolute_url(value) and not is_url_with_scheme(value):  # noqa
        url = urljoin("http://", value)
    else:
        url = urljoin(base_url, value)
    return url
Exemple #2
0
 def request(
     self, method, url_resource, use_api_key=True, request_id=None, **kwargs
 ):
     # type: (Text, Text, bool, Optional[UUID], **Any) -> Response
     req_id = str(uuid.uuid4() if request_id is None else request_id)
     if url_resource is not None:
         # makes URL relative
         url_resource = url_resource.lstrip("/")
     url_resource = urljoin(self.server_url.rstrip("/"), url_resource)
     params = {}
     if use_api_key:
         params["apiKey"] = self.api_key
     params.update(kwargs.get("params", {}))
     headers = self.headers.copy()
     headers.update(kwargs.get("headers", {}))
     headers["x-applitools-eyes-client-request-id"] = req_id
     timeout_sec = kwargs.get("timeout", None)
     if timeout_sec is None:
         timeout_sec = datetime_utils.to_sec(self.timeout_ms)
     response = self.client_session.request(
         method,
         url_resource,
         data=kwargs.get("data", None),
         verify=False,
         params=params,
         headers=headers,
         timeout=timeout_sec,
     )
     try:
         response.raise_for_status()
     except requests.HTTPError as e:
         logger.exception(e)
         logger.error("Error response content is: {}".format(response.text))
     return response
 def request(self, method, url_resource, use_api_key=True, **kwargs):
     # type: (Callable, Text, bool, **Any) -> Response
     if url_resource is not None:
         # makes URL relative
         url_resource = url_resource.lstrip("/")
     url_resource = urljoin(self.server_url, url_resource)
     params = {}
     if use_api_key:
         params["apiKey"] = self.api_key
     params.update(kwargs.get("params", {}))
     headers = kwargs.get("headers", self.headers).copy()
     timeout_sec = kwargs.get("timeout", None)
     if timeout_sec is None:
         timeout_sec = datetime_utils.to_sec(self.timeout_ms)
     response = method(
         url_resource,
         data=kwargs.get("data", None),
         verify=False,
         params=params,
         headers=headers,
         timeout=timeout_sec,
     )
     try:
         response.raise_for_status()
     except requests.HTTPError as e:
         logger.exception(e)
     return response
    def match_window(self, running_session, match_data):
        # type: (RunningSession, MatchWindowData) -> MatchResult
        """
        Matches the current window to the immediate expected window in the Eyes server.
        Notice that a window might be matched later at the end of the test, even if it
        was not immediately matched in this call.

        :param running_session: The current session that is running.
        :param match_data: The data for the requests.post.
        :return: The parsed response.
        """
        logger.debug("match_window called. {}".format(running_session))

        # logger.debug("Data length: %d, data: %s" % (len(data), repr(data)))
        if not self.is_session_started:
            raise EyesError("Session not started")

        data = prepare_match_data(match_data)
        # Using the default headers, but modifying the "content type" to binary
        headers = ServerConnector.DEFAULT_HEADERS.copy()
        headers["Content-Type"] = "application/octet-stream"
        # TODO: allow to send images as base64
        response = self._com.long_request(
            requests.post,
            url_resource=urljoin(self.API_SESSIONS_RUNNING, running_session.id),
            data=data,
            headers=headers,
        )
        match_result = json_utils.attr_from_response(response, MatchResult)
        return match_result
    def render_status_by_id(self, *render_ids):
        # type: (*Text) -> List[RenderStatusResults]
        argument_guard.not_none(render_ids)
        if self._render_info is None:
            raise EyesError("render_info must be fetched first")

        headers = ServerConnector.DEFAULT_HEADERS.copy()
        headers["Content-Type"] = "application/json"
        headers["X-Auth-Token"] = self._render_info.access_token
        url = urljoin(self._render_info.service_url, self.RENDER_STATUS)
        response = self._com.request(
            requests.post,
            url,
            use_api_key=False,
            headers=headers,
            data=json.dumps(render_ids),
        )
        if not response.ok:
            raise EyesError(
                "Error getting server status, {} {}".format(
                    response.status_code, response.content
                )
            )
        # TODO: improve parser to handle similar names
        return json_utils.attr_from_response(response, RenderStatusResults)
    def post_dom_snapshot(self, dom_json):
        # type: (Text) -> Optional[Text]
        """
        Upload the DOM of the tested page.
        Return an URL of uploaded resource which should be posted to :py:   `AppOutput`.
        """
        logger.debug("post_dom_snapshot called.")

        if not self.is_session_started:
            raise EyesError("Session not started")

        headers = ServerConnector.DEFAULT_HEADERS.copy()
        headers["Content-Type"] = "application/octet-stream"
        dom_bytes = gzip_compress(dom_json.encode("utf-8"))

        response = self._com.request(
            requests.post,
            url_resource=urljoin(self.API_SESSIONS_RUNNING, "data"),
            data=dom_bytes,
            headers=headers,
        )
        dom_url = None
        if response.ok:
            dom_url = response.headers["Location"]
        return dom_url
Exemple #7
0
def send_result_report(test_name, passed, parameters=None, group="selenium"):
    report_data = copy(REPORT_DATA)
    report_data["results"] = [prepare_result_data(test_name, passed, parameters)]
    report_data["group"] = group
    r = requests.post(urljoin(REPORT_BASE_URL, "/result"), data=json.dumps(report_data))
    print("Result report send: {} - {}".format(r.status_code, r.text))
    return r
    def stop_session(self, running_session, is_aborted, save):
        # type: (RunningSession, bool, bool) -> TestResults
        """
        Stops a running session in the Eyes server.

        :param running_session: The session to stop.
        :param is_aborted: Whether the server should mark this session as aborted.
        :param save: Whether the session should be automatically saved if it is not aborted.
        :return: Test results of the stopped session.
        """
        logger.debug("stop_session called.")

        if not self.is_session_started:
            raise EyesError("Session not started")

        params = {"aborted": is_aborted, "updateBaseline": save}
        response = self._com.long_request(
            requests.delete,
            url_resource=urljoin(self.API_SESSIONS_RUNNING, running_session.id),
            params=params,
            headers=ServerConnector.DEFAULT_HEADERS,
        )

        test_results = json_utils.attr_from_response(response, TestResults)
        logger.debug("stop_session(): parsed response: {}".format(test_results))

        # mark that session isn't started
        self._is_session_started = False
        return test_results
    def render_put_resource(self, running_render, resource):
        # type: (RunningRender, VGResource) -> Text
        argument_guard.not_none(running_render)
        argument_guard.not_none(resource)
        if self._render_info is None:
            raise EyesError("render_info must be fetched first")

        content = resource.content
        argument_guard.not_none(content)
        logger.debug("resource hash: {} url: {} render id: {}"
                     "".format(resource.hash, resource.url,
                               running_render.render_id))
        headers = ServerConnector.DEFAULT_HEADERS.copy()
        headers["Content-Type"] = resource.content_type
        headers["X-Auth-Token"] = self._render_info.access_token

        url = urljoin(self._render_info.service_url,
                      self.RESOURCES_SHA_256 + resource.hash)
        response = self._com.request(
            requests.put,
            url,
            use_api_key=False,
            headers=headers,
            data=content,
            params={"render-id": running_render.render_id},
        )
        logger.debug("ServerConnector.put_resource - request succeeded")
        if not response.ok:
            raise EyesError("Error putting resource: {}, {}".format(
                response.status_code, response.content))
        return resource.hash
def _apply_base_url(discovered_url, base_url, resource_url=None):
    url = urlparse(discovered_url)
    if url.scheme in ["http", "https"] and url.netloc:
        return discovered_url
    if resource_url and urlparse(resource_url).netloc != urlparse(
            base_url).netloc:
        base_url = resource_url
    return urljoin(base_url, discovered_url)
Exemple #11
0
 def close(self):
     if self.api_key is None:
         print("WARNING: BatchClose wont be done cause no APPLITOOLS_API_KEY is set")
         return
     if str2bool(get_env_with_prefix("APPLITOOLS_DONT_CLOSE_BATCHES")):
         print("APPLITOOLS_DONT_CLOSE_BATCHES environment variable set to true.")
         return
     for batch_id in self._ids:
         print("close batch called with {}".format(batch_id))
         url = urljoin(
             self.server_url.rstrip("/"),
             "api/sessions/batches/{}/close/bypointerid".format(
                 quote_plus(batch_id)
             ),
         )
         res = requests.delete(url, params={"apiKey": self.api_key}, verify=False)
         print("delete batch is done with {} status".format(res.status_code))
Exemple #12
0
 def get_text_in_running_session_image(self, data):
     # type: (TextSettingsData) -> List[Text]
     logger.debug(
         "call",
         _class=self.__class__.__name__,
         _method="extract_text",
         text_region_data=data,
     )
     resp = self._com.long_request(
         "post",
         urljoin(self.API_SESSIONS_RUNNING, "images/text"),
         data=json_utils.to_json(data),
     )
     if resp.ok:
         return resp.json()
     raise EyesError(
         "ServerConnector.extract_text - unexpected status {}".format(
             resp.status_code
         )
     )
    def match_window(self, running_session, match_data):
        # type: (RunningSession, MatchWindowData) -> MatchResult
        """
        Matches the current window to the immediate expected window in the Eyes server.
        Notice that a window might be matched later at the end of the test, even if it
        was not immediately matched in this call.

        :param running_session: The current session that is running.
        :param match_data: The data for the requests.post.
        :return: The parsed response.
        """
        logger.debug("match_window called. {}".format(running_session))

        # logger.debug("Data length: %d, data: %s" % (len(data), repr(data)))
        if not self.is_session_started:
            raise EyesError("Session not started")
        app_output = match_data.app_output
        # when screenshot_url is present we don't need to upload again
        if app_output.screenshot_url is None and app_output.screenshot_bytes:
            app_output.screenshot_url = self.try_upload_image(
                match_data.app_output.screenshot_bytes)

        if app_output.screenshot_url is None:
            raise EyesError(
                "MatchWindow failed: could not upload image to storage service."
            )
        logger.info("Screenshot image URL: {}".format(
            app_output.screenshot_url))
        data = json_utils.to_json(match_data)
        headers = ServerConnector.DEFAULT_HEADERS.copy()
        response = self._com.long_request(
            "post",
            url_resource=urljoin(self.API_SESSIONS_RUNNING,
                                 running_session.id),
            data=data,
            headers=headers,
        )
        return json_utils.attr_from_response(response, MatchResult)
    def render(self, *render_requests):
        # type: (*RenderRequest) -> List[RunningRender]
        logger.debug("render called with {}".format(render_requests))
        if self._render_info is None:
            raise EyesError("render_info must be fetched first")

        url = urljoin(self._render_info.service_url, self.RENDER)

        headers = ServerConnector.DEFAULT_HEADERS.copy()
        headers["Content-Type"] = "application/json"
        headers["X-Auth-Token"] = self._render_info.access_token

        data = json_utils.to_json(render_requests)
        response = self._com.request(
            requests.post, url, use_api_key=False, headers=headers, data=data
        )
        if response.ok or response.status_code == requests.codes.not_found:
            return json_utils.attr_from_response(response, RunningRender)
        raise EyesError(
            "ServerConnector.render - unexpected status ({})\n\tcontent{}".format(
                response.status_code, response.content
            )
        )
Exemple #15
0
 def get_text_regions_in_running_session_image(self, data):
     # type: (TextSettingsData) -> PATTERN_TEXT_REGIONS
     logger.debug(
         "call",
         _class=self.__class__.__name__,
         _method="extract_text_regions",
         text_region_data=data,
     )
     resp = self._com.long_request(
         "post",
         urljoin(self.API_SESSIONS_RUNNING, "images/textregions"),
         data=json_utils.to_json(data),
     )
     if resp.ok:
         return {
             pattern: json_utils.attr_from_dict(regions, TextRegion)
             for pattern, regions in iteritems(resp.json())
         }
     raise EyesError(
         "ServerConnector.extract_text_regions - unexpected status {}".format(
             resp.status_code
         )
     )
Exemple #16
0
 def _ufg_request(self, method, url_resource, **kwargs):
     headers = ServerConnector.DEFAULT_HEADERS.copy()
     headers["Content-Type"] = "application/json"
     headers["X-Auth-Token"] = self._render_info.access_token
     full_url = urljoin(self._render_info.service_url, url_resource)
     return self._com.request(method, full_url, headers=headers, **kwargs)
def _apply_base_url(discovered_url, base_url):
    url = urlparse(discovered_url)
    if url.scheme in ["http", "https"] and url.netloc:
        return discovered_url
    return urljoin(base_url, discovered_url)