blob: 6a59713fdd1f3ee7d60f756296cdc419f5e30122 [file] [log] [blame]
Matteo Scandolod2044a42017-08-07 16:08:28 -07001# Copyright 2017-present Open Networking Foundation
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
Zack Williams045b63d2019-01-22 16:30:57 -070015from __future__ import print_function
Zack Williams5c2ea232019-01-30 15:23:01 -070016
Scott Baker7dddd512017-10-24 10:13:34 -070017import os
Scott Bakerff104cc2017-08-14 15:24:41 -070018import random
Scott Bakerff104cc2017-08-14 15:24:41 -070019import string
Scott Bakerd1940972017-05-01 15:45:32 -070020import sys
21import unittest
Zack Williams5c2ea232019-01-30 15:23:01 -070022
23try: # python 3
24 from io import StringIO
Scott Baker4185dca2019-06-07 09:13:43 -070025 from unittest.mock import patch, MagicMock
Zack Williams5c2ea232019-01-30 15:23:01 -070026except ImportError: # python 2
27 from StringIO import StringIO
Scott Baker4185dca2019-06-07 09:13:43 -070028 from mock import patch, MagicMock
Zack Williams5c2ea232019-01-30 15:23:01 -070029
Scott Bakerd1940972017-05-01 15:45:32 -070030
Scott Baker7dddd512017-10-24 10:13:34 -070031# by default, use fake stub rather than real core
Zack Williams045b63d2019-01-22 16:30:57 -070032USE_FAKE_STUB = True
Scott Bakerd1940972017-05-01 15:45:32 -070033
Zack Williams045b63d2019-01-22 16:30:57 -070034PARENT_DIR = os.path.join(os.path.dirname(__file__), "..")
35
Scott Bakerd1940972017-05-01 15:45:32 -070036
Scott Baker4185dca2019-06-07 09:13:43 -070037class ORMTestBaseClass(unittest.TestCase):
Scott Baker7dddd512017-10-24 10:13:34 -070038 def setUp(self):
Scott Bakere5f0f682018-06-18 10:21:35 -070039 from xosconfig import Config
Zack Williams045b63d2019-01-22 16:30:57 -070040
Scott Bakere5f0f682018-06-18 10:21:35 -070041 test_path = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
42 config = os.path.join(test_path, "test_config.yaml")
43 Config.clear()
Zack Williams045b63d2019-01-22 16:30:57 -070044 Config.init(config, "synchronizer-config-schema.yaml")
45 if USE_FAKE_STUB:
Scott Baker7dddd512017-10-24 10:13:34 -070046 sys.path.append(PARENT_DIR)
47
Scott Baker9e477252019-01-07 11:49:45 -080048 # Import these after config, in case they depend on config
49 from xosapi.orm import ORMQuerySet, ORMLocalObjectManager
Zack Williams045b63d2019-01-22 16:30:57 -070050
Scott Baker9e477252019-01-07 11:49:45 -080051 self.ORMQuerySet = ORMQuerySet
52 self.ORMLocalObjectManager = ORMLocalObjectManager
53
Scott Baker4185dca2019-06-07 09:13:43 -070054 self.orm = self.make_coreapi()
55
Scott Baker7dddd512017-10-24 10:13:34 -070056 def tearDown(self):
Zack Williams045b63d2019-01-22 16:30:57 -070057 if USE_FAKE_STUB:
Scott Baker7dddd512017-10-24 10:13:34 -070058 sys.path.remove(PARENT_DIR)
59
Scott Bakerf0ee0dc2017-05-15 10:10:05 -070060 def make_coreapi(self):
61 if USE_FAKE_STUB:
Scott Baker7dddd512017-10-24 10:13:34 -070062 import xosapi.orm
Scott Bakerb96ba432018-02-26 09:53:48 -080063 from fake_stub import FakeStub, FakeProtos, FakeObj
Scott Baker7dddd512017-10-24 10:13:34 -070064
Scott Bakerc0017032018-05-01 10:54:26 -070065 xosapi.orm.import_convenience_methods()
66
Scott Bakerf0ee0dc2017-05-15 10:10:05 -070067 stub = FakeStub()
Zack Williams045b63d2019-01-22 16:30:57 -070068 api = xosapi.orm.ORMStub(
69 stub=stub,
70 package_name="xos",
71 protos=FakeProtos(),
72 empty=FakeObj,
73 enable_backoff=False,
74 )
Scott Bakerf0ee0dc2017-05-15 10:10:05 -070075 return api
76 else:
77 return xos_grpc_client.coreapi
78
Scott Bakerd1940972017-05-01 15:45:32 -070079
Scott Baker4185dca2019-06-07 09:13:43 -070080class TestORMWrapper(ORMTestBaseClass):
81 """ Tests for the ORMWrapper class """
Scott Bakerd1940972017-05-01 15:45:32 -070082
Scott Baker4185dca2019-06-07 09:13:43 -070083 def test_ORMWrapper_fields_differ(self):
84 testModel = self.orm.TestModel(intfield=7, stringfield="foo")
85 self.assertTrue(testModel.fields_differ("a", "b"))
86 self.assertFalse(testModel.fields_differ("a", "a"))
Scott Bakere1607b82018-09-20 14:10:59 -070087
Scott Baker9e477252019-01-07 11:49:45 -080088 def test_ORMWrapper_dict(self):
Scott Baker4185dca2019-06-07 09:13:43 -070089 testModel = self.orm.TestModel(intfield=7, stringfield="foo")
Scott Baker9e477252019-01-07 11:49:45 -080090
91 self.assertDictEqual(testModel._dict, {"intfield": 7, "stringfield": "foo"})
92
Scott Baker5b7fba02018-10-17 08:46:46 -070093 def test_ORMWrapper_new_diff(self):
Scott Baker4185dca2019-06-07 09:13:43 -070094 site = self.orm.Site(name="mysite")
Scott Baker5b7fba02018-10-17 08:46:46 -070095
96 self.assertEqual(site.is_new, True)
97 self.assertEqual(site._dict, {"name": "mysite"})
98 self.assertEqual(site.diff, {})
99 self.assertEqual(site.changed_fields, ["name"])
100 self.assertEqual(site.has_field_changed("name"), False)
101 self.assertEqual(site.has_field_changed("login_base"), False)
Scott Baker4185dca2019-06-07 09:13:43 -0700102 self.assertEqual(site.has_changed, False)
Scott Baker5b7fba02018-10-17 08:46:46 -0700103
104 site.login_base = "bar"
105
Zack Williams045b63d2019-01-22 16:30:57 -0700106 self.assertEqual(site._dict, {"login_base": "bar", "name": "mysite"})
107 self.assertEqual(site.diff, {"login_base": (None, "bar")})
Scott Baker5b7fba02018-10-17 08:46:46 -0700108 self.assertIn("name", site.changed_fields)
109 self.assertIn("login_base", site.changed_fields)
110 self.assertEqual(site.has_field_changed("name"), False)
111 self.assertEqual(site.has_field_changed("login_base"), True)
Scott Baker4185dca2019-06-07 09:13:43 -0700112 self.assertEqual(site.has_changed, True)
Scott Baker5b7fba02018-10-17 08:46:46 -0700113 self.assertEqual(site.get_field_diff("login_base"), (None, "bar"))
114
115 def test_ORMWrapper_existing_diff(self):
Scott Baker4185dca2019-06-07 09:13:43 -0700116 site = self.orm.Site(name="mysite", login_base="foo")
Scott Baker5b7fba02018-10-17 08:46:46 -0700117 site.save()
Scott Baker4185dca2019-06-07 09:13:43 -0700118 site = self.orm.Site.objects.first()
Scott Baker5b7fba02018-10-17 08:46:46 -0700119
120 self.assertEqual(site.is_new, False)
121 self.assertEqual(site._dict, {"id": 1, "name": "mysite", "login_base": "foo"})
122 self.assertEqual(site.diff, {})
123 self.assertEqual(site.changed_fields, [])
124 self.assertEqual(site.has_field_changed("name"), False)
125 self.assertEqual(site.has_field_changed("login_base"), False)
Scott Baker4185dca2019-06-07 09:13:43 -0700126 self.assertEqual(site.has_changed, False)
Scott Baker5b7fba02018-10-17 08:46:46 -0700127
128 site.login_base = "bar"
129
Zack Williams045b63d2019-01-22 16:30:57 -0700130 self.assertEqual(site._dict, {"id": 1, "login_base": "bar", "name": "mysite"})
131 self.assertEqual(site.diff, {"login_base": ("foo", "bar")})
Scott Baker5b7fba02018-10-17 08:46:46 -0700132 self.assertIn("login_base", site.changed_fields)
133 self.assertEqual(site.has_field_changed("name"), False)
134 self.assertEqual(site.has_field_changed("login_base"), True)
Scott Baker4185dca2019-06-07 09:13:43 -0700135 self.assertEqual(site.has_changed, True)
Scott Baker5b7fba02018-10-17 08:46:46 -0700136
137 def test_ORMWrapper_diff_after_save(self):
Scott Baker4185dca2019-06-07 09:13:43 -0700138 site = self.orm.Site(name="mysite", login_base="foo")
Scott Baker5b7fba02018-10-17 08:46:46 -0700139 site.save()
Scott Baker4185dca2019-06-07 09:13:43 -0700140 site = self.orm.Site.objects.first()
Scott Baker5b7fba02018-10-17 08:46:46 -0700141
142 self.assertEqual(site.diff, {})
143
144 site.login_base = "bar"
145
Zack Williams045b63d2019-01-22 16:30:57 -0700146 self.assertEqual(site.diff, {"login_base": ("foo", "bar")})
Scott Baker5b7fba02018-10-17 08:46:46 -0700147
148 site.save()
149
150 self.assertEqual(site.diff, {})
151
Scott Baker9e477252019-01-07 11:49:45 -0800152 def test_ORMWrapper_recompute_initial(self):
153 """ For saved models, Recompute_initial should take recompute the set of initial values, removing all items
154 from the diff set.
155 """
156
Scott Baker4185dca2019-06-07 09:13:43 -0700157 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800158 testModel.save()
159
160 testModel.intfield = 9
161 self.assertEqual(testModel.changed_fields, ["intfield"])
162
163 testModel.recompute_initial()
164 self.assertEqual(testModel.changed_fields, [])
165
Scott Baker9e477252019-01-07 11:49:45 -0800166 def test_ORMWrapper_save_changed_fields(self):
Scott Baker4185dca2019-06-07 09:13:43 -0700167 testModel = self.orm.TestModel(intfield=7, stringfield="foo")
Scott Baker9e477252019-01-07 11:49:45 -0800168 testModel.save()
169
Zack Williams045b63d2019-01-22 16:30:57 -0700170 testModel.intfield = 9
Scott Baker9e477252019-01-07 11:49:45 -0800171
Zack Williams045b63d2019-01-22 16:30:57 -0700172 with patch.object(
Scott Baker4185dca2019-06-07 09:13:43 -0700173 self.orm.grpc_stub, "UpdateTestModel", wraps=self.orm.grpc_stub.UpdateTestModel
Zack Williams045b63d2019-01-22 16:30:57 -0700174 ) as update:
Scott Baker9e477252019-01-07 11:49:45 -0800175 testModel.save_changed_fields()
Scott Baker5dc7cc52019-01-18 15:05:27 -0800176
177 self.assertEqual(update.call_count, 1)
178 self.assertIn("metadata", update.call_args[1])
Zack Williams045b63d2019-01-22 16:30:57 -0700179 update_fields_arg = [
180 x[1] for x in update.call_args[1]["metadata"] if x[0] == "update_fields"
181 ]
Scott Baker5dc7cc52019-01-18 15:05:27 -0800182 self.assertEqual(update_fields_arg, ["intfield"])
Scott Baker9e477252019-01-07 11:49:45 -0800183
Scott Baker4185dca2019-06-07 09:13:43 -0700184 def test_ORMWrapper_create_attr(self):
185 testModel = self.orm.TestModel()
186 testModel.create_attr("some_new_attribute", "foo")
187 self.assertEqual(testModel.some_new_attribute, "foo")
188
Scott Baker9e477252019-01-07 11:49:45 -0800189 def test_ORMWrapper_get_generic_foreignkeys(self):
190 """ Currently this is a placeholder that returns an empty list """
191
Scott Baker4185dca2019-06-07 09:13:43 -0700192 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800193 self.assertEqual(testModel.get_generic_foreignkeys(), [])
194
195 def test_ORMWrapper_gen_fkmap(self):
196 """ TestModelTwo includes a foreignkey relation to TestModel, and the fkmap should contain that relation """
197
Scott Baker4185dca2019-06-07 09:13:43 -0700198 testModelTwo = self.orm.TestModelTwo()
Scott Baker9e477252019-01-07 11:49:45 -0800199
Zack Williams045b63d2019-01-22 16:30:57 -0700200 self.assertDictEqual(
201 testModelTwo.gen_fkmap(),
202 {
203 "testmodel": {
204 "kind": "fk",
205 "modelName": "TestModel",
206 "reverse_fieldName": "testmodeltwos",
207 "src_fieldName": "testmodel_id",
208 }
209 },
210 )
Scott Baker9e477252019-01-07 11:49:45 -0800211
212 def test_ORMWrapper_gen_reverse_fkmap(self):
213 """ TestModel includes a reverse relation back to TestModelTwo, and the reverse_fkmap should contain that
214 relation.
215 """
216
Scott Baker4185dca2019-06-07 09:13:43 -0700217 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800218
Zack Williams045b63d2019-01-22 16:30:57 -0700219 self.assertDictEqual(
220 testModel.gen_reverse_fkmap(),
221 {
222 "testmodeltwos": {
223 "modelName": "TestModelTwo",
224 "src_fieldName": "testmodeltwos_ids",
225 "writeable": False,
226 }
227 },
228 )
Scott Baker9e477252019-01-07 11:49:45 -0800229
230 def test_ORMWrapper_fk_resolve(self):
231 """ If we create a TestModelTwo that has a foreign key reference to a TestModel, then calling fk_resolve should
232 return that model.
233 """
234
Scott Baker4185dca2019-06-07 09:13:43 -0700235 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800236 testModel.save()
237
Scott Baker4185dca2019-06-07 09:13:43 -0700238 testModelTwo = self.orm.TestModelTwo(testmodel_id=testModel.id)
Scott Baker9e477252019-01-07 11:49:45 -0800239
240 testModel_resolved = testModelTwo.fk_resolve("testmodel")
241 self.assertEqual(testModel_resolved.id, testModel.id)
242
Scott Baker7ab456b2019-01-08 14:58:13 -0800243 # the cache should have been populated
244 self.assertIn(("testmodel", testModel_resolved), testModelTwo.cache.items())
245
Scott Baker9e477252019-01-07 11:49:45 -0800246 def test_ORMWrapper_reverse_fk_resolve(self):
247 """ If a TestModelTwo has a relation to TestModel, then TestModel's reverse_fk should be resolvable to a list
248 of TestModelTwo objects.
249 """
250
Scott Baker4185dca2019-06-07 09:13:43 -0700251 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800252 testModel.save()
253
Scott Baker4185dca2019-06-07 09:13:43 -0700254 testModelTwo = self.orm.TestModelTwo(testmodel_id=testModel.id)
Scott Baker9e477252019-01-07 11:49:45 -0800255 testModelTwo.save()
256
257 # fake_stub.py doesn't populate the reverse relations for us, so force what the server would have done...
258 testModel._wrapped_class.testmodeltwos_ids = [testModelTwo.id]
259
260 testModelTwos_resolved = testModel.reverse_fk_resolve("testmodeltwos")
261 self.assertEqual(testModelTwos_resolved.count(), 1)
262
Scott Baker7ab456b2019-01-08 14:58:13 -0800263 # the reverse_cache should have been populated
Zack Williams045b63d2019-01-22 16:30:57 -0700264 self.assertIn(
265 ("testmodeltwos", testModelTwos_resolved), testModel.reverse_cache.items()
266 )
Scott Baker7ab456b2019-01-08 14:58:13 -0800267
Scott Baker9e477252019-01-07 11:49:45 -0800268 def test_ORMWrapper_fk_set(self):
269 """ fk_set will set the testmodel field on TesTModelTwo to point to the TestModel. """
270
Scott Baker4185dca2019-06-07 09:13:43 -0700271 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800272 testModel.save()
273
Scott Baker4185dca2019-06-07 09:13:43 -0700274 testModelTwo = self.orm.TestModelTwo()
Scott Baker9e477252019-01-07 11:49:45 -0800275
276 testModelTwo.fk_set("testmodel", testModel)
277
278 self.assertEqual(testModelTwo.testmodel_id, testModel.id)
279
280 def test_ORMWrapper_post_save_fixups_remove(self):
281 """ Apply a post_save_fixup that removes a reverse foreign key """
282
Scott Baker4185dca2019-06-07 09:13:43 -0700283 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800284 testModel.save()
285
Scott Baker4185dca2019-06-07 09:13:43 -0700286 testModelTwo = self.orm.TestModelTwo(testmodel_id=testModel.id)
Scott Baker9e477252019-01-07 11:49:45 -0800287
288 # fake_stub.py doesn't populate the reverse relations for us, so force what the server would have done...
289 testModel._wrapped_class.testmodeltwos_ids = [testModelTwo.id]
290
Zack Williams045b63d2019-01-22 16:30:57 -0700291 post_save_fixups = [
292 {
293 "src_fieldName": "testmodel",
294 "dest_id": None, # this field appears to not be used...
295 "dest_model": testModel,
296 "remove": True,
297 "reverse_fieldName": "testmodeltwos",
298 }
299 ]
Scott Baker9e477252019-01-07 11:49:45 -0800300
301 testModelTwo.post_save_fixups = post_save_fixups
302 testModelTwo.do_post_save_fixups()
303
304 self.assertEqual(testModel._wrapped_class.testmodeltwos_ids, [])
305
306 def test_ORMWrapper_post_save_fixups_add(self):
307 """ Apply a post_save_fixup that adds a reverse foreign key """
308
Scott Baker4185dca2019-06-07 09:13:43 -0700309 testModel = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800310 testModel.save()
311
Scott Baker4185dca2019-06-07 09:13:43 -0700312 testModelTwo = self.orm.TestModelTwo(testmodel_id=testModel.id)
Scott Baker9e477252019-01-07 11:49:45 -0800313 testModelTwo.save()
314
315 # Make sure the reverse_relation is unpopulated. This should be the case, as fake_stub.py() doesn't populate
316 # the reverse relation. But let's be sure, in case someone fixes that.
317 testModel._wrapped_class.testmodeltwos_ids = []
318
Zack Williams045b63d2019-01-22 16:30:57 -0700319 post_save_fixups = [
320 {
321 "src_fieldName": "testmodel",
322 "dest_id": None, # this field appears to not be used...
323 "dest_model": testModel,
324 "remove": False,
325 "reverse_fieldName": "testmodeltwos",
326 }
327 ]
Scott Baker9e477252019-01-07 11:49:45 -0800328
329 testModelTwo.post_save_fixups = post_save_fixups
330 testModelTwo.do_post_save_fixups()
331
332 self.assertEqual(testModel._wrapped_class.testmodeltwos_ids, [testModelTwo.id])
333
Scott Baker9e477252019-01-07 11:49:45 -0800334 def test_ORMWrapper_tologdict(self):
335 """ Tologdict contains the model name and id, used for structured logging """
Scott Baker4185dca2019-06-07 09:13:43 -0700336 testModel = self.orm.TestModel(intfield=7, stringfile="foo")
Scott Baker9e477252019-01-07 11:49:45 -0800337
Zack Williams045b63d2019-01-22 16:30:57 -0700338 self.assertDictEqual(
339 testModel.tologdict(), {"model_name": "TestModel", "pk": 0}
340 )
Scott Baker9e477252019-01-07 11:49:45 -0800341
Scott Baker4185dca2019-06-07 09:13:43 -0700342 def test_repr_name(self):
343 s = self.orm.Slice(name="foo")
344 self.assertNotEqual(s, None)
345 self.assertEqual(repr(s), "<Slice: foo>")
346
347 def test_repr_noname(self):
348 s = self.orm.Slice()
349 self.assertNotEqual(s, None)
350 self.assertEqual(repr(s), "<Slice: id-0>")
351
352 def test_str_name(self):
353 s = self.orm.Slice(name="foo")
354 self.assertNotEqual(s, None)
355 self.assertEqual(str(s), "foo")
356
357 def test_str_noname(self):
358 s = self.orm.Slice()
359 self.assertNotEqual(s, None)
360 self.assertEqual(str(s), "Slice-0")
361
362 def test_dumpstr_name(self):
363 s = self.orm.Slice(name="foo")
364 self.assertNotEqual(s, None)
365 self.assertEqual(s.dumpstr(), 'name: "foo"\n')
366
367 def test_dumpstr_noname(self):
368 s = self.orm.Slice()
369 self.assertNotEqual(s, None)
370 self.assertEqual(s.dumpstr(), "")
371
372 def test_dump(self):
373 """ dump() is like dumpstr() but prints to stdout. Mock stdout by using a stringIO. """
374
375 s = self.orm.Slice(name="foo")
376 self.assertNotEqual(s, None)
377 with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
378 s.dump()
379 self.assertEqual(mock_stdout.getvalue(), 'name: "foo"\n\n')
380
381 def test_invalidate_cache(self):
382 testModel = self.orm.TestModel()
383
384 # populate the caches with some placeholders we can test for
385 testModel.cache = {"a": 1}
386 testModel.reverse_cache = {"b": 2}
387
388 testModel.invalidate_cache()
389
390 self.assertEqual(testModel.cache, {})
391 self.assertEqual(testModel.reverse_cache, {})
392
393 def test_leaf_model_trivial(self):
394 service = self.orm.Service(name="myservice")
395 service.save()
396 self.assertEqual(service.leaf_model_name, "Service")
397
398 def test_leaf_model_descendant(self):
399 onos_service = self.orm.ONOSService(name="myservice")
400 onos_service.save()
401 self.assertEqual(onos_service.model_name, "ONOSService")
402 self.assertEqual(onos_service.leaf_model_name, "ONOSService")
403
404 service = self.orm.Service.objects.get(id=onos_service.id)
405 self.assertEqual(service.id, onos_service.id)
406 self.assertEqual(service.model_name, "Service")
407 self.assertEqual(service.leaf_model_name, "ONOSService")
408
409 onos_service_cast = service.leaf_model
410 self.assertEqual(onos_service_cast.model_name, "ONOSService")
411 self.assertEqual(onos_service_cast.leaf_model_name, "ONOSService")
412 self.assertEqual(onos_service_cast.id, onos_service.id)
413
414 def test_ORMWrapper_model_name(self):
415 testModel = self.orm.TestModel()
416 self.assertEqual(testModel.model_name, "TestModel")
417
Scott Baker9e477252019-01-07 11:49:45 -0800418 def test_ORMWrapper_ansible_tag(self):
419 """ Ansible_tag is used by old-style synchronizers. Deprecated. """
420
Scott Baker4185dca2019-06-07 09:13:43 -0700421 testModel = self.orm.TestModel(id=7)
Scott Baker9e477252019-01-07 11:49:45 -0800422
423 self.assertEqual(testModel.ansible_tag, "TestModel_7")
424
Scott Bakerea1f4d02018-12-17 10:21:50 -0800425
Scott Baker4185dca2019-06-07 09:13:43 -0700426class TestORMQuerySet(ORMTestBaseClass):
427 """ Tests for high-level ORMQuerySet class """
Scott Bakerea1f4d02018-12-17 10:21:50 -0800428
Scott Baker9e477252019-01-07 11:49:45 -0800429 def test_ORMQuerySet_first_nonempty(self):
Zack Williams045b63d2019-01-22 16:30:57 -0700430 qs = self.ORMQuerySet([1, 2, 3])
Scott Baker9e477252019-01-07 11:49:45 -0800431 self.assertEqual(qs.first(), 1)
432
433 def test_ORMQuerySet_first_empty(self):
434 qs = self.ORMQuerySet([])
435 self.assertEqual(qs.first(), None)
436
437 def test_ORMQuerySet_exists_nonempty(self):
Zack Williams045b63d2019-01-22 16:30:57 -0700438 qs = self.ORMQuerySet([1, 2, 3])
Scott Baker9e477252019-01-07 11:49:45 -0800439 self.assertEqual(qs.exists(), True)
440
441 def test_ORMQuerySet_exists_empty(self):
442 qs = self.ORMQuerySet()
443 self.assertEqual(qs.exists(), False)
444
Scott Baker4185dca2019-06-07 09:13:43 -0700445
446class TestORMLocalObjectManager(ORMTestBaseClass):
447 """ Tests for high-level ORMLocalObjectManager class """
448
Scott Baker9e477252019-01-07 11:49:45 -0800449 def test_ORMLocalObjectManager_nonempty(self):
450 """ Test all(), first(), exists(), and count() together since they're all closely related. Use a nonempty
451 list.
452 """
Scott Baker4185dca2019-06-07 09:13:43 -0700453 t = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800454 t.save()
455
456 lobjs = self.ORMLocalObjectManager(t.stub, "TestModel", [t.id], False)
457 self.assertEqual(len(lobjs.all()), 1)
458 self.assertEqual(lobjs.all()[0].id, t.id)
459 self.assertEqual(lobjs.exists(), True)
460 self.assertEqual(lobjs.count(), 1)
461 self.assertEqual(lobjs.first().id, t.id)
462
463 def test_ORMLocalObjectManager_empty(self):
464 """ Test all(), first(), exists(), and count() together since they're all closely related. Use an empty
465 list.
466 """
Scott Baker4185dca2019-06-07 09:13:43 -0700467 t = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800468 t.save()
469
470 lobjs = self.ORMLocalObjectManager(t.stub, "TestModel", [], False)
471 self.assertEqual(len(lobjs.all()), 0)
472 self.assertEqual(lobjs.exists(), False)
473 self.assertEqual(lobjs.count(), 0)
474 self.assertEqual(lobjs.first(), None)
475
476 def test_ORMLocalObjectManager_not_writeable(self):
477 """ An ORMLocalObjectManager that is not writeable should throw exceptions on add() and remove() """
Scott Baker4185dca2019-06-07 09:13:43 -0700478 t = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800479 t.save()
480
481 lobjs = self.ORMLocalObjectManager(t.stub, "TestModel", [t.id], False)
482
483 with self.assertRaises(Exception) as e:
484 lobjs.add(123)
Zack Williams5c2ea232019-01-30 15:23:01 -0700485 self.assertEqual(str(e.exception), "Only ManyToMany lists are writeable")
Scott Baker9e477252019-01-07 11:49:45 -0800486
487 with self.assertRaises(Exception) as e:
488 lobjs.remove(123)
Zack Williams5c2ea232019-01-30 15:23:01 -0700489 self.assertEqual(str(e.exception), "Only ManyToMany lists are writeable")
Scott Baker9e477252019-01-07 11:49:45 -0800490
491 def test_ORMLocalObjectManager_add(self):
Scott Baker4185dca2019-06-07 09:13:43 -0700492 t = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800493 t.save()
494
495 lobjs = self.ORMLocalObjectManager(t.stub, "TestModel", [], True)
496 lobjs.add(t)
497 self.assertEqual(lobjs.count(), 1)
498 self.assertEqual(lobjs.first().id, t.id)
499
500 def test_ORMLocalObjectManager_remove(self):
Scott Baker4185dca2019-06-07 09:13:43 -0700501 t = self.orm.TestModel()
Scott Baker9e477252019-01-07 11:49:45 -0800502 t.save()
503
504 lobjs = self.ORMLocalObjectManager(t.stub, "TestModel", [t.id], True)
505 lobjs.remove(t)
506 self.assertEqual(lobjs.count(), 0)
Scott Baker5b7fba02018-10-17 08:46:46 -0700507
Zack Williams045b63d2019-01-22 16:30:57 -0700508
Scott Baker4185dca2019-06-07 09:13:43 -0700509class TestORMObjectManager(ORMTestBaseClass):
510 """ Tests for ORMObjectManager class """
511
512 def test_wrap_single(self):
513 wrapped_obj = self.orm.all_grpc_classes["Site"](name="mysite")
514 orm_obj = self.orm.Site.objects.wrap_single(wrapped_obj)
515 self.assertEqual(orm_obj._wrapped_class, wrapped_obj)
516
517 def test_wrap_list(self):
518 wrapped_obj = self.orm.all_grpc_classes["Site"](name="mysite")
519 wrapped_list = MagicMock(items=[wrapped_obj])
520 orm_objs = self.orm.Site.objects.wrap_list(wrapped_list)
521 self.assertEqual(len(orm_objs), 1)
522 self.assertEqual(orm_objs[0]._wrapped_class, wrapped_obj)
523
524 def test_objects_all(self):
525 orig_len_sites = len(self.orm.Site.objects.all())
526 site = self.orm.Site(name="mysite")
527 site.save()
528 sites = self.orm.Site.objects.all()
529 self.assertEqual(len(sites), orig_len_sites + 1)
530
531 def test_objects_first(self):
532 site = self.orm.Site(name="mysite")
533 site.save()
534 site = self.orm.Site.objects.first()
535 self.assertNotEqual(site, None)
536
537 def test_filter_query_iexact(self):
538 with patch.object(self.orm.grpc_stub, "FilterTestModel", autospec=True) as filter:
539 self.orm.TestModel.objects.filter(name__iexact="foo")
540 self.assertEqual(filter.call_count, 1)
541 q = filter.call_args[0][0]
542
543 self.assertEqual(q.kind, q.DEFAULT)
544 self.assertEqual(len(q.elements), 1)
545 self.assertEqual(q.elements[0].operator, q.elements[0].IEXACT)
546 self.assertEqual(q.elements[0].sValue, "foo")
547
548 def test_filter_query_equal(self):
549 with patch.object(self.orm.grpc_stub, "FilterTestModel", autospec=True) as filter:
550 self.orm.TestModel.objects.filter(name="foo")
551 self.assertEqual(filter.call_count, 1)
552 q = filter.call_args[0][0]
553
554 self.assertEqual(q.kind, q.DEFAULT)
555 self.assertEqual(len(q.elements), 1)
556 self.assertEqual(q.elements[0].operator, q.elements[0].EQUAL)
557 self.assertEqual(q.elements[0].sValue, "foo")
558
559 def test_filter_special(self):
560 with patch.object(self.orm.grpc_stub, "FilterTestModel", autospec=True) as filter:
561 self.orm.TestModel.objects.filter_special(kind=self.orm.TestModel.objects.SYNCHRONIZER_DIRTY_OBJECTS)
562 self.assertEqual(filter.call_count, 1)
563 q = filter.call_args[0][0]
564 self.assertEqual(q.kind, q.SYNCHRONIZER_DIRTY_OBJECTS)
565
566 def test_get(self):
567 site = self.orm.Site(name="mysite")
568 site.save()
569 self.assertTrue(site.id > 0)
570 got_site = self.orm.Site.objects.get(id=site.id)
571 self.assertNotEqual(got_site, None)
572 self.assertEqual(got_site.id, site.id)
573
574 def test_new(self):
575 site = self.orm.Site.objects.new(name="mysite")
576 site.save()
577 self.assertTrue(site.id > 0)
578
579
580class TestORMModelClass(ORMTestBaseClass):
581 """ Tests for ORMModelClass class """
582
583 def test_name(self):
584 self.assertEqual(self.orm.Site.__name__, "Site")
585
586 def test_content_type_id(self):
587 self.assertNotEqual(self.orm.Site.content_type_id, None)
588
589 def test_call(self):
590 new_obj = self.orm.Site(name="mysite")
591 self.assertNotEqual(new_obj, None)
592 self.assertEqual(new_obj.name, "mysite")
593
594
595class TestORM(ORMTestBaseClass):
596 """ Tests for OMRStub and misc high-level ORM operations """
597
598 def test_add_default_metadata(self):
599 md = []
600 self.orm.add_default_metadata(md)
601 self.assertListEqual(md, [('caller_kind', 'grpcapi')])
602
603 def test_make_ID(self):
604 id_proto = self.orm.make_ID(123)
605 self.assertEqual(id_proto.id, 123)
606
607 def test_make_empty(self):
608 empty_proto = self.orm.make_empty()
609 self.assertNotEqual(empty_proto, None)
610
611 def test_make_Query(self):
612 query_proto = self.orm.make_Query()
613 self.assertNotEqual(query_proto, None)
614 self.assertTrue(hasattr(query_proto, "elements"))
615
616 def test_listObjects(self):
617 objs = self.orm.listObjects()
618 self.assertIn("Slice", objs)
619
620 def test_create(self):
621 site = self.orm.Site(name="mysite")
622 site.save()
623 self.assertTrue(site.id > 0)
624
625 def test_save_existing(self):
626 orig_len_sites = len(self.orm.Site.objects.all())
627 site = self.orm.Site(name="mysite")
628 site.save()
629 self.assertTrue(site.id > 0)
630
631 # there should be one new site
632 self.assertEqual(len(self.orm.Site.objects.all()), orig_len_sites + 1)
633
634 # retrieve the site, and update it
635 created_site_id = site.id
636 site = self.orm.Site.objects.get(id=created_site_id)
637 site.name = "mysitetwo"
638 site.save()
639
640 # the site_id should not have changed
641 self.assertEqual(site.id, created_site_id)
642
643 # there should still be only one new site
644 self.assertEqual(len(self.orm.Site.objects.all()), orig_len_sites + 1)
645
646 # the name should have changed
647 self.assertEqual(self.orm.Site.objects.get(id=created_site_id).name, "mysitetwo")
648
649 def test_delete(self):
650 orig_len_sites = len(self.orm.Site.objects.all())
651 site = self.orm.Site(name="mysite")
652 site.save()
653 self.assertTrue(site.id > 0)
654 site.delete()
655 sites = self.orm.Site.objects.all()
656 self.assertEqual(len(sites), orig_len_sites)
657
658 def test_content_type_map(self):
659 self.assertTrue("Slice" in self.orm.content_type_map.values())
660 self.assertTrue("Site" in self.orm.content_type_map.values())
661 self.assertTrue("Tag" in self.orm.content_type_map.values())
662
663 def test_foreign_key_get(self):
664 site = self.orm.Site(name="mysite")
665 site.save()
666 self.assertTrue(site.id > 0)
667 user = self.orm.User(
668 email="fake_"
669 + "".join(
670 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
671 ),
672 site_id=site.id,
673 )
674 user.save()
675 self.assertTrue(user.id > 0)
676 slice = self.orm.Slice(name="mysite_foo", site_id=site.id, creator_id=user.id)
677 slice.save()
678 self.assertTrue(slice.id > 0)
679 self.assertNotEqual(slice.site, None)
680 self.assertEqual(slice.site.id, site.id)
681
682 def test_foreign_key_set_with_invalidate(self):
683 site = self.orm.Site(name="mysite")
684 site.save()
685 self.assertTrue(site.id > 0)
686 user = self.orm.User(
687 email="fake_"
688 + "".join(
689 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
690 ),
691 site_id=site.id,
692 )
693 user.save()
694 self.assertTrue(user.id > 0)
695 slice = self.orm.Slice(name="mysite_foo", site=site, creator_id=user.id)
696 slice.save()
697 slice.invalidate_cache()
698 self.assertTrue(slice.id > 0)
699 self.assertNotEqual(slice.site, None)
700 self.assertEqual(slice.site.id, site.id)
701 if not USE_FAKE_STUB:
702 self.assertTrue(slice.id in slice.site.slices_ids)
703
704 def test_foreign_key_set_without_invalidate(self):
705 site = self.orm.Site(name="mysite")
706 site.save()
707 self.assertTrue(site.id > 0)
708 user = self.orm.User(
709 email="fake_"
710 + "".join(
711 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
712 ),
713 site_id=site.id,
714 )
715 user.save()
716 self.assertTrue(user.id > 0)
717 slice = self.orm.Slice(name="mysite_foo", site=site, creator_id=user.id)
718 slice.save()
719 self.assertTrue(slice.id > 0)
720 self.assertNotEqual(slice.site, None)
721 self.assertEqual(slice.site.id, site.id)
722 if not USE_FAKE_STUB:
723 self.assertTrue(slice.id in slice.site.slices_ids)
724 ids_from_models = [x.id for x in slice.site.slices.all()]
725 self.assertTrue(slice.id in ids_from_models)
726
727 def test_foreign_key_reset(self):
728 site = self.orm.Site(name="mysite")
729 site.save()
730 self.assertTrue(site.id > 0)
731 user = self.orm.User(
732 email="fake_"
733 + "".join(
734 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
735 ),
736 site_id=site.id,
737 )
738 user.save()
739 self.assertTrue(user.id > 0)
740 slice = self.orm.Slice(name="mysite_foo", site=site, creator_id=user.id)
741 slice.save()
742 self.assertTrue(slice.id > 0)
743 self.assertNotEqual(slice.site, None)
744 self.assertEqual(slice.site.id, site.id)
745 if not USE_FAKE_STUB:
746 self.assertTrue(slice.id in site.slices_ids)
747 self.assertTrue(slice.id in slice.site.slices_ids)
748
749 site2 = self.orm.Site(name="mysite2")
750 site2.save()
751 slice.name = "mysite2_foo"
752 slice.site = site2
753 slice.save()
754 self.assertNotEqual(slice.site, None)
755 self.assertEqual(slice.site.id, site2.id)
756 if not USE_FAKE_STUB:
757 self.assertTrue(slice.id not in site.slices_ids)
758 self.assertTrue(slice.id in site2.slices_ids)
759 self.assertTrue(slice.id in slice.site.slices_ids)
760 ids_from_models1 = [x.id for x in site.slices.all()]
761 self.assertTrue(slice.id not in ids_from_models1)
762 ids_from_models2 = [x.id for x in site2.slices.all()]
763 self.assertTrue(slice.id in ids_from_models2)
764
765 def test_foreign_key_back_and_forth_even(self):
766 site = self.orm.Site(name="mysite")
767 site.save()
768 self.assertTrue(site.id > 0)
769 user = self.orm.User(
770 email="fake_"
771 + "".join(
772 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
773 ),
774 site_id=site.id,
775 )
776 user.save()
777 self.assertTrue(user.id > 0)
778 slice = self.orm.Slice(name="mysite_foo", site=site, creator_id=user.id)
779 slice.save()
780 self.assertTrue(slice.id > 0)
781 self.assertNotEqual(slice.site, None)
782 self.assertEqual(slice.site.id, site.id)
783 if not USE_FAKE_STUB:
784 self.assertTrue(slice.id in site.slices_ids)
785 self.assertTrue(slice.id in slice.site.slices_ids)
786
787 site2 = self.orm.Site(name="mysite2")
788 site2.save()
789 slice.name = "mysite2_foo"
790 slice.site = site2
791 slice.site = site
792 slice.site = site2
793 slice.site = site
794 slice.save()
795 self.assertNotEqual(slice.site, None)
796 self.assertEqual(slice.site.id, site.id)
797 if not USE_FAKE_STUB:
798 self.assertTrue(slice.id not in site2.slices_ids)
799 self.assertTrue(slice.id in site.slices_ids)
800 self.assertTrue(slice.id in slice.site.slices_ids)
801
802 def test_foreign_key_back_and_forth_odd(self):
803 site = self.orm.Site(name="mysite")
804 site.save()
805 self.assertTrue(site.id > 0)
806 user = self.orm.User(
807 email="fake_"
808 + "".join(
809 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
810 ),
811 site_id=site.id,
812 )
813 user.save()
814 self.assertTrue(user.id > 0)
815 slice = self.orm.Slice(name="mysite_foo", site=site, creator_id=user.id)
816 slice.save()
817 self.assertTrue(slice.id > 0)
818 self.assertNotEqual(slice.site, None)
819 self.assertEqual(slice.site.id, site.id)
820 if not USE_FAKE_STUB:
821 self.assertTrue(slice.id in site.slices_ids)
822 self.assertTrue(slice.id in slice.site.slices_ids)
823
824 site2 = self.orm.Site(name="mysite2")
825 site2.save()
826 slice.name = "mysite2_foo"
827 slice.site = site2
828 slice.site = site
829 slice.site = site2
830 slice.site = site
831 slice.site = site2
832 slice.save()
833 self.assertNotEqual(slice.site, None)
834 self.assertEqual(slice.site.id, site2.id)
835 if not USE_FAKE_STUB:
836 self.assertTrue(slice.id not in site.slices_ids)
837 self.assertTrue(slice.id in site2.slices_ids)
838 self.assertTrue(slice.id in slice.site.slices_ids)
839
840 def test_foreign_key_create_null(self):
841 site = self.orm.Site(name="mysite")
842 site.save()
843 self.assertTrue(site.id > 0)
844 user = self.orm.User(
845 email="fake_"
846 + "".join(
847 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
848 ),
849 site_id=site.id,
850 )
851 user.save()
852 self.assertTrue(user.id > 0)
853 slice = self.orm.Slice(
854 name="mysite_foo", site=site, service=None, creator_id=user.id
855 )
856 slice.save()
857 slice.invalidate_cache()
858 self.assertTrue(slice.id > 0)
859 self.assertEqual(slice.service, None)
860
861 def test_foreign_key_set_null(self):
862 site = self.orm.Site(name="mysite")
863 site.save()
864 self.assertTrue(site.id > 0)
865 user = self.orm.User(
866 email="fake_"
867 + "".join(
868 random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
869 ),
870 site_id=site.id,
871 )
872 user.save()
873 self.assertTrue(user.id > 0)
874 service = self.orm.Service(name="myservice")
875 service.save()
876 self.assertTrue(service.id > 0)
877 # start out slice.service is non-None
878 slice = self.orm.Slice(
879 name="mysite_foo", site=site, service=service, creator_id=user.id
880 )
881 slice.save()
882 slice.invalidate_cache()
883 self.assertTrue(slice.id > 0)
884 self.assertNotEqual(slice.service, None)
885 self.assertEqual(slice.service.id, service.id)
886 # now set it to None
887 slice.service = None
888 slice.save()
889 slice.invalidate_cache()
890 self.assertEqual(slice.service, None)
891
892 def test_generic_foreign_key_get(self):
893 service = self.orm.Service(name="myservice")
894 service.save()
895 site = self.orm.Site(name="mysite")
896 site.save()
897 self.assertTrue(site.id > 0)
898 tag = self.orm.Tag(
899 service=service,
900 name="mytag",
901 value="somevalue",
902 content_type=site.self_content_type_id,
903 object_id=site.id,
904 )
905 tag.save()
906 self.assertTrue(tag.id > 0)
907 self.assertNotEqual(tag.content_object, None)
908 self.assertEqual(tag.content_object.id, site.id)
909
910 def test_generic_foreign_key_get_decl(self):
911 service = self.orm.Service(name="myservice")
912 service.save()
913 site = self.orm.Site(name="mysite")
914 site.save()
915 self.assertTrue(site.id > 0)
916 tag = self.orm.Tag(
917 service=service,
918 name="mytag",
919 value="somevalue",
920 content_type=site.self_content_type_id + "_decl",
921 object_id=site.id,
922 )
923 tag.save()
924 self.assertTrue(tag.id > 0)
925 self.assertNotEqual(tag.content_object, None)
926 self.assertEqual(tag.content_object.id, site.id)
927
928 def test_generic_foreign_key_get_bad_contenttype(self):
929 service = self.orm.Service(name="myservice")
930 service.save()
931 site = self.orm.Site(name="mysite")
932 site.save()
933 self.assertTrue(site.id > 0)
934 tag = self.orm.Tag(
935 service=service,
936 name="mytag",
937 value="somevalue",
938 content_type="does_not_exist",
939 object_id=site.id,
940 )
941 tag.save()
942 self.assertTrue(tag.id > 0)
943 with self.assertRaises(Exception) as e:
944
945 self.assertEqual(
946 str(e.exception),
947 "Content_type does_not_exist not found in self.content_type_map",
948 )
949
950 def test_generic_foreign_key_get_bad_id(self):
951 service = self.orm.Service(name="myservice")
952 service.save()
953 site = self.orm.Site(name="mysite")
954 site.save()
955 self.assertTrue(site.id > 0)
956 tag = self.orm.Tag(
957 service=service,
958 name="mytag",
959 value="somevalue",
960 content_type=site.self_content_type_id,
961 object_id=4567,
962 )
963 tag.save()
964 self.assertTrue(tag.id > 0)
965 with self.assertRaises(Exception) as e:
966 self.assertEqual(
967 str(e.exception), "Object 4567 of model Site was not found"
968 )
969
970 def test_generic_foreign_key_set(self):
971 service = self.orm.Service(name="myservice")
972 service.save()
973 site = self.orm.Site(name="mysite")
974 site.save()
975 self.assertTrue(site.id > 0)
976 tag = self.orm.Tag(service=service, name="mytag", value="somevalue")
977 tag.content_object = site
978 tag.invalidate_cache()
979 self.assertEqual(tag.content_type, site.self_content_type_id)
980 self.assertEqual(tag.object_id, site.id)
981 tag.save()
982 self.assertTrue(tag.id > 0)
983 self.assertNotEqual(tag.content_object, None)
984 self.assertEqual(tag.content_object.id, site.id)
985
986 def test_field_null(self):
987 """ In a saved object, if a nullable field is left set to None, make sure the ORM returns None """
988
989 tm = self.orm.TestModel()
990 tm.save()
991
992 tm = self.orm.TestModel.objects.all()[0]
993 self.assertFalse(tm._wrapped_class.HasField("intfield"))
994 self.assertEqual(tm.intfield, None)
995
996 def test_field_null_new(self):
997 """ For models that haven't been saved yet, reading the field should return the gRPC default """
998
999 tm = self.orm.TestModel()
1000
1001 self.assertEqual(tm.intfield, 0)
1002
1003 def test_field_non_null(self):
1004 """ In a saved object, if a nullable field is set to a value, then make sure the ORM returns the value """
1005
1006 tm = self.orm.TestModel(intfield=3)
1007 tm.save()
1008
1009 tm = self.orm.TestModel.objects.all()[0]
1010 self.assertEqual(tm.intfield, 3)
1011
1012 def test_field_set_null(self):
1013 """ Setting a field to None is not allowed """
1014
1015 tm = self.orm.TestModel()
1016 with self.assertRaises(Exception) as e:
1017 tm.intfile = None
1018 self.assertEqual(
1019 str(e.exception),
1020 "Setting a non-foreignkey field to None is not supported",
1021 )
1022
1023 def test_deleted_objects_all(self):
1024 orig_len_sites = len(self.orm.Site.objects.all())
1025 orig_len_deleted_sites = len(self.orm.Site.deleted_objects.all())
1026 site = self.orm.Site(name="mysite")
1027 site.save()
1028 site.delete()
1029 sites = self.orm.Site.objects.all()
1030 self.assertEqual(len(sites), orig_len_sites)
1031 deleted_sites = self.orm.Site.deleted_objects.all()
1032 self.assertEqual(len(deleted_sites), orig_len_deleted_sites + 1)
1033
1034 def test_deleted_objects_filter(self):
1035 with patch.object(
1036 self.orm.grpc_stub, "FilterTestModel", wraps=self.orm.grpc_stub.FilterTestModel
1037 ) as filter:
1038 foo = self.orm.TestModel(name="foo")
1039 foo.save()
1040 foo.delete()
1041
1042 # There should be no live objects
1043 objs = self.orm.TestModel.objects.filter(name="foo")
1044 self.assertEqual(len(objs), 0)
1045
1046 # There should be one deleted object
1047 deleted_objs = self.orm.TestModel.deleted_objects.filter(name="foo")
1048 self.assertEqual(len(deleted_objs), 1)
1049
1050 # Two calls, one for when we checked live objects, the other for when we checked deleted objects
1051 self.assertEqual(filter.call_count, 2)
1052 q = filter.call_args[0][0]
1053
1054 # Now spy on the query that was generated, to make sure it looks like we expect
1055 self.assertEqual(q.kind, q.SYNCHRONIZER_DELETED_OBJECTS)
1056 self.assertEqual(len(q.elements), 1)
1057 self.assertEqual(q.elements[0].operator, q.elements[0].EQUAL)
1058 self.assertEqual(q.elements[0].sValue, "foo")
1059
1060
Scott Baker7dddd512017-10-24 10:13:34 -07001061def main():
1062 global USE_FAKE_STUB
1063 global xos_grpc_client
Scott Bakerff104cc2017-08-14 15:24:41 -07001064
Scott Baker7dddd512017-10-24 10:13:34 -07001065 # Command-line argument of -R will cause this test to use a real grpc server
1066 # rather than the fake stub.
Scott Bakerff104cc2017-08-14 15:24:41 -07001067
Scott Baker7dddd512017-10-24 10:13:34 -07001068 if "-R" in sys.argv:
1069 USE_FAKE_STUB = False
1070 sys.argv.remove("-R")
1071 # Note: will leave lots of litter (users, sites, etc) behind in the database
Scott Bakerd1940972017-05-01 15:45:32 -07001072
Scott Baker7dddd512017-10-24 10:13:34 -07001073 if USE_FAKE_STUB:
1074 unittest.main()
1075 else:
1076 # This assumes xos-client python library is installed, and a gRPC server
1077 # is available.
Scott Bakerd1940972017-05-01 15:45:32 -07001078
Scott Baker7dddd512017-10-24 10:13:34 -07001079 from xosapi import xos_grpc_client
Scott Bakerf0ee0dc2017-05-15 10:10:05 -07001080
Zack Williams045b63d2019-01-22 16:30:57 -07001081 print("Using xos-client library and core server")
Scott Bakerf0ee0dc2017-05-15 10:10:05 -07001082
Scott Baker7dddd512017-10-24 10:13:34 -07001083 def test_callback():
1084 try:
Zack Williams045b63d2019-01-22 16:30:57 -07001085 sys.argv = sys.argv[
1086 :1
Zack Williams5c2ea232019-01-30 15:23:01 -07001087 ]
1088 # unittest does not like xos_grpc_client's command line
1089 # arguments (TODO: find a cooperative approach)
Scott Baker7dddd512017-10-24 10:13:34 -07001090 unittest.main()
Zack Williams5c2ea232019-01-30 15:23:01 -07001091 except SystemExit as e:
Scott Baker7dddd512017-10-24 10:13:34 -07001092 global exitStatus
1093 exitStatus = e.code
Scott Bakerf0ee0dc2017-05-15 10:10:05 -07001094
Scott Baker7dddd512017-10-24 10:13:34 -07001095 xos_grpc_client.start_api_parseargs(test_callback)
Scott Bakerf0ee0dc2017-05-15 10:10:05 -07001096
Scott Baker7dddd512017-10-24 10:13:34 -07001097 sys.exit(exitStatus)
Scott Bakerf0ee0dc2017-05-15 10:10:05 -07001098
Zack Williams045b63d2019-01-22 16:30:57 -07001099
Scott Baker7dddd512017-10-24 10:13:34 -07001100if __name__ == "__main__":
1101 main()