11import json
2+ import os .path
3+ import shutil
4+ import tempfile
5+ from os import listdir
26from os .path import isfile
37
48import pytest
1317DEFAULT_OLD_RESULT_FILENAME = ".pytest-queries.old"
1418
1519
16- def _set_session (config , new_session ):
17- config . pytest_django_queries_session = new_session
20+ def is_slave (config ):
21+ return hasattr ( config , "slaveinput" )
1822
1923
20- def _get_session (request ):
21- return request .config .pytest_django_queries_session
24+ def get_slaveid (config ):
25+ if hasattr (config , "slaveinput" ):
26+ return config .workerinput ["slaveid" ]
27+ else :
28+ return "master"
2229
2330
24- class _Session (object ):
25- def __init__ (self , save_path , backup_path ):
26- """
27- :param save_path:
28- :type save_path: str
31+ def save_results_to_json (save_path , backup_path , data ):
32+ if backup_path and isfile (save_path ):
33+ create_backup (save_path , backup_path )
2934
30- :param backup_path:
31- :type backup_path: bool
32- """
33- self .save_path = save_path
34- self .backup_path = backup_path
35- self ._data = {}
35+ with open (save_path , "w" ) as fp :
36+ json .dump (data , fp , indent = 2 )
3637
37- def add_entry (self , module_name , test_name , query_count ):
38- module_data = self ._data .setdefault (module_name , {})
39- module_data [test_name ] = {"query-count" : query_count }
4038
41- def save_json (self ):
42- if self .backup_path and isfile (self .save_path ):
43- create_backup (self .save_path , self .backup_path )
39+ def add_entry (request , queries , dirout ):
40+ module_name = request .node .module .__name__
41+ test_name = request .node .name
42+ query_count = len (queries )
4443
45- with open (self .save_path , "w" ) as fp :
46- json .dump (self ._data , fp , indent = 2 )
44+ result_line = "%s\t %s\t %s\n " % (module_name , test_name , query_count )
45+ save_path = os .path .join (dirout , get_slaveid (request .config ))
46+ if os .path .isfile (save_path ):
47+ mode = "a"
48+ else :
49+ mode = "w"
4750
48- def finish (self ):
49- """Serialize and export the test data if performance tests were run."""
50-
51- if not self ._data :
52- return
53-
54- self .save_json ()
51+ with open (save_path , mode = mode ) as fp :
52+ fp .write (result_line )
5553
5654
5755def pytest_addoption (parser ):
@@ -90,20 +88,13 @@ def pytest_load_initial_conftests(early_config, parser, args):
9088 "" % PYTEST_QUERY_COUNT_MARKER ,
9189 )
9290
93- save_path = early_config .known_args_namespace .queries_results_save_path
9491 backup_path = early_config .known_args_namespace .queries_backup_results
9592
9693 # Set default value if the flag was provided without value in arguments
9794 if backup_path is None and "--django-backup-queries" in args :
9895 backup_path = DEFAULT_OLD_RESULT_FILENAME
9996
100- _set_session (early_config , _Session (save_path , backup_path ))
101-
102-
103- @pytest .hookimpl (hookwrapper = True )
104- def pytest_sessionfinish (session , exitstatus ):
105- _get_session (session ).finish ()
106- yield
97+ early_config .known_args_namespace .queries_backup_results = backup_path
10798
10899
109100def _process_query_count_marker (request , * _args , ** kwargs ):
@@ -128,15 +119,64 @@ def _pytest_query_marker(request):
128119 _process_query_count_marker (request , * marker .args , ** marker .kwargs )
129120
130121
122+ def pytest_configure (config ):
123+ config .django_queries_shared_directory = tempfile .mkdtemp (
124+ prefix = "pytest-django-queries"
125+ )
126+
127+
128+ def pytest_unconfigure (config ):
129+ results_path = config .django_queries_shared_directory
130+ test_results = {}
131+
132+ for filename in listdir (results_path ):
133+ with open (os .path .join (results_path , filename )) as fp :
134+ for result_line in fp .readlines ():
135+ result_line = result_line .strip ()
136+
137+ if not result_line :
138+ continue
139+
140+ module_name , test_name , query_count = result_line .split ("\t " )
141+
142+ module_entries = test_results .setdefault (module_name , {})
143+ module_entries [test_name ] = {"query-count" : int (query_count )}
144+
145+ if test_results :
146+ save_results_to_json (
147+ save_path = config .known_args_namespace .queries_results_save_path ,
148+ backup_path = config .known_args_namespace .queries_backup_results ,
149+ data = test_results ,
150+ )
151+
152+ # clean up the temporary directory
153+ shutil .rmtree (config .django_queries_shared_directory )
154+
155+
156+ def pytest_configure_node (node ):
157+ node .slaveinput [
158+ "_django_queries_shared_dir"
159+ ] = node .config .django_queries_shared_directory
160+
161+
162+ pytest_configure_node .optionalhook = True
163+
164+
165+ def get_shared_directory (request ):
166+ """Returns a unique and temporary directory which can be shared by
167+ master or worker nodes in xdist runs.
168+ """
169+ if not is_slave (request .config ):
170+ return request .config .django_queries_shared_directory
171+ else :
172+ return request .config .slaveinput ["_django_queries_shared_dir" ]
173+
174+
131175@pytest .fixture
132176def count_queries (request ):
133177 """Wrap a test to count the number of performed queries."""
134178 from django .db import connection
135179
136180 with CaptureQueriesContext (connection ) as context :
137181 yield context
138- query_count = len (context )
139-
140- module = request .node .module .__name__
141- bench_name = request .node .name
142- _get_session (request ).add_entry (module , bench_name , query_count )
182+ add_entry (request , context , get_shared_directory (request ))
0 commit comments