22
22
import functools
23
23
import os
24
24
import sys
25
+ import traceback
25
26
import types
26
27
27
28
from bson import json_util , SON , Int64
@@ -168,7 +169,11 @@ def __init__(self, test_class):
168
169
self ._test_class = test_class
169
170
170
171
def __getitem__ (self , item ):
171
- return self ._entities [item ]
172
+ try :
173
+ return self ._entities [item ]
174
+ except KeyError :
175
+ self ._test_class .fail ('Could not find entity named %s in map' % (
176
+ item ,))
172
177
173
178
def __setitem__ (self , key , value ):
174
179
if not isinstance (key , text_type ):
@@ -193,9 +198,9 @@ def _create_entity(self, entity_spec):
193
198
# - uriOptions
194
199
# - useMultipleMongoses
195
200
uri_options = spec .get ('uriOptions' , {})
196
- observe_events = spec .get ('observeEvents' )
201
+ observe_events = spec .get ('observeEvents' , [] )
197
202
ignore_commands = spec .get ('ignoreCommandMonitoringEvents' , [])
198
- if observe_events :
203
+ if len ( observe_events ) or len ( ignore_commands ) :
199
204
listener = EventListenerUtil (observe_events , ignore_commands )
200
205
client = rs_or_single_client (
201
206
event_listeners = [listener ], ** uri_options )
@@ -234,7 +239,7 @@ def _create_entity(self, entity_spec):
234
239
self ._test_class .fail (
235
240
'Expected entity %s to be of type MongoClient, got %s' % (
236
241
spec ['client' ], type (client )))
237
- opts = camel_to_snake_args (spec [ 'sessionOptions' ] )
242
+ opts = camel_to_snake_args (spec . get ( 'sessionOptions' , {}) )
238
243
if 'default_transaction_options' in opts :
239
244
txn_opts = parse_spec_options (
240
245
opts ['default_transaction_options' ])
@@ -477,7 +482,7 @@ def match_event(self, expectation, actual):
477
482
'Unsupported event type %s' % (event_type ,))
478
483
479
484
480
- class UnifiedSpecTestMixin (IntegrationTest ):
485
+ class UnifiedSpecTestMixinV1 (IntegrationTest ):
481
486
"""Mixin class to run test cases from test specification files.
482
487
483
488
Assumes that tests conform to the `unified test format
@@ -486,7 +491,7 @@ class UnifiedSpecTestMixin(IntegrationTest):
486
491
Specification of the test suite being currently run is available as
487
492
a class attribute ``TEST_SPEC``.
488
493
"""
489
- SCHEMA_VERSION = '1.0'
494
+ SCHEMA_VERSION = Version . from_string ( '1.0' )
490
495
491
496
@staticmethod
492
497
def should_run_on (run_on_spec ):
@@ -510,19 +515,17 @@ def insert_initial_data(self, initial_data):
510
515
coll .drop ()
511
516
512
517
# documents MAY be an empty list
513
- if documents :
518
+ if len ( documents ) :
514
519
coll .insert_many (documents )
515
520
516
521
@classmethod
517
522
def setUpClass (cls ):
518
523
# super call creates internal client cls.client
519
- super (UnifiedSpecTestMixin , cls ).setUpClass ()
524
+ super (UnifiedSpecTestMixinV1 , cls ).setUpClass ()
520
525
521
526
# process schemaVersion
522
- version = cls .TEST_SPEC ['schemaVersion' ]
523
- version_tuple = tuple (version .split ('.' , 2 )[:2 ])
524
- max_version_tuple = tuple (cls .SCHEMA_VERSION .split ('.' , 2 )[:2 ])
525
- if not version_tuple <= max_version_tuple :
527
+ version = Version .from_string (cls .TEST_SPEC ['schemaVersion' ])
528
+ if not version <= cls .SCHEMA_VERSION :
526
529
raise unittest .SkipTest (
527
530
'expected schemaVersion %s or lower, got %s' % (
528
531
cls .SCHEMA_VERSION , version ))
@@ -534,19 +537,11 @@ def setUpClass(cls):
534
537
535
538
@classmethod
536
539
def tearDownClass (cls ):
537
- super (UnifiedSpecTestMixin , cls ).tearDownClass ()
540
+ super (UnifiedSpecTestMixinV1 , cls ).tearDownClass ()
538
541
cls .client .close ()
539
542
540
543
def setUp (self ):
541
- super (UnifiedSpecTestMixin , self ).setUp ()
542
-
543
- # process createEntities
544
- self .entity_map = EntityMapUtil (self )
545
- self .entity_map .create_entities_from_spec (
546
- self .TEST_SPEC .get ('createEntities' , []))
547
-
548
- # process initialData
549
- self .insert_initial_data (self .TEST_SPEC .get ('initialData' , []))
544
+ super (UnifiedSpecTestMixinV1 , self ).setUp ()
550
545
551
546
# initialize internals
552
547
self .match_evaluator = MatchEvaluatorUtil (self )
@@ -855,6 +850,14 @@ def verify_outcome(self, spec):
855
850
actual_documents )
856
851
857
852
def run_scenario (self , spec ):
853
+ # process createEntities
854
+ self .entity_map = EntityMapUtil (self )
855
+ self .entity_map .create_entities_from_spec (
856
+ self .TEST_SPEC .get ('createEntities' , []))
857
+
858
+ # process initialData
859
+ self .insert_initial_data (self .TEST_SPEC .get ('initialData' , []))
860
+
858
861
# process test-level runOnRequirements
859
862
run_on_spec = spec .get ('runOnRequirements' , [])
860
863
if not self .should_run_on (run_on_spec ):
@@ -887,14 +890,29 @@ def test_case(self):
887
890
888
891
for test_spec in cls .TEST_SPEC ['tests' ]:
889
892
description = test_spec ['description' ]
890
- test_name = 'test_%s' % (
891
- description . strip ( '. ' ). replace (' ' , '_' ).replace ('.' , '_' ),)
893
+ test_name = 'test_%s' % (description . strip ( '. ' ).
894
+ replace (' ' , '_' ).replace ('.' , '_' ),)
892
895
test_method = create_test (copy .deepcopy (test_spec ))
893
896
test_method .__name__ = test_name
897
+
898
+ if description in cls .EXPECTED_FAILURES :
899
+ test_method = unittest .expectedFailure (test_method )
900
+
894
901
setattr (cls , test_name , test_method )
895
902
896
903
897
- def generate_test_classes (test_path , module = __name__ , class_name_prefix = '' ):
904
+ _ALL_MIXIN_CLASSES = [
905
+ UnifiedSpecTestMixinV1 ,
906
+ # add mixin classes for new schema major versions here
907
+ ]
908
+
909
+
910
+ _SCHEMA_VERSION_MAJOR_TO_MIXIN_CLASS = {
911
+ KLASS .SCHEMA_VERSION [0 ]: KLASS for KLASS in _ALL_MIXIN_CLASSES }
912
+
913
+
914
+ def generate_test_classes (test_path , module = __name__ , class_name_prefix = '' ,
915
+ expected_failures = []):
898
916
"""Method for generating test classes. Returns a dictionary where keys are
899
917
the names of test classes and values are the test class objects."""
900
918
test_klasses = {}
@@ -905,29 +923,43 @@ def test_base_class_factory(test_spec):
905
923
the metaclass __init__ is invoked."""
906
924
class SpecTestBase (with_metaclass (UnifiedSpecTestMeta )):
907
925
TEST_SPEC = test_spec
926
+ EXPECTED_FAILURES = expected_failures
908
927
return SpecTestBase
909
928
910
929
for dirpath , _ , filenames in os .walk (test_path ):
911
930
dirname = os .path .split (dirpath )[- 1 ]
912
931
913
932
for filename in filenames :
914
- with open (os .path .join (dirpath , filename )) as scenario_stream :
933
+ fpath = os .path .join (dirpath , filename )
934
+ with open (fpath ) as scenario_stream :
915
935
# Use tz_aware=False to match how CodecOptions decodes
916
936
# dates.
917
937
opts = json_util .JSONOptions (tz_aware = False )
918
- scenario_def = ScenarioDict (
919
- json_util .loads (scenario_stream .read (),
920
- json_options = opts ))
938
+ scenario_def = json_util .loads (
939
+ scenario_stream .read (), json_options = opts )
921
940
922
941
test_type = os .path .splitext (filename )[0 ]
923
942
snake_class_name = 'Test%s_%s_%s' % (
924
943
class_name_prefix , dirname .replace ('-' , '_' ),
925
944
test_type .replace ('-' , '_' ).replace ('.' , '_' ))
926
945
class_name = snake_to_camel (snake_class_name )
927
946
928
- test_klasses [class_name ] = type (
929
- class_name ,
930
- (UnifiedSpecTestMixin , test_base_class_factory (scenario_def ),),
931
- {'__module__' : module })
947
+ try :
948
+ schema_version = Version .from_string (
949
+ scenario_def ['schemaVersion' ])
950
+ mixin_class = _SCHEMA_VERSION_MAJOR_TO_MIXIN_CLASS .get (
951
+ schema_version [0 ])
952
+ if mixin_class is None :
953
+ print ('Ignoring test file %s with '
954
+ 'unsupported schemaVersion %s' %
955
+ (fpath , schema_version ))
956
+ test_klasses [class_name ] = type (
957
+ class_name ,
958
+ (mixin_class , test_base_class_factory (scenario_def ),),
959
+ {'__module__' : module })
960
+ except (AttributeError , KeyError , TypeError ):
961
+ print ("Ignoring invalid test file '%s'\n "
962
+ "Original exception: %s" %
963
+ (fpath , traceback .format_exc ()))
932
964
933
965
return test_klasses
0 commit comments