Exemplo n.º 1
0
def fake_azure_storage(files=None):
    container_name = "somecontainer"
    account_name = "someaccount"
    account_key = "somekey"
    storage_path = ""

    service = BlobServiceClient(AZURE_STORAGE_URL_STRING.format("someaccount"))
    endpoint = service.primary_hostname
    files = files if files is not None else {}

    container_prefix = os.path.join("/" + container_name, storage_path).rstrip("/")

    @urlmatch(netloc=endpoint[0], path=container_prefix + "$")
    def get_container(url, request):
        return {"status_code": 200, "content": "{}"}

    @urlmatch(netloc=endpoint[0], path=container_prefix + "/.+")
    def container_file(url, request):
        filename = url.path[len(container_prefix) + 1 :]

        if request.method == "GET":
            return {
                "status_code": 200 if filename in files else 404,
                "headers": {
                    "ETag": "foobar",
                },
                "content": files.get(filename) if filename in files else "",
            }

        if request.method == "HEAD":
            return {
                "status_code": 200 if filename in files else 404,
                "headers": {
                    "ETag": "foobar",
                }
                if filename in files
                else {"x-ms-error-code": "ResourceNotFound"},
                "content": "",
            }

        if request.method == "DELETE":
            files.pop(filename)
            return {
                "status_code": 202,
            }

        if request.method == "PUT":
            query_params = parse_qs(url.query)
            if query_params.get("comp") == ["properties"]:
                return {
                    "status_code": 201,
                    "content": "{}",
                    "headers": {
                        "x-ms-request-server-encrypted": "false",
                        "last-modified": "Wed, 21 Oct 2015 07:28:00 GMT",
                    },
                }

            if query_params.get("comp") == ["block"]:
                block_id = query_params["blockid"][0]
                files[filename] = files.get(filename) or {}
                files[filename][block_id] = request.body
                return {
                    "status_code": 201,
                    "content": "{}",
                    "headers": {
                        "Content-MD5": base64.b64encode(md5(request.body).digest()).decode("ascii"),
                        "ETag": "foo",
                        "x-ms-request-server-encrypted": "false",
                        "last-modified": "Wed, 21 Oct 2015 07:28:00 GMT",
                    },
                }

            if query_params.get("comp") == ["blocklist"]:
                parsed = minidom.parseString(request.body)
                latest = parsed.getElementsByTagName("Latest")
                combined = []
                for latest_block in latest:
                    combined.append(files[filename][latest_block.childNodes[0].data])

                files[filename] = b"".join(combined)
                return {
                    "status_code": 201,
                    "content": "{}",
                    "headers": {
                        "Content-MD5": base64.b64encode(md5(files[filename]).digest()).decode(
                            "ascii"
                        ),
                        "ETag": "foo",
                        "x-ms-request-server-encrypted": "false",
                        "last-modified": "Wed, 21 Oct 2015 07:28:00 GMT",
                    },
                }

            if request.headers.get("x-ms-copy-source"):
                copy_source = request.headers["x-ms-copy-source"]
                print("DEBUG REQUEST SOURCE:", copy_source)
                copy_path = urlparse(copy_source).path[len(container_prefix) + 1 :]
                files[filename] = files[copy_path]
                return {
                    "status_code": 202,
                    "content": "",
                    "headers": {
                        "x-ms-request-server-encrypted": "false",
                        "x-ms-copy-status": "success",
                        "last-modified": "Wed, 21 Oct 2015 07:28:00 GMT",
                    },
                }

            files[filename] = request.body

            return {
                "status_code": 201,
                "content": "{}",
                "headers": {
                    "Content-MD5": base64.b64encode(md5(request.body).digest()).decode("ascii"),
                    "ETag": "foo",
                    "x-ms-request-server-encrypted": "false",
                    "last-modified": "Wed, 21 Oct 2015 07:28:00 GMT",
                },
            }

        return {"status_code": 405, "content": ""}

    @urlmatch(netloc=endpoint[0], path=".+")
    def catchall(url, request):
        return {"status_code": 405, "content": ""}

    with HTTMock(get_container, container_file, catchall):
        yield AzureStorage(None, container_name, storage_path, account_name)
Exemplo n.º 2
0
 def test_tag_delete_users(self):
     with HTTMock(wechat_api_mock):
         res = self.client.tag.delete_users(1, [1, 2, 3])
         self.assertEqual(0, res['errcode'])
Exemplo n.º 3
0
 def test_batch_get_result(self):
     with HTTMock(wechat_api_mock):
         res = self.client.batch.get_result('123456')
         self.assertEqual(0, res['errcode'])
         self.assertEqual(1, res['status'])
 def test_get_extra_info_ok(self):
     with HTTMock(extra):
         info = self.idm.get_extra_info('frobnar')
         self.assertEqual(info.get('foo'), 1)
 def test_login_success(self):
     with HTTMock(entity_200):
         self.idm.login('fabrice', {})
     self.assertTrue(_called)
 def test_login_error_forbidden(self):
     with HTTMock(entity_403):
         with self.assertRaises(ServerError) as ctx:
             self.idm.login('fabrice', {})
     self.assertEqual(403, ctx.exception.args[0])
     self.assertTrue(_called)
 def test_discharge_error_invalid_macaroon(self):
     macaroon = self._makeMockMacaroon()
     with HTTMock(discharge_macaroon_200):
         with self.assertRaises(InvalidMacaroon):
             self.idm.discharge('Brad', macaroon)
Exemplo n.º 8
0
 def test_method_fallback(self):
     with HTTMock(unmatched_method, any_mock):
         r = requests.get('http://example.com/')
     self.assertEqual(r.content, 'Hello from example.com')
Exemplo n.º 9
0
 def test_400_response(self):
     with HTTMock(example_400_response):
         r = requests.get('http://example.com/')
     self.assertEqual(r.status_code, 400)
     self.assertEqual(r.content, 'Bad request.')
Exemplo n.º 10
0
 def test_all_str_response(self):
     with HTTMock(self.string_response_content):
         r = requests.get('https://foo_bar')
     self.assertEqual(r.content, 'Hello')
Exemplo n.º 11
0
 def test_return_type(self):
     with HTTMock(any_mock):
         r = requests.get('http://domain.com/')
     self.assertTrue(isinstance(r, requests.Response))
Exemplo n.º 12
0
 def test_all_requests_response(self):
     with HTTMock(self.response_content):
         r = requests.get('https://foo_bar')
     self.assertEqual(r.status_code, 200)
     self.assertEqual(r.content, 'Oh hai')
Exemplo n.º 13
0
 def test_raw_get(self):
     with HTTMock(self.response_content_success):
         resp = self._conn.raw_get("/known_path")
     self.assertEqual(resp.content, b'response_ok')
     self.assertEqual(resp.status_code, 200)
Exemplo n.º 14
0
    def test_get_permissions(self):
        """
        A user may see a member's data sources, if:
          - the request.user is the member, or
          - the request.user is in an Organization that has an approved
            ResourceRequest for the member's data
        """
        # Create a member
        member = UserFactory()
        # The member has received an access_token to get their own data.
        provider_name = Resource.name
        access_token = 'accessTOKENhere'
        UserSocialAuthFactory(
            user=member,
            provider=provider_name,
            extra_data={'refresh_token': 'refreshTOKEN', 'access_token': access_token}
        )

        # The URLs that will be used in this test
        member_data_url = reverse(self.url_name, kwargs={'pk': member.pk})

        with self.subTest("A member's data sources without an approved ResourceRequest"):

            # We mock the use of the requests library, so we don't make real
            # requests from within the test.
            with HTTMock(self.response_content_success):
                response = self.client.get(member_data_url)

            # The request.user does not have access to the member's data
            self.assertEqual(response.status_code, 302)

        with self.subTest(
            "A member's data sources with an approved ResourceRequest, other Organization"
        ):
            # The member has approved some Organization's request for the member's data
            organization = OrganizationFactory()
            resource_request = ResourceRequestFactory(
                member=member,
                organization=organization,
                resourcegrant=None,
                status=REQUEST_APPROVED
            )
            resource_grant = ResourceGrantFactory(
                member=resource_request.member,
                organization=resource_request.organization,
                resource_class_path=resource_request.resource_class_path,
                resource_request=resource_request
            )

            # We mock the use of the requests library, so we don't make real
            # requests from within the test.
            with HTTMock(self.response_content_success):
                response = self.client.get(member_data_url)

            # The request.user now has access to the member's data
            self.assertEqual(response.status_code, 302)

        with self.subTest(
            "A member's data sources with approved ResourceRequest from request.user's Organization"
        ):
            # The request.user is now in the organization
            organization.users.add(self.user)

            # We mock the use of the requests library, so we don't make real
            # requests from within the test.
            with HTTMock(self.response_content_success):
                response = self.client.get(member_data_url)

            # The request.user does not have access to the member's data, since
            # the request.user is not in the organization.
            self.assertEqual(response.status_code, 200)

        with self.subTest('A member requesting their own data'):
            self.client.logout()
            self.client.force_login(member)

            # We mock the use of the requests library, so we don't make real
            # requests from within the test.
            with HTTMock(self.response_content_success):
                response = self.client.get(member_data_url)

            # The request.user has access to their own data, regardless of their
            # Organization.
            self.assertEqual(response.status_code, 200)

            # Even if we remove the ResourceRequest and ResourceGrant objects,
            # the member is allowed to see their own data.
            resource_request.delete()
            resource_grant.delete()
            with HTTMock(self.response_content_success):
                response = self.client.get(member_data_url)
            self.assertEqual(response.status_code, 200)
Exemplo n.º 15
0
 def test_get_user_info(self):
     with HTTMock(wechat_api_mock):
         self.oauth.fetch_access_token('123456')
         res = self.oauth.get_user_info()
         self.assertEqual('OPENID', res['openid'])
Exemplo n.º 16
0
 def test_real_request_fallback(self):
     with HTTMock(any_mock):
         with HTTMock(google_mock, facebook_mock):
             r = requests.get('http://example.com/')
     self.assertEqual(r.status_code, 200)
     self.assertEqual(r.content, 'Hello from example.com')
Exemplo n.º 17
0
 def test_check_access_token(self):
     with HTTMock(wechat_api_mock):
         self.oauth.fetch_access_token('123456')
         res = self.oauth.check_access_token()
         self.assertEqual(True, res)
Exemplo n.º 18
0
class MessageHandlerTestCase(TestCase):

    # Common strings
    remind_desc = '提醒我明天上午十点开会'
    instructions_to_use = '如需设置提醒'
    remind_base_on_location = '基于地理位置的提醒'

    mock = HTTMock(access_token_mock, semantic_parser_mock)

    @classmethod
    def setUpTestData(cls):
        cls.mock.__enter__()

    def setUp(self):
        self.user = WechatUser(openid='FromUser', nickname='UserName')
        self.user.save()
        self.settings(WX_APPID='123').enable()
        wechat_client.appid = '123'
        # Disable scheduler
        post_save.disconnect(dispatch_uid='update-scheduler')

    def build_wechat_msg(self, req_text):
        return parse_message(req_text)

    def test_text(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1348831860</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[%s]]></Content>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """ % self.remind_desc
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn('时间:', resp_xml)
        self.assertNotIn('重复:', resp_xml)

    def test_repeat_text(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1348831860</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[%s]]></Content>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """ % '每月20号提醒我还信用卡'
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn('时间:', resp_xml)
        self.assertIn('重复:', resp_xml)
        self.assertIn('每月', resp_xml)

    def test_image(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1348831860</CreateTime>
        <MsgType><![CDATA[image]]></MsgType>
        <PicUrl><![CDATA[this is a url]]></PicUrl>
        <MediaId><![CDATA[media_id]]></MediaId>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn(self.instructions_to_use, resp_xml)

    def test_voice(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1357290913</CreateTime>
        <MsgType><![CDATA[voice]]></MsgType>
        <MediaId><![CDATA[media_id]]></MediaId>
        <Format><![CDATA[Format]]></Format>
        <Recognition><![CDATA[%s]]></Recognition>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """ % self.remind_desc
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn('时间:', resp_xml)

    def test_video(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1357290913</CreateTime>
        <MsgType><![CDATA[video]]></MsgType>
        <MediaId><![CDATA[media_id]]></MediaId>
        <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn(self.instructions_to_use, resp_xml)

    def test_shortvideo(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1357290913</CreateTime>
        <MsgType><![CDATA[shortvideo]]></MsgType>
        <MediaId><![CDATA[media_id]]></MediaId>
        <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn(self.instructions_to_use, resp_xml)

    def test_location(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1351776360</CreateTime>
        <MsgType><![CDATA[location]]></MsgType>
        <Location_X>23.134521</Location_X>
        <Location_Y>113.358803</Location_Y>
        <Scale>20</Scale>
        <Label><![CDATA[位置信息]]></Label>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn(self.remind_base_on_location, resp_xml)

    def test_link(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>1351776360</CreateTime>
        <MsgType><![CDATA[link]]></MsgType>
        <Title><![CDATA[公众平台官网链接]]></Title>
        <Description><![CDATA[公众平台官网链接]]></Description>
        <Url><![CDATA[url]]></Url>
        <MsgId>1234567890123456</MsgId>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn(self.instructions_to_use, resp_xml)

    def test_subscribe_event(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>123456789</CreateTime>
        <MsgType><![CDATA[event]]></MsgType>
        <Event><![CDATA[subscribe]]></Event>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn('直接输入文字或者语音就可以快速创建提醒', resp_xml)
        self.user.refresh_from_db()
        self.assertTrue(self.user.subscribe)

    def test_unsubscribe_event(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>123456789</CreateTime>
        <MsgType><![CDATA[event]]></MsgType>
        <Event><![CDATA[unsubscribe]]></Event>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.user.refresh_from_db()
        self.assertFalse(self.user.subscribe)

    def test_location_event(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>123456789</CreateTime>
        <MsgType><![CDATA[event]]></MsgType>
        <Event><![CDATA[LOCATION]]></Event>
        <Latitude>23.137466</Latitude>
        <Longitude>113.352425</Longitude>
        <Precision>119.385040</Precision>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn(self.remind_base_on_location, resp_xml)

    def test_click_event_for_remind_today(self):
        req_text = """
        <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[FromUser]]></FromUserName>
        <CreateTime>123456789</CreateTime>
        <MsgType><![CDATA[event]]></MsgType>
        <Event><![CDATA[CLICK]]></Event>
        <EventKey><![CDATA[time_remind_today]]></EventKey>
        </xml>
        """
        wechat_msg = self.build_wechat_msg(req_text)
        resp_xml = handle_message(wechat_msg)
        self.assertIn('今天没有提醒', resp_xml)
        WechatUser(openid='abc', nickname='abc').save()
        r = Remind(time=timezone.now(), owner_id=self.user.pk, event='睡觉')
        r.save()
        resp_xml = handle_message(wechat_msg)
        self.assertIn(r.title(), resp_xml)
        self.assertIn(r.local_time_string('G:i'), resp_xml)

        r = Remind(time=timezone.now(), owner_id=self.user.pk, event='吃饭', participants=['abc'])
        r.save()
        self.assertEqual(WechatUser.objects.get(pk='abc').get_time_reminds().first(), r)
 def test_discharge_successful(self):
     macaroon = self._makeMockMacaroon(
         ('http://example.com/', "caveat_key", "identifier"))
     with HTTMock(discharge_macaroon_200):
         results = self.idm.discharge('Brad', macaroon)
     self.assertEqual(base64.urlsafe_b64encode(b'"something"'), results)
Exemplo n.º 20
0
 def apimock(self):
     return HTTMock(self.api_list, self.api_report, self.api_report_v2,
                    self.api_nutrients, self.api_search)
 def test_discharge_token_successful(self):
     with HTTMock(discharge_token_200):
         results = self.idm.discharge_token('Brad')
     self.assertEqual(b'["something"]', base64.urlsafe_b64decode(results))
 def test_find_item(self):
     with HTTMock(archive_mock):
         items = self.provider.find(self.query)
     self.assertEqual(len(items.docs), 2)
     self.assertEqual(items._count, 25000)
 def test_set_extra_info_ok(self):
     with HTTMock(extra):
         # This will blow up if set_extra_info isn't passing the data along
         # correctly--see the assert in extra above.
         self.idm.set_extra_info('frobnar', {'foo': 1})
Exemplo n.º 24
0
 def test_simple_command(self):
     with HTTMock(cmd_simple):
         cmd = ipfsApi.commands.Command('/simple')
         res = cmd.request(self._client)
         self.assertEquals(res['Message'], 'okay')
Exemplo n.º 25
0
    def test_fetch_to_jimi(self, update_renditions_mock):
        service = OrangelogicSearchProvider(self.provider)

        update_renditions_mock.side_effects = set_rendition

        self.app.media.get.return_value = io.BytesIO(
            read_fixture(
                '9e627f74b97841b3b8562b6547ada9c7-d1538139479c43e88021152.jpg',
                'rb'))

        with HTTMock(auth_ok, fetch_ok):
            with patch.dict(superdesk.resources, resources):
                fetched = service.fetch({})
            update_renditions_mock.assert_called_once_with(
                fetched,
                'https://example.com/htm/GetDocumentAPI.aspx?F=TRX&DocID=2RLQZBCB4R4R4&token=token.foo',
                None,
            )

        self.assertEqual('picture', fetched['type'])
        self.assertIsInstance(fetched['firstcreated'], datetime)

        # populate ids
        fetched['family_id'] = fetched['guid']

        with patch.dict(superdesk.resources, resources):
            formatter = JimiFormatter()
            xml = formatter.format(fetched, {})[0][1]

        root = etree.fromstring(xml.encode(formatter.ENCODING))

        self.assertEqual('Pictures', root.find('Services').text)

        item = root.find('ContentItem')

        self.assertEqual('Zhang Yuwei', item.find('Byline').text)
        self.assertEqual('I', item.find('Category').text)
        self.assertEqual('News - Optional', item.find('Ranking').text)
        self.assertEqual('5', item.find('RankingValue').text)
        self.assertEqual('THE ASSOCIATED PRESS', item.find('Credit').text)
        self.assertEqual('Virus Outbreak China Vaccine',
                         item.find('SlugProper').text)
        self.assertEqual('Unknown AP', item.find('Source').text)
        self.assertEqual('Beijing', item.find('City').text)
        self.assertEqual('China', item.find('Country').text)
        self.assertEqual('Beijing;;China', item.find('Placeline').text)
        # self.assertEqual('XIN902', item.find('OrigTransRef').text)
        self.assertEqual('SUB', item.find('BylineTitle').text)
        self.assertEqual('NHG', item.find('CaptionWriter').text)
        self.assertEqual('Xinhua', item.find('Copyright').text)
        self.assertIn(
            "In this April 10, 2020, photo released by Xinhua News Agency, a staff",
            item.find('EnglishCaption').text)
        self.assertEqual('2020-04-12T00:09:37', item.find('DateTaken').text)
        self.assertEqual(
            'NO SALES, PHOTO RELEASED BY XINHUA NEWS AGENCY APRIL 10, 2020 PHOTO',
            item.find('SpecialInstructions').text)
        self.assertEqual('Unknown AP', item.find('ArchiveSources').text)
        self.assertEqual('9e627f74b97841b3b8562b6547ada9c7',
                         item.find('CustomField1').text)
        self.assertEqual('Xinhua', item.find('CustomField6').text)
Exemplo n.º 26
0
 def test_arg_command(self):
     with HTTMock(cmd_with_arg):
         cmd = ipfsApi.commands.ArgCommand('/arg')
         res = cmd.request(self._client, 'arg1')
         self.assertEquals(res['Arg'][0], 'arg1')
Exemplo n.º 27
0
 def test_tag_list(self):
     with HTTMock(wechat_api_mock):
         res = self.client.tag.list()
         self.assertEqual(2, len(res))
Exemplo n.º 28
0
 def test_refresh_access_token(self):
     with HTTMock(wechat_api_mock):
         res = self.oauth.refresh_access_token('123456')
         self.assertEqual('ACCESS_TOKEN', res['access_token'])
Exemplo n.º 29
0
 def test_user_convert_to_openid(self):
     with HTTMock(wechat_api_mock):
         res = self.client.user.convert_to_openid('zhangsan')
         self.assertEqual('oDOGms-6yCnGrRovBj2yHij5JL6E', res['openid'])
         self.assertEqual('wxf874e15f78cc84a7', res['appid'])
Exemplo n.º 30
0
 def test_qrcode_view_with_enketo_error(self):
     with HTTMock(enketo_error_mock):
         response = self._get_grcode_view_response()
         self.assertEqual(response.status_code, 400)