Beispiel #1
0
    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")
Beispiel #2
0
    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
Beispiel #3
0
    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)
Beispiel #4
0
    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
        }
Beispiel #5
0
    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")
Beispiel #6
0
    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
        }