def _read_expected_cookies(session, rspec, test_block_config): """ Read cookies to inject into request, ignoring others which are present Args: session (Session): session object rspec (dict): test spec test_block_config (dict): config available for test Returns: dict: cookies to use in request, if any """ # Need to do this down here - it is separate from getting request args as # it depends on the state of the session existing_cookies = session.cookies.get_dict() cookies_to_use = format_keys( rspec.get("cookies", None), test_block_config["variables"] ) if cookies_to_use is None: logger.debug("No cookies specified in request, sending all") return None elif cookies_to_use in ([], {}): logger.debug("Not sending any cookies with request") return {} def partition(pred, iterable): """From itertools documentation""" t1, t2 = tee(iterable) return list(filterfalse(pred, t1)), list(filter(pred, t2)) # Cookies are either a single list item, specitying which cookie to send, or # a mapping, specifying cookies to override expected, extra = partition(lambda x: isinstance(x, dict), cookies_to_use) missing = set(expected) - set(existing_cookies.keys()) if missing: logger.error("Missing cookies") raise exceptions.MissingCookieError( "Tried to use cookies '{}' in request but only had '{}' available".format( expected, existing_cookies ) ) # 'extra' should be a list of dictionaries - merge them into one here from_extra = {k: v for mapping in extra for (k, v) in mapping.items()} if len(extra) != len(from_extra): logger.error("Duplicate cookie override values specified") raise exceptions.DuplicateCookieError( "Tried to override the value of a cookie multiple times in one request" ) overwritten = [i for i in expected if i in from_extra] if overwritten: logger.error("Duplicate cookies found in request") raise exceptions.DuplicateCookieError( "Asked to use cookie {} from previous request but also redefined it as {}".format( overwritten, from_extra ) ) from_cookiejar = {c: existing_cookies.get(c) for c in expected} return deep_dict_merge(from_cookiejar, from_extra)
def __init__(self, session, rspec, test_block_config): """Prepare request Args: session (requests.Session): existing session rspec (dict): test spec test_block_config (dict): Any configuration for this the block of tests Raises: UnexpectedKeysError: If some unexpected keys were used in the test spec. Only valid keyword args to requests can be passed """ if "meta" in rspec: meta = rspec.pop("meta") if meta and "clear_session_cookies" in meta: session.cookies.clear_session_cookies() expected = { "method", "url", "headers", "data", "params", "auth", "json", "verify", "files", "stream", "timeout", "cookies", "cert", # "hooks", } check_expected_keys(expected, rspec) request_args = get_request_args(rspec, test_block_config) # Need to do this down here - it is separate from getting request args as # it depends on the state of the session if "cookies" in rspec: existing_cookies = session.cookies.get_dict() missing = set(rspec["cookies"]) - set(existing_cookies.keys()) if missing: logger.error("Missing cookies") raise exceptions.MissingCookieError( "Tried to use cookies '{}' in request but only had '{}' available" .format(rspec["cookies"], existing_cookies)) request_args["cookies"] = { c: existing_cookies.get(c) for c in rspec["cookies"] } logger.debug("Request args: %s", request_args) request_args.update(allow_redirects=False) self._request_args = request_args # There is no way using requests to make a prepared request that will # not follow redirects, so instead we have to do this. This also means # that we can't have the 'pre-request' hook any more because we don't # create a prepared request. def prepared_request(): # If there are open files, create a context manager around each so # they will be closed at the end of the request. with ExitStack() as stack: stack.enter_context( _set_cookies_for_request(session, request_args)) self._request_args.update(self._get_file_arguments(stack)) return session.request(**self._request_args) self._prepared = prepared_request