def test_compute_now(self):
        """
        Check thread is not started when computing is requested to be done now
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as imgFile:
            img = ImageFile(imgFile)
            s1 = Snapshot(stepResult=StepResult.objects.get(id=1),
                          refSnapshot=None,
                          pixelsDiff=None)
            s1.save()
            s1.image.save("img", img)
            s1.save()
            s2 = Snapshot(stepResult=StepResult.objects.get(id=2),
                          refSnapshot=None,
                          pixelsDiff=None)
            s2.save()
            s2.image.save("img", img)
            s2.save()

            self.assertFalse(s1.computed)
            self.assertFalse(s2.computed)

            DiffComputer.get_instance().compute_now(s1, s2)

            # something has been computed
            self.assertIsNotNone(s2.pixelsDiff)
            self.assertEqual(s2.refSnapshot, s1,
                             "refSnapshot should have been updated")

            self.assertFalse(
                s1.computed)  # reference picture, computed flag remains False
            self.assertTrue(s2.computed)  # diff computed, flag changed
    def test_compute_diff_with_tolerance_lower_than_difference(self):
        """
        Check that tooManyDiffs is True as % of differences is higher than tolerance
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as reference:
            with open("snapshotServer/tests/data/test_Image1Mod.png",
                      'rb') as step:
                img_reference = ImageFile(reference)
                img_step = ImageFile(step)
                ref_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=1),
                    refSnapshot=None,
                    pixelsDiff=None)
                ref_snapshot.save()
                ref_snapshot.image.save("img", img_reference)
                ref_snapshot.save()
                step_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=2),
                    refSnapshot=None,
                    pixelsDiff=None,
                    diffTolerance=0.005)
                step_snapshot.save()
                step_snapshot.image.save("img", img_step)
                step_snapshot.save()

                DiffComputer.get_instance().compute_now(
                    ref_snapshot, step_snapshot)

                # something has been computed
                self.assertIsNotNone(step_snapshot.pixelsDiff)
                self.assertTrue(step_snapshot.tooManyDiffs)
 def test_create_instance(self):
     """
     Check we always have the same instance
     """
     self.assertIsNone(DiffComputer._instance)
     inst = DiffComputer.get_instance()
     self.assertIsNotNone(inst, "an instance should have been created")
     self.assertEqual(DiffComputer.get_instance(), inst,
                      "the same instance should always be returned")
    def test_error_message_reset(self):
        """
        Check that if an error occurs during _compute_diff() method, 'computed' flag is still set to 'True' whatever the result is, and 'computingError' is filled  
        If an other computing is done, and no error occurs, then, 'computingError' is reset to an empty string
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as reference:
            with open("snapshotServer/tests/data/test_Image1Mod.png",
                      'rb') as step:
                img_reference = ImageFile(reference)
                img_step = ImageFile(step)
                ref_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=1),
                    refSnapshot=None,
                    pixelsDiff=None)
                ref_snapshot.save()
                ref_snapshot.image.save("img", img_reference)
                ref_snapshot.save()
                step_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=2),
                    refSnapshot=None,
                    pixelsDiff=None)
                step_snapshot.save()
                step_snapshot.image.save("img", img_step)
                step_snapshot.save()

                diff_computer = DiffComputer.get_instance()
                diff_computer.mark_diff = MagicMock(
                    side_effect=Exception("error while computing"))
                diff_computer.add_jobs(ref_snapshot,
                                       step_snapshot,
                                       check_test_mode=True)
                time.sleep(1)
                self.assertIsNotNone(DiffComputer._instance,
                                     "thread should still be running")

                # check error has been saved
                self.assertTrue(
                    Snapshot.objects.get(id=step_snapshot.id).computed)
                self.assertEqual(
                    Snapshot.objects.get(id=step_snapshot.id).computingError,
                    "error while computing")

                # check error has been removed as computing is ok
                DiffComputer.stopThread()  # reset DiffComputer instance
                diff_computer_ok = DiffComputer.get_instance()
                diff_computer_ok.add_jobs(ref_snapshot,
                                          step_snapshot,
                                          check_test_mode=True)
                time.sleep(1)
                self.assertTrue(
                    Snapshot.objects.get(id=step_snapshot.id).computed)
                self.assertEqual(
                    Snapshot.objects.get(id=step_snapshot.id).computingError,
                    "")
 def test_stop_thread(self):
     """
     Thread should be stopped and instance deleted
     """
     inst = DiffComputer.get_instance()
     DiffComputer.stopThread()
     self.assertIsNone(DiffComputer._instance)
    def test_add_jobs(self):
        """
        Check we can add jobs and they get computed
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as imgFile:
            img = ImageFile(imgFile)
            s1 = Snapshot(stepResult=StepResult.objects.get(id=1),
                          refSnapshot=None,
                          pixelsDiff=None)
            s1.save()
            s1.image.save("img", img)
            s1.save()
            s2 = Snapshot(stepResult=StepResult.objects.get(id=2),
                          refSnapshot=None,
                          pixelsDiff=None)
            s2.save()
            s2.image.save("img", img)
            s2.save()
            s3 = Snapshot(stepResult=StepResult.objects.get(id=1),
                          refSnapshot=None,
                          pixelsDiff=None)
            s3.save()
            s3.image.save("img", img)
            s3.save()

            diff_computer = DiffComputer.get_instance()
            diff_computer.add_jobs(s1, s2, check_test_mode=False)
            diff_computer.add_jobs(s1, s3, check_test_mode=False)
            time.sleep(1)
            diff_computer.stopThread()

            # something has been computed
            self.assertIsNotNone(s2.pixelsDiff)
            self.assertIsNotNone(s3.pixelsDiff)
    def test_ref_is_none(self):
        """
        Check no error is raised when reference is None. Nothing happens for the stepSnapshot
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as imgFile:
            img = ImageFile(imgFile)
            s2 = Snapshot(stepResult=StepResult.objects.get(id=2),
                          refSnapshot=None,
                          pixelsDiff=b'')
            s2.save()
            s2.image.save("img", img)
            s2.save()

            DiffComputer.get_instance().compute_now(None, s2)

            # something has been computed
            self.assertIsNone(s2.pixelsDiff)
            self.assertIsNone(s2.refSnapshot,
                              "refSnapshot should have not been updated")
    def test_compute_using_exclude_zones_from_step(self):
        """
        issue #57: Check that computing takes into account exclude zone from step snapshot that could be added by seleniumRobot
        """

        with patch.object(DiffComputer.picture_comparator,
                          'get_changed_pixels',
                          wraps=DiffComputer.picture_comparator.
                          get_changed_pixels) as wrapped_get_changed_pixels:
            with open("snapshotServer/tests/data/test_Image1.png",
                      'rb') as imgFile:
                img = ImageFile(imgFile)
                ref_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=1),
                    refSnapshot=None,
                    pixelsDiff=None)
                ref_snapshot.save()
                ref_snapshot.image.save("img", img)
                ref_snapshot.save()
                step_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=2),
                    refSnapshot=None,
                    pixelsDiff=None)
                step_snapshot.save()
                step_snapshot.image.save("img", img)
                step_snapshot.save()

                exclusion1 = ExcludeZone(x=0,
                                         y=0,
                                         width=10,
                                         height=10,
                                         snapshot=step_snapshot)
                exclusion1.save()

                DiffComputer.get_instance().compute_now(
                    ref_snapshot, step_snapshot)

                # check exclude zone has been used for comparison
                wrapped_get_changed_pixels.assert_called_with(
                    ref_snapshot.image.path, step_snapshot.image.path,
                    [exclusion1.toRectangle()])
    def test_compute_now_no_save(self):
        """
        Check snapshot is not saved if it's not requested
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as imgFile:
            img = ImageFile(imgFile, name="img.png")
            s1 = Snapshot(stepResult=StepResult.objects.get(id=1),
                          image=img,
                          refSnapshot=None,
                          pixelsDiff=None)

            # as we do not save any snapshot, image has to be copied manually where DiffComputer expects it
            shutil.copyfile("snapshotServer/tests/data/test_Image1.png",
                            settings.MEDIA_ROOT + os.sep + "img.png")

            s2 = Snapshot(stepResult=StepResult.objects.get(id=2),
                          image=img,
                          refSnapshot=None,
                          pixelsDiff=None)

            self.assertFalse(s1.computed)
            self.assertFalse(s2.computed)

            DiffComputer.get_instance().compute_now(s1,
                                                    s2,
                                                    save_snapshot=False)

            # something has been computed
            self.assertIsNotNone(s2.pixelsDiff)
            self.assertEqual(s2.refSnapshot, s1,
                             "refSnapshot should have been updated")
            self.assertIsNone(s1.id)
            self.assertIsNone(s2.id)

            self.assertFalse(
                s1.computed)  # reference picture, computed flag remains False
            self.assertTrue(s2.computed)  # diff computed, flag changed
    def test_ref_image_is_none(self):
        """
        Check no error is raised when image data is missing
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as imgFile:
            img = ImageFile(imgFile)
            s1 = Snapshot(stepResult=StepResult.objects.get(id=1),
                          refSnapshot=None,
                          pixelsDiff=None)
            s1.save()
            s2 = Snapshot(stepResult=StepResult.objects.get(id=2),
                          refSnapshot=None,
                          pixelsDiff=b'')
            s2.save()
            s2.image.save("img", img)
            s2.save()

            DiffComputer.get_instance().compute_now(s1, s2)

            # something has been computed
            self.assertIsNone(s2.pixelsDiff)
            self.assertEqual(s2.refSnapshot, s1,
                             "refSnapshot should have been updated")
    def test_compute_diff_without_tolerance(self):
        """
        Check difference is found between two different images
        """
        with open("snapshotServer/tests/data/test_Image1.png",
                  'rb') as reference:
            with open("snapshotServer/tests/data/test_Image1Mod.png",
                      'rb') as step:
                img_reference = ImageFile(reference)
                img_step = ImageFile(step)
                ref_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=1),
                    refSnapshot=None,
                    pixelsDiff=None)
                ref_snapshot.save()
                ref_snapshot.image.save("img", img_reference)
                ref_snapshot.save()
                step_snapshot = Snapshot(
                    stepResult=StepResult.objects.get(id=2),
                    refSnapshot=None,
                    pixelsDiff=None)
                step_snapshot.save()
                step_snapshot.image.save("img", img_step)
                step_snapshot.save()

                DiffComputer.get_instance().compute_now(
                    ref_snapshot, step_snapshot)

                # something has been computed
                self.assertIsNotNone(step_snapshot.pixelsDiff)
                self.assertTrue(step_snapshot.tooManyDiffs)
                self.assertEqual(step_snapshot.refSnapshot, ref_snapshot,
                                 "refSnapshot should have been updated")

                self.assertTrue(step_snapshot.computed)
                self.assertTrue(step_snapshot.computingError == '')
Пример #12
0
def submission_delete(sender, instance, **kwargs):
    """
    When a snapshot is deleted, remove the associated picture
    Also rebuild reference tree for snapshots that could have referenced this one
    """

    from snapshotServer.controllers.DiffComputer import DiffComputer

    # deletion of image file
    instance.image.delete(False)

    # recompute references if this snapshot is a reference for other
    for snapshot in instance.snapshotsUntilNextRef(instance):

        test_case = instance.stepResult.testCase

        # search any reference snapshot that exists previously
        ref_snapshots = Snapshot.objects.filter(
            stepResult__testCase__testCase__name=test_case.testCase.name,
            stepResult__testCase__session__version=test_case.session.version,
            stepResult__testCase__session__environment=test_case.session.
            environment,
            stepResult__testCase__session__browser=test_case.session.browser,
            stepResult__step=snapshot.stepResult.step,
            refSnapshot=None,
            id__lt=snapshot.id,
            name=snapshot.name).exclude(id=instance.id)

        # we find a reference snapshot, recompute diff
        if len(ref_snapshots) > 0:
            snapshot.refSnapshot = ref_snapshots.last()
            snapshot.save()

            diff_computer = DiffComputer.get_instance()

            # recompute diff pixels
            diff_computer.compute_now(snapshot.refSnapshot, snapshot)

            # recompute all following snapshot as they will depend on a previous ref
            for snap in snapshot.snapshotsUntilNextRef(snapshot):
                diff_computer.add_jobs(snapshot.refSnapshot, snap)

        # no reference snapshot found, only remove information about reference which makes this snapshot a reference
        else:
            snapshot.refSnapshot = None
            snapshot.save()
 def test_error_while_computing(self):
     """
     Check that if an error occurs during computing, 
     """
     s1 = Snapshot(stepResult=StepResult.objects.get(id=1),
                   refSnapshot=None,
                   pixelsDiff=None)
     s1.save()
     s2 = Snapshot(stepResult=StepResult.objects.get(id=2),
                   refSnapshot=None,
                   pixelsDiff=None)
     s2.save()
     diff_computer = DiffComputer.get_instance()
     diff_computer._compute_diff = MagicMock(
         side_effect=Exception("error while computing"))
     diff_computer.add_jobs(s1, s2, check_test_mode=False)
     time.sleep(0.7)
     self.assertIsNotNone(DiffComputer._instance,
                          "thread should still be running")
    def post(self, request, *args, **kwargs):
        try:
            step_snapshot = Snapshot.objects.get(pk=args[0])

            # compute has sense when a reference exists
            if step_snapshot.refSnapshot:

                diff_computer = DiffComputer.get_instance()
                diff_computer.compute_now(step_snapshot.refSnapshot,
                                          step_snapshot)

                # start computing differences for other snapshots sharing the same reference
                for snap in step_snapshot.snapshotWithSameRef():
                    diff_computer.add_jobs(step_snapshot.refSnapshot, snap)

                return HttpResponse(status=200)
            else:
                return HttpResponse(status=304)

        except Exception as e:
            return HttpResponse(status=404)
    def compare_or_store_snapshot(self, form, step_result):

        image = form.cleaned_data['image']  # the image file
        name = form.cleaned_data['name']  # name of the image
        store_snapshot = form.cleaned_data[
            'storeSnapshot']  # do we store the image or not. If False, only comparison is returned
        diff_tolerance = form.cleaned_data.get(
            'diffTolerance', 0.0)  # percentage of admissible error
        compare_option = form.cleaned_data.get('compare',
                                               'true')  # how we compare image

        # check if a reference exists for this step in the same test case / same application / same version / same environment / same browser / same name
        most_recent_reference_snapshot = Snapshot.objects.filter(
            stepResult__step=step_result.step,  # same step in the test case
            stepResult__testCase__testCase__name=step_result.testCase.testCase.
            name,  # same test case
            stepResult__testCase__session__version=step_result.testCase.
            session.version,  # same version
            stepResult__testCase__session__environment=step_result.testCase.
            session.environment,  # same environment
            stepResult__testCase__session__browser=step_result.testCase.
            session.browser,  # same browser
            refSnapshot=None,  # a reference image
            name=name).order_by('pk').last()  # same snapshot name

        # check for a reference in previous versions
        if not most_recent_reference_snapshot:
            for app_version in reversed(
                    step_result.testCase.session.version.previousVersions()):
                most_recent_reference_snapshot = Snapshot.objects.filter(
                    stepResult__step=step_result.step,
                    stepResult__testCase__testCase__name=step_result.testCase.
                    testCase.name,
                    stepResult__testCase__session__version=app_version,
                    stepResult__testCase__session__environment=step_result.
                    testCase.session.environment,
                    stepResult__testCase__session__browser=step_result.
                    testCase.session.browser,
                    refSnapshot=None,
                    name=name).order_by('pk').last()
                if most_recent_reference_snapshot:
                    break

        diff_pixels_percentage = 0.0

        if most_recent_reference_snapshot:
            step_snapshot = Snapshot(
                stepResult=step_result,
                image=image,
                refSnapshot=most_recent_reference_snapshot,
                name=name,
                compareOption=compare_option,
                diffTolerance=diff_tolerance)
            if store_snapshot:
                step_snapshot.save()

                # compute difference if a reference already exist
                DiffComputer.get_instance().add_jobs(
                    most_recent_reference_snapshot, step_snapshot)

            else:
                try:

                    # as we don't save step_snapshot (it's temp computation), we still save the image data temporary at the location it's expected
                    with open(step_snapshot.image.path, 'wb') as img:
                        img.write(image.read())
                        img.flush()

                        DiffComputer.get_instance().compute_now(
                            most_recent_reference_snapshot,
                            step_snapshot,
                            save_snapshot=False)
                finally:
                    try:
                        os.remove(step_snapshot.image.path)
                    except Exception as e:
                        pass

                if step_snapshot.pixelsDiff is not None:
                    with io.BytesIO(step_snapshot.pixelsDiff) as input:
                        diff_pixels_percentage = 100 * (
                            sum(list(Image.open(input).getdata(3))) /
                            255) / (step_snapshot.image.width *
                                    step_snapshot.image.height)

        else:
            # snapshot is marked as computed as this is a reference snapshot
            step_snapshot = Snapshot(stepResult=step_result,
                                     image=image,
                                     refSnapshot=None,
                                     name=name,
                                     compareOption=compare_option,
                                     computed=True,
                                     diffTolerance=diff_tolerance)
            if store_snapshot:
                step_snapshot.save()

        return HttpResponse(json.dumps({
            'id':
            step_snapshot.id,
            'computed':
            step_snapshot.computed,
            'computingError':
            step_snapshot.computingError,
            'diffPixelPercentage':
            diff_pixels_percentage,
            'tooManyDiffs':
            step_snapshot.tooManyDiffs
        }),
                            content_type='application/json',
                            status=201)
Пример #16
0
    def get_context_data(self, **kwargs):
        """
        Look for the snapshot of our session
        @param sessionId
        @param testCaseId    a TestCaseInSession object id
        @param testStepId    a TestStep object id
        """
        context = super(PictureView, self).get_context_data(**kwargs)
        context['captureList'] = []
        context['testCaseId'] = self.kwargs['testCaseInSessionId']
        context['testStepId'] = self.kwargs['testStepId']

        step = TestStep.objects.get(pk=self.kwargs['testStepId'])

        context['testStepName'] = step.name
        context['status'] = step.isOkWithSnapshots(
            self.kwargs['testCaseInSessionId'])

        # check that the user has permissions to edit exclusion zones. If not buttons will be disabled
        authenticated_to_edit = not self.security_api_enabled or (
            self.security_api_enabled and self.request.user.is_authenticated)
        allowed_to_edit = not self.security_enabled or (
            self.security_enabled and self.request.user.has_perms([
                'snapshotServer.add_excludezone',
                'snapshotServer.change_excludezone',
                'snapshotServer.delete_excludezone'
            ]))

        context['editable'] = authenticated_to_edit and allowed_to_edit
        if context['editable']:
            context['editButtonText'] = 'Edit'
        elif not authenticated_to_edit:
            context['editButtonText'] = 'You must log in to edit.'
        elif not allowed_to_edit:
            context['editButtonText'] = "You don't have right to edit"

        step_snapshots = Snapshot.objects.filter(
            stepResult__testCase=self.kwargs['testCaseInSessionId'],
            stepResult__step=self.kwargs['testStepId']).order_by('id')

        for step_snapshot in step_snapshots:
            if step_snapshot:

                # request should contain the snapshotId when makeRef is sent. Filter on it
                if 'makeRef' in self.request.GET and 'snapshotId' in self.request.GET and int(
                        self.request.GET['snapshotId']
                ) == step_snapshot.id and context['editable']:

                    if self.request.GET[
                            'makeRef'] == 'True' and step_snapshot.refSnapshot is not None:
                        previous_snapshot = step_snapshot.refSnapshot
                        step_snapshot.refSnapshot = None
                        step_snapshot.pixelsDiff = None
                        step_snapshot.save()

                        # Compute differences for the following snapshots as they will depend on this new ref
                        for snap in step_snapshot.snapshotsUntilNextRef(
                                previous_snapshot):
                            DiffComputer.get_instance().add_jobs(
                                step_snapshot, snap)

                        # copy exclude zones to the new ref so that they may be processed independently
                        for exclude_zone in ExcludeZone.objects.filter(
                                snapshot=previous_snapshot):
                            exclude_zone.copy_to_snapshot(step_snapshot)

                    elif self.request.GET[
                            'makeRef'] == 'False' and step_snapshot.refSnapshot is None:
                        # search a reference with a lower id, meaning that it has been recorded before our step
                        # search with the same test case name / same step name / same application version / same environment / same browser / same image name so that comparison
                        # is done on same basis
                        # TODO: reference could be searched in previous versions
                        test_case = TestCaseInSession.objects.get(
                            pk=self.kwargs['testCaseInSessionId'])
                        ref_snapshots = Snapshot.objects.filter(
                            stepResult__testCase__testCase__name=test_case.
                            testCase.name,
                            stepResult__testCase__session__version=test_case.
                            session.version,
                            stepResult__testCase__session__environment=test_case
                            .session.environment,
                            stepResult__testCase__session__browser=test_case.
                            session.browser,
                            stepResult__step=self.kwargs['testStepId'],
                            refSnapshot=None,
                            id__lt=step_snapshot.id,
                            name=step_snapshot.name)

                        # do not remove reference flag if our snapshot is the very first one
                        if len(ref_snapshots) > 0:
                            step_snapshot.refSnapshot = ref_snapshots.last()
                            step_snapshot.save()

                            diff_computer = DiffComputer.get_instance()

                            # recompute diff pixels
                            diff_computer.compute_now(
                                step_snapshot.refSnapshot, step_snapshot)

                            # recompute all following snapshot as they will depend on a previous ref
                            for snap in step_snapshot.snapshotsUntilNextRef(
                                    step_snapshot):
                                diff_computer.add_jobs(
                                    step_snapshot.refSnapshot, snap)

                ref_snapshot = step_snapshot.refSnapshot

                # extract difference pixel. Recompute in case this step is no more a reference
                diff_pixels_bin = step_snapshot.pixelsDiff

                if os.path.isfile(settings.MEDIA_ROOT + os.sep +
                                  step_snapshot.image.name):
                    snapshot_width = step_snapshot.image.width
                    snapshot_height = step_snapshot.image.height
                else:
                    snapshot_height = 0
                    snapshot_width = 0

                if diff_pixels_bin and snapshot_width and snapshot_height:
                    try:
                        diff_pixels = pickle.loads(diff_pixels_bin)
                        diff_picture = base64.b64encode(
                            DiffComputer.get_instance().mark_diff(
                                step_snapshot.image.width,
                                step_snapshot.image.height,
                                diff_pixels)).decode('ascii')
                        diff_pixels_percentage = 0.0
                    except Exception:
                        #                         diff_picture_bin
                        diff_picture = base64.b64encode(
                            diff_pixels_bin).decode('ascii')
                        with io.BytesIO(diff_pixels_bin) as input:
                            diff_pixels_percentage = 100 * (
                                sum(list(Image.open(input).getdata(3))) /
                                255) / (step_snapshot.image.width *
                                        step_snapshot.image.height)

                else:
                    diff_pixels = []
                    diff_picture = None
                    diff_pixels_percentage = 0.0

            # not snapshot has been recorded for this session
            else:
                ref_snapshot = None
                diff_pixels = []
                diff_picture = None
                diff_pixels_percentage = 0.0

            step_snapshot_context = {
                'name': step_snapshot.name,
                'reference': ref_snapshot,
                'stepSnapshot': step_snapshot,
                'width': snapshot_width,
                'height': snapshot_height,
                'diffB64': diff_picture,
                'diffPercentage': diff_pixels_percentage
            }
            context['captureList'].append(step_snapshot_context)

        return context