Beispiel #1
0
class TestOneTimeWorkflowNotification(TestCase):
    """ Tests are defined in the g-sheet test grid under:
    WF EMAILS for unit tests (middle level)
  """
    def setUp(self):
        super(TestOneTimeWorkflowNotification, self).setUp()
        self.api = Api()
        self.wf_generator = WorkflowsGenerator()
        self.object_generator = ObjectGenerator()

        self.random_objects = self.object_generator.generate_random_objects()
        self.random_people = [
            self.object_generator.generate_person(user_role="Administrator")[1]
            for _ in range(5)
        ]
        self.create_test_cases()

        self.create_users()

        db.session.query(Notification).delete()

        def init_decorator(init):
            def new_init(self, *args, **kwargs):
                init(self, *args, **kwargs)
                if hasattr(self, "created_at"):
                    self.created_at = datetime.now()

            return new_init

        Notification.__init__ = init_decorator(Notification.__init__)

    def tearDown(self):
        db.session.query(Notification).delete()

    def short_dict(self, obj, plural):
        return {
            "href": "/api/%s/%d" % (plural, obj.id),
            "id": obj.id,
            "type": obj.__class__.__name__,
        }

    def setup_cycle_tasks(self):
        """Prepare environment with couple of active cycle tasks."""
        with freeze_time("2018-11-01"):
            _, workflow = self.wf_generator.generate_workflow(
                self.one_time_workflow_1)
            self.wf_generator.generate_cycle(workflow)
            self.wf_generator.activate_workflow(workflow)
        return all_models.CycleTaskGroupObjectTask.query

    def assert_nofication_sent_with(self, text):
        """Assert if text exists in sent notification."""
        with mock.patch("ggrc.notifications.common.send_email") as send_email:
            self.client.get("/_notifications/send_daily_digest")
            _, _, content = send_email.call_args[0]
        self.assertIn(text, content)

    def assert_nofication_sent_without(self, text):
        """Assert if text doesn't exist in sent notification."""
        with mock.patch("ggrc.notifications.common.send_email") as send_email:
            self.client.get("/_notifications/send_daily_digest")
            _, _, content = send_email.call_args[0]
        self.assertNotIn(text, content)

    def test_one_time_wf(self):
        # setup
        with freeze_time("2015-04-07 03:21:34"):
            wf_response, wf = self.wf_generator.generate_workflow(
                data={
                    # admin will be the current user
                    "notify_on_change":
                    True,  # force real time updates
                    "title":
                    "One-time WF",
                    "notify_custom_message":
                    textwrap.dedent("""\
              Hi all.
              Did you know that Irelnd city namd Newtownmountkennedy has 19
              letters? But it's not the longest one. The recordsman is the
              city in New Zealand that contains 97 letter."""),
                })

            _, tg = self.wf_generator.generate_task_group(
                wf,
                data={
                    "title": "TG #1 for the One-time WF",
                    "contact": self.short_dict(self.tgassignee1, "people"),
                })

            self.wf_generator.generate_task_group_task(
                tg, {
                    "title": "task #1 for one-time workflow",
                    "contact": self.short_dict(self.member1, "people"),
                    "start_date": "04/07/2015",
                    "end_date": "04/15/2015",
                })

            self.wf_generator.generate_task_group_object(
                tg, self.random_objects[0])
            self.wf_generator.generate_task_group_object(
                tg, self.random_objects[1])

        # test
        with freeze_time("2015-04-07 03:21:34"):
            cycle_response, cycle = self.wf_generator.generate_cycle(wf)
            self.wf_generator.activate_workflow(wf)

            common.get_daily_notifications()

    def test_deprecated_ct_acl_update(self):
        """Test if acl update for deprecated CT will not create notification."""
        cycle_task = self.setup_cycle_tasks().first()
        cycle_task_title = cycle_task.title
        response = self.api.put(cycle_task, {"status": "Deprecated"})
        self.assert200(response)
        self.assert_nofication_sent_without(cycle_task_title)

        task_assignee = all_models.AccessControlRole.query.filter_by(
            name="Task Assignees",
            object_type="CycleTaskGroupObjectTask",
        ).first()
        person = self.object_generator.generate_person(user_role="Creator")[1]
        response = self.api.put(
            cycle_task, {
                "access_control_list": [{
                    "ac_role_id": task_assignee.id,
                    "person": {
                        "id": person.id,
                        "type": "Person",
                    }
                }]
            })
        self.assert200(response)
        self.assert_nofication_sent_without(cycle_task_title)

    def test_restore_deprecated_ct(self):
        """Test notifications for CT which was restored from Deprecated."""
        cycle_task = self.setup_cycle_tasks().first()
        cycle_task_title = cycle_task.title

        self.assert_nofication_sent_with(cycle_task_title)

        response = self.api.put(cycle_task, {"status": "Deprecated"})
        self.assert200(response)
        self.assert_nofication_sent_without(cycle_task_title)

        response = self.api.put(cycle_task, {"status": "Assigned"})
        self.assert200(response)
        self.assert_nofication_sent_with(cycle_task_title)

    def create_test_cases(self):
        def person_dict(person_id):
            return {
                "href": "/api/people/%d" % person_id,
                "id": person_id,
                "type": "Person"
            }

        self.one_time_workflow_1 = {
            "title":
            "one time test workflow",
            "description":
            "some test workflow",
            # admin will be current user with id == 1
            "task_groups": [
                {
                    "title":
                    "one time task group",
                    "task_group_tasks": [
                        {
                            "title": "task_{}".format(str(uuid.uuid4())),
                            "description": "some task",
                            "contact": person_dict(self.random_people[0].id),
                            "start_date": date(2015, 5, 1),  # friday
                            "end_date": date(2015, 5, 5),
                        },
                        {
                            "title": "task_{}".format(str(uuid.uuid4())),
                            "description": "some task",
                            "contact": person_dict(self.random_people[1].id),
                            "start_date": date(2015, 5, 4),
                            "end_date": date(2015, 5, 7),
                        }
                    ],
                    "task_group_objects":
                    self.random_objects[:2]
                },
                {
                    "title":
                    "another one time task group",
                    "task_group_tasks": [
                        {
                            "title": "task_{}".format(str(uuid.uuid4())),
                            "description": "some task",
                            "contact": person_dict(self.random_people[0].id),
                            "start_date": date(2015, 5, 8),  # friday
                            "end_date": date(2015, 5, 12),
                        },
                        {
                            "title": "task_{}".format(str(uuid.uuid4())),
                            "description": "some task",
                            "contact": person_dict(self.random_people[2].id),
                            "start_date": date(2015, 5, 1),  # friday
                            "end_date": date(2015, 5, 5),
                        }
                    ],
                    "task_group_objects": []
                }
            ]
        }

    def create_users(self):
        _, self.admin1 = self.object_generator.generate_person(
            # data={"name": "User1 Admin1", "email": "*****@*****.**"},
            user_role="Administrator")
        _, self.tgassignee1 = self.object_generator.generate_person(
            # data={"name": "User2 TGassignee1",
            #       "email": "*****@*****.**"},
            user_role="Administrator")
        _, self.member1 = self.object_generator.generate_person(
            # data={"name": "User3 Member1", "email": "*****@*****.**"},
            user_role="Administrator")
        _, self.member2 = self.object_generator.generate_person(
            # data={"name": "User4 Member2", "email": "*****@*****.**"},
            user_role="Administrator")
class TestCycleTaskImportUpdate(TestCase):
    """ This class contains simple cycle task update tests using import
  functionality
  """

    CSV_DIR = join(abspath(dirname(__file__)), "test_csvs/")

    def setUp(self):
        super(TestCycleTaskImportUpdate, self).setUp()
        self.wf_generator = WorkflowsGenerator()
        self.object_generator = ObjectGenerator()
        self.random_objects = self.object_generator.generate_random_objects(2)
        _, self.person_1 = self.object_generator.generate_person(
            user_role="Administrator")
        self.ftime_active = "2016-07-01"
        self.ftime_historical = "2014-05-01"
        self._create_test_cases_data()
        # It is needed because cycle-tasks are generated automatically with
        # 'slug' based on auto_increment 'id' field.
        # At start of each test we suppose that created cycle-task's 'slug'
        # lie in range from 1 to 10.
        db.session.execute('ALTER TABLE cycle_task_group_object_tasks '
                           'AUTO_INCREMENT = 1')

    def test_cycle_task_correct(self):
        """Test cycle task update via import with correct data"""
        self._generate_cycle_tasks()
        with freeze_time(self.ftime_active):
            response = self.import_file("cycle_task_correct.csv")
            self._check_csv_response(response, {})
            self._cmp_tasks(self.expected_cycle_task_correct)

    def test_cycle_task_warnings(self):
        """Test cycle task update via import with data which is the reason of
    warnings about non-importable columns."""
        self._generate_cycle_tasks()
        with freeze_time(self.ftime_active):
            response = self.import_file("cycle_task_warnings.csv")
            self._check_csv_response(response, self.expected_warnings)
            self._cmp_tasks(self.expected_cycle_task_correct)

    def test_cycle_task_create_error(self):
        """Test cycle task update via import with data which is the reason of
    errors about new cycle task creation."""
        self._generate_cycle_tasks()
        with freeze_time(self.ftime_active):
            response = self.import_file("cycle_task_create_error.csv")
            self._check_csv_response(response, self.expected_create_error)
            self._cmp_tasks(self.expected_cycle_task_correct)

    def test_cycle_task_date_error(self):
        """Test cycle task update via import with data which is the reason of
    errors about incorrect dates in csv file."""
        self._generate_cycle_tasks()
        with freeze_time(self.ftime_active):
            response = self.import_file("cycle_task_date_error.csv")
            self._check_csv_response(response, self.expected_date_error)
            self._cmp_tasks(self.expected_cycle_task_date_error)

    def test_cycle_task_permission_error(self):
        """Test cycle task update via import with non-admin user which is the
    reason of error. Only admin can update cycle tasks via import."""
        self._generate_cycle_tasks()
        with freeze_time(self.ftime_active):
            _, creator = self.object_generator.generate_person(
                user_role="Creator")
            response = self.import_file("cycle_task_correct.csv",
                                        person=creator)
            self._check_csv_response(response, self.expected_permission_error)
            # Cycle tasks' data shouldn't be changed in test DB after import run from
            # non-admin user
            expected_cycle_task_permission_error = {}
            expected_cycle_task_permission_error.update(
                self.generated_cycle_tasks_active)
            expected_cycle_task_permission_error.update(
                self.generated_cycle_tasks_historical)
            self._cmp_tasks(expected_cycle_task_permission_error)

    def _cmp_tasks(self, expected_ctasks):
        """Compare tasks values from argument's list and test DB."""
        for ctask in db.session.query(CycleTaskGroupObjectTask).all():
            if ctask.slug not in expected_ctasks:
                continue
            exp_task = expected_ctasks[ctask.slug]
            for attr, val in exp_task.iteritems():
                self.assertEqual(str(getattr(ctask, attr, None)), val)

    # pylint: disable=too-many-arguments
    def _activate_workflow(self, ftime, workflow, task_group, task_group_tasks,
                           random_object, cycle_tasks):
        """Helper which is responsible for active cycle-tasks creation"""
        with freeze_time(ftime):
            _, wf = self.wf_generator.generate_workflow(workflow)
            _, tg = self.wf_generator.generate_task_group(wf, task_group)
            for task in task_group_tasks:
                self.wf_generator.generate_task_group_task(tg, task)
            self.wf_generator.generate_task_group_object(tg, random_object)

            _, cycle = self.wf_generator.generate_cycle(wf)
            self.wf_generator.activate_workflow(wf)

            for exp_slug, exp_task in cycle_tasks.iteritems():
                obj = db.session.query(CycleTaskGroupObjectTask).filter_by(
                    slug=exp_slug).first()
                if exp_task["status"] == "Verified":
                    self.wf_generator.modify_object(obj,
                                                    {"status": "Finished"})
                self.wf_generator.modify_object(obj,
                                                {"status": exp_task["status"]})
        self._cmp_tasks(cycle_tasks)
        return cycle

    def _generate_cycle_tasks(self):
        """Helper which is responsible for test data creation"""
        self._activate_workflow(self.ftime_active, self.workflow_active,
                                self.task_group_active,
                                self.task_group_tasks_active,
                                self.random_objects[0],
                                self.generated_cycle_tasks_active)
        cycle = self._activate_workflow(self.ftime_historical,
                                        self.workflow_historical,
                                        self.task_group_historical,
                                        self.task_group_tasks_historical,
                                        self.random_objects[1],
                                        self.generated_cycle_tasks_historical)
        with freeze_time(self.ftime_historical):
            cycle = Cycle.query.get(cycle.id)
            self.wf_generator.modify_object(cycle, data={"is_current": False})

    def _create_test_cases_data(self):
        """Create test cases data: for object generation,
    expected data for checks"""
        def person_dict(person_id):
            """Return person data"""
            return {
                "href": "/api/people/%d" % person_id,
                "id": person_id,
                "type": "Person"
            }

        self.workflow_active = {
            "title": "workflow active title",
            "description": "workflow active description",
            "frequency": "one_time",
            "owners": [person_dict(self.person_1.id)],
            "notify_on_change": False,
        }

        self.task_group_active = {
            "title": "task group active title",
            "contact": person_dict(self.person_1.id),
        }

        self.task_group_tasks_active = [{
            "title":
            "task active title 1",
            "description":
            "task active description 1",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/01/2016",
            "end_date":
            "07/06/2016",
        }, {
            "title":
            "task active title 2",
            "description":
            "task active description 2",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/07/2016",
            "end_date":
            "07/12/2016",
        }, {
            "title":
            "task active title 3",
            "description":
            "task active description 3",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/13/2016",
            "end_date":
            "07/18/2016",
        }, {
            "title":
            "task active title 4",
            "description":
            "task active description 4",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/19/2016",
            "end_date":
            "07/24/2016",
        }, {
            "title":
            "task active title 5",
            "description":
            "task active description 5",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/25/2016",
            "end_date":
            "07/30/2016",
        }]

        # Active cycle tasks which should be generated from previous structure
        # at the beginning of each test
        self.generated_cycle_tasks_active = {
            "CYCLETASK-1": {
                "title": self.task_group_tasks_active[0]["title"],
                "description": self.task_group_tasks_active[0]["description"],
                "start_date": "2016-07-01",
                "end_date": "2016-07-06",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Assigned"
            },
            "CYCLETASK-2": {
                "title": self.task_group_tasks_active[1]["title"],
                "description": self.task_group_tasks_active[1]["description"],
                "start_date": "2016-07-07",
                "end_date": "2016-07-12",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Declined"
            },
            "CYCLETASK-3": {
                "title": self.task_group_tasks_active[2]["title"],
                "description": self.task_group_tasks_active[2]["description"],
                "start_date": "2016-07-13",
                "end_date": "2016-07-18",
                "finished_date": "None",
                "verified_date": "None",
                "status": "InProgress"
            },
            "CYCLETASK-4": {
                "title": self.task_group_tasks_active[3]["title"],
                "description": self.task_group_tasks_active[3]["description"],
                "start_date": "2016-07-19",
                "end_date": "2016-07-24",
                "finished_date": "2016-07-01 00:00:00",
                "verified_date": "None",
                "status": "Finished"
            },
            "CYCLETASK-5": {
                "title": self.task_group_tasks_active[4]["title"],
                "description": self.task_group_tasks_active[4]["description"],
                "start_date": "2016-07-25",
                "end_date": "2016-07-30",
                "finished_date": "2016-07-01 00:00:00",
                "verified_date": "2016-07-01 00:00:00",
                "status": "Verified"
            }
        }

        self.workflow_historical = {
            "title": "workflow historical title",
            "description": "workflow historical description",
            "frequency": "one_time",
            "owners": [person_dict(self.person_1.id)],
            "notify_on_change": False,
        }

        self.task_group_historical = {
            "title": "task group historical title",
            "contact": person_dict(self.person_1.id),
        }

        self.task_group_tasks_historical = [
            {
                "title": "task historical title 1",
                "description": "task historical description 1",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/01/2014",
                "end_date": "05/06/2014",
            },
            {
                "title": "task historical title 2",
                "description": "task historical description 2",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/07/2014",
                "end_date": "05/12/2014",
            },
            {
                "title": "task historical title 3",
                "description": "task historical description 3",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/13/2014",
                "end_date": "05/18/2014",
            },
            {
                "title": "task historical title 4",
                "description": "task historical description 4",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/19/2014",
                "end_date": "05/24/2014",
            },
            {
                "title": "task historical title 5",
                "description": "task historical description 5",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/25/2014",
                "end_date": "05/30/2014",
            },
        ]

        # Historical cycle tasks which should be generated from previous structure
        # at the beginning of each test.
        self.generated_cycle_tasks_historical = {
            "CYCLETASK-6": {
                "title": self.task_group_tasks_historical[0]["title"],
                "description":
                self.task_group_tasks_historical[0]["description"],
                "start_date": "2014-05-01",
                "end_date": "2014-05-06",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Assigned"
            },
            "CYCLETASK-7": {
                "title": self.task_group_tasks_historical[1]["title"],
                "description":
                self.task_group_tasks_historical[1]["description"],
                "start_date": "2014-05-07",
                "end_date": "2014-05-12",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Declined"
            },
            "CYCLETASK-8": {
                "title": self.task_group_tasks_historical[2]["title"],
                "description":
                self.task_group_tasks_historical[2]["description"],
                "start_date": "2014-05-13",
                "end_date": "2014-05-18",
                "finished_date": "None",
                "verified_date": "None",
                "status": "InProgress"
            },
            "CYCLETASK-9": {
                "title": self.task_group_tasks_historical[3]["title"],
                "description":
                self.task_group_tasks_historical[3]["description"],
                "start_date": "2014-05-19",
                "end_date": "2014-05-24",
                "finished_date": "2014-05-01 00:00:00",
                "verified_date": "None",
                "status": "Finished"
            },
            "CYCLETASK-10": {
                "title": self.task_group_tasks_historical[4]["title"],
                "description":
                self.task_group_tasks_historical[4]["description"],
                "start_date": "2014-05-25",
                "end_date": "2014-05-30",
                "finished_date": "2014-05-01 00:00:00",
                "verified_date": "2014-05-01 00:00:00",
                "status": "Verified"
            }
        }

        # Expected cycle tasks which should be created in correct cycle task update
        # case. It is needed for most tests.
        self.expected_cycle_task_correct = {
            "CYCLETASK-1": {
                "title": self.task_group_tasks_active[0]["title"] + " one",
                "description":
                self.task_group_tasks_active[0]["description"] + " one",
                "start_date": "2016-06-01",
                "end_date": "2016-06-06",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Assigned"
            },
            "CYCLETASK-2": {
                "title": self.task_group_tasks_active[1]["title"] + " two",
                "description":
                self.task_group_tasks_active[1]["description"] + " two",
                "start_date": "2016-06-07",
                "end_date": "2016-06-12",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Declined"
            },
            "CYCLETASK-3": {
                "title": self.task_group_tasks_active[2]["title"] + " three",
                "description":
                self.task_group_tasks_active[2]["description"] + " three",
                "start_date": "2016-06-13",
                "end_date": "2016-06-18",
                "finished_date": "None",
                "verified_date": "None",
                "status": "InProgress"
            },
            "CYCLETASK-4": {
                "title": self.task_group_tasks_active[3]["title"] + " four",
                "description":
                self.task_group_tasks_active[3]["description"] + " four",
                "start_date": "2016-06-19",
                "end_date": "2016-06-24",
                "finished_date": "2016-07-19 00:00:00",
                "verified_date": "None",
                "status": "Finished"
            },
            "CYCLETASK-5": {
                "title": self.task_group_tasks_active[4]["title"] + " five",
                "description":
                self.task_group_tasks_active[4]["description"] + " five",
                "start_date": "2016-06-25",
                "end_date": "2016-06-30",
                "finished_date": "2016-07-25 00:00:00",
                "verified_date": "2016-08-30 00:00:00",
                "status": "Verified"
            },
            "CYCLETASK-6": {
                "title":
                self.task_group_tasks_historical[0]["title"] + " one",
                "description":
                self.task_group_tasks_historical[0]["description"] + " one",
                "start_date":
                "2014-04-01",
                "end_date":
                "2014-04-06",
                "finished_date":
                "2014-05-01 00:00:00",
                "verified_date":
                "2014-06-06 00:00:00",
                "status":
                "Assigned"
            },
            "CYCLETASK-7": {
                "title":
                self.task_group_tasks_historical[1]["title"] + " two",
                "description":
                self.task_group_tasks_historical[1]["description"] + " two",
                "start_date":
                "2014-04-07",
                "end_date":
                "2014-04-12",
                "finished_date":
                "2014-05-07 00:00:00",
                "verified_date":
                "None",
                "status":
                "Declined"
            },
            "CYCLETASK-8": {
                "title":
                self.task_group_tasks_historical[2]["title"] + " three",
                "description":
                self.task_group_tasks_historical[2]["description"] + " three",
                "start_date":
                "2014-04-13",
                "end_date":
                "2014-04-18",
                "finished_date":
                "2014-05-13 00:00:00",
                "verified_date":
                "2014-06-18 00:00:00",
                "status":
                "InProgress"
            },
            "CYCLETASK-9": {
                "title":
                self.task_group_tasks_historical[3]["title"] + " four",
                "description":
                self.task_group_tasks_historical[3]["description"] + " four",
                "start_date":
                "2014-04-19",
                "end_date":
                "2014-04-24",
                "finished_date":
                "2014-05-19 00:00:00",
                "verified_date":
                "None",
                "status":
                "Finished"
            },
            "CYCLETASK-10": {
                "title":
                self.task_group_tasks_historical[4]["title"] + " five",
                "description":
                self.task_group_tasks_historical[4]["description"] + " five",
                "start_date":
                "2014-04-25",
                "end_date":
                "2014-04-30",
                "finished_date":
                "2014-05-25 00:00:00",
                "verified_date":
                "2014-06-30 00:00:00",
                "status":
                "Verified"
            }
        }

        # Below is description of warning for non-importable columns. It is needed
        # for test_cycle_task_warnings.
        importable_column_names = []
        for field_name in CycleTaskGroupObjectTask.IMPORTABLE_FIELDS:
            if field_name == 'slug':
                continue
            # pylint: disable=protected-access
            importable_column_names.append(
                CycleTaskGroupObjectTask._aliases.get(field_name, field_name))
        self.expected_warnings = {
            'Cycle Task Group Object Task': {
                'block_warnings': {
                    errors.ONLY_IMPORTABLE_COLUMNS_WARNING.format(
                        line=2, columns=", ".join(importable_column_names))
                },
            }
        }

        # This is an error message which should be shown during
        # test_cycle_task_create_error test
        self.expected_create_error = {
            'Cycle Task Group Object Task': {
                'row_errors': {errors.CREATE_INSTANCE_ERROR.format(line=13)}
            }
        }

        # Below is expected date errors for test_cycle_task_date_error. They should
        # be shown during date validator's tests.
        self.expected_date_error = {
            'Cycle Task Group Object Task': {
                'row_errors': {
                    errors.INVALID_START_END_DATES.format(
                        line=3,
                        start_date="Start Date",
                        end_date="End Date",
                    ),
                    errors.INVALID_STATUS_DATE_CORRELATION.format(
                        line=4,
                        date="Actual Finish Date",
                        status="not Finished",
                    ),
                    errors.INVALID_STATUS_DATE_CORRELATION.format(
                        line=5,
                        date="Actual Verified Date",
                        status="not Verified",
                    ),
                    errors.INVALID_STATUS_DATE_CORRELATION.format(
                        line=6,
                        date="Actual Verified Date",
                        status="not Verified",
                    ),
                    errors.INVALID_START_END_DATES.format(
                        line=7,
                        start_date="Actual Finish Date",
                        end_date="Actual Verified Date",
                    ),
                    errors.INVALID_START_END_DATES.format(
                        line=8,
                        start_date="Start Date",
                        end_date="End Date",
                    ),
                    errors.MISSING_VALUE_ERROR.format(
                        line=9,
                        column_name="Actual Finish Date",
                    ),
                    errors.INVALID_START_END_DATES.format(
                        line=10,
                        start_date="Actual Finish Date",
                        end_date="Actual Verified Date",
                    ),
                },
            }
        }
        # Below is expected cycle-tasks data which should appear in test DB after
        # test_cycle_task_date_error run
        self.expected_cycle_task_date_error = dict()
        self.expected_cycle_task_date_error.update(
            self.generated_cycle_tasks_active)
        self.expected_cycle_task_date_error.update(
            self.generated_cycle_tasks_historical)
        self.expected_cycle_task_date_error["CYCLETASK-9"] = (
            self.expected_cycle_task_correct["CYCLETASK-9"])
        self.expected_cycle_task_date_error["CYCLETASK-10"] = (
            self.expected_cycle_task_correct["CYCLETASK-10"])

        # Expected error message which should be shown after
        # test_cycle_task_permission_error run
        self.expected_permission_error = {
            'Cycle Task Group Object Task': {
                'block_errors': {errors.PERMISSION_ERROR.format(line=2)}
            }
        }
class TestCycleTaskImportUpdate(BaseTestCycleTaskImportUpdate):

  """ This class contains simple cycle task update tests using import
  functionality
  """

  CSV_DIR = join(abspath(dirname(__file__)), "test_csvs/")

  def setUp(self):
    super(TestCycleTaskImportUpdate, self).setUp()
    self.wf_generator = WorkflowsGenerator()
    self.object_generator = ObjectGenerator()
    self.random_objects = self.object_generator.generate_random_objects(2)
    _, self.person_1 = self.object_generator.generate_person(
        user_role="Administrator")
    self.ftime_active = "2016-07-01"
    self.ftime_historical = "2014-05-01"
    self._create_test_cases_data()
    # It is needed because cycle-tasks are generated automatically with
    # 'slug' based on auto_increment 'id' field.
    # At start of each test we suppose that created cycle-task's 'slug'
    # lie in range from 1 to 10.
    db.session.execute('ALTER TABLE cycle_task_group_object_tasks '
                       'AUTO_INCREMENT = 1')

  def test_cycle_task_correct(self):
    """Test cycle task update via import with correct data"""
    self._generate_cycle_tasks()
    with freeze_time(self.ftime_active):
      response = self.import_file("cycle_task_correct.csv")
      self._check_csv_response(response, {})
      self._cmp_tasks(self.expected_cycle_task_correct)

  def test_cycle_task_warnings(self):
    """Test cycle task update via import with data which is the reason of
    warnings about non-importable columns."""
    self._generate_cycle_tasks()
    with freeze_time(self.ftime_active):
      response = self.import_file("cycle_task_warnings.csv")
      self._check_csv_response(response, self.expected_warnings)
      self._cmp_tasks(self.expected_cycle_task_correct)

  def test_cycle_task_create_error(self):
    """Test cycle task update via import with data which is the reason of
    errors about new cycle task creation."""
    self._generate_cycle_tasks()
    with freeze_time(self.ftime_active):
      response = self.import_file("cycle_task_create_error.csv")
      self._check_csv_response(response, self.expected_create_error)
      self._cmp_tasks(self.expected_cycle_task_correct)

  def test_cycle_task_date_error(self):
    """Test cycle task update via import with data which is the reason of
    errors about incorrect dates in csv file."""
    self._generate_cycle_tasks()
    with freeze_time(self.ftime_active):
      response = self.import_file("cycle_task_date_error.csv")
      self._check_csv_response(response, self.expected_date_error)
      self._cmp_tasks(self.expected_cycle_task_date_error)

  def test_cycle_task_permission_error(self):
    """Test cycle task update via import with non-admin user which is the
    reason of error. Only admin can update cycle tasks via import."""
    self._generate_cycle_tasks()
    with freeze_time(self.ftime_active):
      _, creator = self.object_generator.generate_person(user_role="Creator")
      response = self.import_file("cycle_task_correct.csv", person=creator)
      self._check_csv_response(response, self.expected_permission_error)
      # Cycle tasks' data shouldn't be changed in test DB after import run from
      # non-admin user
      expected_cycle_task_permission_error = {}
      expected_cycle_task_permission_error.update(
          self.generated_cycle_tasks_active)
      expected_cycle_task_permission_error.update(
          self.generated_cycle_tasks_historical)
      self._cmp_tasks(expected_cycle_task_permission_error)

  def _cmp_tasks(self, expected_ctasks):
    """Compare tasks values from argument's list and test DB."""
    for ctask in db.session.query(CycleTaskGroupObjectTask).all():
      if ctask.slug not in expected_ctasks:
        continue
      exp_task = expected_ctasks[ctask.slug]
      for attr, val in exp_task.iteritems():
        self.assertEqual(str(getattr(ctask, attr, None)), val)

  # pylint: disable=too-many-arguments
  def _activate_workflow(self, ftime, workflow, task_group, task_group_tasks,
                         random_object, cycle_tasks):
    """Helper which is responsible for active cycle-tasks creation"""
    with freeze_time(ftime):
      _, wf = self.wf_generator.generate_workflow(workflow)
      _, tg = self.wf_generator.generate_task_group(wf, task_group)
      for task in task_group_tasks:
        self.wf_generator.generate_task_group_task(tg, task)
      self.wf_generator.generate_task_group_object(tg, random_object)

      _, cycle = self.wf_generator.generate_cycle(wf)
      self.wf_generator.activate_workflow(wf)

      for exp_slug, exp_task in cycle_tasks.iteritems():
        obj = db.session.query(CycleTaskGroupObjectTask).filter_by(
            slug=exp_slug
        ).first()
        if exp_task["status"] == "Verified":
          self.wf_generator.modify_object(obj, {"status": "Finished"})
        self.wf_generator.modify_object(obj, {"status": exp_task["status"]})
    self._cmp_tasks(cycle_tasks)
    return cycle

  def _generate_cycle_tasks(self):
    """Helper which is responsible for test data creation"""
    self._activate_workflow(self.ftime_active, self.workflow_active,
                            self.task_group_active,
                            self.task_group_tasks_active,
                            self.random_objects[0],
                            self.generated_cycle_tasks_active)
    cycle = self._activate_workflow(self.ftime_historical,
                                    self.workflow_historical,
                                    self.task_group_historical,
                                    self.task_group_tasks_historical,
                                    self.random_objects[1],
                                    self.generated_cycle_tasks_historical)
    with freeze_time(self.ftime_historical):
      cycle = Cycle.query.get(cycle.id)
      self.wf_generator.modify_object(cycle, data={"is_current": False})

  def _create_test_cases_data(self):
    """Create test cases data: for object generation,
    expected data for checks"""
    def person_dict(person_id):
      """Return person data"""
      return {
          "href": "/api/people/%d" % person_id,
          "id": person_id,
          "type": "Person"
      }

    self.workflow_active = {
        "title": "workflow active title",
        "description": "workflow active description",
        "frequency": "one_time",
        "owners": [person_dict(self.person_1.id)],
        "notify_on_change": False,
    }

    self.task_group_active = {
        "title": "task group active title",
        "contact": person_dict(self.person_1.id),
    }

    self.task_group_tasks_active = [{
        "title": "task active title 1",
        "description": "task active description 1",
        "contact": person_dict(self.person_1.id),
        "start_date": "07/01/2016",
        "end_date": "07/06/2016",
    }, {
        "title": "task active title 2",
        "description": "task active description 2",
        "contact": person_dict(self.person_1.id),
        "start_date": "07/07/2016",
        "end_date": "07/12/2016",
    }, {
        "title": "task active title 3",
        "description": "task active description 3",
        "contact": person_dict(self.person_1.id),
        "start_date": "07/13/2016",
        "end_date": "07/18/2016",
    }, {
        "title": "task active title 4",
        "description": "task active description 4",
        "contact": person_dict(self.person_1.id),
        "start_date": "07/19/2016",
        "end_date": "07/24/2016",
    }, {
        "title": "task active title 5",
        "description": "task active description 5",
        "contact": person_dict(self.person_1.id),
        "start_date": "07/25/2016",
        "end_date": "07/30/2016",
    }]

    # Active cycle tasks which should be generated from previous structure
    # at the beginning of each test
    self.generated_cycle_tasks_active = {
        "CYCLETASK-1": {
            "title": self.task_group_tasks_active[0]["title"],
            "description": self.task_group_tasks_active[0]["description"],
            "start_date": "2016-07-01",
            "end_date": "2016-07-06",
            "finished_date": "None",
            "verified_date": "None",
            "status": "Assigned"
        },
        "CYCLETASK-2": {
            "title": self.task_group_tasks_active[1]["title"],
            "description": self.task_group_tasks_active[1]["description"],
            "start_date": "2016-07-07",
            "end_date": "2016-07-12",
            "finished_date": "None",
            "verified_date": "None",
            "status": "Declined"
        },
        "CYCLETASK-3": {
            "title": self.task_group_tasks_active[2]["title"],
            "description": self.task_group_tasks_active[2]["description"],
            "start_date": "2016-07-13",
            "end_date": "2016-07-18",
            "finished_date": "None",
            "verified_date": "None",
            "status": "InProgress"
        },
        "CYCLETASK-4": {
            "title": self.task_group_tasks_active[3]["title"],
            "description": self.task_group_tasks_active[3]["description"],
            "start_date": "2016-07-19",
            "end_date": "2016-07-24",
            "finished_date": "2016-07-01 00:00:00",
            "verified_date": "None",
            "status": "Finished"
        },
        "CYCLETASK-5": {
            "title": self.task_group_tasks_active[4]["title"],
            "description": self.task_group_tasks_active[4]["description"],
            "start_date": "2016-07-25",
            "end_date": "2016-07-30",
            "finished_date": "2016-07-01 00:00:00",
            "verified_date": "2016-07-01 00:00:00",
            "status": "Verified"
        }
    }

    self.workflow_historical = {
        "title": "workflow historical title",
        "description": "workflow historical description",
        "frequency": "one_time",
        "owners": [person_dict(self.person_1.id)],
        "notify_on_change": False,
    }

    self.task_group_historical = {
        "title": "task group historical title",
        "contact": person_dict(self.person_1.id),
    }

    self.task_group_tasks_historical = [{
        "title": "task historical title 1",
        "description": "task historical description 1",
        "contact": person_dict(self.person_1.id),
        "start_date": "05/01/2014",
        "end_date": "05/06/2014",
    }, {
        "title": "task historical title 2",
        "description": "task historical description 2",
        "contact": person_dict(self.person_1.id),
        "start_date": "05/07/2014",
        "end_date": "05/12/2014",
    }, {
        "title": "task historical title 3",
        "description": "task historical description 3",
        "contact": person_dict(self.person_1.id),
        "start_date": "05/13/2014",
        "end_date": "05/18/2014",
    }, {
        "title": "task historical title 4",
        "description": "task historical description 4",
        "contact": person_dict(self.person_1.id),
        "start_date": "05/19/2014",
        "end_date": "05/24/2014",
    }, {
        "title": "task historical title 5",
        "description": "task historical description 5",
        "contact": person_dict(self.person_1.id),
        "start_date": "05/25/2014",
        "end_date": "05/30/2014",
    },
    ]

    # Historical cycle tasks which should be generated from previous structure
    # at the beginning of each test.
    self.generated_cycle_tasks_historical = {
        "CYCLETASK-6": {
            "title": self.task_group_tasks_historical[0]["title"],
            "description": self.task_group_tasks_historical[0]["description"],
            "start_date": "2014-05-01",
            "end_date": "2014-05-06",
            "finished_date": "None",
            "verified_date": "None",
            "status": "Assigned"
        },
        "CYCLETASK-7": {
            "title": self.task_group_tasks_historical[1]["title"],
            "description": self.task_group_tasks_historical[1]["description"],
            "start_date": "2014-05-07",
            "end_date": "2014-05-12",
            "finished_date": "None",
            "verified_date": "None",
            "status": "Declined"
        },
        "CYCLETASK-8": {
            "title": self.task_group_tasks_historical[2]["title"],
            "description": self.task_group_tasks_historical[2]["description"],
            "start_date": "2014-05-13",
            "end_date": "2014-05-18",
            "finished_date": "None",
            "verified_date": "None",
            "status": "InProgress"
        },
        "CYCLETASK-9": {
            "title": self.task_group_tasks_historical[3]["title"],
            "description": self.task_group_tasks_historical[3]["description"],
            "start_date": "2014-05-19",
            "end_date": "2014-05-24",
            "finished_date": "2014-05-01 00:00:00",
            "verified_date": "None",
            "status": "Finished"
        },
        "CYCLETASK-10": {
            "title": self.task_group_tasks_historical[4]["title"],
            "description": self.task_group_tasks_historical[4]["description"],
            "start_date": "2014-05-25",
            "end_date": "2014-05-30",
            "finished_date": "2014-05-01 00:00:00",
            "verified_date": "2014-05-01 00:00:00",
            "status": "Verified"
        }
    }

    # Expected cycle tasks which should be created in correct cycle task update
    # case. It is needed for most tests.
    self.expected_cycle_task_correct = {
        "CYCLETASK-1": {
            "title": self.task_group_tasks_active[0]["title"] + " one",
            "description":
                self.task_group_tasks_active[0]["description"] + " one",
            "start_date": "2016-06-01",
            "end_date": "2016-06-06",
            "finished_date": "None",
            "verified_date": "None",
            "status": "Assigned"
        },
        "CYCLETASK-2": {
            "title": self.task_group_tasks_active[1]["title"] + " two",
            "description":
                self.task_group_tasks_active[1]["description"] + " two",
            "start_date": "2016-06-07",
            "end_date": "2016-06-12",
            "finished_date": "None",
            "verified_date": "None",
            "status": "Declined"
        },
        "CYCLETASK-3": {
            "title": self.task_group_tasks_active[2]["title"] + " three",
            "description":
                self.task_group_tasks_active[2]["description"] + " three",
            "start_date": "2016-06-13",
            "end_date": "2016-06-18",
            "finished_date": "None",
            "verified_date": "None",
            "status": "InProgress"
        },
        "CYCLETASK-4": {
            "title": self.task_group_tasks_active[3]["title"] + " four",
            "description":
                self.task_group_tasks_active[3]["description"] + " four",
            "start_date": "2016-06-19",
            "end_date": "2016-06-24",
            "finished_date": "2016-07-19 00:00:00",
            "verified_date": "None",
            "status": "Finished"
        },
        "CYCLETASK-5": {
            "title": self.task_group_tasks_active[4]["title"] + " five",
            "description":
                self.task_group_tasks_active[4]["description"] + " five",
            "start_date": "2016-06-25",
            "end_date": "2016-06-30",
            "finished_date": "2016-07-25 00:00:00",
            "verified_date": "2016-08-30 00:00:00",
            "status": "Verified"
        },
        "CYCLETASK-6": {
            "title": self.task_group_tasks_historical[0]["title"] + " one",
            "description":
                self.task_group_tasks_historical[0]["description"] + " one",
            "start_date": "2014-04-01",
            "end_date": "2014-04-06",
            "finished_date": "2014-05-01 00:00:00",
            "verified_date": "2014-06-06 00:00:00",
            "status": "Assigned"
        },
        "CYCLETASK-7": {
            "title": self.task_group_tasks_historical[1]["title"] + " two",
            "description":
                self.task_group_tasks_historical[1]["description"] + " two",
            "start_date": "2014-04-07",
            "end_date": "2014-04-12",
            "finished_date": "2014-05-07 00:00:00",
            "verified_date": "None",
            "status": "Declined"
        },
        "CYCLETASK-8": {
            "title": self.task_group_tasks_historical[2]["title"] + " three",
            "description":
                self.task_group_tasks_historical[2]["description"] + " three",
            "start_date": "2014-04-13",
            "end_date": "2014-04-18",
            "finished_date": "2014-05-13 00:00:00",
            "verified_date": "2014-06-18 00:00:00",
            "status": "InProgress"
        },
        "CYCLETASK-9": {
            "title": self.task_group_tasks_historical[3]["title"] + " four",
            "description":
                self.task_group_tasks_historical[3]["description"] + " four",
            "start_date": "2014-04-19",
            "end_date": "2014-04-24",
            "finished_date": "2014-05-19 00:00:00",
            "verified_date": "None",
            "status": "Finished"
        },
        "CYCLETASK-10": {
            "title": self.task_group_tasks_historical[4]["title"] + " five",
            "description":
                self.task_group_tasks_historical[4]["description"] + " five",
            "start_date": "2014-04-25",
            "end_date": "2014-04-30",
            "finished_date": "2014-05-25 00:00:00",
            "verified_date": "2014-06-30 00:00:00",
            "status": "Verified"
        }
    }

    # Below is description of warning for non-importable columns. It is needed
    # for test_cycle_task_warnings.
    importable_column_names = []
    for field_name in CycleTaskGroupObjectTask.IMPORTABLE_FIELDS:
      if field_name == 'slug':
        continue
      # pylint: disable=protected-access
      name = CycleTaskGroupObjectTask._aliases.get(field_name, field_name)
      if isinstance(name, dict):
        name = name['display_name']
      importable_column_names.append(name)
    self.expected_warnings = self.generate_expected_warning(
        *importable_column_names)

    # This is an error message which should be shown during
    # test_cycle_task_create_error test
    self.expected_create_error = {
        'Cycle Task': {
            'row_errors': {errors.CREATE_INSTANCE_ERROR.format(line=13)}
        }
    }

    # Below is expected date errors for test_cycle_task_date_error. They should
    # be shown during date validator's tests.
    self.expected_date_error = {
        'Cycle Task': {
            'row_errors': {
                errors.INVALID_START_END_DATES.format(
                    line=3,
                    start_date="Start Date",
                    end_date="End Date",
                ),
                errors.INVALID_STATUS_DATE_CORRELATION.format(
                    line=4,
                    date="Actual Finish Date",
                    status="not Finished",
                ),
                errors.INVALID_STATUS_DATE_CORRELATION.format(
                    line=5,
                    date="Actual Verified Date",
                    status="not Verified",
                ),
                errors.INVALID_STATUS_DATE_CORRELATION.format(
                    line=6,
                    date="Actual Verified Date",
                    status="not Verified",
                ),
                errors.INVALID_START_END_DATES.format(
                    line=7,
                    start_date="Actual Finish Date",
                    end_date="Actual Verified Date",
                ),
                errors.INVALID_START_END_DATES.format(
                    line=8,
                    start_date="Start Date",
                    end_date="End Date",
                ),
                errors.MISSING_VALUE_ERROR.format(
                    line=9,
                    column_name="Actual Finish Date",
                ),
                errors.INVALID_START_END_DATES.format(
                    line=10,
                    start_date="Actual Finish Date",
                    end_date="Actual Verified Date",
                ),
            },
        }
    }
    # Below is expected cycle-tasks data which should appear in test DB after
    # test_cycle_task_date_error run
    self.expected_cycle_task_date_error = dict()
    self.expected_cycle_task_date_error.update(
        self.generated_cycle_tasks_active)
    self.expected_cycle_task_date_error.update(
        self.generated_cycle_tasks_historical)
    self.expected_cycle_task_date_error["CYCLETASK-9"] = (
        self.expected_cycle_task_correct["CYCLETASK-9"])
    self.expected_cycle_task_date_error["CYCLETASK-10"] = (
        self.expected_cycle_task_correct["CYCLETASK-10"])

    # Expected error message which should be shown after
    # test_cycle_task_permission_error run
    self.expected_permission_error = {
        'Cycle Task': {
            'block_errors': {errors.PERMISSION_ERROR.format(line=2)}
        }
    }
Beispiel #4
0
class TestOneTimeWorkflowNotification(TestCase):

  """ Tests are defined in the g-sheet test grid under:
    WF EMAILS for unit tests (middle level)
  """

  def setUp(self):
    super(TestOneTimeWorkflowNotification, self).setUp()
    self.api = Api()
    self.wf_generator = WorkflowsGenerator()
    self.object_generator = ObjectGenerator()

    self.random_objects = self.object_generator.generate_random_objects()
    self.random_people = [
        self.object_generator.generate_person(user_role="Administrator")[1]
        for _ in range(5)]
    self.create_test_cases()

    self.create_users()

    db.session.query(Notification).delete()

    def init_decorator(init):
      def new_init(self, *args, **kwargs):
        init(self, *args, **kwargs)
        if hasattr(self, "created_at"):
          self.created_at = datetime.now()
      return new_init

    Notification.__init__ = init_decorator(Notification.__init__)

  def tearDown(self):
    db.session.query(Notification).delete()

  def short_dict(self, obj, plural):
    return {
        "href": "/api/%s/%d" % (plural, obj.id),
        "id": obj.id,
        "type": obj.__class__.__name__,
    }

  def setup_cycle_tasks(self):
    """Prepare environment with couple of active cycle tasks."""
    with freeze_time("2018-11-01"):
      _, workflow = self.wf_generator.generate_workflow(
          self.one_time_workflow_1
      )
      self.wf_generator.generate_cycle(workflow)
      self.wf_generator.activate_workflow(workflow)
    return all_models.CycleTaskGroupObjectTask.query

  def assert_nofication_sent_with(self, text):
    """Assert if text exists in sent notification."""
    with mock.patch("ggrc.notifications.common.send_email") as send_email:
      self.client.get("/_notifications/send_daily_digest")
      _, _, content = send_email.call_args[0]
    self.assertIn(text, content)

  def assert_nofication_sent_without(self, text):
    """Assert if text doesn't exist in sent notification."""
    with mock.patch("ggrc.notifications.common.send_email") as send_email:
      self.client.get("/_notifications/send_daily_digest")
      _, _, content = send_email.call_args[0]
    self.assertNotIn(text, content)

  def test_one_time_wf(self):
    # setup
    with freeze_time("2015-04-07 03:21:34"):
      wf_response, wf = self.wf_generator.generate_workflow(data={
          # admin will be the current user
          "notify_on_change": True,  # force real time updates
          "title": "One-time WF",
          "notify_custom_message": textwrap.dedent("""\
              Hi all.
              Did you know that Irelnd city namd Newtownmountkennedy has 19
              letters? But it's not the longest one. The recordsman is the
              city in New Zealand that contains 97 letter."""),
      })

      _, tg = self.wf_generator.generate_task_group(wf, data={
          "title": "TG #1 for the One-time WF",
          "contact": self.short_dict(self.tgassignee1, "people"),
      })

      self.wf_generator.generate_task_group_task(tg, {
          "title": "task #1 for one-time workflow",
          "contact": self.short_dict(self.member1, "people"),
          "start_date": "04/07/2015",
          "end_date": "04/15/2015",
      })

      self.wf_generator.generate_task_group_object(tg, self.random_objects[0])
      self.wf_generator.generate_task_group_object(tg, self.random_objects[1])

    # test
    with freeze_time("2015-04-07 03:21:34"):
      cycle_response, cycle = self.wf_generator.generate_cycle(wf)
      self.wf_generator.activate_workflow(wf)

      common.get_daily_notifications()

  def test_deprecated_ct_acl_update(self):
    """Test if acl update for deprecated CT will not create notification."""
    cycle_task = self.setup_cycle_tasks().first()
    cycle_task_title = cycle_task.title
    response = self.api.put(cycle_task, {"status": "Deprecated"})
    self.assert200(response)
    self.assert_nofication_sent_without(cycle_task_title)

    task_assignee = all_models.AccessControlRole.query.filter_by(
        name="Task Assignees",
        object_type="CycleTaskGroupObjectTask",
    ).first()
    person = self.object_generator.generate_person(user_role="Creator")[1]
    response = self.api.put(
        cycle_task,
        {
            "access_control_list": [{
                "ac_role_id": task_assignee.id,
                "person": {
                    "id": person.id,
                    "type": "Person",
                }
            }]
        }
    )
    self.assert200(response)
    self.assert_nofication_sent_without(cycle_task_title)

  def test_restore_deprecated_ct(self):
    """Test notifications for CT which was restored from Deprecated."""
    cycle_task = self.setup_cycle_tasks().first()
    cycle_task_title = cycle_task.title

    self.assert_nofication_sent_with(cycle_task_title)

    response = self.api.put(cycle_task, {"status": "Deprecated"})
    self.assert200(response)
    self.assert_nofication_sent_without(cycle_task_title)

    response = self.api.put(cycle_task, {"status": "Assigned"})
    self.assert200(response)
    self.assert_nofication_sent_with(cycle_task_title)

  def create_test_cases(self):
    def person_dict(person_id):
      return {
          "href": "/api/people/%d" % person_id,
          "id": person_id,
          "type": "Person"
      }

    self.one_time_workflow_1 = {
        "title": "one time test workflow",
        "description": "some test workflow",
        # admin will be current user with id == 1
        "task_groups": [{
            "title": "one time task group",
            "task_group_tasks": [{
                "title": "task_{}".format(str(uuid.uuid4())),
                "description": "some task",
                "contact": person_dict(self.random_people[0].id),
                "start_date": date(2015, 5, 1),  # friday
                "end_date": date(2015, 5, 5),
            }, {
                "title": "task_{}".format(str(uuid.uuid4())),
                "description": "some task",
                "contact": person_dict(self.random_people[1].id),
                "start_date": date(2015, 5, 4),
                "end_date": date(2015, 5, 7),
            }],
            "task_group_objects": self.random_objects[:2]
        }, {
            "title": "another one time task group",
            "task_group_tasks": [{
                "title": "task_{}".format(str(uuid.uuid4())),
                "description": "some task",
                "contact": person_dict(self.random_people[0].id),
                "start_date": date(2015, 5, 8),  # friday
                "end_date": date(2015, 5, 12),
            }, {
                "title": "task_{}".format(str(uuid.uuid4())),
                "description": "some task",
                "contact": person_dict(self.random_people[2].id),
                "start_date": date(2015, 5, 1),  # friday
                "end_date": date(2015, 5, 5),
            }],
            "task_group_objects": []
        }]
    }

  def create_users(self):
    _, self.admin1 = self.object_generator.generate_person(
        # data={"name": "User1 Admin1", "email": "*****@*****.**"},
        user_role="Administrator")
    _, self.tgassignee1 = self.object_generator.generate_person(
        # data={"name": "User2 TGassignee1",
        #       "email": "*****@*****.**"},
        user_role="Administrator")
    _, self.member1 = self.object_generator.generate_person(
        # data={"name": "User3 Member1", "email": "*****@*****.**"},
        user_role="Administrator")
    _, self.member2 = self.object_generator.generate_person(
        # data={"name": "User4 Member2", "email": "*****@*****.**"},
        user_role="Administrator")
Beispiel #5
0
class TestOneTimeWorkflowNotification(TestCase):
    """ Tests are defined in the g-sheet test grid under:
    WF EMAILS for unit tests (middle level)
  """
    def setUp(self):
        super(TestOneTimeWorkflowNotification, self).setUp()
        self.api = Api()
        self.wf_generator = WorkflowsGenerator()
        self.object_generator = ObjectGenerator()

        self.random_objects = self.object_generator.generate_random_objects()
        self.random_people = [
            self.object_generator.generate_person(user_role="Administrator")[1]
            for _ in range(5)
        ]
        self.create_test_cases()

        self.create_users()

        db.session.query(Notification).delete()

        def init_decorator(init):
            def new_init(self, *args, **kwargs):
                init(self, *args, **kwargs)
                if hasattr(self, "created_at"):
                    self.created_at = datetime.now()

            return new_init

        Notification.__init__ = init_decorator(Notification.__init__)

    def tearDown(self):
        db.session.query(Notification).delete()

    def short_dict(self, obj, plural):
        return {
            "href": "/api/%s/%d" % (plural, obj.id),
            "id": obj.id,
            "type": obj.__class__.__name__,
        }

    def test_one_time_wf(self):
        # setup
        with freeze_time("2015-04-07 03:21:34"):
            wf_response, wf = self.wf_generator.generate_workflow(
                data={
                    "owners":
                    None,  # owner will be the current user
                    "notify_on_change":
                    True,  # force real time updates
                    "title":
                    "One-time WF",
                    "notify_custom_message":
                    textwrap.dedent("""\
              Hi all.
              Did you know that Irelnd city namd Newtownmountkennedy has 19
              letters? But it's not the longest one. The recordsman is the
              city in New Zealand that contains 97 letter."""),
                })

            _, tg = self.wf_generator.generate_task_group(
                wf,
                data={
                    "title": "TG #1 for the One-time WF",
                    "contact": self.short_dict(self.tgassignee1, "people"),
                })

            self.wf_generator.generate_task_group_task(
                tg, {
                    "title": "task #1 for one-time workflow",
                    "contact": self.short_dict(self.member1, "people"),
                    "start_date": "04/07/2015",
                    "end_date": "04/15/2015",
                })

            self.wf_generator.generate_task_group_object(
                tg, self.random_objects[0])
            self.wf_generator.generate_task_group_object(
                tg, self.random_objects[1])

        # test
        with freeze_time("2015-04-07 03:21:34"):
            cycle_response, cycle = self.wf_generator.generate_cycle(wf)
            self.wf_generator.activate_workflow(wf)

            common.get_daily_notifications()

    def create_test_cases(self):
        def person_dict(person_id):
            return {
                "href": "/api/people/%d" % person_id,
                "id": person_id,
                "type": "Person"
            }

        self.one_time_workflow_1 = {
            "title":
            "one time test workflow",
            "description":
            "some test workflow",
            "owners": [person_dict(self.random_people[3].id)],
            "task_groups": [
                {
                    "title":
                    "one time task group",
                    "task_group_tasks": [
                        {
                            "title": "task 1",
                            "description": "some task",
                            "contact": person_dict(self.random_people[0].id),
                            "start_date": date(2015, 5, 1),  # friday
                            "end_date": date(2015, 5, 5),
                        },
                        {
                            "title": "task 2",
                            "description": "some task",
                            "contact": person_dict(self.random_people[1].id),
                            "start_date": date(2015, 5, 4),
                            "end_date": date(2015, 5, 7),
                        }
                    ],
                    "task_group_objects":
                    self.random_objects[:2]
                },
                {
                    "title":
                    "another one time task group",
                    "task_group_tasks": [
                        {
                            "title": "task 1 in tg 2",
                            "description": "some task",
                            "contact": person_dict(self.random_people[0].id),
                            "start_date": date(2015, 5, 8),  # friday
                            "end_date": date(2015, 5, 12),
                        },
                        {
                            "title": "task 2 in tg 2",
                            "description": "some task",
                            "contact": person_dict(self.random_people[2].id),
                            "start_date": date(2015, 5, 1),  # friday
                            "end_date": date(2015, 5, 5),
                        }
                    ],
                    "task_group_objects": []
                }
            ]
        }

    def create_users(self):
        _, self.owner1 = self.object_generator.generate_person(
            # data={"name": "User1 Owner1", "email": "*****@*****.**"},
            user_role="Administrator")
        _, self.tgassignee1 = self.object_generator.generate_person(
            # data={"name": "User2 TGassignee1",
            #       "email": "*****@*****.**"},
            user_role="Administrator")
        _, self.member1 = self.object_generator.generate_person(
            # data={"name": "User3 Member1", "email": "*****@*****.**"},
            user_role="Administrator")
        _, self.member2 = self.object_generator.generate_person(
            # data={"name": "User4 Member2", "email": "*****@*****.**"},
            user_role="Administrator")
class TestOneTimeWorkflowNotification(TestCase):

  """ Tests are defined in the g-sheet test grid under:
    WF EMAILS for unit tests (middle level)
  """

  def setUp(self):
    super(TestOneTimeWorkflowNotification, self).setUp()
    self.api = Api()
    self.wf_generator = WorkflowsGenerator()
    self.object_generator = ObjectGenerator()

    self.random_objects = self.object_generator.generate_random_objects()
    self.random_people = [
        self.object_generator.generate_person(user_role="Administrator")[1]
        for _ in range(5)]
    self.create_test_cases()

    self.create_users()

    db.session.query(Notification).delete()

    def init_decorator(init):
      def new_init(self, *args, **kwargs):
        init(self, *args, **kwargs)
        if hasattr(self, "created_at"):
          self.created_at = datetime.now()
      return new_init

    Notification.__init__ = init_decorator(Notification.__init__)

  def tearDown(self):
    db.session.query(Notification).delete()

  def short_dict(self, obj, plural):
    return {
        "href": "/api/%s/%d" % (plural, obj.id),
        "id": obj.id,
        "type": obj.__class__.__name__,
    }

  def test_one_time_wf(self):
    # setup
    with freeze_time("2015-04-07 03:21:34"):
      wf_response, wf = self.wf_generator.generate_workflow(data={
          # admin will be the current user
          "notify_on_change": True,  # force real time updates
          "title": "One-time WF",
          "notify_custom_message": textwrap.dedent("""\
              Hi all.
              Did you know that Irelnd city namd Newtownmountkennedy has 19
              letters? But it's not the longest one. The recordsman is the
              city in New Zealand that contains 97 letter."""),
      })

      _, tg = self.wf_generator.generate_task_group(wf, data={
          "title": "TG #1 for the One-time WF",
          "contact": self.short_dict(self.tgassignee1, "people"),
      })

      self.wf_generator.generate_task_group_task(tg, {
          "title": "task #1 for one-time workflow",
          "contact": self.short_dict(self.member1, "people"),
          "start_date": "04/07/2015",
          "end_date": "04/15/2015",
      })

      self.wf_generator.generate_task_group_object(tg, self.random_objects[0])
      self.wf_generator.generate_task_group_object(tg, self.random_objects[1])

    # test
    with freeze_time("2015-04-07 03:21:34"):
      cycle_response, cycle = self.wf_generator.generate_cycle(wf)
      self.wf_generator.activate_workflow(wf)

      common.get_daily_notifications()

  def create_test_cases(self):
    def person_dict(person_id):
      return {
          "href": "/api/people/%d" % person_id,
          "id": person_id,
          "type": "Person"
      }

    self.one_time_workflow_1 = {
        "title": "one time test workflow",
        "description": "some test workflow",
        # admin will be current user with id == 1
        "task_groups": [{
            "title": "one time task group",
            "task_group_tasks": [{
                "title": "task 1",
                "description": "some task",
                "contact": person_dict(self.random_people[0].id),
                "start_date": date(2015, 5, 1),  # friday
                "end_date": date(2015, 5, 5),
            }, {
                "title": "task 2",
                "description": "some task",
                "contact": person_dict(self.random_people[1].id),
                "start_date": date(2015, 5, 4),
                "end_date": date(2015, 5, 7),
            }],
            "task_group_objects": self.random_objects[:2]
        }, {
            "title": "another one time task group",
            "task_group_tasks": [{
                "title": "task 1 in tg 2",
                "description": "some task",
                "contact": person_dict(self.random_people[0].id),
                "start_date": date(2015, 5, 8),  # friday
                "end_date": date(2015, 5, 12),
            }, {
                "title": "task 2 in tg 2",
                "description": "some task",
                "contact": person_dict(self.random_people[2].id),
                "start_date": date(2015, 5, 1),  # friday
                "end_date": date(2015, 5, 5),
            }],
            "task_group_objects": []
        }]
    }

  def create_users(self):
    _, self.admin1 = self.object_generator.generate_person(
        # data={"name": "User1 Admin1", "email": "*****@*****.**"},
        user_role="Administrator")
    _, self.tgassignee1 = self.object_generator.generate_person(
        # data={"name": "User2 TGassignee1",
        #       "email": "*****@*****.**"},
        user_role="Administrator")
    _, self.member1 = self.object_generator.generate_person(
        # data={"name": "User3 Member1", "email": "*****@*****.**"},
        user_role="Administrator")
    _, self.member2 = self.object_generator.generate_person(
        # data={"name": "User4 Member2", "email": "*****@*****.**"},
        user_role="Administrator")
class TestCycleTaskImportUpdate(BaseTestCycleTaskImportUpdate):
    """ This class contains simple cycle task update tests using import
  functionality
  """

    CSV_DIR = join(abspath(dirname(__file__)), "test_csvs/")

    IMPORTABLE_COLUMN_NAMES = [
        "Summary",
        "Task Description",
        "Start Date",
        "Due Date",
        "State",
        "Task Assignees",
        "Task Secondary Assignees",
    ]

    def setUp(self):
        super(TestCycleTaskImportUpdate, self).setUp()
        self.wf_generator = WorkflowsGenerator()
        self.object_generator = ObjectGenerator()
        self.random_objects = self.object_generator.generate_random_objects(2)
        self.person_1 = ggrc_factories.PersonFactory()
        self.ftime_active = "2016-07-01"
        self.ftime_historical = "2014-05-01"
        self._create_test_cases_data()
        # It is needed because cycle-tasks are generated automatically with
        # 'slug' based on auto_increment 'id' field.
        # At start of each test we suppose that created cycle-task's 'slug'
        # lie in range from 1 to 10.
        db.session.execute('ALTER TABLE cycle_task_group_object_tasks '
                           'AUTO_INCREMENT = 1')

    def test_cycle_task_correct(self):
        """Test cycle task update via import with correct data"""
        self._generate_cycle_tasks()
        with freeze_time(self.ftime_active):
            cycle_task = wf_factories.CycleTaskGroupObjectTaskFactory(
                description="task active description 1")
            self.import_data(
                collections.OrderedDict([
                    ("object_type", "Cycle Task Group Object Task"),
                    ("Code*", cycle_task.slug),
                    ("description", "task active description 1"),
                ]))

        self._cmp_tasks(self.expected_cycle_task_correct)

    def test_cycle_task_warnings(self):
        """Test cycle task update via import with data which is the reason of
    warnings about non-importable columns."""
        self._generate_cycle_tasks()

        expected_warnings = {
            'Cycle Task': {
                'block_warnings': {
                    errors.ONLY_IMPORTABLE_COLUMNS_WARNING.format(
                        line=2,
                        columns=", ".join(self.IMPORTABLE_COLUMN_NAMES))
                },
                'row_warnings': []
            }
        }

        with freeze_time(self.ftime_active):
            person = ggrc_factories.PersonFactory()
            cycle_task = wf_factories.CycleTaskGroupObjectTaskFactory(
                title="task active title134567890")
            ct_data = collections.OrderedDict([
                ("object_type", "Cycle Task Group Object Task"),
                ("Code*", cycle_task.slug),
                ("Summary*", "task active title1-Updated"),
                ("Task Description", "task active title1 description"),
                ("Start Date", self.ftime_historical),
                ("Due Date", self.ftime_active),
                ("Actual Finish Date", self.ftime_active),
                ("Actual Verified Date", self.ftime_active),
                ("State", "Assigned"),
                ("Task Assignees", person.email),
                ("Task Secondary Assignees", person.email),
            ])

            response = self.import_data(ct_data)
            self._check_csv_response(response, expected_warnings)
            self._cmp_tasks(self.expected_cycle_task_correct)

    def test_cycle_task_permission_error(self):
        """Test cycle task update via import with non-admin user which is the
    reason of error. Only admin can update cycle tasks via import."""
        self._generate_cycle_tasks()
        with freeze_time(self.ftime_active):
            _, creator = self.object_generator.generate_person(
                user_role="Creator")

            cycle_task = wf_factories.CycleTaskGroupObjectTaskFactory(
                description="task active description 1")
            ct_data = collections.OrderedDict([
                ("object_type", "Cycle Task Group Object Task"),
                ("Code*", cycle_task.slug),
            ])
            response = self.import_data(ct_data, person=creator, safe=False)
            self._check_csv_response(response, self.expected_permission_error)
            # Cycle tasks' data shouldn't be changed in test DB after import run from
            # non-admin user

            expected_cycle_task_permission_error = {}
            expected_cycle_task_permission_error.update(
                self.generated_cycle_tasks_active)
            expected_cycle_task_permission_error.update(
                self.generated_cycle_tasks_historical)
            self._cmp_tasks(expected_cycle_task_permission_error)

    def _cmp_tasks(self, expected_ctasks):
        """Compare tasks values from argument's list and test DB."""
        for ctask in db.session.query(CycleTaskGroupObjectTask).all():
            if ctask.title not in expected_ctasks:
                continue
            exp_task = expected_ctasks[ctask.title]
            for attr, val in exp_task.iteritems():
                self.assertEqual(
                    str(getattr(ctask, attr, None)), val,
                    "attr {} value for {} not expected".format(
                        attr, ctask.title))

    # pylint: disable=too-many-arguments
    def _activate_workflow(self, ftime, workflow, task_group, task_group_tasks,
                           random_object, cycle_tasks):
        """Helper which is responsible for active cycle-tasks creation"""
        with freeze_time(ftime):
            _, wf = self.wf_generator.generate_workflow(workflow)
            _, tg = self.wf_generator.generate_task_group(wf, task_group)
            for task in task_group_tasks:
                self.wf_generator.generate_task_group_task(tg, task)
            self.wf_generator.generate_task_group_object(tg, random_object)
            _, cycle = self.wf_generator.generate_cycle(wf)
            self.wf_generator.activate_workflow(wf)
            for exp_slug, exp_task in cycle_tasks.iteritems():
                obj = db.session.query(CycleTaskGroupObjectTask).filter_by(
                    slug=exp_slug).first()
                if exp_task["status"] == "Verified":
                    self.wf_generator.modify_object(obj,
                                                    {"status": "Finished"})
                self.wf_generator.modify_object(obj,
                                                {"status": exp_task["status"]})
        self._cmp_tasks(cycle_tasks)
        return cycle

    def _generate_cycle_tasks(self):
        """Helper which is responsible for test data creation"""
        self._activate_workflow(self.ftime_active, self.workflow_active,
                                self.task_group_active,
                                self.task_group_tasks_active,
                                self.random_objects[0],
                                self.generated_cycle_tasks_active)
        cycle = self._activate_workflow(self.ftime_historical,
                                        self.workflow_historical,
                                        self.task_group_historical,
                                        self.task_group_tasks_historical,
                                        self.random_objects[1],
                                        self.generated_cycle_tasks_historical)
        with freeze_time(self.ftime_historical):
            cycle = Cycle.query.get(cycle.id)
            self.wf_generator.modify_object(cycle, data={"is_current": False})

    def _create_test_cases_data(self):
        """Create test cases data: for object generation,
    expected data for checks"""
        def person_dict(person_id):
            """Return person data"""
            return {
                "href": "/api/people/%d" % person_id,
                "id": person_id,
                "type": "Person"
            }

        wf_admin_role_id = {
            n: i
            for (
                i,
                n) in role.get_custom_roles_for(Workflow.__name__).iteritems()
        }['Admin']

        self.workflow_active = {
            "title":
            "workflow active title",
            "description":
            "workflow active description",
            "is_verification_needed":
            True,
            "access_control_list":
            [acl_helper.get_acl_json(wf_admin_role_id, self.person_1.id)],
            "notify_on_change":
            False,
        }

        self.task_group_active = {
            "title": "task group active title",
            "contact": person_dict(self.person_1.id),
        }

        self.task_group_tasks_active = [{
            "title":
            "task active title 1",
            "description":
            "task active description 1",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/01/2016",
            "end_date":
            "07/06/2016",
        }, {
            "title":
            "task active title 2",
            "description":
            "task active description 2",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/07/2016",
            "end_date":
            "07/12/2016",
        }, {
            "title":
            "task active title 3",
            "description":
            "task active description 3",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/13/2016",
            "end_date":
            "07/18/2016",
        }, {
            "title":
            "task active title 4",
            "description":
            "task active description 4",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/19/2016",
            "end_date":
            "07/24/2016",
        }, {
            "title":
            "task active title 5",
            "description":
            "task active description 5",
            "contact":
            person_dict(self.person_1.id),
            "start_date":
            "07/25/2016",
            "end_date":
            "07/30/2016",
        }]

        # Active cycle tasks which should be generated from previous structure
        # at the beginning of each test
        self.generated_cycle_tasks_active = {
            "CYCLETASK-1": {
                "title": self.task_group_tasks_active[0]["title"],
                "description": self.task_group_tasks_active[0]["description"],
                "start_date": "2016-07-01",
                "end_date": "2016-07-06",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Assigned"
            },
            "CYCLETASK-2": {
                "title": self.task_group_tasks_active[1]["title"],
                "description": self.task_group_tasks_active[1]["description"],
                "start_date": "2016-07-07",
                "end_date": "2016-07-12",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Declined"
            },
            "CYCLETASK-3": {
                "title": self.task_group_tasks_active[2]["title"],
                "description": self.task_group_tasks_active[2]["description"],
                "start_date": "2016-07-13",
                "end_date": "2016-07-18",
                "finished_date": "None",
                "verified_date": "None",
                "status": "In Progress"
            },
            "CYCLETASK-4": {
                "title": self.task_group_tasks_active[3]["title"],
                "description": self.task_group_tasks_active[3]["description"],
                "start_date": "2016-07-19",
                "end_date": "2016-07-22",
                "finished_date": "2016-07-01",
                "verified_date": "None",
                "status": "Finished"
            },
            "CYCLETASK-5": {
                "title": self.task_group_tasks_active[4]["title"],
                "description": self.task_group_tasks_active[4]["description"],
                "start_date": "2016-07-25",
                "end_date": "2016-07-29",
                "finished_date": "2016-07-01",
                "verified_date": "2016-07-01",
                "status": "Verified"
            }
        }

        self.workflow_historical = {
            "title":
            "workflow historical title",
            "description":
            "workflow historical description",
            "is_verification_needed":
            True,
            "access_control_list":
            [acl_helper.get_acl_json(wf_admin_role_id, self.person_1.id)],
            "notify_on_change":
            False,
        }

        self.task_group_historical = {
            "title": "task group historical title",
            "contact": person_dict(self.person_1.id),
        }

        self.task_group_tasks_historical = [
            {
                "title": "task historical title 1",
                "description": "task historical description 1",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/01/2014",
                "end_date": "05/06/2014",
            },
            {
                "title": "task historical title 2",
                "description": "task historical description 2",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/07/2014",
                "end_date": "05/12/2014",
            },
            {
                "title": "task historical title 3",
                "description": "task historical description 3",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/13/2014",
                "end_date": "05/18/2014",
            },
            {
                "title": "task historical title 4",
                "description": "task historical description 4",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/19/2014",
                "end_date": "05/24/2014",
            },
            {
                "title": "task historical title 5",
                "description": "task historical description 5",
                "contact": person_dict(self.person_1.id),
                "start_date": "05/25/2014",
                "end_date": "05/30/2014",
            },
        ]

        # Historical cycle tasks which should be generated from previous structure
        # at the beginning of each test.
        self.generated_cycle_tasks_historical = {
            "CYCLETASK-6": {
                "title": self.task_group_tasks_historical[0]["title"],
                "description":
                self.task_group_tasks_historical[0]["description"],
                "start_date": "2014-05-01",
                "end_date": "2014-05-06",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Assigned"
            },
            "CYCLETASK-7": {
                "title": self.task_group_tasks_historical[1]["title"],
                "description":
                self.task_group_tasks_historical[1]["description"],
                "start_date": "2014-05-07",
                "end_date": "2014-05-12",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Declined"
            },
            "CYCLETASK-8": {
                "title": self.task_group_tasks_historical[2]["title"],
                "description":
                self.task_group_tasks_historical[2]["description"],
                "start_date": "2014-05-13",
                "end_date": "2014-05-16",
                "finished_date": "None",
                "verified_date": "None",
                "status": "In Progress"
            },
            "CYCLETASK-9": {
                "title": self.task_group_tasks_historical[3]["title"],
                "description":
                self.task_group_tasks_historical[3]["description"],
                "start_date": "2014-05-19",
                "end_date": "2014-05-23",
                "finished_date": "2014-05-01",
                "verified_date": "None",
                "status": "Finished"
            },
            "CYCLETASK-10": {
                "title": self.task_group_tasks_historical[4]["title"],
                "description":
                self.task_group_tasks_historical[4]["description"],
                "start_date": "2014-05-23",
                "end_date": "2014-05-30",
                "finished_date": "2014-05-01",
                "verified_date": "2014-05-01",
                "status": "Verified"
            }
        }

        # Expected cycle tasks which should be created in correct cycle task update
        # case. It is needed for most tests.
        self.expected_cycle_task_correct = {
            "CYCLETASK-1": {
                "title": self.task_group_tasks_active[0]["title"] + " one",
                "description":
                self.task_group_tasks_active[0]["description"] + " one",
                "start_date": "2016-06-01",
                "end_date": "2016-06-06",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Assigned"
            },
            "CYCLETASK-2": {
                "title": self.task_group_tasks_active[1]["title"] + " two",
                "description":
                self.task_group_tasks_active[1]["description"] + " two",
                "start_date": "2016-06-07",
                "end_date": "2016-06-12",
                "finished_date": "None",
                "verified_date": "None",
                "status": "Declined"
            },
            "CYCLETASK-3": {
                "title": self.task_group_tasks_active[2]["title"] + " three",
                "description":
                self.task_group_tasks_active[2]["description"] + " three",
                "start_date": "2016-06-13",
                "end_date": "2016-06-18",
                "finished_date": "None",
                "verified_date": "None",
                "status": "In Progress"
            },
            "CYCLETASK-4": {
                "title": self.task_group_tasks_active[3]["title"] + " four",
                "description":
                self.task_group_tasks_active[3]["description"] + " four",
                "start_date": "2016-06-19",
                "end_date": "2016-06-24",
                "status": "Finished"
            },
            "CYCLETASK-5": {
                "title": self.task_group_tasks_active[4]["title"] + " five",
                "description":
                self.task_group_tasks_active[4]["description"] + " five",
                "start_date": "2016-06-25",
                "end_date": "2016-06-30",
                "finished_date": "2016-07-01",
                "verified_date": "2016-07-01",
                "status": "Verified"
            },
            "CYCLETASK-6": {
                "title":
                self.task_group_tasks_historical[0]["title"] + " one",
                "description":
                self.task_group_tasks_historical[0]["description"] + " one",
                "start_date":
                "2014-04-01",
                "end_date":
                "2014-04-06",
                "finished_date":
                "None",
                "verified_date":
                "None",
                "status":
                "Assigned"
            },
            "CYCLETASK-7": {
                "title":
                self.task_group_tasks_historical[1]["title"] + " two",
                "description":
                self.task_group_tasks_historical[1]["description"] + " two",
                "start_date":
                "2014-04-07",
                "end_date":
                "2014-04-12",
                "finished_date":
                "None",
                "verified_date":
                "None",
                "status":
                "Declined"
            },
            "CYCLETASK-8": {
                "title":
                self.task_group_tasks_historical[2]["title"] + " three",
                "description":
                self.task_group_tasks_historical[2]["description"] + " three",
                "start_date":
                "2014-04-13",
                "end_date":
                "2014-04-18",
                "finished_date":
                "None",
                "verified_date":
                "None",
                "status":
                "In Progress"
            },
            "CYCLETASK-9": {
                "title":
                self.task_group_tasks_historical[3]["title"] + " four",
                "description":
                self.task_group_tasks_historical[3]["description"] + " four",
                "start_date":
                "2014-04-19",
                "end_date":
                "2014-04-24",
                "status":
                "Finished"
            },
            "CYCLETASK-10": {
                "title":
                self.task_group_tasks_historical[4]["title"] + " five",
                "description":
                self.task_group_tasks_historical[4]["description"] + " five",
                "start_date":
                "2014-04-25",
                "end_date":
                "2014-04-30",
                "finished_date":
                "2014-05-01",
                "verified_date":
                "2014-05-01",
                "status":
                "Verified"
            }
        }

        # This is an error message which should be shown during
        # test_cycle_task_create_error test
        self.expected_create_error = {
            'Cycle Task': {
                'row_errors': {errors.CREATE_INSTANCE_ERROR.format(line=13)}
            }
        }

        # Below is expected date errors for test_cycle_task_date_error. They should
        # be shown during date validator's tests.
        self.expected_date_error = {
            'Cycle Task': {
                'row_errors': {
                    errors.INVALID_START_END_DATES.format(
                        line=3,
                        start_date="Start Date",
                        end_date="End Date",
                    ),
                    errors.INVALID_START_END_DATES.format(
                        line=8,
                        start_date="Start Date",
                        end_date="End Date",
                    ),
                },
            }
        }
        # Below is expected cycle-tasks data which should appear in test DB after
        # test_cycle_task_date_error run
        self.expected_cycle_task_date_error = dict()
        self.expected_cycle_task_date_error.update(
            self.generated_cycle_tasks_active)
        self.expected_cycle_task_date_error.update(
            self.generated_cycle_tasks_historical)
        self.expected_cycle_task_date_error["CYCLETASK-9"] = (
            self.expected_cycle_task_correct["CYCLETASK-9"])
        self.expected_cycle_task_date_error["CYCLETASK-10"] = (
            self.expected_cycle_task_correct["CYCLETASK-10"])

        # Expected error message which should be shown after
        # test_cycle_task_permission_error run
        self.expected_permission_error = {
            'Cycle Task': {
                'block_errors': {errors.PERMISSION_ERROR.format(line=2)}
            }
        }