Skip to content

Commit 6a9b4b3

Browse files
committed
Merge pull request #4 from elibixby/localtesting
Localtesting
2 parents 23fb0ab + 7664eec commit 6a9b4b3

File tree

7 files changed

+458
-0
lines changed

7 files changed

+458
-0
lines changed

localtesting/queue.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
queue:
2+
- name: default
3+
rate: 5/s
4+
- name: queue-1
5+
rate: 5/s
6+
- name: queue-2
7+
rate: 5/s

localtesting/runner.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/python
2+
# Copyright 2015 Google Inc
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
# [START runner]
17+
import optparse
18+
import sys
19+
import unittest
20+
import os
21+
22+
USAGE = """%prog SDK_PATH TEST_PATH
23+
Run unit tests for App Engine apps.
24+
25+
SDK_PATH Path to Google Cloud or Google App Engine SDK installation, usually
26+
~/google_cloud_sdk
27+
TEST_PATH Path to package containing test modules"""
28+
29+
30+
def main(sdk_path, test_path):
31+
# If the sdk path points to a google cloud sdk installation
32+
# then we should alter it to point to the GAE platform location.
33+
if os.path.exists(os.path.join(sdk_path, 'platform/google_appengine')):
34+
sys.path.insert(0, os.path.join(sdk_path, 'platform/google_appengine'))
35+
else:
36+
sys.path.insert(0, sdk_path)
37+
38+
# Ensure that the google.appengine.* packages are available
39+
# in tests as well as all bundled third-party packages.
40+
import dev_appserver
41+
dev_appserver.fix_sys_path()
42+
43+
# Loading appengine_config from the current project ensures that any
44+
# changes to configuration there are available to all tests (e.g.
45+
# sys.path modifications, namespaces, etc.)
46+
try:
47+
import appengine_config
48+
(appengine_config)
49+
except ImportError:
50+
print "Note: unable to import appengine_config."
51+
52+
# Discover and run tests.
53+
suite = unittest.loader.TestLoader().discover(test_path)
54+
unittest.TextTestRunner(verbosity=2).run(suite)
55+
56+
57+
if __name__ == '__main__':
58+
parser = optparse.OptionParser(USAGE)
59+
options, args = parser.parse_args()
60+
if len(args) != 2:
61+
print 'Error: Exactly 2 arguments required.'
62+
parser.print_help()
63+
sys.exit(1)
64+
SDK_PATH = args[0]
65+
TEST_PATH = args[1]
66+
main(SDK_PATH, TEST_PATH)
67+
68+
# [END runner]

localtesting/test_datastore.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Copyright 2015 Google Inc
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+
# [START imports]
16+
import unittest
17+
from google.appengine.api import memcache
18+
from google.appengine.ext import ndb
19+
from google.appengine.ext import testbed
20+
# [END imports]
21+
22+
23+
# [START datastore_example_1]
24+
class TestModel(ndb.Model):
25+
"""A model class used for testing."""
26+
number = ndb.IntegerProperty(default=42)
27+
text = ndb.StringProperty()
28+
29+
30+
class TestEntityGroupRoot(ndb.Model):
31+
"""Entity group root"""
32+
pass
33+
34+
35+
def GetEntityViaMemcache(entity_key):
36+
"""Get entity from memcache if available, from datastore if not."""
37+
entity = memcache.get(entity_key)
38+
if entity is not None:
39+
return entity
40+
key = ndb.Key(urlsafe=entity_key)
41+
entity = key.get()
42+
if entity is not None:
43+
memcache.set(entity_key, entity)
44+
return entity
45+
# [END datastore_example_1]
46+
47+
48+
# [START datastore_example_test]
49+
class DatstoreTestCase(unittest.TestCase):
50+
51+
def setUp(self):
52+
# First, create an instance of the Testbed class.
53+
self.testbed = testbed.Testbed()
54+
# Then activate the testbed, which prepares the service stubs for use.
55+
self.testbed.activate()
56+
# Next, declare which service stubs you want to use.
57+
self.testbed.init_datastore_v3_stub()
58+
self.testbed.init_memcache_stub()
59+
# Clear ndb's in-context cache between tests.
60+
# This prevents data from leaking between tests.
61+
# Alternatively, you could disable caching by
62+
# using ndb.get_context().set_cache_policy(False)
63+
ndb.get_context().clear_cache()
64+
65+
# [END datastore_example_test]
66+
67+
# [START datastore_example_teardown]
68+
def tearDown(self):
69+
self.testbed.deactivate()
70+
# [END datastore_example_teardown]
71+
72+
# [START datastore_example_insert]
73+
def testInsertEntity(self):
74+
TestModel().put()
75+
self.assertEqual(1, len(TestModel.query().fetch(2)))
76+
# [END datastore_example_insert]
77+
78+
# [START datastore_example_filter]
79+
def testFilterByNumber(self):
80+
root = TestEntityGroupRoot(id="root")
81+
TestModel(parent=root.key).put()
82+
TestModel(number=17, parent=root.key).put()
83+
query = TestModel.query(ancestor=root.key).filter(TestModel.number == 42)
84+
results = query.fetch(2)
85+
self.assertEqual(1, len(results))
86+
self.assertEqual(42, results[0].number)
87+
# [END datastore_example_filter]
88+
89+
# [START datastore_example_memcache]
90+
def testGetEntityViaMemcache(self):
91+
entity_key = TestModel(number=18).put().urlsafe()
92+
retrieved_entity = GetEntityViaMemcache(entity_key)
93+
self.assertNotEqual(None, retrieved_entity)
94+
self.assertEqual(18, retrieved_entity.number)
95+
# [END datastore_example_memcache]
96+
97+
98+
# [START HRD_example_1]
99+
from google.appengine.datastore import datastore_stub_util
100+
101+
102+
class HighReplicationTestCaseOne(unittest.TestCase):
103+
104+
def setUp(self):
105+
# First, create an instance of the Testbed class.
106+
self.testbed = testbed.Testbed()
107+
# Then activate the testbed, which prepares the service stubs for use.
108+
self.testbed.activate()
109+
# Create a consistency policy that will simulate the High Replication
110+
# consistency model.
111+
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(
112+
probability=0)
113+
# Initialize the datastore stub with this policy.
114+
self.testbed.init_datastore_v3_stub(consistency_policy=self.policy)
115+
# Initialize memcache stub too, since ndb also uses memcache
116+
self.testbed.init_memcache_stub()
117+
# Clear in-context cache before each test.
118+
ndb.get_context().clear_cache()
119+
120+
def tearDown(self):
121+
self.testbed.deactivate()
122+
123+
def testEventuallyConsistentGlobalQueryResult(self):
124+
class TestModel(ndb.Model):
125+
pass
126+
127+
user_key = ndb.Key('User', 'ryan')
128+
129+
# Put two entities
130+
ndb.put_multi([
131+
TestModel(parent=user_key),
132+
TestModel(parent=user_key)
133+
])
134+
135+
# Global query doesn't see the data.
136+
self.assertEqual(0, TestModel.query().count(3))
137+
# Ancestor query does see the data.
138+
self.assertEqual(2, TestModel.query(ancestor=user_key).count(3))
139+
# [END HRD_example_1]
140+
141+
# [START HRD_example_2]
142+
def testDeterministicOutcome(self):
143+
# 50% chance to apply.
144+
self.policy.SetProbability(.5)
145+
# Use the pseudo random sequence derived from seed=2.
146+
self.policy.SetSeed(2)
147+
148+
class TestModel(ndb.Model):
149+
pass
150+
151+
TestModel().put()
152+
153+
self.assertEqual(0, TestModel.query().count(3))
154+
self.assertEqual(0, TestModel.query().count(3))
155+
# Will always be applied before the third query.
156+
self.assertEqual(1, TestModel.query().count(3))
157+
# [END HRD_example_2]
158+
159+
160+
# [START main]
161+
if __name__ == '__main__':
162+
unittest.main()
163+
# [END main]

localtesting/test_env_vars.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2015 Google Inc
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+
# [START env_example]
16+
import unittest
17+
import os
18+
from google.appengine.ext import testbed
19+
20+
21+
class EnvVarsTestCase(unittest.TestCase):
22+
def setUp(self):
23+
self.testbed = testbed.Testbed()
24+
self.testbed.activate()
25+
self.testbed.setup_env(
26+
app_id='your-app-id',
27+
my_config_setting='example',
28+
overwrite=True)
29+
30+
def tearDown(self):
31+
self.testbed.deactivate()
32+
33+
def testEnvVars(self):
34+
assert os.environ['APPLICATION_ID'] == 'your-app-id'
35+
assert os.environ['MY_CONFIG_SETTING'] == 'example'
36+
# [END env_example]
37+
38+
if __name__ == '__main__':
39+
unittest.main()

localtesting/test_login.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright 2015 Google Inc
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+
# [START login_example]
16+
import unittest
17+
from google.appengine.ext import testbed
18+
from google.appengine.api import users
19+
20+
21+
class LoginTestCase(unittest.TestCase):
22+
# [START setup]
23+
def setUp(self):
24+
self.testbed = testbed.Testbed()
25+
self.testbed.activate()
26+
self.testbed.init_user_stub()
27+
# [END setup]
28+
29+
def tearDown(self):
30+
self.testbed.deactivate()
31+
32+
# [START login]
33+
def loginUser(self, email='[email protected]', id='123', is_admin=False):
34+
self.testbed.setup_env(
35+
user_email=email,
36+
user_id=id,
37+
user_is_admin='1' if is_admin else '0',
38+
overwrite=True)
39+
# [END login]
40+
41+
# [START test]
42+
def testLogin(self):
43+
assert not users.get_current_user()
44+
self.loginUser()
45+
assert users.get_current_user().email() == '[email protected]'
46+
self.loginUser(is_admin=True)
47+
assert users.is_current_user_admin()
48+
# [END test]
49+
# [END login_example]
50+
51+
if __name__ == '__main__':
52+
unittest.main()

localtesting/test_mail.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright 2015 Google Inc
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+
# [START mail_example]
16+
import unittest
17+
from google.appengine.ext import testbed
18+
from google.appengine.api import mail
19+
20+
21+
class MailTestCase(unittest.TestCase):
22+
23+
def setUp(self):
24+
self.testbed = testbed.Testbed()
25+
self.testbed.activate()
26+
self.testbed.init_mail_stub()
27+
self.mail_stub = self.testbed.get_stub(testbed.MAIL_SERVICE_NAME)
28+
29+
def tearDown(self):
30+
self.testbed.deactivate()
31+
32+
def testMailSent(self):
33+
mail.send_mail(to='[email protected]',
34+
subject='This is a test',
35+
36+
body='This is a test e-mail')
37+
messages = self.mail_stub.get_sent_messages(to='[email protected]')
38+
self.assertEqual(1, len(messages))
39+
self.assertEqual('[email protected]', messages[0].to)
40+
# [END mail_example]
41+
42+
if __name__ == '__main__':
43+
unittest.main()

0 commit comments

Comments
 (0)