1# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6from autotest_lib.client.cros.video import method_logger
7from autotest_lib.client.cros.image_comparison import comparison_result
8
9# TODO (mussa): We will use data generated by running tests using this class.
10# If we can do with one comparer we may not need this class.
11
12class UploadOnFailComparer(object):
13    """
14    Compares a test image against a golden image.
15
16    Uses a local comparer first to do the comparison, for every comparison
17    that return fail, it uses remote comparer.
18
19    """
20
21
22    @method_logger.log
23    def __init__(self, local_comparer, remote_comparer, threshold=0):
24        """
25        @param local_comparer: object impementing compare(), local comparer.
26        @param remote_comparer: object implementing compare(), remote comparer.
27        @param threshold: int, a value which the pixel difference between test
28                          image and golden image has to exceed before the
29                          remote comparer is used.
30
31        """
32        self.local_comparer = local_comparer
33        self.remote_comparer = remote_comparer
34        self.threshold = threshold
35
36
37    def __enter__(self):
38        return self
39
40
41    @method_logger.log
42    def compare(self, golden_image_path, test_image_path, box=None):
43        """
44        Compares a test image against a golden image using up to two comparers.
45
46        If the local comparer reports a fail, use the remote comparer to
47        compare the same images.
48
49        E.g of use case: You have two comparers, one is local and another is
50        web-based. Web-based comparer has the advantage of storing information
51        you need to look at the results later.
52        Local comparer is fast and reduces the load on the web-based comparer.
53
54        Use local comparer as primary comparer and only invoke the web-based
55        comparer on test images that differ from their golden counterparts.
56
57        @param golden_image_path: path, complete path to the golden image.
58        @param test_image_path: path, complete path  to the test image.
59        @param box: int tuple, left, upper, right, lower pixel coordinates
60                    defining a box region within which the comparison is made.
61
62        @return: int, differing pixels as per double check comparer.
63
64        """
65        logging.debug('Using primary comparer..')
66
67        with self.local_comparer:
68            res = self.local_comparer.compare(golden_image_path,
69                                                 test_image_path,
70                                                 box)
71            diffpx = res.diff_pixel_count
72        logging.debug('Primary comparison complete. Diff pixels = %d', diffpx)
73
74        diffpx2 = -1
75        comp_res = res.comparison_url
76
77        if (diffpx > self.threshold):
78            logging.debug('Threshold diff pixels is %d', self.threshold)
79            logging.debug('Diff pxls > threshold. Using remote comparer.')
80
81            with self.remote_comparer:
82                res_remote = self.remote_comparer.compare(golden_image_path,
83                                                          test_image_path,
84                                                          box)
85                diffpx2 = res_remote.diff_pixel_count
86
87            if not comp_res:
88                comp_res = res_remote.comparison_url
89
90            logging.debug('Secondary comparison complete. Diff pixels = %d',
91                          diffpx2)
92
93        diffpx_return = diffpx2 if diffpx2 != -1 else diffpx
94
95
96        return comparison_result.ComparisonResult(diffpx_return,
97                                                  comp_res)
98
99
100    def __exit__(self, exc_type, exc_val, exc_tb):
101        pass
102