def test_get_parameters(self): """ Test search_common.get_parameters() """ # Empty params, only default values are returned params = get_parameters({}) ok_(params) for i in params: typei = type(params[i]) if i in ("from_date", "to_date", "build_from", "build_to"): ok_(typei is datetime.datetime) else: ok_(not params[i] or typei is int or typei is str or typei is list) # Empty params params = get_parameters({ "terms": "", "fields": "", "products": "", "from_date": "", "to_date": "", "versions": "", "reasons": "", "release_channels": "", "os": "", "search_mode": "", "build_ids": "", "report_process": "", "report_type": "", "plugin_in": "", "plugin_search_mode": "", "plugin_terms": "" }) assert params, "SearchCommon.get_parameters() returned something " \ "empty or null." for i in params: typei = type(params[i]) if i in ("from_date", "to_date", "build_from", "build_to"): ok_(typei is datetime.datetime) else: ok_(not params[i] or typei is int or typei is str or typei is list) # Test with encoded slashes in terms and signature params = get_parameters({ "terms": ["some", "terms/sig"], "signature": "my/little/signature" }) ok_("signature" in params) ok_("terms" in params) eq_(params["terms"], ["some", "terms/sig"]) eq_(params["signature"], "my/little/signature")
def prepare_search_params(self, **kwargs): """Return a dictionary of parameters for a search-like SQL query. Uses socorro.middleware.search_common.get_parameters() for arguments filtering. """ params = search_common.get_parameters(kwargs) if not params["signature"]: raise MissingArgumentError('signature') params["terms"] = params["signature"] params["search_mode"] = "is_exactly" # Default mode falls back to starts_with for postgres if params["plugin_search_mode"] == "default": params["plugin_search_mode"] = "starts_with" # Searching for terms in plugins if params["report_process"] == "plugin" and params["plugin_terms"]: params["plugin_terms"] = " ".join(params["plugin_terms"]) params["plugin_terms"] = Crashes.prepare_terms( params["plugin_terms"], params["plugin_search_mode"] ) # Get information about the versions util_service = Util(config=self.context) params["versions_info"] = util_service.versions_info(**params) # Parsing the versions params["versions_string"] = params["versions"] (params["versions"], params["products"]) = Crashes.parse_versions( params["versions"], params["products"] ) # Changing the OS ids to OS names if hasattr(self.context, 'webapi'): context = self.context.webapi else: # old middleware context = self.context for i, elem in enumerate(params["os"]): for platform in context.platforms: if platform["id"] == elem: params["os"][i] = platform["name"] return params
def test_build_reports_sql_where(self): """ Test PostgreSQLBase.build_reports_sql_where().""" config = self.get_dummy_context() pgbase = self.get_instance() params = search_common.get_parameters({}) # Get default search params default_params = util.DotDict(params.copy()) sql_params = {} # ..................................................................... # Test 1: default values for parameters sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 2: terms and search_mode = is_exactly sql_params = {} params.terms = "signature" params.search_mode = "is_exactly" sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND r.signature=%(term)s" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "term": params.terms } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 3: terms and search_mode != is_exactly sql_params = {} params.terms = "signature%" params.search_mode = "starts_with" sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND r.signature LIKE %(term)s" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "term": params.terms } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 4: products sql_params = {} params.terms = default_params.terms params.search_mode = default_params.search_mode params.products = ["Firefox", "Fennec"] sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND (r.product=%(product0)s OR " \ "r.product=%(product1)s)" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "product0": "Firefox", "product1": "Fennec" } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 5: os sql_params = {} params.products = default_params.products params.os = ["Windows"] sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND (r.os_name=%(os0)s)" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "os0": "Windows" } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 6: build_ids sql_params = {} params.os = default_params.os params.build_ids = ["20120101123456"] sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND (r.build=%(build0)s)" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "build0": "20120101123456" } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 7: reasons sql_params = {} params.build_ids = default_params.build_ids params.reasons = ["EXCEPTION", "OVERFLOW"] sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND (r.reason=%(reason0)s OR " \ "r.reason=%(reason1)s)" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "reason0": "EXCEPTION", "reason1": "OVERFLOW" } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 8: report_type sql_params = {} params.reasons = default_params.reasons params.report_type = "crash" sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND r.hangid IS NULL" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 9: versions sql_params = {} params.report_type = default_params.report_type params.versions = ["Firefox", "12.0a1", "Fennec", "11.0", "Firefox", "13.0b"] params.versions_info = { "Firefox:12.0a1": { "version_string": "12.0a1", "product_name": "Firefox", "major_version": "12.0", "release_channel": "Nightly", "build_id": ["20120101123456"], "is_rapid_beta": False, "from_rapid_beta": False, "from_beta_version": "Firefox:12.0a1", }, "Fennec:11.0": { "version_string": "11.0", "product_name": "Fennec", "major_version": None, "release_channel": None, "build_id": None, "is_rapid_beta": False, "from_rapid_beta": False, "from_beta_version": "Fennec:11.0", }, "Firefox:13.0b1": { "version_string": "13.0b1", "product_name": "Firefox", "major_version": "13.0", "release_channel": "Beta", "build_id": ["20120101123456", "20120101098765"], "is_rapid_beta": False, "from_rapid_beta": True, "from_beta_version": "Firefox:13.0b", }, "Firefox:13.0b": { "version_string": "13.0b", "product_name": "Firefox", "major_version": "13.0b", "release_channel": "Beta", "build_id": None, "is_rapid_beta": True, "from_rapid_beta": True, "from_beta_version": "Firefox:13.0b", } } sql_exp = """ WHERE r.date_processed BETWEEN %(from_date)s AND %(to_date)s AND ((r.release_channel ILIKE 'nightly' AND r.product=%(version0)s AND r.version=%(version1)s) OR (r.product=%(version2)s AND r.version=%(version3)s) OR (r.product=%(version4)s AND r.version=%(version5)s) OR (r.product=%(version6)s AND r.version=%(version7)s) OR (r.release_channel ILIKE 'beta' AND r.build IN ('20120101123456', '20120101098765') AND r.product=%(version8)s AND r.version=%(version9)s) OR (r.product=%(version10)s AND r.version=%(version11)s)) """ sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "version0": "Firefox", "version1": "12.0a1", "version2": "Firefox", "version3": "12.0a1", "version4": "Fennec", "version5": "11.0", "version6": "Fennec", "version7": "11.0", "version8": "Firefox", "version9": "13.0b1", "version10": "Firefox", "version11": "13.0b", } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) # squeeze all \s, \r, \t... sql = " ".join(sql.split()) sql_exp = " ".join(sql_exp.split()) eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 10: report_process = plugin sql_params = {} params.versions = default_params.versions params.versions_infos = None params.report_process = "plugin" sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND r.process_type = 'plugin' AND " \ "plugins_reports.date_processed BETWEEN " \ "%(from_date)s AND %(to_date)s" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 11: report_process != plugin sql_params = {} params.report_process = "content" sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND r.process_type = 'content'" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp) # ..................................................................... # Test 12: plugins sql_params = {} params.report_process = "plugin" params.plugin_terms = "plugin_name" params.plugin_search_mode = "is_exactly" params.plugin_in = ["name"] sql_exp = "WHERE r.date_processed BETWEEN %(from_date)s AND " \ "%(to_date)s AND r.process_type = 'plugin' AND " \ "plugins_reports.date_processed BETWEEN " \ "%(from_date)s AND %(to_date)s AND " \ "(plugins.name=%(plugin_term)s)" sql_params_exp = { "from_date": params.from_date, "to_date": params.to_date, "plugin_term": params.plugin_terms } (sql, sql_params) = pgbase.build_reports_sql_where(params, sql_params, config) sql = " ".join(sql.split()) # squeeze all \s, \r, \t... eq_(sql, sql_exp) eq_(sql_params, sql_params_exp)
def get_list(self, **kwargs): """ List all crashes with a given signature and return them. Both `from_date` and `to_date` (and their aliases `from` and `to`) are required and can not be greater than 30 days apart. Optional arguments: see SearchCommon.get_parameters() """ # aliases if "from" in kwargs and "from_date" not in kwargs: kwargs["from_date"] = kwargs.get("from") if "to" in kwargs and "to_date" not in kwargs: kwargs["to_date"] = kwargs.get("to") if not kwargs.get('from_date'): raise MissingArgumentError('from_date') if not kwargs.get('to_date'): raise MissingArgumentError('to_date') from_date = datetimeutil.datetimeFromISOdateString(kwargs['from_date']) to_date = datetimeutil.datetimeFromISOdateString(kwargs['to_date']) span_days = (to_date - from_date).days if span_days > 30: raise BadArgumentError( 'Span between from_date and to_date can not be more than 30' ) # start with the default sort_order = { 'key': 'date_processed', 'direction': 'DESC' } if 'sort' in kwargs: sort_order['key'] = kwargs.pop('sort') _recognized_sort_orders = ( 'date_processed', 'uptime', 'user_comments', 'uuid', 'uuid_text', 'product', 'version', 'build', 'signature', 'url', 'os_name', 'os_version', 'cpu_name', 'cpu_info', 'address', 'reason', 'last_crash', 'install_age', 'hangid', 'process_type', 'release_channel', 'install_time', 'duplicate_of', ) if sort_order['key'] not in _recognized_sort_orders: raise BadArgumentError( '%s is not a recognized sort order key' % sort_order['key'] ) sort_order['direction'] = 'ASC' if str(kwargs.get('reverse', '')).lower() == 'true': if kwargs.pop('reverse'): sort_order['direction'] = 'DESC' include_raw_crash = kwargs.get('include_raw_crash') or False params = search_common.get_parameters(kwargs) if not params["signature"]: raise MissingArgumentError('signature') params["terms"] = params["signature"] params["search_mode"] = "is_exactly" # Default mode falls back to starts_with for postgres if params["plugin_search_mode"] == "default": params["plugin_search_mode"] = "starts_with" # Limiting to a signature if params["terms"]: params["terms"] = self.prepare_terms(params["terms"], params["search_mode"]) # Searching for terms in plugins if params["report_process"] == "plugin" and params["plugin_terms"]: params["plugin_terms"] = " ".join(params["plugin_terms"]) params["plugin_terms"] = self.prepare_terms( params["plugin_terms"], params["plugin_search_mode"] ) # Get information about the versions util_service = Util(config=self.context) params["versions_info"] = util_service.versions_info(**params) # Parsing the versions params["versions_string"] = params["versions"] (params["versions"], params["products"]) = self.parse_versions( params["versions"], params["products"] ) if hasattr(self.context, 'webapi'): context = self.context.webapi else: # old middleware context = self.context # Changing the OS ids to OS names for i, elem in enumerate(params["os"]): for platform in context.platforms: if platform["id"][:3] == elem[:3]: params["os"][i] = platform["name"] # Creating the parameters for the sql query sql_params = { } # Preparing the different parts of the sql query sql_select = """ SELECT r.date_processed, r.uptime, r.user_comments, r.uuid::uuid, r.uuid as uuid_text, r.product, r.version, r.build, r.signature, r.url, r.os_name, r.os_version, r.cpu_name, r.cpu_info, r.address, r.reason, r.last_crash, r.install_age, r.hangid, r.process_type, r.release_channel, (r.client_crash_date - (r.install_age * INTERVAL '1 second')) AS install_time """ if include_raw_crash: pass else: sql_select += """ , rd.duplicate_of """ wrapped_select = """ WITH report_slice AS ( %s ), dupes AS ( SELECT report_slice.uuid, rd.duplicate_of FROM reports_duplicates rd JOIN report_slice ON report_slice.uuid_text = rd.uuid WHERE rd.date_processed BETWEEN %%(from_date)s AND %%(to_date)s ) SELECT rs.*, dupes.duplicate_of, rc.raw_crash FROM report_slice rs LEFT OUTER JOIN dupes USING (uuid) LEFT OUTER JOIN raw_crashes rc ON rs.uuid = rc.uuid AND rc.date_processed BETWEEN %%(from_date)s AND %%(to_date)s """ sql_from = self.build_reports_sql_from(params) if not include_raw_crash: sql_from = """%s LEFT OUTER JOIN reports_duplicates rd ON r.uuid = rd.uuid """ % sql_from sql_where, sql_params = self.build_reports_sql_where( params, sql_params, self.context ) sql_order = """ ORDER BY %(key)s %(direction)s """ % sort_order sql_limit, sql_params = self.build_reports_sql_limit( params, sql_params ) # Assembling the query if include_raw_crash: sql_query = "\n".join(( "/* socorro.external.postgresql.report.Report.list */", sql_select, sql_from, sql_where, sql_order, sql_limit) ) else: sql_query = "\n".join(( "/* socorro.external.postgresql.report.Report.list */", sql_select, sql_from, sql_where, sql_order, sql_limit) ) # Query for counting the results sql_count_query = "\n".join(( "/* socorro.external.postgresql.report.Report.list */", "SELECT count(*)", sql_from, sql_where) ) # Querying the DB with self.get_connection() as connection: total = self.count( sql_count_query, sql_params, error_message="Failed to count crashes from reports.", connection=connection ) # No need to call Postgres if we know there will be no results if total: if include_raw_crash: sql_query = wrapped_select % sql_query results = self.query( sql_query, sql_params, error_message="Failed to retrieve crashes from reports", connection=connection ).zipped() else: results = [] crashes = [] for crash in results: assert crash['uuid'] == crash['uuid_text'] crash.pop('uuid_text') if not include_raw_crash and 'raw_crash' in crash: crash.pop('raw_crash') for i in crash: try: crash[i] = datetimeutil.date_to_string(crash[i]) except TypeError: pass crashes.append(crash) return { "hits": crashes, "total": total }
def test_get_parameters(self): """ Test search_common.get_parameters() """ # Empty params, only default values are returned params = get_parameters({}) ok_(params) for i in params: typei = type(params[i]) if i in ("from_date", "to_date", "build_from", "build_to"): ok_(typei is datetime.datetime) else: ok_( not params[i] or typei is int or typei is str or typei is list ) # Empty params params = get_parameters({ "terms": "", "fields": "", "products": "", "from_date": "", "to_date": "", "versions": "", "reasons": "", "release_channels": "", "os": "", "search_mode": "", "build_ids": "", "report_process": "", "report_type": "", "plugin_in": "", "plugin_search_mode": "", "plugin_terms": "" }) assert params, "SearchCommon.get_parameters() returned something " \ "empty or null." for i in params: typei = type(params[i]) if i in ("from_date", "to_date", "build_from", "build_to"): ok_(typei is datetime.datetime) else: ok_( not params[i] or typei is int or typei is str or typei is list ) # Test with encoded slashes in terms and signature params = get_parameters({ "terms": ["some", "terms/sig"], "signature": "my/little/signature" }) ok_("signature" in params) ok_("terms" in params) eq_(params["terms"], ["some", "terms/sig"]) eq_(params["signature"], "my/little/signature")