Python 为什么这些测试在此自定义Flask会话接口中失败?
我正在Flask中编写一个混合的单页web/PhoneGap应用程序。由于PhoneGap应用程序中的cookie基本上不可用,因此我实现了一个完全避免cookie的自定义。它将会话数据存储在应用程序数据库中,并在HTTP请求和响应主体中显式传递会话ID 我创建了一个具有简化测试用例的。它本身仍然是一个相当大的项目,但自述文件应该可以帮助您快速找到自己的方法。repo包括七个测试,当使用Flask默认的基于cookie的会话接口时,所有测试都成功,而当使用我的自定义会话接口时,所有测试都失败。主要的问题似乎是数据有时不会保留在会话对象上,但这很神秘,因为会话对象继承了Python的内置dict,它不应该自动忘记数据。此外,会话接口非常简单,与其他接口相比似乎没有任何明显的错误 更令人沮丧的是,自定义会话接口在实际应用程序中似乎工作正常。只有单元测试失败了。但是,由于这个原因,假设会话接口在所有情况下都能正常工作是不安全的 非常感谢您的帮助 Edit:Gist不接受简化的测试用例,因为它包含目录。我现在将它转移到一个成熟的GitHub存储库中。完成后,我将再次更新此帖子 新建编辑:将简化的测试用例移动到适当的GitHub repo。自述文件仍然提到“这一要点”,对不起。您的问题主要归结为在测试请求中提供会话令牌。如果不提供令牌,则会话为空 我假设您的实际应用程序正确地发送了会话令牌,因此看起来工作正常 修复测试用例以正确通过并不需要太多 每个请求都尝试根据post参数加载会话 在会话实现中:Python 为什么这些测试在此自定义Flask会话接口中失败?,python,session,flask,customization,Python,Session,Flask,Customization,我正在Flask中编写一个混合的单页web/PhoneGap应用程序。由于PhoneGap应用程序中的cookie基本上不可用,因此我实现了一个完全避免cookie的自定义。它将会话数据存储在应用程序数据库中,并在HTTP请求和响应主体中显式传递会话ID 我创建了一个具有简化测试用例的。它本身仍然是一个相当大的项目,但自述文件应该可以帮助您快速找到自己的方法。repo包括七个测试,当使用Flask默认的基于cookie的会话接口时,所有测试都成功,而当使用我的自定义会话接口时,所有测试都失败。主
def open_session(self, app, request):
s = Session()
if 't' in request.form:
....
return s
def save_session(self, app, session, response):
if session.modified and 'token' in session:
...
# save session to database
...
这意味着每个不是POST
(或PUT
)且未发送t
的请求将
有一个空白会议
而基于cookies的实现将始终具有可用的会话令牌
并且能够加载以前请求的会话
以下是您的一个示例测试:
def test_authorize_captcha_expired(self):
with self.client as c:
with c.session_transaction() as s:
s['captcha-answer'] = u'one two three'.split()
s['captcha-expires'] = datetime.today() - timedelta(minutes=1)
self.assertEqual(c.post('/test', data={
'ca': 'one two three',
}).status_code, 400)
您尚未为post to/test
提供t
值。因此它得到了一个空白
没有验证码的会话将过期
密钥,并引发密钥错误
您的会话需要一个“令牌”密钥才能保存
在会话实现中:
def open_session(self, app, request):
s = Session()
if 't' in request.form:
....
return s
def save_session(self, app, session, response):
if session.modified and 'token' in session:
...
# save session to database
...
因此,当您有:
with c.session_transaction() as s:
s['captcha-answer'] = u'one two three'.split()
s['captcha-expires'] = datetime.today() - timedelta(minutes=1)
实际上没有会话写入数据库。对于任何后续请求
使用。请注意,它确实需要写入数据库,因为每次请求时,open\u session
都会尝试从数据库加载内容
要解决大多数情况,您需要在创建会话时提供一个“令牌”,并为使用该令牌的任何请求提供一个带有该令牌的“t”
因此,我上面使用的样本测试结果如下:
def test_authorize_captcha_expired(self):
with self.client as c:
token = generate_key(SystemRandom())
with c.session_transaction() as s:
s['token'] = token
s['captcha-answer'] = u'one two three'.split()
s['captcha-expires'] = datetime.today() - timedelta(minutes=1)
self.assertEqual(c.post('/test', data={
'ca': 'one two three',
't': token
}).status_code, 400)
当您使用json响应时,您可以更改令牌
…但您在发出后续请求时未使用新令牌
def test_reply_to_reflection_passthrough(self):
with self.client as c:
token = 'abcdef'
...
response2 = c.post('/reflection/1/reply', data={
'p': 'test4',
'r': 'testmessage',
't': token,
}, ...
至此,发到/reflection/1/reply
的帖子生成了一个新的
令牌并将其保存,因此关键密钥最后一次回复
不在
会话由abcdef
标识。如果这是一个基于cookies的会话,那么最后一次回复
将可用于下一个请求
所以要修正这个测试。。。使用新令牌
def test_reply_to_reflection_passthrough(self):
with self.client as c:
...
response2 = c.post('/reflection/1/reply', data={
...
token = session['token']
with c.session_transaction(method="POST", data={'t':token}) as s:
s['token'] = token
s['last-request'] = datetime.now() - timedelta(milliseconds=1001)
response3 = c.post('/reflection/1/reply', data={
...
重定向将丢失会话令牌
在测试测试\u bump
中:
def test_bump(self):
response = self.client.post(
'/admin/tip/action/',
data = {'action': 'Bump', 'rowid': '1',},
follow_redirects=True )
self.assertIn(' tips have been bumped.', response.data)
发送到/admin/tip/action
的帖子返回重定向
这里您正在检查是否存在闪存消息。和即时消息
存储在会话中
对于基于cookie的会话,会话id将与随后的重定向请求一起再次发送
由于会话id被指定为post值,因此不会再次发送,会话和闪存消息将丢失
解决此问题的方法不是遵循重定向,而是通过flasks flash方法检查会话中的数据集
def test_bump(self):
with self.client as c:
token = generate_key(SystemRandom())
with c.session_transaction() as s:
s['token'] = token
c.post('/admin/tip/action/',
data={'action': 'Bump', 'rowid': '1', 't': token})
with c.session_transaction(method="POST", data={'t': token}) as s:
self.assertIn(' tips have been bumped.', s['_flashes'][0][1])
就这些
我已经发送了一个包含上述更改的pull请求,您会发现默认flask会话和会话实现的测试现在都通过了。简单浏览一下您的测试,可以发现您的帖子中没有包含
t
,但您的主应用程序是。不是100%确定,因为有很多东西要看。@SeanVieira那篇略读可能有点太简短了。:-)有时,测试桩确实不包括t
字段,但目标是确认它产生了40倍的错误。当使用Flask的默认会话实现时,所有的测试都通过了。我看到了它期望的成功响应。我遗漏了什么吗?啊,对了,很抱歉搞混了。这实际上可能是特定测试中的问题(这是一个管理视图,其工作方式与其他视图略有不同)!但是,在其他六个失败的测试中,还有其他一些事情正在进行。如果您可以将项目简化为一个片段,这将是很有帮助的:-)无论如何,哪些数据不会保留在会话
对象中?我想知道这是否是因为您继承了dict
。\uuuuu setitem\uuuuu
或\uuuuuu setattr\uuuuu
存在一些问题。您知道Flask是如何与您的会话
对象交互的吗?这看起来已经是一个很好的答案了。谢谢你的辛勤工作。我会详细审查你的拉拽请求。我已经接受了你的回答,并将在我可以的时候奖励赏金(此时我仍需等待三个小时)。@Julian Great!很高兴我能帮上忙。干得好——特别是