def test_registering_new_device_view(self): """Test that the HTML view works.""" hass = MagicMock() with tempfile.NamedTemporaryFile() as fp: hass.config.path.return_value = fp.name fp.close() service = html5.get_service(hass, {}) assert service is not None # assert hass.called assert len(hass.mock_calls) == 3 view = hass.mock_calls[1][1][0] assert view.json_path == fp.name assert view.registrations == {} builder = EnvironBuilder(method='POST', data=json.dumps(SUBSCRIPTION_1)) Request = request_class() resp = view.post(Request(builder.get_environ())) expected = { 'unnamed device': SUBSCRIPTION_1, } assert resp.status_code == 200, resp.response assert view.registrations == expected with open(fp.name) as fpp: assert json.load(fpp) == expected
def test_10_api_endpoint(self): fixed = "ebedeeefegeheiej" otpkey = "cc17a4d77eaed96e9d14b5c87a02e718" uid = "000000000000" otps = ["ebedeeefegeheiejtjtrutblehenfjljrirgdihrfuetljtt", "ebedeeefegeheiejlekvlrlkrcluvctenlnnjfknrhgtjned", "ebedeeefegeheiejktudedbktcnbuntrhdueikggtrugckij", "ebedeeefegeheiejjvjncbnffdrvjcvrbgdfufjgndfetieu", "ebedeeefegeheiejdruibhvlvktcgfjiruhltketifnitbuk" ] token = init_token({"type": "yubikey", "otpkey": otpkey, "otplen": len(otps[0]), "yubikey.prefix": fixed, "serial": "UBAM12345678_1"}) builder = EnvironBuilder(method='GET', headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" g.client_ip = env["REMOTE_ADDR"] req = Request(env) nonce = "random nonce" apiid = "hallo" apikey = "1YMEbMZijD3DzL21UfKGnOOI13c=" set_privacyidea_config("yubikey.apiid.{0!s}".format(apiid), apikey) req.all_data = {'id': apiid, "otp": otps[0], "nonce": nonce} text_type, result = YubikeyTokenClass.api_endpoint(req, g) self.assertEqual(text_type, "plain") self.assertTrue("status=OK" in result, result) self.assertTrue("nonce={0!s}".format(nonce) in result, result)
def test_callback_view_no_jwt(self): """Test that the notification callback view works without JWT.""" hass = MagicMock() m = mock_open() with patch( 'homeassistant.components.notify.html5.open', m, create=True ): hass.config.path.return_value = 'file.conf' service = html5.get_service(hass, {}) assert service is not None # assert hass.called assert len(hass.mock_calls) == 3 view = hass.mock_calls[2][1][0] builder = EnvironBuilder(method='POST', data=json.dumps({ 'type': 'push', 'tag': '3bc28d69-0921-41f1-ac6a-7a627ba0aa72' })) Request = request_class() resp = view.post(Request(builder.get_environ())) assert resp.status_code == 401, resp.response
def test_redirect_url_error_1(self, mock_validate_email): """ Tests the user is redirected to appropriate location """ # Build test environment builder = EnvironBuilder(method='POST', data={'name': 'Valid Guy', 'email': '*****@*****.**', 'redirect': 'http://www.example.com', 'last_name': '', 'token': conf.TOKEN}) env = builder.get_environ() req = Request(env) # Mock validate email so returns false in Travis # Not technically necessary because this will return false in Travis # regardless since it can't find the SMTP server, but kept here for # consistency mock_validate_email.return_value = False # Create app and mock redirect app = handler.create_app() werkzeug.utils.redirect = Mock('werkzeug.utils.redirect') # Mock sendmail function so it doesn't send an actual email smtplib.SMTP.sendmail = Mock('smtplib.SMTP.sendmail') app.on_form_page(req) werkzeug.utils.redirect.assert_called_with( 'http://www.example.com?error=1&message=Invalid+Email', code=302)
def test_registering_new_device_view(self): """Test that the HTML view works.""" hass = MagicMock() m = mock_open() with patch( 'homeassistant.components.notify.html5.open', m, create=True ): hass.config.path.return_value = 'file.conf' service = html5.get_service(hass, {}) assert service is not None # assert hass.called assert len(hass.mock_calls) == 3 view = hass.mock_calls[1][1][0] assert view.json_path == hass.config.path.return_value assert view.registrations == {} builder = EnvironBuilder(method='POST', data=json.dumps(SUBSCRIPTION_1)) Request = request_class() resp = view.post(Request(builder.get_environ())) expected = { 'unnamed device': SUBSCRIPTION_1, } assert resp.status_code == 200, resp.response assert view.registrations == expected handle = m() assert json.loads(handle.write.call_args[0][0]) == expected
def test_15_reset_password(self): builder = EnvironBuilder(method='POST', data={'user': "******", "realm": self.realm1}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) # Set a mangle policy to change the username # and only use the last 4 characters of the username set_policy(name="recover", scope=SCOPE.USER, action="%s" % ACTION.RESYNC) g.policy_object = PolicyClass() req.all_data = {"user": "******", "realm": self.realm1} # There is a user policy without password reset, so an exception is # raised self.assertRaises(PolicyError, check_anonymous_user, req, ACTION.PASSWORDRESET) # The password reset is allowed set_policy(name="recover", scope=SCOPE.USER, action="%s" % ACTION.PASSWORDRESET) g.policy_object = PolicyClass() r = check_anonymous_user(req, ACTION.PASSWORDRESET) self.assertEqual(r, True)
def test_03_no_detail_on_success(self): builder = EnvironBuilder(method='POST', data={'serial': "HOTP123435"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) # The response contains the token type SPASS res = {"jsonrpc": "2.0", "result": {"status": True, "value": True}, "version": "privacyIDEA test", "id": 1, "detail": {"message": "matching 1 tokens", "serial": "HOTP123456", "type": "hotp"}} resp = Response(json.dumps(res)) # Set a policy, that does not allow the detail on success set_policy(name="pol2", scope=SCOPE.AUTHZ, action="no_detail_on_success", client="10.0.0.0/8") g.policy_object = PolicyClass() new_response = no_detail_on_success(req, resp) jresult = json.loads(new_response.data) self.assertTrue("detail" not in jresult, jresult) delete_policy("pol2")
def test_13_remote_user(self): g.logged_in_user = {"username": "******", "role": "admin"} builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" env["REMOTE_USER"] = "******" req = Request(env) # A user, for whom the login via REMOTE_USER is allowed. set_policy(name="ruser", scope=SCOPE.WEBUI, action="%s=%s" % (ACTION.REMOTE_USER, REMOTE_USER.ACTIVE)) g.policy_object = PolicyClass() r = is_remote_user_allowed(req) self.assertEqual(r, [REMOTE_USER.ACTIVE]) # Login for the REMOTE_USER is not allowed. # Only allowed for user "super", but REMOTE_USER=admin set_policy(name="ruser", scope=SCOPE.WEBUI, action="%s=%s" % (ACTION.REMOTE_USER, REMOTE_USER.ACTIVE), user="******") g.policy_object = PolicyClass() r = is_remote_user_allowed(req) self.assertEqual(r, []) delete_policy("ruser")
def test_14_required_email(self): g.logged_in_user = {"username": "******", "role": "admin"} builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) # Set a mangle policy to change the username # and only use the last 4 characters of the username set_policy(name="email1", scope=SCOPE.REGISTER, action="%s=/.*@mydomain\..*" % ACTION.REQUIREDEMAIL) g.policy_object = PolicyClass() # request, that matches the policy req.all_data = {"email": "*****@*****.**"} # This emails is allowed r = required_email(req) self.assertTrue(r) # This email is not allowed req.all_data = {"email": "*****@*****.**"} # This emails is allowed self.assertRaises(RegistrationError, required_email, req) delete_policy("email1") g.policy_object = PolicyClass() # Without a policy, this email can register req.all_data = {"email": "*****@*****.**"} # This emails is allowed r = required_email(req) self.assertTrue(r)
def test_08_encrypt_pin(self): g.logged_in_user = {"username": "******", "role": "admin"} builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) # Set a policy that defines the PIN to be encrypted set_policy(name="pol1", scope=SCOPE.ENROLL, action=ACTION.ENCRYPTPIN) g.policy_object = PolicyClass() # request, that matches the policy req.all_data = { "user": "******", "realm": "home"} encrypt_pin(req) # Check, if the tokenlabel was added self.assertEqual(req.all_data.get("encryptpin"), "True") # finally delete policy delete_policy("pol1")
def test_10_check_external(self): g.logged_in_user = {"username": "******", "role": "user"} builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() req = Request(env) g.policy_object = PolicyClass() req.all_data = { "user": "******", "realm": "home"} # Check success on no definition r = check_external(req) self.assertTrue(r) # Check success with external function current_app.config["PI_INIT_CHECK_HOOK"] = \ "privacyidea.api.lib.prepolicy.mock_success" r = check_external(req) self.assertTrue(r) # Check exception with external function current_app.config["PI_INIT_CHECK_HOOK"] = \ "privacyidea.api.lib.prepolicy.mock_fail" self.assertRaises(Exception, check_external, req)
def test_06_set_tokenlabel(self): g.logged_in_user = {"username": "******", "role": "admin"} builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) # Set a policy that defines the tokenlabel set_policy(name="pol1", scope=SCOPE.ENROLL, action="%s=%s" % (ACTION.TOKENLABEL, "<u>@<r>")) set_policy(name="pol2", scope=SCOPE.ENROLL, action="%s=%s" % (ACTION.TOKENISSUER, "myPI")) g.policy_object = PolicyClass() # request, that matches the policy req.all_data = { "user": "******", "realm": "home"} init_tokenlabel(req) # Check, if the tokenlabel was added self.assertEqual(req.all_data.get("tokenlabel"), "<u>@<r>") # Check, if the tokenissuer was added self.assertEqual(req.all_data.get("tokenissuer"), "myPI") # finally delete policy delete_policy("pol1") delete_policy("pol2")
def test_07_set_random_pin(self): g.logged_in_user = {"username": "******", "role": "admin"} builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) # Set a policy that defines the tokenlabel set_policy(name="pol1", scope=SCOPE.ENROLL, action="%s=%s" % (ACTION.OTPPINRANDOM, "12")) set_policy(name="pinhandling", scope=SCOPE.ENROLL, action="%s=privacyidea.lib.pinhandling.base.PinHandler" % ACTION.PINHANDLING) g.policy_object = PolicyClass() # request, that matches the policy req.all_data = { "user": "******", "realm": "home"} init_random_pin(req) # Check, if the tokenlabel was added self.assertEqual(len(req.all_data.get("pin")), 12) # finally delete policy delete_policy("pol1") delete_policy("pinhandling")
def test_01a_admin_realms(self): admin1 = {"username": "******", "role": "admin", "realm": "realm1"} admin2 = {"username": "******", "role": "admin", "realm": "realm2"} set_policy(name="pol", scope=SCOPE.ADMIN, action="*", adminrealm="realm1") g.policy_object = PolicyClass() builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) req.all_data = {} # admin1 is allowed to do everything g.logged_in_user = admin1 r = check_base_action(req, action="delete") self.assertTrue(r) # admin2 is not allowed. g.logged_in_user = admin2 self.assertRaises(PolicyError, check_base_action, req, action="delete") delete_policy("pol")
def test_03_check_token_upload(self): g.logged_in_user = {"username": "******", "role": "admin"} builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" req = Request(env) req.all_data = {"filename": "token.xml"} # Set a policy, that does allow the action set_policy(name="pol1", scope=SCOPE.ADMIN, action="enrollTOTP, enrollHOTP, %s" % ACTION.IMPORT, client="10.0.0.0/8") g.policy_object = PolicyClass() # Try to import tokens r = check_token_upload(req) self.assertTrue(r) # The admin can not upload from another IP address # An exception is raised env["REMOTE_ADDR"] = "192.168.0.1" req = Request(env) req.all_data = {"filename": "token.xml"} self.assertRaises(PolicyError, check_token_upload, req) # finally delete policy delete_policy("pol1")
def test_submit_handler_foreignid(conn): values = {'format': 'json', 'client': 'app1key', 'user': '******', 'duration': str(TEST_1_LENGTH), 'fingerprint': TEST_1_FP, 'bitrate': 192, 'foreignid': 'foo:123', 'fileformat': 'FLAC'} builder = EnvironBuilder(method='POST', data=values) handler = SubmitHandler(connect=provider(conn)) resp = handler.handle(Request(builder.get_environ())) assert_equals('application/json; charset=UTF-8', resp.content_type) expected = {"status": "ok"} assert_json_equals(expected, resp.data) assert_equals('200 OK', resp.status) query = tables.submission.select().order_by(tables.submission.c.id.desc()).limit(1) submission = conn.execute(query).fetchone() assert_equals(None, submission['mbid']) assert_equals(None, submission['puid']) assert_equals(1, submission['foreignid_id']) assert_equals(1, submission['format_id']) assert_equals(192, submission['bitrate']) assert_equals(TEST_1_FP_RAW, submission['fingerprint']) assert_equals(TEST_1_LENGTH, submission['length']) query = tables.foreignid_vendor.select().order_by(tables.foreignid_vendor.c.id.desc()).limit(1) row = conn.execute(query).fetchone() assert_equals(1, row['id']) assert_equals('foo', row['name']) query = tables.foreignid.select().order_by(tables.foreignid.c.id.desc()).limit(1) row = conn.execute(query).fetchone() assert_equals(1, row['id']) assert_equals(1, row['vendor_id']) assert_equals('123', row['name'])
def test_07_sign_response(self): builder = EnvironBuilder(method='POST', data={}, headers={}) env = builder.get_environ() env["REMOTE_ADDR"] = "192.168.0.1" req = Request(env) req.values = {"user": "******", "pass": "******", "nonce": "12345678"} res = {"jsonrpc": "2.0", "result": {"status": True, "value": True}, "version": "privacyIDEA test", "id": 1} resp = Response(json.dumps(res)) from privacyidea.lib.crypto import Sign g.sign_object = Sign("tests/testdata/private.pem", "tests/testdata/public.pem") new_response = sign_response(req, resp) jresult = json.loads(new_response.data) self.assertEqual(jresult.get("nonce"), "12345678") self.assertEqual(jresult.get("signature"), "7220461805369685253863294214862525311437731987121534735993146952136348520396812489782945679627890785973634896605293523175424850299832912878523161817380029213546063467888018205435416020286712762804412024065559270543774578319469096483246637875013247101135063221604113204491121777932147776087110152414627230087278622508771143940031542890514380486863296102037208395371717795767683973979032142677315402422403254992482761563612174177151960004042109847122772813717599078313600692433727690239340230353616318691769042290314664126975201679642739717702497638318611217001361093950139025744740660953017413716736691777322916588328")
def test_apihandler_ws_error(conn): values = {'format': 'json'} builder = EnvironBuilder(method='POST', data=values) handler = WebServiceErrorHandler(connect=provider(conn)) resp = handler.handle(Request(builder.get_environ())) assert_equals('application/json; charset=UTF-8', resp.content_type) expected = { "status": "error", "error": { "message": "invalid API key", "code": 4, } } assert_json_equals(expected, resp.data) assert_equals('400 BAD REQUEST', resp.status) handler = InternalErrorHandler(connect=provider(conn)) resp = handler.handle(Request(builder.get_environ())) assert_equals('application/json; charset=UTF-8', resp.content_type) expected = { "status": "error", "error": { "message": "internal error", "code": 5, } } assert_json_equals(expected, resp.data) assert_equals('500 INTERNAL SERVER ERROR', resp.status)
def test_submit_handler_with_meta(conn): values = {'format': 'json', 'client': 'app1key', 'user': '******', 'duration': str(TEST_1_LENGTH), 'fingerprint': TEST_1_FP, 'bitrate': 192, 'mbid': 'b9c05616-1874-4d5d-b30e-6b959c922d28', 'fileformat': 'FLAC', 'track': 'Voodoo People', 'artist': 'The Prodigy', 'album': 'Music For The Jitled People', 'albumartist': 'Prodigy', 'trackno': '2', 'discno': '3', 'year': '2030' } builder = EnvironBuilder(method='POST', data=values) handler = SubmitHandler(connect=provider(conn)) resp = handler.handle(Request(builder.get_environ())) assert_equals('application/json; charset=UTF-8', resp.content_type) expected = {"status": "ok"} assert_json_equals(expected, resp.data) assert_equals('200 OK', resp.status) query = tables.submission.select().order_by(tables.submission.c.id.desc()).limit(1) submission = conn.execute(query).fetchone() assert_equals('b9c05616-1874-4d5d-b30e-6b959c922d28', submission['mbid']) assert_equals(1, submission['meta_id']) row = conn.execute("SELECT * FROM meta WHERE id=1").fetchone() expected = { 'id': 1, 'track': 'Voodoo People', 'artist': 'The Prodigy', 'album': 'Music For The Jitled People', 'album_artist': 'Prodigy', 'track_no': 2, 'disc_no': 3, 'year': 2030 } assert_equals(expected, dict(row))
def from_values(cls, *args, **kwargs): """Create a new request object based on the values provided. If environ is given missing values are filled from there. This method is useful for small scripts when you need to simulate a request from an URL. Do not use this method for unittesting, there is a full featured client object (:class:`Client`) that allows to create multipart requests, support for cookies etc. This accepts the same options as the :class:`~werkzeug.test.EnvironBuilder`. .. versionchanged:: 0.5 This method now accepts the same arguments as :class:`~werkzeug.test.EnvironBuilder`. Because of this the `environ` parameter is now called `environ_overrides`. :return: request object """ from werkzeug.test import EnvironBuilder charset = kwargs.pop('charset', cls.charset) kwargs['charset'] = charset builder = EnvironBuilder(*args, **kwargs) try: return builder.get_request(cls) finally: builder.close()
def test_send_email_default(self, mock_validate_email): """ Tests that the form is sent to the correct default address when the 'send_to' field is set to an empty string. Returns true if the form has been sent to [email protected] Errors out if unsuccessful """ builder = EnvironBuilder(method='POST', data={'name': 'Valid Guy', 'email': '*****@*****.**', 'send_to': '', 'last_name': '', 'token': conf.TOKEN, 'redirect': 'http://www.example.com'}) env = builder.get_environ() req = Request(env) # Construct message for assertion msg = handler.create_msg(req) msg_send = MIMEText(str(msg)) msg_subj = handler.set_mail_subject(msg) msg_send['Subject'] = msg_subj msg_send['To'] = conf.EMAIL['default'] # Mock sendmail function smtplib.SMTP.sendmail = Mock('smtplib.SMTP.sendmail') # Call send_email and assert sendmail was correctly called handler.send_email(msg, msg_subj, send_to_email='default') smtplib.SMTP.sendmail.assert_called_with(conf.FROM, conf.EMAIL['default'], msg_send.as_string())
def test_loading_file(self): """Test that it loads image from disk.""" self.hass.wsgi = mock.MagicMock() with NamedTemporaryFile() as fp: fp.write('hello'.encode('utf-8')) fp.flush() assert setup_component(self.hass, 'camera', { 'camera': { 'name': 'config_test', 'platform': 'local_file', 'file_path': fp.name, }}) image_view = self.hass.wsgi.mock_calls[0][1][0] builder = EnvironBuilder(method='GET') Request = request_class() request = Request(builder.get_environ()) request.authenticated = True resp = image_view.get(request, 'camera.config_test') assert resp.status_code == 200, resp.response assert resp.response[0].decode('utf-8') == 'hello'
def test_send_email(self): """ Tests send_email send_email returns True when it successfully sends an email to a default address and errors out when unsuccessful. """ # Build test environment builder = EnvironBuilder(method='POST', data={'name': 'Valid Guy', 'email': '*****@*****.**', 'last_name': '', 'token': conf.TOKEN, 'redirect': 'http://www.example.com'}) env = builder.get_environ() req = Request(env) # Construct message for assertion msg = handler.create_msg(req) msg_send = MIMEText(str(msg)) msg_subj = handler.set_mail_subject(msg) msg_send['Subject'] = msg_subj msg_send['To'] = conf.EMAIL['default'] # Mock sendmail function so it doesn't send an actual email smtplib.SMTP.sendmail = Mock('smtplib.SMTP.sendmail') # Call send_email and assert sendmail was called correctly handler.create_app() handler.send_email(msg, msg_subj) smtplib.SMTP.sendmail.assert_called_with(conf.FROM, conf.EMAIL['default'], msg_send.as_string())
def test_format_message(self): # Build test environment builder = EnvironBuilder(method='POST', data={'name': 'Valid Guy', 'email': '*****@*****.**', 'some_field': ("This is multi line and " "should not be on the " "same line as the title"), 'redirect': 'http://www.example.com', 'last_name': '', 'token': conf.TOKEN}) env = builder.get_environ() req = Request(env) target_message = ("Contact:\n" "--------\n" "NAME: Valid Guy\n" "EMAIL: [email protected]\n\n" "Information:\n" "------------\n" "Some Field:\n\n" "This is multi line and should not be on the same " "line as the title\n\n") message = handler.create_msg(req) formatted_message = handler.format_message(message) self.assertEqual(formatted_message, target_message)
def test_redirect_url_error_3(self, mock_validate_email): """ Tests the user is redirected to appropriate location """ # Build test environment builder = EnvironBuilder(method='POST', data={'name': 'Valid Guy', 'email': '*****@*****.**', 'redirect': 'http://www.example.com', 'last_name': '!', 'token': 'wrong token'}) env = builder.get_environ() req = Request(env) # Mock validate email so returns true in Travis mock_validate_email.return_value = True # Create app and mock redirect app = handler.create_app() werkzeug.utils.redirect = Mock('werkzeug.utils.redirect') # Mock sendmail function so it doesn't send an actual email smtplib.SMTP.sendmail = Mock('smtplib.SMTP.sendmail') app.on_form_page(req) werkzeug.utils.redirect.assert_called_with( 'http://www.example.com?error=3&message=Improper+Form+Submission', code=302)
def test_redirect_url_error_4(self, mock_validate_email): """ Tests the user is redirected to appropriate location """ # Build test environment builder = EnvironBuilder(method='POST', data={'name': 'Valid Guy', 'email': '*****@*****.**', 'redirect': 'http://www.example.com', 'last_name': '', 'token': conf.TOKEN}) env = builder.get_environ() req = Request(env) # Mock validate email so returns true in Travis mock_validate_email.return_value = True app = handler.create_app() werkzeug.utils.redirect = Mock('werkzeug.utils.redirect') # Mock sendmail function so it doesn't send an actual email smtplib.SMTP.sendmail = Mock('smtplib.SMTP.sendmail') for i in range(conf.CEILING + 1): app.on_form_page(req) # Avoid duplicate form error builder.form['name'] = str(i) + builder.form['name'] werkzeug.utils.redirect.assert_called_with( 'http://www.example.com?error=4&message=Too+Many+Requests', code=302)
def test_loading_file(self): """Test that it loads image from disk.""" test_string = 'hello' self.hass.wsgi = mock.MagicMock() with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \ mock.patch('os.access', mock.Mock(return_value=True)): assert setup_component(self.hass, 'camera', { 'camera': { 'name': 'config_test', 'platform': 'local_file', 'file_path': 'mock.file', }}) image_view = self.hass.wsgi.mock_calls[0][1][0] m_open = mock.mock_open(read_data=test_string) with mock.patch( 'homeassistant.components.camera.local_file.open', m_open, create=True ): builder = EnvironBuilder(method='GET') Request = request_class() # pylint: disable=invalid-name request = Request(builder.get_environ()) request.authenticated = True resp = image_view.get(request, 'camera.config_test') assert resp.status_code == 200, resp.response assert resp.response[0].decode('utf-8') == test_string
def setUp(self): self.ctx = app.test_request_context() self.ctx.push() init_data() self.client = app.test_client() builder = EnvironBuilder(method='POST') self.post_env = builder.get_environ()
def test_unregistering_device_view_handles_unknown_subscription(self): """Test that the HTML unregister view handles unknown subscriptions.""" hass = MagicMock() config = { 'some device': SUBSCRIPTION_1, 'other device': SUBSCRIPTION_2, } with tempfile.NamedTemporaryFile() as fp: hass.config.path.return_value = fp.name fp.write(json.dumps(config).encode('utf-8')) fp.flush() service = html5.get_service(hass, {}) assert service is not None # assert hass.called assert len(hass.mock_calls) == 3 view = hass.mock_calls[1][1][0] assert view.json_path == fp.name assert view.registrations == config builder = EnvironBuilder(method='DELETE', data=json.dumps({ 'subscription': SUBSCRIPTION_3['subscription'] })) Request = request_class() resp = view.delete(Request(builder.get_environ())) assert resp.status_code == 200, resp.response assert view.registrations == config with open(fp.name) as fpp: assert json.load(fpp) == config
def handler(self, func, param): builder = EnvironBuilder( method=param['method'], path=param['path'], query_string=param.get('query_string'), headers=param['header'], data=base64.b64decode(param['body']) ) environ = builder.get_environ() request = Request(environ, populate_request=False, shallow=False) response = func(request) status = 200 if isinstance(response, BaseResponse): headers = {} for k, v in response.headers: headers[k] = [v] body_byte = response.get_data() body = base64.b64encode(body_byte).decode('utf-8') status = response.status_code elif isinstance(response, str): headers = {'Content-Type': ['text/plain; charset=utf-8']} body = base64.b64encode( bytes(response, 'utf-8') ).decode('utf-8') else: headers = { 'Content-Type': ['application/json'] } body = encode_base64_json(response).decode('utf-8') return { 'status': status, 'header': headers, 'body': body }
def test_wrong_token_jwt_no_sso(self): Config.jwt_secret = "jwt_token" builder = EnvironBuilder() request = Request(builder.get_environ()) with self.assertRaises(Forbidden): self.valid_token(token="lallabalalla", _request=request)
def test_05_api_endpoint_with_multiple_tokens(self): # We test the behavior of the TiQR token with other CR tokens (ie. an email token) present smtpmock.setdata(response={"*****@*****.**": (200, 'OK')}) other_token = init_token( { "type": "email", "email": "*****@*****.**", "pin": "somepin" }, User('selfservice', self.realm1)) pin = "tiqr" token = init_token({ "type": "tiqr", "pin": pin }, User('selfservice', self.realm1)) idetail = token.get_init_detail() value = idetail.get("tiqrenroll").get("value") # 'tiqrenroll://None?action=metadata&session=b81ecdf74118dcf6fa1cd41d3d4b2fec56c9107f&serial=TiQR000163CB # get the serial and the session m = re.search('&serial=(.*)$', value) serial = m.group(1) m = re.search('&session=(.*)&', value) session = m.group(1) # test meta data builder = EnvironBuilder(method='POST', data={}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" g.client_ip = env["REMOTE_ADDR"] req = Request(env) req.all_data = { "action": "metadata", "session": session, "serial": serial } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "json") self.assertTrue("identity" in r[1], r[1]) self.assertTrue("service" in r[1], r[1]) # Test invalid action req.all_data = {"action": "unknown"} self.assertRaises(Exception, TiqrTokenClass.api_endpoint, req, g) # test enrollment with invalid session req.all_data = { "action": "enrollment", "serial": serial, "session": "123", "secret": KEY20 } self.assertRaises(ParameterError, TiqrTokenClass.api_endpoint, req, g) # test enrollment with valid session req.all_data = { "action": "enrollment", "serial": serial, "session": session, "secret": KEY20 } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") self.assertEqual(r[1], "OK") # test authentication endpoint # create a challenge by issuing validate/triggerchallenge with self.app.test_request_context('/validate/triggerchallenge', method='POST', data={ "user": "******", "realm": self.realm1 }, headers={"Authorization": self.at}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) result = res.json.get("result") detail = res.json.get("detail") self.assertTrue(result.get("status") is True, result) transaction_id = detail.get("transaction_id") # we've got two challenges with the same transaction ID self.assertEqual(len(detail["multi_challenge"]), 2) email_challenge = [ challenge for challenge in detail["multi_challenge"] if challenge["type"] == "email" ][0] self.assertEqual(email_challenge["transaction_id"], transaction_id) tiqr_challenge = [ challenge for challenge in detail["multi_challenge"] if challenge["type"] == "tiqr" ][0] self.assertEqual(tiqr_challenge["transaction_id"], transaction_id) image_url = tiqr_challenge.get("attributes").get("value") self.assertTrue(image_url.startswith("tiqrauth")) # u'tiqrauth://[email protected] # /12335970131032896263/e0fac7bb2e3ea4219ead' # session = 12335970131032896263 # challenge = e0fac7bb2e3ea4219ead r = image_url.split("/") session = r[3] challenge = r[4] # check the URL parsed_url = urlparse(image_url) self.assertEqual(parsed_url.netloc, "*****@*****.**") ocrasuite = token.get_tokeninfo("ocrasuite") ocra_object = OCRA(ocrasuite, key=binascii.unhexlify(KEY20)) # Calculate Response with the challenge. response = ocra_object.get_response(challenge) encoded_user_id = u"{!s}_{!s}".format("selfservice", self.realm1).encode('utf-8') # First, send a wrong response req.all_data = { "response": "12345", "userId": encoded_user_id, "sessionKey": session, "operation": "login" } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") self.assertRegexpMatches(r[1], r"INVALID_RESPONSE:[0-9]+") # Check that the OTP status is still incorrect r = token.check_challenge_response( options={"transaction_id": transaction_id}) self.assertEqual(r, -1) # Send the correct response req.all_data = { "response": response, "userId": encoded_user_id, "sessionKey": session, "operation": "login" } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") self.assertEqual(r[1], "OK") # Send the same response a second time would not work # since the Challenge is marked as answered req.all_data = { "response": response, "userId": encoded_user_id, "sessionKey": session, "operation": "login" } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") self.assertEqual(r[1], "INVALID_CHALLENGE") # Finally we check the OTP status: r = token.check_challenge_response( options={"transaction_id": transaction_id}) self.assertTrue(r > 0, r) # Check the same challenge again. It will fail, since the # challenge was deleted from the database r = token.check_challenge_response( options={"transaction_id": transaction_id}) self.assertTrue(r < 0, r)
def set_request(**kwargs): builder = EnvironBuilder(**kwargs) frappe.local.request = Request(builder.get_environ())
def test_iri_support(): b = EnvironBuilder(u"/föö-bar", base_url=u"http://☃.net/") strict_eq(b.path, "/f%C3%B6%C3%B6-bar") strict_eq(b.base_url, "http://xn--n3h.net/")
def test_iri_support(self): b = EnvironBuilder(u'/föö-bar', base_url=u'http://☃.net/') self.assert_strict_equal(b.path, '/f%C3%B6%C3%B6-bar') self.assert_strict_equal(b.base_url, 'http://xn--n3h.net/')
def path(self, uri): """Returns the physical path that the provided URI respolves to. Returns None if this requesthandler does not support the given URI, or the URI doesnt resolve to a static file. """ suffix = None parsedurl = urlparse(uri) args = dict(parse_qsl(parsedurl.query)) map = Map(self.rules, converters=self.rule_converters) endpoint, params = map.bind(server_name=parsedurl.netloc.split(":")[0], path_info=parsedurl.path).match() if endpoint == self.handle_dataset: # FIXME: This duplicates logic from handle_dataset assert len( args ) <= 1, "Can't handle dataset requests with multiple selectors" for (k, v) in args.items(): params["param"] = k params["value"] = v # at this point, use werkzeug.test.Client or # EnvironmentBuilder to create a fake environ and then a # fake Request object if ".atom" in uri: suffix = "atom" path = "/index.atom" headers = {} else: headers = {"Accept": "text/html"} path = "/index.html" environ = EnvironBuilder(path=path, headers=headers).get_environ() contenttype = self.contenttype(Request(environ), suffix) pathfunc = self.get_dataset_pathfunc(environ, params, contenttype, suffix) if pathfunc: return pathfunc() else: return None elif endpoint == self.handle_doc: # params = self.params_from_uri(uri) # if params: params.update(args) if 'basefile' not in params: return None if 'format' in params: suffix = params['format'] else: if 'attachment' in params: leaf = params['attachment'] else: leaf = uri.split("/")[-1] if "." in leaf: suffix = leaf.rsplit(".", 1)[1] if not suffix: headers = {'Accept': 'text/html'} else: headers = {} environ = EnvironBuilder(path=urlparse(uri).path, headers=headers).get_environ() contenttype = self.contenttype(Request(environ), suffix) pathfunc = self.get_pathfunc(environ, params['basefile'], params, contenttype, suffix) if pathfunc: return pathfunc(params['basefile'])
def test_form_type(self): """Try a normal form-urlencoded request.""" builder = EnvironBuilder(method='POST', data={'foo': 'bar'}) request = Request(builder.get_environ()) data = decode_request(request) assert data['foo'] == 'bar'
def _test_api_endpoint(self, user, expected_netloc): pin = "tiqr" token = init_token({ "type": "tiqr", "pin": pin }, User(user, self.realm1)) idetail = token.get_init_detail() value = idetail.get("tiqrenroll").get("value") # 'tiqrenroll://None?action=metadata&session=b81ecdf74118dcf6fa1cd41d3d4b2fec56c9107f&serial=TiQR000163CB # get the serial and the session m = re.search('&serial=(.*)$', value) serial = m.group(1) m = re.search('&session=(.*)&', value) session = m.group(1) # test meta data builder = EnvironBuilder(method='POST', data={}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" g.client_ip = env["REMOTE_ADDR"] req = Request(env) req.all_data = { "action": "metadata", "session": session, "serial": serial } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "json") self.assertTrue("identity" in r[1], r[1]) self.assertTrue("service" in r[1], r[1]) # Test invalid action req.all_data = {"action": "unknown"} self.assertRaises(Exception, TiqrTokenClass.api_endpoint, req, g) # test enrollment with invalid session req.all_data = { "action": "enrollment", "serial": serial, "session": "123", "secret": KEY20 } self.assertRaises(ParameterError, TiqrTokenClass.api_endpoint, req, g) # test enrollment with valid session req.all_data = { "action": "enrollment", "serial": serial, "session": session, "secret": KEY20 } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") self.assertEqual(r[1], "OK") # test authentication endpoint # create a challenge by issuing validate/check with user and pin session = "" challenge = "" with self.app.test_request_context('/validate/check', method='GET', query_string=urlencode({ "user": user.encode('utf-8'), "realm": self.realm1, "pass": pin })): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) result = res.json.get("result") detail = res.json.get("detail") self.assertTrue(result.get("status") is True, result) self.assertTrue(result.get("value") is False, result) transaction_id = detail.get("transaction_id") image_url = detail.get("attributes").get("value") self.assertTrue(image_url.startswith("tiqrauth")) # u'tiqrauth://[email protected] # /12335970131032896263/e0fac7bb2e3ea4219ead' # session = 12335970131032896263 # challenge = e0fac7bb2e3ea4219ead r = image_url.split("/") session = r[3] challenge = r[4] # check the URL parsed_url = urlparse(image_url) self.assertEqual(parsed_url.netloc, expected_netloc) ocrasuite = token.get_tokeninfo("ocrasuite") ocra_object = OCRA(ocrasuite, key=binascii.unhexlify(KEY20)) # Calculate Response with the challenge. response = ocra_object.get_response(challenge) encoded_user_id = u"{!s}_{!s}".format(user, self.realm1).encode('utf-8') # First, send a wrong response req.all_data = { "response": "12345", "userId": encoded_user_id, "sessionKey": session, "operation": "login" } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") # check the failed response count fcnt1 = token.get_max_failcount() - token.get_failcount() self.assertRegexpMatches(r[1], r"INVALID_RESPONSE:{0!s}".format(fcnt1)) # Try another wrong response req.all_data = { "response": "67890", "userId": encoded_user_id, "sessionKey": session, "operation": "login" } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") # check the failed response count fcnt2 = token.get_max_failcount() - token.get_failcount() self.assertRegexpMatches(r[1], r"INVALID_RESPONSE:{0!s}".format(fcnt2)) # has the failcounter decreased? self.assertEqual(fcnt1 - 1, fcnt2) # Check that the OTP status is still incorrect r = token.check_challenge_response( options={"transaction_id": transaction_id}) self.assertEqual(r, -1) # Send the correct response req.all_data = { "response": response, "userId": encoded_user_id, "sessionKey": session, "operation": "login" } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") self.assertEqual(r[1], "OK") # Send the same response a second time would not work # since the Challenge is marked as answered req.all_data = { "response": response, "userId": encoded_user_id, "sessionKey": session, "operation": "login" } r = TiqrTokenClass.api_endpoint(req, g) self.assertEqual(r[0], "plain") self.assertEqual(r[1], "INVALID_CHALLENGE") # Finally we check the OTP status: r = token.check_challenge_response( options={"transaction_id": transaction_id}) self.assertTrue(r > 0, r) # Check the same challenge again. It will fail, since the # challenge was deleted from the database r = token.check_challenge_response( options={"transaction_id": transaction_id}) self.assertTrue(r < 0, r)
def test_wsgi_app_404(self): Logger.set_log_level("ERROR") res = self.server.wsgi_app( EnvironBuilder('/not_found').get_environ(), None) self.assertIsInstance(res, NotFound)
def _get_werkzeug_request(path): builder = EnvironBuilder(path=path) env = builder.get_environ() return Request(env)
def test_iri_support(self): b = EnvironBuilder(u'/föö-bar', base_url=u'http://☃.net/') assert b.path == '/f%C3%B6%C3%B6-bar' assert b.base_url == 'http://xn--n3h.net/'
def set_request(**kwargs): from werkzeug.test import EnvironBuilder from werkzeug.wrappers import Request builder = EnvironBuilder(**kwargs) frappe.local.request = Request(builder.get_environ())
def test_iri_support(): b = EnvironBuilder("/föö-bar", base_url="http://☃.net/") assert b.path == "/f%C3%B6%C3%B6-bar" assert b.base_url == "http://xn--n3h.net/"
def test_wsgi_app(self): res = self.server.wsgi_app( EnvironBuilder('/contest').get_environ(), None) data = json.loads(res.data.decode()) self.assertFalse(data["has_started"])
import io import pathlib import pytest from werkzeug.exceptions import NotFound from werkzeug.http import http_date from werkzeug.test import EnvironBuilder from werkzeug.utils import send_file from werkzeug.utils import send_from_directory res_path = pathlib.Path(__file__).parent / "res" html_path = res_path / "index.html" txt_path = res_path / "test.txt" environ = EnvironBuilder().get_environ() @pytest.mark.parametrize("path", [html_path, str(html_path)]) def test_path(path): rv = send_file(path, environ) assert rv.mimetype == "text/html" assert rv.direct_passthrough rv.direct_passthrough = False assert rv.data == html_path.read_bytes() rv.close() def test_x_sendfile(): rv = send_file(html_path, environ, use_x_sendfile=True) assert rv.headers["x-sendfile"] == str(html_path)
def make_test_environ_builder(app, path='/', base_url=None, subdomain=None, url_scheme=None, *args, **kwargs): """Create a :class:`~werkzeug.test.EnvironBuilder`, taking some defaults from the application. :param app: The Flask application to configure the environment from. :param path: URL path being requested. :param base_url: Base URL where the utils is being served, which ``path`` is relative to. If not given, built from :data:`PREFERRED_URL_SCHEME`, ``subdomain``, :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. :param url_scheme: Scheme to use instead of :data:`PREFERRED_URL_SCHEME`. :param json: If given, this is serialized as JSON and passed as ``data``. Also defaults ``content_type`` to ``application/json``. :param args: other positional arguments passed to :class:`~werkzeug.test.EnvironBuilder`. :param kwargs: other keyword arguments passed to :class:`~werkzeug.test.EnvironBuilder`. """ assert (not (base_url or subdomain or url_scheme) or (base_url is not None) != bool(subdomain or url_scheme) ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' if base_url is None: http_host = app.config.get('SERVER_NAME') or 'localhost' app_root = app.config['APPLICATION_ROOT'] if subdomain: http_host = '{0}.{1}'.format(subdomain, http_host) if url_scheme is None: url_scheme = app.config['PREFERRED_URL_SCHEME'] url = url_parse(path) base_url = '{scheme}://{netloc}/{path}'.format( scheme=url.scheme or url_scheme, netloc=url.netloc or http_host, path=app_root.lstrip('/')) path = url.path if url.query: sep = b'?' if isinstance(url.query, bytes) else '?' path += sep + url.query if 'json' in kwargs: assert 'data' not in kwargs, ( "Client cannot provide both 'json' and 'data'.") # push a context so flask.json can use utils's json attributes with app.app_context(): kwargs['data'] = json_dumps(kwargs.pop('json')) if 'content_type' not in kwargs: kwargs['content_type'] = 'application/json' return EnvironBuilder(path, base_url, *args, **kwargs)
def test_auth_object(): builder = EnvironBuilder( auth=Authorization("digest", {"username": "******", "password": "******"}) ) request = builder.get_request() assert request.headers["Authorization"].startswith("Digest ")
def test_basic_auth(): builder = EnvironBuilder(auth=("username", "password")) request = builder.get_request() auth = parse_authorization_header(request.headers["Authorization"]) assert auth.username == "username" assert auth.password == "password"
def test_iri_support(): """Test client IRI support""" b = EnvironBuilder(u'/föö-bar', base_url=u'http://☃.net/') assert b.path == '/f%C3%B6%C3%B6-bar' assert b.base_url == 'http://xn--n3h.net/'
class WSGI(RepoTester): # base class w/o tests storetype = 'SQLITE' storelocation = 'data/ferenda.sqlite' # append self.datadir storerepository = 'ferenda' indextype = 'WHOOSH' indexlocation = 'data/whooshindex' # append self.datadir def setUp(self): super(WSGI,self).setUp() if self.storelocation.startswith("data/"): self.storelocation = self.storelocation.replace("data", self.datadir) if self.indexlocation.startswith("data/"): self.indexlocation = self.indexlocation.replace("data", self.datadir) self.put_files_in_place() # use self.repo (simple testcases) or self.repos (complex # testcases like AdvancedAPI)? if hasattr(self, 'repos'): repos = self.repos else: repos = [self.repo] # print("making app: %s %s" % (self.storetype, self.indextype)) config = LayeredConfig(Defaults({'datadir': self.datadir, 'apiendpoint': '/myapi/', 'searchendpoint': '/mysearch/', 'url': 'http://localhost:8000/', 'storetype': self.storetype, 'storelocation': self.storelocation, 'storerepository': self.storerepository, 'indextype': self.indextype, 'indexlocation': self.indexlocation, 'wsgiappclass': 'ferenda.WSGIApp', 'legacyapi': False, 'wsgiexceptionhandler': True})) self.app = manager.make_wsgi_app(config, repos=repos) self.builder = EnvironBuilder('/', base_url="http://localhost:8000/", headers={"Accept": DEFAULT_HTTP_ACCEPT}) def ttl_to_rdf_xml(self, inpath, outpath, store=None): if not store: store = self.repo.store g = Graph() g.parse(data=util.readfile(inpath, encoding="utf-8"), format="turtle") with _open(outpath, "wb") as fp: fp.write(g.serialize(format="pretty-xml")) return g def put_files_in_place(self): # Put files in place: parsed util.ensure_dir(self.repo.store.parsed_path("123/a")) shutil.copy2("test/files/base/parsed/123/a.xhtml", self.repo.store.parsed_path("123/a")) g = self.ttl_to_rdf_xml("test/files/base/distilled/123/a.ttl", self.repo.store.distilled_path("123/a")) # generated util.ensure_dir(self.repo.store.generated_path("123/a")) shutil.copy2("test/files/base/generated/123/a.html", self.repo.store.generated_path("123/a")) shutil.copy2("test/files/base/generated/123/a.html", self.repo.store.generated_path("123/a")) # annotations util.ensure_dir(self.repo.store.annotation_path("123/a")) shutil.copy2("test/files/base/annotations/123/a.grit.xml", self.repo.store.annotation_path("123/a")) # config resources = self.datadir+os.sep+"rsrc"+os.sep+"resources.xml" util.ensure_dir(resources) shutil.copy2("test/files/base/rsrc/resources.xml", resources) # index.html index = self.datadir+os.sep+"index.html" with open(index, "wb") as fp: fp.write(b'<h1>index.html</h1>') # toc/index.html + toc/title/a.html with self.repo.store.open("index", "toc", ".html", "wb") as fp: fp.write(b'<h1>TOC for base</h1>') with self.repo.store.open("title/a", "toc", ".html", "wb") as fp: fp.write(b'<h1>Title starting with "a"</h1>') # distilled/dump.nt with self.repo.store.open("dump", "distilled", ".nt", "wb") as fp: fp.write(g.serialize(format="nt")) def call_wsgi(self, environ=None): if not environ: environ = self.builder.get_environ() start_response = Mock() buf = BytesIO() iterable = self.app(environ, start_response) for chunk in iterable: buf.write(chunk) if hasattr(iterable, 'close'): iterable.close() call_args = start_response.mock_calls[0][1] # call_kwargs = start_response.mock_calls[0][2] return call_args[0], call_args[1], buf.getvalue() def assertResponse(self, wanted_status, wanted_headers, wanted_content, got_status, got_headers, got_content): self.assertEqual(wanted_status, got_status) got_headers = dict(got_headers) for (key, value) in wanted_headers.items(): self.assertEqual(value, got_headers[key]) if wanted_content: self.assertEqual(wanted_content, got_content)
def get_request(obj): builder = EnvironBuilder("/", data=encode.dumper(obj)) builder.headers["content-type"] = "application/json" return JsonWebRequest(builder.get_environ())
def get_request(*args, **kw): return Request(EnvironBuilder(*args, **kw).get_environ())
def make_test_environ_builder(app, path="/", base_url=None, subdomain=None, url_scheme=None, *args, **kwargs): """Create a :class:`~werkzeug.test.EnvironBuilder`, taking some defaults from the application. :param app: The Flask application to configure the environment from. :param path: URL path being requested. :param base_url: Base URL where the app is being served, which ``path`` is relative to. If not given, built from :data:`PREFERRED_URL_SCHEME`, ``subdomain``, :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. :param url_scheme: Scheme to use instead of :data:`PREFERRED_URL_SCHEME`. :param json: If given, this is serialized as JSON and passed as ``data``. Also defaults ``content_type`` to ``application/json``. :param args: other positional arguments passed to :class:`~werkzeug.test.EnvironBuilder`. :param kwargs: other keyword arguments passed to :class:`~werkzeug.test.EnvironBuilder`. """ assert not (base_url or subdomain or url_scheme) or (base_url is not None) != bool( subdomain or url_scheme ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' if base_url is None: http_host = app.config.get("SERVER_NAME") or "localhost" app_root = app.config["APPLICATION_ROOT"] if subdomain: http_host = "{0}.{1}".format(subdomain, http_host) if url_scheme is None: url_scheme = app.config["PREFERRED_URL_SCHEME"] url = url_parse(path) base_url = "{scheme}://{netloc}/{path}".format( scheme=url.scheme or url_scheme, netloc=url.netloc or http_host, path=app_root.lstrip("/"), ) path = url.path if url.query: sep = b"?" if isinstance(url.query, bytes) else "?" path += sep + url.query # TODO use EnvironBuilder.json_dumps once we require Werkzeug 0.15 if "json" in kwargs: assert "data" not in kwargs, "Client cannot provide both 'json' and 'data'." kwargs["data"] = json_dumps(kwargs.pop("json"), app=app) if "content_type" not in kwargs: kwargs["content_type"] = "application/json" return EnvironBuilder(path, base_url, *args, **kwargs)
class TestFileByDigestMiddleware(unittest.TestCase): def setUp(self): # Choose a size that is larger than FileCacher.CHUNK_SIZE. self.content = \ bytes(random.getrandbits(8) for _ in range(17 * 1024)) self.digest = bytes_digest(self.content) self.filename = "foobar.pdf" self.mimetype = "image/jpeg" self.file_cacher = Mock() self.file_cacher.get_file = Mock( side_effect=lambda digest: io.BytesIO(self.content)) self.file_cacher.get_size = Mock(return_value=len(self.content)) self.serve_file = True self.provide_filename = True self.wsgi_app = \ FileServerMiddleware(self.file_cacher,self.wrapped_wsgi_app) self.environ_builder = EnvironBuilder("/some/url") self.client = Client(self.wsgi_app, Response) @responder def wrapped_wsgi_app(self, environ, start_response): self.assertEqual(environ, self.environ) if self.serve_file: headers = {FileServerMiddleware.DIGEST_HEADER: self.digest} if self.provide_filename: headers[FileServerMiddleware.FILENAME_HEADER] = self.filename return Response(headers=headers, mimetype=self.mimetype) else: return Response(b"some other content", mimetype="text/plain") def request(self, headers=None): if headers is not None: for key, value in headers: self.environ_builder.headers.add(key, value) self.environ = self.environ_builder.get_environ() return self.client.open(self.environ) def test_success(self): response = self.request() self.assertEqual(response.status_code, 200) self.assertEqual(response.mimetype, self.mimetype) self.assertEqual( response.headers.get("content-disposition"), "attachment; filename=%s" % quote_header_value(self.filename)) self.assertTupleEqual(response.get_etag(), (self.digest, False)) self.assertEqual(response.accept_ranges, "bytes") self.assertGreater(response.cache_control.max_age, 0) self.assertTrue(response.cache_control.private) self.assertFalse(response.cache_control.public) self.assertEqual(response.get_data(), self.content) self.file_cacher.get_file.assert_called_once_with(self.digest) def test_not_a_file(self): self.serve_file = False response = self.request() self.assertEqual(response.status_code, 200) self.assertEqual(response.mimetype, "text/plain") self.assertEqual(response.get_data(), b"some other content") def test_no_filename(self): self.provide_filename = False response = self.request() self.assertNotIn("content-disposition", response.headers) def test_not_found(self): self.file_cacher.get_file.side_effect = KeyError() response = self.request() self.assertEqual(response.status_code, 404) self.file_cacher.get_file.assert_called_once_with(self.digest) def test_tombstone(self): self.file_cacher.get_file.side_effect = TombstoneError() response = self.request() self.assertEqual(response.status_code, 503) self.file_cacher.get_file.assert_called_once_with(self.digest) def test_conditional_request(self): # Test an etag that matches. response = self.request(headers=[("If-None-Match", self.digest)]) self.assertEqual(response.status_code, 304) self.assertEqual(len(response.get_data()), 0) def test_conditional_request_no_match(self): # Test an etag that doesn't match. response = self.request(headers=[("If-None-Match", "not the etag")]) self.assertEqual(response.status_code, 200) self.assertEqual(response.get_data(), self.content) def test_range_request(self): # Test a range that is strictly included. response = self.request(headers=[("Range", "bytes=256-767")]) self.assertEqual(response.status_code, 206) self.assertEqual(response.content_range.units, "bytes") self.assertEqual(response.content_range.start, 256) self.assertEqual(response.content_range.stop, 768) self.assertEqual(response.content_range.length, 1024) self.assertEqual(response.get_data(), self.content[256:768]) def test_range_request_end_overflows(self): # Test a range that ends after the end of the file. response = self.request(headers=[("Range", "bytes=256-2047")]) self.assertEqual(response.status_code, 206) self.assertEqual(response.content_range.units, "bytes") self.assertEqual(response.content_range.start, 256) self.assertEqual(response.content_range.stop, 1024) self.assertEqual(response.content_range.length, 1024) self.assertEqual(response.get_data(), self.content[256:]) def test_range_request_start_overflows(self): # Test a range that starts after the end of the file. response = self.request(headers=[("Range", "bytes=1536-")]) self.assertEqual(response.status_code, 416)