Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ba53d37

Browse filesBrowse files
authored
Add test for firetactoe. (GoogleCloudPlatform#594)
* Add test for firetactoe. * Fix style errors. * Remove rest_api.py, which may be obsolete. The doc that depends on this is undergoing a rewrite that obviates the need for this file. Plus, checking for "null" seems unnecessary, and there are a bunch of style things that aren't passing our linter.
1 parent 530ab8a commit ba53d37
Copy full SHA for ba53d37

File tree

Expand file treeCollapse file tree

3 files changed

+169
-111
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+169
-111
lines changed

‎appengine/standard/firebase/firetactoe/firetactoe.py

Copy file name to clipboardExpand all lines: appengine/standard/firebase/firetactoe/firetactoe.py
+9-3Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def _get_firebase_db_url(_memo={}):
6464
_memo['dburl'] = url.group(1)
6565
return _memo['dburl']
6666

67+
6768
# [START authed_http]
6869
def _get_http(_memo={}):
6970
"""Provides an authed http object."""
@@ -79,6 +80,7 @@ def _get_http(_memo={}):
7980
return _memo['http']
8081
# [END authed_http]
8182

83+
8284
# [START send_msg]
8385
def _send_firebase_message(u_id, message=None):
8486
"""Updates data in firebase. If a message is provided, then it updates
@@ -94,6 +96,7 @@ def _send_firebase_message(u_id, message=None):
9496
return _get_http().request(url, 'DELETE')
9597
# [END send_msg]
9698

99+
97100
# [START create_token]
98101
def create_custom_token(uid, valid_minutes=60):
99102
"""Create a secure token for the given id.
@@ -105,17 +108,17 @@ def create_custom_token(uid, valid_minutes=60):
105108
"""
106109

107110
# use the app_identity service from google.appengine.api to get the
108-
# project's service account email automatically
111+
# project's service account email automatically
109112
client_email = app_identity.get_service_account_name()
110113

111114
now = int(time.time())
112-
# encode the required claims
115+
# encode the required claims
113116
# per https://firebase.google.com/docs/auth/server/create-custom-tokens
114117
payload = base64.b64encode(json.dumps({
115118
'iss': client_email,
116119
'sub': client_email,
117120
'aud': _IDENTITY_ENDPOINT,
118-
'uid': uid, # this is the important parameter as it will be the channel id
121+
'uid': uid, # the important parameter, as it will be the channel id
119122
'iat': now,
120123
'exp': now + (valid_minutes * 60),
121124
}))
@@ -127,6 +130,7 @@ def create_custom_token(uid, valid_minutes=60):
127130
app_identity.sign_blob(to_sign)[1]))
128131
# [END create_token]
129132

133+
130134
class Game(ndb.Model):
131135
"""All the data we store for a game"""
132136
userX = ndb.UserProperty()
@@ -193,6 +197,7 @@ def make_move(self, position, user):
193197
return
194198
# [END make_move]
195199

200+
196201
# [START move_route]
197202
@app.route('/move', methods=['POST'])
198203
def move():
@@ -204,6 +209,7 @@ def move():
204209
return ''
205210
# [END move_route]
206211

212+
207213
# [START route_delete]
208214
@app.route('/delete', methods=['POST'])
209215
def delete():
+160Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import re
16+
17+
from google.appengine.api import users
18+
from google.appengine.ext import ndb
19+
import httplib2
20+
import pytest
21+
import webtest
22+
23+
import firetactoe
24+
25+
26+
class MockHttp(object):
27+
"""Mock the Http object, so we can set what the response will be."""
28+
def __init__(self, status, content=''):
29+
self.content = content
30+
self.status = status
31+
self.request_url = None
32+
33+
def __call__(self, *args, **kwargs):
34+
return self
35+
36+
def request(self, url, method, content='', *args, **kwargs):
37+
self.request_url = url
38+
self.request_method = method
39+
self.request_content = content
40+
return self, self.content
41+
42+
43+
@pytest.fixture
44+
def app(testbed, monkeypatch, login):
45+
# Don't let the _get_http function memoize its value
46+
orig_get_http = firetactoe._get_http
47+
monkeypatch.setattr(firetactoe, '_get_http', lambda: orig_get_http({}))
48+
49+
# Provide a test firebase config. The following will set the databaseURL
50+
# databaseURL: "http://firebase.com/test-db-url"
51+
monkeypatch.setattr(
52+
firetactoe, '_FIREBASE_CONFIG', '../firetactoe_test.py')
53+
54+
login(id='38')
55+
56+
return webtest.TestApp(firetactoe.app)
57+
58+
59+
def test_index_new_game(app, monkeypatch):
60+
mock_http = MockHttp(200)
61+
monkeypatch.setattr(httplib2, 'Http', mock_http)
62+
63+
response = app.get('/')
64+
65+
assert 'g=' in response.body
66+
# Look for the unique game token
67+
assert re.search(
68+
r'initGame[^\n]+\'[\w+/=]+\.[\w+/=]+\.[\w+/=]+\'', response.body)
69+
70+
assert firetactoe.Game.query().count() == 1
71+
72+
assert mock_http.request_url.startswith(
73+
'http://firebase.com/test-db-url/channels/')
74+
assert mock_http.request_method == 'PATCH'
75+
76+
77+
def test_index_existing_game(app, monkeypatch):
78+
mock_http = MockHttp(200)
79+
monkeypatch.setattr(httplib2, 'Http', mock_http)
80+
userX = users.User('x@example.com', _user_id='123')
81+
firetactoe.Game(id='razem', userX=userX).put()
82+
83+
response = app.get('/?g=razem')
84+
85+
assert 'g=' in response.body
86+
# Look for the unique game token
87+
assert re.search(
88+
r'initGame[^\n]+\'[\w+/=]+\.[\w+/=]+\.[\w+/=]+\'', response.body)
89+
90+
assert firetactoe.Game.query().count() == 1
91+
game = ndb.Key('Game', 'razem').get()
92+
assert game is not None
93+
assert game.userO.user_id() == '38'
94+
95+
assert mock_http.request_url.startswith(
96+
'http://firebase.com/test-db-url/channels/')
97+
assert mock_http.request_method == 'PATCH'
98+
99+
100+
def test_index_nonexisting_game(app, monkeypatch):
101+
mock_http = MockHttp(200)
102+
monkeypatch.setattr(httplib2, 'Http', mock_http)
103+
firetactoe.Game(id='razem', userX=users.get_current_user()).put()
104+
105+
app.get('/?g=razemfrazem', status=404)
106+
107+
assert mock_http.request_url is None
108+
109+
110+
def test_opened(app, monkeypatch):
111+
mock_http = MockHttp(200)
112+
monkeypatch.setattr(httplib2, 'Http', mock_http)
113+
firetactoe.Game(id='razem', userX=users.get_current_user()).put()
114+
115+
app.post('/opened?g=razem', status=200)
116+
117+
assert mock_http.request_url.startswith(
118+
'http://firebase.com/test-db-url/channels/')
119+
assert mock_http.request_method == 'PATCH'
120+
121+
122+
def test_bad_move(app, monkeypatch):
123+
mock_http = MockHttp(200)
124+
monkeypatch.setattr(httplib2, 'Http', mock_http)
125+
firetactoe.Game(
126+
id='razem', userX=users.get_current_user(), board=9*' ',
127+
moveX=True).put()
128+
129+
app.post('/move?g=razem', {'i': 10}, status=400)
130+
131+
assert mock_http.request_url is None
132+
133+
134+
def test_move(app, monkeypatch):
135+
mock_http = MockHttp(200)
136+
monkeypatch.setattr(httplib2, 'Http', mock_http)
137+
firetactoe.Game(
138+
id='razem', userX=users.get_current_user(), board=9*' ',
139+
moveX=True).put()
140+
141+
app.post('/move?g=razem', {'i': 0}, status=200)
142+
143+
game = ndb.Key('Game', 'razem').get()
144+
assert game.board == 'X' + (8 * ' ')
145+
146+
assert mock_http.request_url.startswith(
147+
'http://firebase.com/test-db-url/channels/')
148+
assert mock_http.request_method == 'PATCH'
149+
150+
151+
def test_delete(app, monkeypatch):
152+
mock_http = MockHttp(200)
153+
monkeypatch.setattr(httplib2, 'Http', mock_http)
154+
firetactoe.Game(id='razem', userX=users.get_current_user()).put()
155+
156+
app.post('/delete?g=razem', status=200)
157+
158+
assert mock_http.request_url.startswith(
159+
'http://firebase.com/test-db-url/channels/')
160+
assert mock_http.request_method == 'DELETE'

‎appengine/standard/firebase/firetactoe/rest_api.py

Copy file name to clipboardExpand all lines: appengine/standard/firebase/firetactoe/rest_api.py
-108Lines changed: 0 additions & 108 deletions
This file was deleted.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.