Esempio n. 1
0
class TestDocumentQueries(TestCase):
  """Tests for /query api for Document instance filtering."""

  def setUp(self):
    super(TestDocumentQueries, self).setUp()
    self.api = Api()

  @ddt.data(all_models.Document.FILE, all_models.Document.REFERENCE_URL)
  def test_filter_document_by_type(self, kind):
    """Test filter documents by document type."""
    data = {
        all_models.Document.FILE: factories.DocumentFileFactory().id,
        all_models.Document.REFERENCE_URL:
            factories.DocumentReferenceUrlFactory().id,
    }
    query_request_data = [{
        u'fields': [],
        u'filters': {
            u'expression': {
                u'left': u'kind',
                u'op': {u'name': u'='},
                u'right': kind,
            }
        },
        u'limit': [0, 5],
        u'object_name': u'Document',
        u'permissions': u'read',
        u'type': u'values',
    }]
    resp = self.api.send_request(self.api.client.post,
                                 data=query_request_data,
                                 api_link="/query")
    self.assertEqual(1, resp.json[0]["Document"]["count"])
    self.assertEqual(data[kind],
                     resp.json[0]["Document"]["values"][0]["id"])
Esempio n. 2
0
class TestDocumentQueries(TestCase):
    """Tests for /query api for Document instance filtering."""
    def setUp(self):
        super(TestDocumentQueries, self).setUp()
        self.api = Api()

    @ddt.data(all_models.Document.ATTACHMENT, all_models.Document.URL)
    def test_filter_document_by_type(self, document_type):
        """Test filter documents by document type."""
        data = {
            all_models.Document.ATTACHMENT: factories.EvidenceFactory().id,
            all_models.Document.URL: factories.UrlFactory().id,
        }
        query_request_data = [{
            u'fields': [],
            u'filters': {
                u'expression': {
                    u'left': u'document_type',
                    u'op': {
                        u'name': u'='
                    },
                    u'right': document_type,
                }
            },
            u'limit': [0, 5],
            u'object_name': u'Document',
            u'permissions': u'read',
            u'type': u'values',
        }]
        resp = self.api.send_request(self.api.client.post,
                                     data=query_request_data,
                                     api_link="/query")
        self.assertEqual(1, resp.json[0]["Document"]["count"])
        self.assertEqual(data[document_type],
                         resp.json[0]["Document"]["values"][0]["id"])
Esempio n. 3
0
class TestCommentQueries(TestCase):
  """Tests for /query api for Comment instance ordering."""

  def setUp(self):
    super(TestCommentQueries, self).setUp()
    self.api = Api()

  def test_comment_ordering(self):
    """Check ordering for comment"""
    with factories.single_commit():
      cgot = wf_factories.CycleTaskGroupObjectTaskFactory()
      comment1 = factories.CommentFactory(
          description="comment 1",
          created_at=datetime.datetime(2017, 1, 1, 7, 31, 32)
      )
      comment2 = factories.CommentFactory(
          description="comment 2",
          created_at=datetime.datetime(2017, 1, 1, 7, 31, 42)
      )
      factories.RelationshipFactory(source=comment1, destination=cgot)
      factories.RelationshipFactory(source=comment2, destination=cgot)

    query_request_data = [
        {
            u"object_name": u"Comment",
            u"filters": {
                u"expression": {
                    u"object_name": u"CycleTaskGroupObjectTask",
                    u"op": {
                        u"name": u"relevant"
                    },
                    u"ids": [cgot.id]
                }
            },
            u"order_by": [{
                u"name": u"created_at",
                u"desc": True
            }]
        }
    ]
    resp = self.api.send_request(
        self.api.client.post, data=query_request_data, api_link="/query"
    )
    self.assertEqual(2, resp.json[0]["Comment"]["count"])
    self.assertEqual(
        "comment 2", resp.json[0]["Comment"]["values"][0]["description"]
    )
    self.assertEqual(
        "comment 1", resp.json[0]["Comment"]["values"][1]["description"]
    )
Esempio n. 4
0
class TestProgramQueries(TestCase):
  """Tests for /query api for Program child parent operators."""

  def setUp(self):
    super(TestProgramQueries, self).setUp()
    self.api = Api()

  @ddt.data("child", "parent")
  def test_mega_operators(self, operator):
    """Test {0} operator"""
    with factories.single_commit():
      program_a = factories.ProgramFactory()
      program_c = factories.ProgramFactory()
      program_b = factories.ProgramFactory()
      factories.RelationshipFactory(source=program_b,
                                    destination=program_a)
      factories.RelationshipFactory(source=program_c,
                                    destination=program_b)
    program_b_id = program_b.id
    if operator == "child":
      query_id = program_c.id
    elif operator == "parent":
      query_id = program_a.id
    query_request_data = [
        {
            u"object_name": u"Program",
            u"filters": {
                u"expression": {
                    u"object_name": u"Program",
                    u"op": {
                        u"name": operator
                    },
                    u"ids": [query_id]
                }
            },
            u"order_by": [{
                u"name": u"created_at",
                u"desc": True
            }]
        }
    ]
    resp = self.api.send_request(
        self.api.client.post, data=query_request_data, api_link="/query"
    )
    self.assertEqual(1, resp.json[0]["Program"]["count"])
    self.assertEqual(
        program_b_id, resp.json[0]["Program"]["values"][0]["id"]
    )
Esempio n. 5
0
class TestProgramQueries(TestCase):
    """Tests for /query api for Program child parent operators."""
    def setUp(self):
        super(TestProgramQueries, self).setUp()
        self.api = Api()

    @ddt.data("child", "parent")
    def test_mega_operators(self, operator):
        """Test {0} operator"""
        with factories.single_commit():
            program_a = factories.ProgramFactory()
            program_c = factories.ProgramFactory()
            program_b = factories.ProgramFactory()
            factories.RelationshipFactory(source=program_b,
                                          destination=program_a)
            factories.RelationshipFactory(source=program_c,
                                          destination=program_b)
        program_b_id = program_b.id
        if operator == "child":
            query_id = program_c.id
        elif operator == "parent":
            query_id = program_a.id
        query_request_data = [{
            u"object_name":
            u"Program",
            u"filters": {
                u"expression": {
                    u"object_name": u"Program",
                    u"op": {
                        u"name": operator
                    },
                    u"ids": [query_id]
                }
            },
            u"order_by": [{
                u"name": u"created_at",
                u"desc": True
            }]
        }]
        resp = self.api.send_request(self.api.client.post,
                                     data=query_request_data,
                                     api_link="/query")
        self.assertEqual(1, resp.json[0]["Program"]["count"])
        self.assertEqual(program_b_id,
                         resp.json[0]["Program"]["values"][0]["id"])
Esempio n. 6
0
class TestCommentQueries(TestCase):
    """Tests for /query api for Comment instance ordering."""
    def setUp(self):
        super(TestCommentQueries, self).setUp()
        self.api = Api()

    def test_comment_ordering(self):
        """Check ordering for comment"""
        with factories.single_commit():
            cgot = wf_factories.CycleTaskGroupObjectTaskFactory()
            comment1 = factories.CommentFactory(description="comment 1",
                                                created_at=datetime.datetime(
                                                    2017, 1, 1, 7, 31, 32))
            comment2 = factories.CommentFactory(description="comment 2",
                                                created_at=datetime.datetime(
                                                    2017, 1, 1, 7, 31, 42))
            factories.RelationshipFactory(source=comment1, destination=cgot)
            factories.RelationshipFactory(source=comment2, destination=cgot)

        query_request_data = [{
            u"object_name":
            u"Comment",
            u"filters": {
                u"expression": {
                    u"object_name": u"CycleTaskGroupObjectTask",
                    u"op": {
                        u"name": u"relevant"
                    },
                    u"ids": [cgot.id]
                }
            },
            u"order_by": [{
                u"name": u"created_at",
                u"desc": True
            }]
        }]
        resp = self.api.send_request(self.api.client.post,
                                     data=query_request_data,
                                     api_link="/query")
        self.assertEqual(2, resp.json[0]["Comment"]["count"])
        self.assertEqual("comment 2",
                         resp.json[0]["Comment"]["values"][0]["description"])
        self.assertEqual("comment 1",
                         resp.json[0]["Comment"]["values"][1]["description"])
Esempio n. 7
0
class TestFilterByAuditor(TestCase):
  """ Test for filter by Auditor. """

  def setUp(self):
    super(TestFilterByAuditor, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()
    _, self.auditor = self.generator.generate_person(user_role="Creator")
    auditor_role = all_models.Role.query.filter_by(name="Auditor").first()
    with factories.single_commit():
      self.audit = factories.AuditFactory(status="In Progress")
      self.audit_id = self.audit.id
      audit_context = factories.ContextFactory()
      self.audit.context = audit_context
      rbac_factories.UserRoleFactory(
          context=audit_context,
          role=auditor_role,
          person=self.auditor)
    self.api.set_user(self.auditor)

  def test_query_audits_by_auditor(self):
    """test get audit as query get"""
    objects = self.api.get_query(all_models.Audit, "")
    self.assertEqual(1, len(objects.json["audits_collection"]["audits"]))
    audit_dict = objects.json["audits_collection"]["audits"][0]
    self.assertEqual(self.audit_id, audit_dict["id"])

  def test_filter_audits_by_auditor(self):
    """Test query on audit Global Search.

    This query is the fact query that frontend is sending in global search.
    """
    query_request_data = [
        {
            u'fields': [],
            u'filters': {
                u'expression': {
                    u'left': {
                        u'left': u'status',
                        u'op': {u'name': u'='},
                        u'right': u'Planned'
                    },
                    u'op': {u'name': u'OR'},
                    u'right': {
                        u'left': {
                            u'left': u'status',
                            u'op': {u'name': u'='},
                            u'right': u'In Progress'
                        },
                        u'op': {u'name': u'OR'},
                        u'right': {
                            u'left': {
                                u'left': u'status',
                                u'op': {u'name': u'='},
                                u'right': u'Manager Review'
                            },
                            u'op': {u'name': u'OR'},
                            u'right': {
                                u'left': {
                                    u'left': u'status',
                                    u'op': {u'name': u'='},
                                    u'right': u'Ready for External Review',
                                },
                                u'op': {u'name': u'OR'},
                                u'right': {
                                    u'left': u'status',
                                    u'op': {u'name': u'='},
                                    u'right': u'Completed',
                                }
                            },
                        },
                    },
                },
                u'keys': [u'status'],
                u'order_by': {
                    u'compare': None,
                    u'keys': [],
                    u'order': u'',
                }
            },
            u'limit': [0, 5],
            u'object_name': u'Audit',
            u'permissions': u'read',
            u'type': u'values',
        },
        {
            u'filters': {
                u'expression': {
                    u'ids': [u'150'],
                    u'object_name': u'undefined',
                    u'op': {u'name': u'relevant'}
                },
                u'keys': [],
                u'order_by': {u'compare': None, u'keys': [], u'order': u''}
            },
            u'object_name': u'Audit',
            u'type': u'ids',
        },
    ]
    resp = self.api.send_request(self.api.client.post,
                                 data=query_request_data,
                                 api_link="/query")
    self.assertEqual(1, resp.json[0]["Audit"]["count"])
    self.assertEqual(self.audit_id, resp.json[0]["Audit"]["values"][0]["id"])
Esempio n. 8
0
class TestWorkflowsApiPost(TestCase):

  def setUp(self):
    super(TestWorkflowsApiPost, self).setUp()
    self.api = Api()
    self.generator = wf_generator.WorkflowsGenerator()

  def tearDown(self):
    pass

  def test_send_invalid_data(self):
    data = self.get_workflow_dict()
    del data["workflow"]["title"]
    del data["workflow"]["context"]
    response = self.api.post(all_models.Workflow, data)
    self.assert400(response)
    # TODO: check why response.json["message"] is empty

  def test_create_one_time_workflows(self):
    data = self.get_workflow_dict()
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_weekly_workflow(self):
    """Test create valid weekly wf"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 7
    data["workflow"]["unit"] = "day"
    data["workflow"]["title"] = "Weekly"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_annually_workflow(self):
    """Test create valid annual wf"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 12
    data["workflow"]["unit"] = "month"
    data["workflow"]["title"] = "Annually"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  @ddt.data("wrong value", 0, -4)
  def test_create_wrong_repeat_every_workflow(self, value):  # noqa pylint: disable=invalid-name
    """Test case for invalid repeat_every value"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = value
    data["workflow"]["unit"] = "month"
    data["workflow"]["title"] = "Wrong wf"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 400)

  def test_create_wrong_unit_workflow(self):
    """Test case for invalid unit value"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 12
    data["workflow"]["unit"] = "wrong value"
    data["workflow"]["title"] = "Wrong wf"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 400)

  def test_create_task_group(self):
    wf_data = self.get_workflow_dict()
    wf_data["workflow"]["title"] = "Create_task_group"
    wf_response = self.api.post(all_models.Workflow, wf_data)

    data = self.get_task_group_dict(wf_response.json["workflow"])

    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

  # TODO: Api should be able to handle invalid data
  @unittest.skip("Not implemented.")
  def test_create_task_group_invalid_workflow_data(self):  # noqa pylint: disable=invalid-name
    data = self.get_task_group_dict({"id": -1, "context": {"id": -1}})
    response = self.api.post(all_models.TaskGroup, data)
    self.assert400(response)

  @staticmethod
  def get_workflow_dict():
    data = {
        "workflow": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "title": "One_time",
            "description": "",
            "unit": None,
            "repeat_every": None,
            "notify_on_change": False,
            "task_group_title": "Task Group 1",
            "notify_custom_message": "",
            "is_verification_needed": True,
            "owners": None,
            "context": None,
        }
    }
    return data

  @staticmethod
  def get_task_group_dict(workflow):
    data = {
        "task_group": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "_transient": {},
            "contact": {
                "id": 1,
                "href": "/api/people/1",
                "type": "Person"
            },
            "workflow": {
                "id": workflow["id"],
                "href": "/api/workflows/%d" % workflow["id"],
                "type": "Workflow"
            },
            "context": {
                "id": workflow["context"]["id"],
                "href": "/api/contexts/%d" % workflow["context"]["id"],
                "type": "Context"
            },
            "modal_title": "Create Task Group",
            "title": "Create_task_group",
            "description": "",
        }
    }
    return data

  @ddt.data({},
            {"repeat_every": 5,
             "unit": "month"})
  def test_repeat_multiplier_field(self, data):
    """Check repeat_multiplier is set to 0 after wf creation.
    """
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(**data)
    workflow_id = workflow.id
    self.assertEqual(
        0,
        all_models.Workflow.query.get(workflow_id).repeat_multiplier
    )

  # TODO: Unskip in the patch 2
  @unittest.skip("Will be activated in patch 2")
  def test_change_to_one_time_wf(self):
    """Check repeat_every and unit can be set to Null only together."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                              unit="day")
    resp = self.api.put(workflow, {"repeat_every": None,
                                   "unit": None})
    self.assert200(resp)

  @ddt.data({"repeat_every": 5},
            {"unit": "month"})
  def test_change_repeat_every(self, data):
    """Check repeat_every or unit can not be changed once set."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory()
    resp = self.api.put(workflow, data)
    self.assert400(resp)

  def test_not_change_to_one_time_wf(self):
    """Check repeat_every or unit can't be set to Null separately.
    This test will be useful in the 2nd patch, where we allow to change
    WF setup
    """
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                              unit="day")
    resp = self.api.put(workflow, {"repeat_every": None})
    self.assert400(resp)
    resp = self.api.put(workflow, {"unit": None})
    self.assert400(resp)

  @ddt.data(True, False)
  def test_autogen_verification_flag(self, flag):
    """Check is_verification_needed flag for activate WF action."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
      group = wf_factories.TaskGroupFactory(workflow=workflow)
      wf_factories.TaskGroupTaskFactory(task_group=group)
    data = [{
        "cycle": {
            "autogenerate": True,
            "isOverdue": False,
            "workflow": {
                "id": workflow.id,
                "type": "Workflow",
            },
            "context": {
                "id": workflow.context_id,
                "type": "Context",
            },
        }
    }]
    resp = self.api.send_request(
        self.api.client.post,
        api_link="/api/cycles",
        data=data)
    cycle_id = resp.json[0][1]["cycle"]["id"]
    self.assertEqual(
        flag,
        all_models.Cycle.query.get(cycle_id).is_verification_needed)

  @ddt.data(True, False)
  def test_change_verification_flag_positive(self, flag):  # noqa pylint: disable=invalid-name
    """is_verification_needed flag is changeable for DRAFT workflow."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": not flag})
    self.assert200(resp)
    self.assertEqual(
        all_models.Workflow.query.get(workflow_id).is_verification_needed,
        not flag)

  @ddt.data(True, False)
  def test_change_verification_flag_negative(self, flag):  # noqa pylint: disable=invalid-name
    with freezegun.freeze_time("2017-08-10"):
      with factories.single_commit():
        workflow = wf_factories.WorkflowFactory(
            unit=all_models.Workflow.WEEK_UNIT,
            is_verification_needed=flag,
            repeat_every=1)
        wf_factories.TaskGroupTaskFactory(
            task_group=wf_factories.TaskGroupFactory(
                context=factories.ContextFactory(),
                workflow=workflow
            ),
            # Two cycles should be created
            start_date=datetime.date(2017, 8, 3),
            end_date=datetime.date(2017, 8, 7))
      workflow_id = workflow.id
      self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
      self.generator.activate_workflow(workflow)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.status, all_models.Workflow.ACTIVE)
      resp = self.api.put(workflow, {"is_verification_needed": not flag})
      self.assert400(resp)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.is_verification_needed, flag)

      # End all current cycles
      for cycle in workflow.cycles:
        self.generator.modify_object(cycle, {'is_current': False})
      workflow = all_models.Workflow.query.filter(
          all_models.Workflow.id == workflow_id).first()
      self.assertEqual(workflow.status, all_models.Workflow.INACTIVE)
      resp = self.api.put(workflow, {"is_verification_needed": not flag})
      self.assert400(resp)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.is_verification_needed, flag)

  @ddt.data(True, False)
  def test_not_change_vf_flag(self, flag):
    """Check is_verification_needed not change on update."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": flag})
    self.assert200(resp)
    self.assertEqual(
        flag,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)

  @ddt.data(True, False, None)
  def test_create_vf_flag(self, flag):
    """Check is_verification_needed flag setup on create."""
    data = self.get_workflow_dict()
    if flag is None:
      data['workflow'].pop('is_verification_needed', None)
    else:
      data['workflow']['is_verification_needed'] = flag
    resp = self.api.post(all_models.Workflow, data)
    self.assertEqual(201, resp.status_code)
    workflow_id = resp.json['workflow']['id']
    self.assertEqual(
        flag if flag is not None else True,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestWorkflowsApiPost(TestCase):
    """Test class for ggrc workflow api post action."""
    def setUp(self):
        super(TestWorkflowsApiPost, self).setUp()
        self.api = Api()
        self.generator = wf_generator.WorkflowsGenerator()
        self.wf_admin_id = all_models.Person.query.first().id
        with factories.single_commit():
            self.people_ids = [factories.PersonFactory().id for _ in xrange(6)]

    def tearDown(self):
        pass

    def _delete_and_check_related_acl(self, related_model, exp_acl_count,
                                      is_deleted):
        """Delete related model and check remaining ACL count.

    Args:
        related_model: related model class
        exp_acl_count: expected related ACL count after delete operation
        is_deleted: is related object already deleted
    """
        if is_deleted:
            related_count = related_model.query.count()
            self.assertEqual(related_count, 0)
        else:
            related = related_model.query.one()
            response = self.api.delete(related)
            self.assert200(response)

        related_acl_count = all_models.AccessControlList.query.filter(
            all_models.AccessControlList.object_type ==
            related_model.__name__).count()
        self.assertEqual(related_acl_count, 0)

        bg_task_count = all_models.AccessControlList.query.filter(
            all_models.AccessControlList.object_type ==
            "BackgroundTask").count()

        all_acl_count = all_models.AccessControlList.query.count()
        self.assertEqual(all_acl_count - bg_task_count, exp_acl_count)

    def test_acl_on_object_deletion(self):
        """Test related ACL records removed on related object delete"""
        self._create_propagation_acl_test_data()
        acl_count = all_models.AccessControlList.query.count()
        self.assertNotEqual(acl_count, 0)

        admin = all_models.Person.query.get(1)
        self.api.set_user(admin)

        related_models = (
            (all_models.TaskGroup, 16, False),
            (all_models.TaskGroupTask, 16, True),
            (all_models.Cycle, 2, False),
            (all_models.CycleTaskGroup, 2, True),
            (all_models.CycleTaskGroupObjectTask, 2, True),
        )
        for related_model, acl_count, is_deleted in related_models:
            self._delete_and_check_related_acl(related_model, acl_count,
                                               is_deleted)

    def test_acl_on_workflow_delete(self):
        """Test related ACL records removed on Workflow delete"""
        self._create_propagation_acl_test_data()
        acl_count = all_models.AccessControlList.query.count()
        self.assertNotEqual(acl_count, 0)

        admin = all_models.Person.query.get(1)
        self.api.set_user(admin)
        workflow = all_models.Workflow.query.one()
        response = self.api.delete(workflow)
        self.assert200(response)

        acl_count = all_models.AccessControlList.query.count()
        bg_acl_count = all_models.AccessControlList.query.filter(
            all_models.AccessControlList.object_type ==
            "BackgroundTask").count()
        self.assertEqual(acl_count, bg_acl_count)

    def test_acl_for_new_related_object(self):
        """Test Workflow ACL propagation for new related objects."""
        data = self.get_workflow_dict()
        acl_map = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Workflow Member'],
        }
        data["workflow"]["access_control_list"] = acl_helper.get_acl_list(
            acl_map)
        data["workflow"]["unit"] = "week"
        data["workflow"]["repeat_every"] = 1
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

        data = self.get_task_group_dict(response.json["workflow"])
        data["task_group"]["contact"]["id"] = self.people_ids[2]
        data["task_group"]["contact"]["href"] = "/api/people/{}".format(
            self.people_ids[2])
        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

        task_group = all_models.TaskGroup.eager_query().one()
        data = self.get_task_dict(task_group)
        data["task_group_task"]["start_date"] = "2018-01-04"
        data["task_group_task"]["end_date"] = "2018-01-05"
        response = self.api.post(all_models.TaskGroupTask, data)
        self.assertEqual(response.status_code, 201)

        workflow = all_models.Workflow.query.one()
        with freezegun.freeze_time("2018-01-05"):  # Generate 1 cycle
            self.generator.activate_workflow(workflow)

        cycle_task = all_models.CycleTaskGroupObjectTask.query.one()
        with factories.single_commit():
            comment = factories.CommentFactory()
            factories.RelationshipFactory(source=comment,
                                          destination=cycle_task)

        self._check_propagated_acl(2, has_comment=True)

    @ddt.data('Admin', 'Workflow Member')
    def test_tg_assignee(self, role_name):
        """Test TaskGroup assignee already has {0} role."""
        data = self.get_workflow_dict()
        init_acl = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES[role_name],
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            init_acl)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

        data = self.get_task_group_dict(response.json["workflow"])
        data["task_group"]["contact"]["id"] = self.people_ids[1]
        data["task_group"]["contact"]["href"] = "/api/people/{}".format(
            self.people_ids[1])
        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

        workflow = all_models.Workflow.query.one()
        task_group = all_models.TaskGroup.query.one()

        ac_people = all_models.AccessControlPerson.query.filter(
            all_models.AccessControlPerson.person_id == task_group.contact_id,
        ).all()
        self.assertEqual(len(ac_people), 1)

        actual = {(acp.ac_list.object_type, acp.ac_list.object_id)
                  for acp in ac_people}
        self.assertIn((workflow.type, workflow.id), actual)
        self.assertNotIn((task_group.type, task_group.id), actual)

    def test_task_group_assignee_gets_workflow_member(self):  # noqa pylint: disable=invalid-name
        """Test TaskGroup assignee gets WorkflowMember role."""
        data = self.get_workflow_dict()
        init_acl = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Workflow Member'],
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            init_acl)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

        data = self.get_task_group_dict(response.json["workflow"])
        data["task_group"]["contact"]["id"] = self.people_ids[2]
        data["task_group"]["contact"]["href"] = "/api/people/{}".format(
            self.people_ids[2])
        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

        workflow = all_models.Workflow.query.one()

        wf_members = [
            acp.person.id for acp in
            workflow.acr_name_acl_map["Workflow Member"].access_control_people
        ]
        self.assertIn(self.people_ids[2], wf_members)

    def _create_propagation_acl_test_data(self):  # noqa pylint: disable=invalid-name
        """Create objects for Workflow ACL propagation test."""
        with freezegun.freeze_time("2017-08-9"):
            with factories.single_commit():
                workflow = wf_factories.WorkflowFactory(
                    title='wf1',
                    unit=all_models.Workflow.WEEK_UNIT,
                    is_verification_needed=True,
                    repeat_every=1)
                wf_factories.TaskGroupTaskFactory(
                    title='tgt1',
                    task_group=wf_factories.TaskGroupFactory(
                        title='tg1',
                        context=factories.ContextFactory(),
                        workflow=workflow),
                    # One cycle should be created
                    start_date=datetime.date(2017, 8, 3),
                    end_date=datetime.date(2017, 8, 7))
            self.generator.activate_workflow(workflow)
            workflow = all_models.Workflow.query.one()
            acl_map = {
                self.people_ids[0]: WF_ROLES['Admin'],
                self.people_ids[1]: WF_ROLES['Workflow Member'],
                self.people_ids[2]: WF_ROLES['Workflow Member'],
            }
            put_params = {
                'access_control_list': acl_helper.get_acl_list(acl_map)
            }
            response = self.api.put(workflow, put_params)
            self.assert200(response)

    def _check_propagated_acl(self, roles_count, has_comment=False):
        """ Check Workflow propagated ACL records.

    Args:
        roles_count: roles' count created in test
        has_comment: indicator that related objects contain comments
    """
        related_objects = [
            (all_models.TaskGroup.query.one().id,
             all_models.TaskGroup.__name__),
            (all_models.TaskGroupTask.query.one().id,
             all_models.TaskGroupTask.__name__),
            (all_models.Cycle.query.one().id, all_models.Cycle.__name__),
            (all_models.CycleTaskGroup.query.one().id,
             all_models.CycleTaskGroup.__name__),
            (all_models.CycleTaskGroupObjectTask.query.one().id,
             all_models.CycleTaskGroupObjectTask.__name__),
        ]
        if has_comment:
            related_objects.append((all_models.Comment.query.one().id,
                                    all_models.Comment.__name__), )

        # *2 is for relationships
        related_count = roles_count * len(related_objects) * 2

        # additional acl count for Relationship and Comment propagation of
        # Task Assignees/Task Secondary Assignees access control roles
        if has_comment:
            related_count += roles_count * 2

        all_acls = all_models.AccessControlList.query.filter(
            all_models.AccessControlList.parent_id_nn != 0).count()
        self.assertEqual(all_acls, related_count)

    def test_assign_workflow_acl(self):
        """Test propagation Workflow ACL roles on Workflow's update ACL records."""
        self._create_propagation_acl_test_data()
        self._check_propagated_acl(2)

    def test_unassign_workflow_acl(self):
        """Test propagation Workflow ACL roles on person unassigned."""
        self._create_propagation_acl_test_data()
        with freezegun.freeze_time("2017-08-9"):
            workflow = all_models.Workflow.query.one()
            acl_map = {
                self.people_ids[0]: WF_ROLES['Admin'],
                self.people_ids[1]: WF_ROLES['Workflow Member'],
            }
            put_params = {
                'access_control_list': acl_helper.get_acl_list(acl_map)
            }
            response = self.api.put(workflow, put_params)
            self.assert200(response)

        self._check_propagated_acl(2)

    def test_post_workflow_with_acl(self):
        """Test PUT workflow with ACL."""
        data = self.get_workflow_dict()

        exp_res = {
            self.wf_admin_id: WF_ROLES['Admin'],
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Workflow Member'],
            self.people_ids[2]: WF_ROLES['Workflow Member'],
            self.people_ids[3]: WF_ROLES['Workflow Member']
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            exp_res)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)
        workflow = all_models.Workflow.eager_query().one()
        act_res = {
            person.id: acl.ac_role_id
            for person, acl in workflow.access_control_list
        }
        self.assertDictEqual(exp_res, act_res)

    def test_update_workflow_acl_people(self):
        """Test PUT workflow with updated ACL."""
        data = self.get_workflow_dict()
        init_map = {
            self.wf_admin_id: WF_ROLES['Admin'],
            self.people_ids[0]: WF_ROLES['Workflow Member'],
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            init_map)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)
        exp_res = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Admin'],
            self.people_ids[2]: WF_ROLES['Workflow Member'],
            self.people_ids[3]: WF_ROLES['Workflow Member'],
            self.people_ids[4]: WF_ROLES['Workflow Member']
        }
        workflow = all_models.Workflow.eager_query().one()
        put_params = {'access_control_list': acl_helper.get_acl_list(exp_res)}
        response = self.api.put(workflow, put_params)
        self.assert200(response)
        workflow = all_models.Workflow.eager_query().one()
        act_res = {
            person.id: acl.ac_role_id
            for person, acl in workflow.access_control_list
        }
        self.assertDictEqual(exp_res, act_res)

    def test_send_invalid_data(self):
        """Test send invalid data on Workflow post."""
        data = self.get_workflow_dict()
        del data["workflow"]["title"]
        response = self.api.post(all_models.Workflow, data)
        self.assert400(response)

    def test_create_one_time_workflows(self):
        """Test simple create one time Workflow over api."""
        data = self.get_workflow_dict()
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_weekly_workflow(self):
        """Test create valid weekly wf"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 7
        data["workflow"]["unit"] = "day"
        data["workflow"]["title"] = "Weekly"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_annually_workflow(self):
        """Test create valid annual wf"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 12
        data["workflow"]["unit"] = "month"
        data["workflow"]["title"] = "Annually"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    @ddt.data("wrong value", 0, -4)
    def test_create_wrong_repeat_every_workflow(self, value):  # noqa pylint: disable=invalid-name
        """Test case for invalid repeat_every value"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = value
        data["workflow"]["unit"] = "month"
        data["workflow"]["title"] = "Wrong wf"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 400)

    def test_create_wrong_unit_workflow(self):
        """Test case for invalid unit value"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 12
        data["workflow"]["unit"] = "wrong value"
        data["workflow"]["title"] = "Wrong wf"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 400)

    def test_create_task_group(self):
        """Test create task group over api."""
        wf_data = self.get_workflow_dict()
        wf_data["workflow"]["title"] = "Create_task_group"
        wf_response = self.api.post(all_models.Workflow, wf_data)

        data = self.get_task_group_dict(wf_response.json["workflow"])

        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

    def test_incorrect_wf_id_on_tg_post(self):
        """Tests incorrect id in tg post payload.

    Tests that 400 is raised on tg post if id in
    payload has incorrect type."""
        wf_data = self.get_workflow_dict()
        wf_response = self.api.post(all_models.Workflow, wf_data)
        data = {
            "workflow": {
                "id": {
                    "id": wf_response.json["workflow"]["id"]
                },
                "type": "Workflow"
            }
        }
        tg_response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(tg_response.status_code, 400)
        self.assertEqual(tg_response.json["message"],
                         ("Either type or id are specified "
                          "incorrectly in the request payload."))

    @staticmethod
    def get_workflow_dict():
        return {
            "workflow": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "title": "One_time",
                "description": "",
                "unit": None,
                "repeat_every": None,
                "notify_on_change": False,
                "task_group_title": "Task Group 1",
                "notify_custom_message": "",
                "is_verification_needed": True,
                "context": None,
            }
        }

    def get_task_group_dict(self, workflow):
        return {
            "task_group": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "_transient": {},
                "contact": {
                    "id": self.wf_admin_id,
                    "href": "/api/people/{}".format(self.wf_admin_id),
                    "type": "Person"
                },
                "workflow": {
                    "id": workflow["id"],
                    "href": "/api/workflows/%d" % workflow["id"],
                    "type": "Workflow"
                },
                "context": {
                    "id": workflow["context"]["id"],
                    "href": "/api/contexts/%d" % workflow["context"]["id"],
                    "type": "Context"
                },
                "modal_title": "Create Task Group",
                "title": "Create_task_group",
                "description": "",
            }
        }

    def get_task_dict(self, task_group):
        return {
            "task_group_task": {
                "start_date": "2017-12-25",
                "end_date": "2017-12-31",
                "custom_attributes": {},
                "contact": {
                    "id": self.wf_admin_id,
                    "href": "/api/people/{}".format(self.wf_admin_id),
                    "type": "Person"
                },
                "task_group": {
                    "id": task_group.id,
                    "href": "/api/task_groups/{}".format(task_group.id),
                    "type": "TaskGroup"
                },
                "context": {
                    "id": task_group.context_id,
                    "href": "/api/contexts/{}".format(task_group.context_id),
                    "type": "Context"
                },
                "title": "Create_task",
                "task_type": "text",
                "description": ""
            }
        }

    @ddt.data({}, {"repeat_every": 5, "unit": "month"})
    def test_repeat_multiplier_field(self, data):
        """Check repeat_multiplier is set to 0 after wf creation."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(**data)
        workflow_id = workflow.id
        self.assertEqual(
            0,
            all_models.Workflow.query.get(workflow_id).repeat_multiplier)

    # TODO: Unskip in the patch 2
    @unittest.skip("Will be activated in patch 2")
    def test_change_to_one_time_wf(self):
        """Check repeat_every and unit can be set to Null only together."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                                    unit="day")
        resp = self.api.put(workflow, {"repeat_every": None, "unit": None})
        self.assert200(resp)

    @ddt.data({"repeat_every": 5}, {"unit": "month"})
    def test_change_repeat_every(self, data):
        """Check repeat_every or unit can not be changed once set."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory()
        resp = self.api.put(workflow, data)
        self.assert400(resp)

    def test_not_change_to_one_time_wf(self):
        """Check repeat_every or unit can't be set to Null separately.
    This test will be useful in the 2nd patch, where we allow to change
    WF setup
    """
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                                    unit="day")
        resp = self.api.put(workflow, {"repeat_every": None})
        self.assert400(resp)
        resp = self.api.put(workflow, {"unit": None})
        self.assert400(resp)

    @ddt.data(True, False)
    def test_autogen_verification_flag(self, flag):
        """Check is_verification_needed flag for activate WF action."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
            group = wf_factories.TaskGroupFactory(workflow=workflow)
            wf_factories.TaskGroupTaskFactory(task_group=group)
        data = [{
            "cycle": {
                "autogenerate": True,
                "isOverdue": False,
                "title": factories.random_str(prefix='cycle - '),
                "workflow": {
                    "id": workflow.id,
                    "type": "Workflow",
                },
                "context": {
                    "id": workflow.context_id,
                    "type": "Context",
                },
            }
        }]
        resp = self.api.send_request(self.api.client.post,
                                     api_link="/api/cycles",
                                     data=data)
        cycle_id = resp.json[0][1]["cycle"]["id"]
        self.assertEqual(
            flag,
            all_models.Cycle.query.get(cycle_id).is_verification_needed)

    @ddt.data(True, False)
    def test_verification_flag_positive(self, flag):  # noqa pylint: disable=invalid-name
        """is_verification_needed flag is changeable for DRAFT workflow."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": not flag})
        self.assert200(resp)
        self.assertEqual(
            all_models.Workflow.query.get(workflow_id).is_verification_needed,
            not flag)

    @ddt.data(True, False)
    def test_verification_flag_negative(self, flag):
        """Test immutable verification flag on active workflows."""
        with freezegun.freeze_time("2017-08-10"):
            with factories.single_commit():
                workflow = wf_factories.WorkflowFactory(
                    unit=all_models.Workflow.WEEK_UNIT,
                    is_verification_needed=flag,
                    repeat_every=1)
                wf_factories.TaskGroupTaskFactory(
                    task_group=wf_factories.TaskGroupFactory(
                        context=factories.ContextFactory(), workflow=workflow),
                    # Two cycles should be created
                    start_date=datetime.date(2017, 8, 3),
                    end_date=datetime.date(2017, 8, 7))
            workflow_id = workflow.id
            self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
            self.generator.activate_workflow(workflow)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.status, all_models.Workflow.ACTIVE)
            resp = self.api.put(workflow, {"is_verification_needed": not flag})
            self.assert400(resp)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.is_verification_needed, flag)

            # End all current cycles
            for cycle in workflow.cycles:
                self.generator.modify_object(cycle, {'is_current': False})
            workflow = all_models.Workflow.query.filter(
                all_models.Workflow.id == workflow_id).first()
            self.assertEqual(workflow.status, all_models.Workflow.INACTIVE)
            resp = self.api.put(workflow, {"is_verification_needed": not flag})
            self.assert400(resp)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.is_verification_needed, flag)

    @ddt.data(True, False)
    def test_not_change_vf_flag(self, flag):
        """Check is_verification_needed not change on update."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": flag})
        self.assert200(resp)
        self.assertEqual(
            flag,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)

    @ddt.data(True, False, None)
    def test_create_vf_flag(self, flag):
        """Check is_verification_needed flag setup on create."""
        data = self.get_workflow_dict()
        if flag is None:
            data['workflow'].pop('is_verification_needed', None)
        else:
            data['workflow']['is_verification_needed'] = flag
        resp = self.api.post(all_models.Workflow, data)
        self.assertEqual(201, resp.status_code)
        workflow_id = resp.json['workflow']['id']
        self.assertEqual(
            flag if flag is not None else False,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)
Esempio n. 10
0
class TestWorkflowsApiPost(TestCase):
    """Test class for ggrc workflow api post action."""
    def setUp(self):
        super(TestWorkflowsApiPost, self).setUp()
        self.api = Api()
        self.generator = wf_generator.WorkflowsGenerator()

    def tearDown(self):
        pass

    def test_send_invalid_data(self):
        """Test send invalid data on Workflow post."""
        data = self.get_workflow_dict()
        del data["workflow"]["title"]
        del data["workflow"]["context"]
        response = self.api.post(all_models.Workflow, data)
        self.assert400(response)
        # TODO: check why response.json["message"] is empty

    def test_create_one_time_workflows(self):
        """Test simple create one time Workflow over api."""
        data = self.get_workflow_dict()
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_weekly_workflow(self):
        """Test create valid weekly wf"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 7
        data["workflow"]["unit"] = "day"
        data["workflow"]["title"] = "Weekly"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_annually_workflow(self):
        """Test create valid annual wf"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 12
        data["workflow"]["unit"] = "month"
        data["workflow"]["title"] = "Annually"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    @ddt.data("wrong value", 0, -4)
    def test_create_wrong_repeat_every_workflow(self, value):  # noqa pylint: disable=invalid-name
        """Test case for invalid repeat_every value"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = value
        data["workflow"]["unit"] = "month"
        data["workflow"]["title"] = "Wrong wf"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 400)

    def test_create_wrong_unit_workflow(self):
        """Test case for invalid unit value"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 12
        data["workflow"]["unit"] = "wrong value"
        data["workflow"]["title"] = "Wrong wf"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 400)

    def test_create_task_group(self):
        """Test create task group over api."""
        wf_data = self.get_workflow_dict()
        wf_data["workflow"]["title"] = "Create_task_group"
        wf_response = self.api.post(all_models.Workflow, wf_data)

        data = self.get_task_group_dict(wf_response.json["workflow"])

        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

    # TODO: Api should be able to handle invalid data
    @unittest.skip("Not implemented.")
    def test_create_task_group_invalid_workflow_data(self):  # noqa pylint: disable=invalid-name
        """Test create task group with invalid data."""
        data = self.get_task_group_dict({"id": -1, "context": {"id": -1}})
        response = self.api.post(all_models.TaskGroup, data)
        self.assert400(response)

    @staticmethod
    def get_workflow_dict():
        return {
            "workflow": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "title": "One_time",
                "description": "",
                "unit": None,
                "repeat_every": None,
                "notify_on_change": False,
                "task_group_title": "Task Group 1",
                "notify_custom_message": "",
                "is_verification_needed": True,
                "owners": None,
                "context": None,
            }
        }

    @staticmethod
    def get_task_group_dict(workflow):
        return {
            "task_group": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "_transient": {},
                "contact": {
                    "id": 1,
                    "href": "/api/people/1",
                    "type": "Person"
                },
                "workflow": {
                    "id": workflow["id"],
                    "href": "/api/workflows/%d" % workflow["id"],
                    "type": "Workflow"
                },
                "context": {
                    "id": workflow["context"]["id"],
                    "href": "/api/contexts/%d" % workflow["context"]["id"],
                    "type": "Context"
                },
                "modal_title": "Create Task Group",
                "title": "Create_task_group",
                "description": "",
            }
        }

    @ddt.data({}, {"repeat_every": 5, "unit": "month"})
    def test_repeat_multiplier_field(self, data):
        """Check repeat_multiplier is set to 0 after wf creation."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(**data)
        workflow_id = workflow.id
        self.assertEqual(
            0,
            all_models.Workflow.query.get(workflow_id).repeat_multiplier)

    # TODO: Unskip in the patch 2
    @unittest.skip("Will be activated in patch 2")
    def test_change_to_one_time_wf(self):
        """Check repeat_every and unit can be set to Null only together."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                                    unit="day")
        resp = self.api.put(workflow, {"repeat_every": None, "unit": None})
        self.assert200(resp)

    @ddt.data({"repeat_every": 5}, {"unit": "month"})
    def test_change_repeat_every(self, data):
        """Check repeat_every or unit can not be changed once set."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory()
        resp = self.api.put(workflow, data)
        self.assert400(resp)

    def test_not_change_to_one_time_wf(self):
        """Check repeat_every or unit can't be set to Null separately.
    This test will be useful in the 2nd patch, where we allow to change
    WF setup
    """
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                                    unit="day")
        resp = self.api.put(workflow, {"repeat_every": None})
        self.assert400(resp)
        resp = self.api.put(workflow, {"unit": None})
        self.assert400(resp)

    @ddt.data(True, False)
    def test_autogen_verification_flag(self, flag):
        """Check is_verification_needed flag for activate WF action."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
            group = wf_factories.TaskGroupFactory(workflow=workflow)
            wf_factories.TaskGroupTaskFactory(task_group=group)
        data = [{
            "cycle": {
                "autogenerate": True,
                "isOverdue": False,
                "workflow": {
                    "id": workflow.id,
                    "type": "Workflow",
                },
                "context": {
                    "id": workflow.context_id,
                    "type": "Context",
                },
            }
        }]
        resp = self.api.send_request(self.api.client.post,
                                     api_link="/api/cycles",
                                     data=data)
        cycle_id = resp.json[0][1]["cycle"]["id"]
        self.assertEqual(
            flag,
            all_models.Cycle.query.get(cycle_id).is_verification_needed)

    @ddt.data(True, False)
    def test_change_verification_flag_positive(self, flag):  # noqa pylint: disable=invalid-name
        """is_verification_needed flag is changeable for DRAFT workflow."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": not flag})
        self.assert200(resp)
        self.assertEqual(
            all_models.Workflow.query.get(workflow_id).is_verification_needed,
            not flag)

    @ddt.data(True, False)
    def test_change_verification_flag_negative(self, flag):  # noqa pylint: disable=invalid-name
        with freezegun.freeze_time("2017-08-10"):
            with factories.single_commit():
                workflow = wf_factories.WorkflowFactory(
                    unit=all_models.Workflow.WEEK_UNIT,
                    is_verification_needed=flag,
                    repeat_every=1)
                wf_factories.TaskGroupTaskFactory(
                    task_group=wf_factories.TaskGroupFactory(
                        context=factories.ContextFactory(), workflow=workflow),
                    # Two cycles should be created
                    start_date=datetime.date(2017, 8, 3),
                    end_date=datetime.date(2017, 8, 7))
            workflow_id = workflow.id
            self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
            self.generator.activate_workflow(workflow)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.status, all_models.Workflow.ACTIVE)
            resp = self.api.put(workflow, {"is_verification_needed": not flag})
            self.assert400(resp)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.is_verification_needed, flag)

            # End all current cycles
            for cycle in workflow.cycles:
                self.generator.modify_object(cycle, {'is_current': False})
            workflow = all_models.Workflow.query.filter(
                all_models.Workflow.id == workflow_id).first()
            self.assertEqual(workflow.status, all_models.Workflow.INACTIVE)
            resp = self.api.put(workflow, {"is_verification_needed": not flag})
            self.assert400(resp)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.is_verification_needed, flag)

    @ddt.data(True, False)
    def test_not_change_vf_flag(self, flag):
        """Check is_verification_needed not change on update."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": flag})
        self.assert200(resp)
        self.assertEqual(
            flag,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)

    @ddt.data(True, False, None)
    def test_create_vf_flag(self, flag):
        """Check is_verification_needed flag setup on create."""
        data = self.get_workflow_dict()
        if flag is None:
            data['workflow'].pop('is_verification_needed', None)
        else:
            data['workflow']['is_verification_needed'] = flag
        resp = self.api.post(all_models.Workflow, data)
        self.assertEqual(201, resp.status_code)
        workflow_id = resp.json['workflow']['id']
        self.assertEqual(
            flag if flag is not None else True,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestWorkflowsApiPost(TestCase):
    """Test class for ggrc workflow api post action."""
    def setUp(self):
        super(TestWorkflowsApiPost, self).setUp()
        self.api = Api()
        self.generator = wf_generator.WorkflowsGenerator()
        with factories.single_commit():
            self.people_ids = [factories.PersonFactory().id for _ in xrange(6)]

    def tearDown(self):
        pass

    def _delete_and_check_related_acl(self, related_model, exp_acl_count,
                                      is_deleted):
        """Delete related model and check remaining ACL count.

    Args:
        related_model: related model class
        exp_acl_count: expected related ACL count after delete operation
        is_deleted: is related object already deleted
    """
        if is_deleted:
            related_count = related_model.query.count()
            self.assertEqual(related_count, 0)
        else:
            related = related_model.query.one()
            response = self.api.delete(related)
            self.assert200(response)

        related_acl_count = all_models.AccessControlList.query.filter(
            all_models.AccessControlList.object_type ==
            related_model.__name__).count()
        self.assertEqual(related_acl_count, 0)

        all_acl_count = all_models.AccessControlList.query.count()
        self.assertEqual(all_acl_count, exp_acl_count)

    def test_related_acl_removed_on_related_obj_delete(self):  # noqa pylint: disable=invalid-name
        """Test related ACL records removed on related object delete"""
        self._create_propagation_acl_test_data()
        acl_count = all_models.AccessControlList.query.count()
        self.assertNotEqual(acl_count, 0)

        admin = all_models.Person.query.get(1)
        self.api.set_user(admin)

        related_models = (
            (all_models.CycleTaskEntry, 18, False),
            (all_models.TaskGroup, 12, False),
            (all_models.TaskGroupTask, 12, True),
            (all_models.Cycle, 3, False),
            (all_models.CycleTaskGroup, 3, True),
            (all_models.CycleTaskGroupObjectTask, 3, True),
        )
        for related_model, acl_count, is_deleted in related_models:
            self._delete_and_check_related_acl(related_model, acl_count,
                                               is_deleted)

    def test_related_acl_removed_on_workflow_delete(self):  # noqa pylint: disable=invalid-name
        """Test related ACL records removed on Workflow delete"""
        self._create_propagation_acl_test_data()
        acl_count = all_models.AccessControlList.query.count()
        self.assertNotEqual(acl_count, 0)

        admin = all_models.Person.query.get(1)
        self.api.set_user(admin)
        workflow = all_models.Workflow.query.one()
        response = self.api.delete(workflow)
        self.assert200(response)

        acl_count = all_models.AccessControlList.query.count()
        self.assertEqual(acl_count, 0)

    def test_propagate_acl_for_new_related_object(self):  # noqa pylint: disable=invalid-name
        """Test Workflow ACL propagation for new related objects."""
        data = self.get_workflow_dict()
        acl_map = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Workflow Member'],
        }
        data["workflow"]["access_control_list"] = acl_helper.get_acl_list(
            acl_map)
        data["workflow"]["unit"] = "week"
        data["workflow"]["repeat_every"] = 1
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

        data = self.get_task_group_dict(response.json["workflow"])
        data["task_group"]["contact"]["id"] = self.people_ids[2]
        data["task_group"]["contact"]["href"] = "/api/people/{}".format(
            self.people_ids[2])
        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

        task_group = all_models.TaskGroup.eager_query().one()
        data = self.get_task_dict(task_group)
        data["task_group_task"]["start_date"] = "2018-01-04"
        data["task_group_task"]["end_date"] = "2018-01-05"
        response = self.api.post(all_models.TaskGroupTask, data)
        self.assertEqual(response.status_code, 201)

        workflow = all_models.Workflow.query.one()
        with freezegun.freeze_time("2018-01-05"):  # Generate 1 cycle
            self.generator.activate_workflow(workflow)

        cycle_task = all_models.CycleTaskGroupObjectTask.query.one()
        cycle = all_models.Cycle.query.one()
        data = self.get_comment_dict(cycle_task, cycle)
        response = self.api.post(all_models.CycleTaskEntry, data)
        self.assertEqual(response.status_code, 201)

        self._check_propagated_acl(3)

    @ddt.data('Admin', 'Workflow Member')
    def test_task_group_assignee_has_workflow_role(self, role_name):  # noqa pylint: disable=invalid-name
        """Test TaskGroup assignee already has Workflow role."""
        data = self.get_workflow_dict()
        init_acl = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES[role_name],
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            init_acl)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

        data = self.get_task_group_dict(response.json["workflow"])
        data["task_group"]["contact"]["id"] = self.people_ids[1]
        data["task_group"]["contact"]["href"] = "/api/people/{}".format(
            self.people_ids[1])
        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

        workflow = all_models.Workflow.query.one()
        task_group = all_models.TaskGroup.query.one()

        actual_acl = all_models.AccessControlList.eager_query().filter(
            all_models.AccessControlList.person_id == task_group.contact_id,
        ).all()
        self.assertEqual(len(actual_acl), 2)

        expected = {
            role_name: (workflow.type, workflow.id),
            "{} Mapped".format(role_name): (task_group.type, task_group.id)
        }
        actual = {
            acl.ac_role.name: (acl.object_type, acl.object_id)
            for acl in actual_acl
        }
        self.assertDictEqual(expected, actual)

    def test_task_group_assignee_gets_workflow_member(self):  # noqa pylint: disable=invalid-name
        """Test TaskGroup assignee gets WorkflowMember role."""
        data = self.get_workflow_dict()
        init_acl = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Workflow Member'],
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            init_acl)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

        data = self.get_task_group_dict(response.json["workflow"])
        data["task_group"]["contact"]["id"] = self.people_ids[2]
        data["task_group"]["contact"]["href"] = "/api/people/{}".format(
            self.people_ids[2])
        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

        workflow = all_models.Workflow.query.one()
        task_group = all_models.TaskGroup.query.one()

        parent_acl = all_models.AccessControlList.eager_query().filter(
            all_models.AccessControlList.person_id == task_group.contact_id,
            all_models.AccessControlList.object_type == workflow.type,
            all_models.AccessControlList.object_id == workflow.id).one()
        tg_acl = all_models.AccessControlList.eager_query().filter(
            all_models.AccessControlList.person_id == task_group.contact_id,
            all_models.AccessControlList.object_type == task_group.type,
            all_models.AccessControlList.object_id == task_group.id).one()
        self.assertEqual(parent_acl.ac_role.name, "Workflow Member")
        self.assertEqual(tg_acl.parent_id, parent_acl.id)
        self.assertEqual(tg_acl.ac_role.name, "Workflow Member Mapped")

    def _create_propagation_acl_test_data(self):  # noqa pylint: disable=invalid-name
        """Create objects for Workflow ACL propagation test."""
        with freezegun.freeze_time("2017-08-9"):
            with factories.single_commit():
                workflow = wf_factories.WorkflowFactory(
                    title='wf1',
                    unit=all_models.Workflow.WEEK_UNIT,
                    is_verification_needed=True,
                    repeat_every=1)
                wf_factories.TaskGroupTaskFactory(
                    title='tgt1',
                    task_group=wf_factories.TaskGroupFactory(
                        title='tg1',
                        context=factories.ContextFactory(),
                        workflow=workflow),
                    # One cycle should be created
                    start_date=datetime.date(2017, 8, 3),
                    end_date=datetime.date(2017, 8, 7))
            self.generator.activate_workflow(workflow)
            cycle = all_models.Cycle.query.one()
            cycle_task = all_models.CycleTaskGroupObjectTask.query.one()
            wf_factories.CycleTaskEntryFactory(
                cycle=cycle,
                cycle_task_group_object_task=cycle_task,
                description="Cycle task comment",
            )
            workflow = all_models.Workflow.query.one()
            acl_map = {
                self.people_ids[0]: WF_ROLES['Admin'],
                self.people_ids[1]: WF_ROLES['Workflow Member'],
                self.people_ids[2]: WF_ROLES['Workflow Member'],
            }
            put_params = {
                'access_control_list': acl_helper.get_acl_list(acl_map)
            }
            response = self.api.put(workflow, put_params)
            self.assert200(response)

    def _check_propagated_acl(self, roles_count):
        """Check Workflow propagated ACL records.

    Args:
        roles_count: roles' count created in test
    """
        related_objects = ((all_models.TaskGroup.query.one().id,
                            all_models.TaskGroup.__name__),
                           (all_models.TaskGroupTask.query.one().id,
                            all_models.TaskGroupTask.__name__),
                           (all_models.Cycle.query.one().id,
                            all_models.Cycle.__name__),
                           (all_models.CycleTaskGroup.query.one().id,
                            all_models.CycleTaskGroup.__name__),
                           (all_models.CycleTaskGroupObjectTask.query.one().id,
                            all_models.CycleTaskGroupObjectTask.__name__),
                           (all_models.CycleTaskEntry.query.one().id,
                            all_models.CycleTaskEntry.__name__))
        related_count = len(related_objects)

        all_acl = [
            acl for acl in all_models.AccessControlList.eager_query().all()
        ]
        self.assertEqual(len(all_acl),
                         roles_count + roles_count * related_count)

        workflow = all_models.Workflow.query.one()
        parent_acl, related_acl = [], []
        for acl in all_acl:
            if (not acl.parent_id and acl.object_id == workflow.id
                    and acl.object_type == workflow.type):
                parent_acl.append(acl)
            else:
                related_acl.append(acl)

        result = defaultdict(set)
        for p_acl in parent_acl:
            for r_acl in related_acl:
                if (r_acl.ac_role.name == '{} Mapped'.format(
                        p_acl.ac_role.name) and r_acl.parent_id == p_acl.id
                        and r_acl.person_id == p_acl.person_id):
                    result[p_acl.id].add((r_acl.object_id, r_acl.object_type))
        self.assertEqual(roles_count, len(result))

        for related_pairs in result.values():
            self.assertEqual(related_count, len(related_pairs))
            self.assertItemsEqual(related_objects, related_pairs)

    def test_assign_workflow_acl_people_and_propagate(self):  # noqa pylint: disable=invalid-name
        """Test propagation Workflow ACL roles on Workflow's update ACL records."""
        self._create_propagation_acl_test_data()
        self._check_propagated_acl(3)

    def test_unassign_workflow_acl_people_and_propagate(self):  # noqa pylint: disable=invalid-name
        """Test propagation Workflow ACL roles on person unassigned."""
        self._create_propagation_acl_test_data()
        with freezegun.freeze_time("2017-08-9"):
            workflow = all_models.Workflow.query.one()
            acl_map = {
                self.people_ids[0]: WF_ROLES['Admin'],
                self.people_ids[1]: WF_ROLES['Workflow Member'],
            }
            put_params = {
                'access_control_list': acl_helper.get_acl_list(acl_map)
            }
            response = self.api.put(workflow, put_params)
            self.assert200(response)

        self._check_propagated_acl(2)

    def test_post_workflow_with_acl_people(self):  # noqa pylint: disable=invalid-name
        """Test PUT workflow with ACL."""
        data = self.get_workflow_dict()
        exp_res = {
            1: WF_ROLES['Admin'],
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Workflow Member'],
            self.people_ids[2]: WF_ROLES['Workflow Member'],
            self.people_ids[3]: WF_ROLES['Workflow Member']
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            exp_res)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)
        workflow = all_models.Workflow.eager_query().one()
        act_res = {
            acl.person_id: acl.ac_role_id
            for acl in workflow.access_control_list
        }
        self.assertDictEqual(exp_res, act_res)

    def test_update_workflow_acl_people(self):
        """Test PUT workflow with updated ACL."""
        data = self.get_workflow_dict()
        init_map = {
            1: WF_ROLES['Admin'],
            self.people_ids[0]: WF_ROLES['Workflow Member'],
        }
        data['workflow']['access_control_list'] = acl_helper.get_acl_list(
            init_map)
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)
        exp_res = {
            self.people_ids[0]: WF_ROLES['Admin'],
            self.people_ids[1]: WF_ROLES['Admin'],
            self.people_ids[2]: WF_ROLES['Workflow Member'],
            self.people_ids[3]: WF_ROLES['Workflow Member'],
            self.people_ids[4]: WF_ROLES['Workflow Member']
        }
        workflow = all_models.Workflow.eager_query().one()
        put_params = {'access_control_list': acl_helper.get_acl_list(exp_res)}
        response = self.api.put(workflow, put_params)
        self.assert200(response)
        workflow = all_models.Workflow.eager_query().one()
        act_res = {
            acl.person_id: acl.ac_role_id
            for acl in workflow.access_control_list
        }
        self.assertDictEqual(exp_res, act_res)

    def test_send_invalid_data(self):
        """Test send invalid data on Workflow post."""
        data = self.get_workflow_dict()
        del data["workflow"]["title"]
        del data["workflow"]["context"]
        response = self.api.post(all_models.Workflow, data)
        self.assert400(response)
        # TODO: check why response.json["message"] is empty

    def test_create_one_time_workflows(self):
        """Test simple create one time Workflow over api."""
        data = self.get_workflow_dict()
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_weekly_workflow(self):
        """Test create valid weekly wf"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 7
        data["workflow"]["unit"] = "day"
        data["workflow"]["title"] = "Weekly"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_annually_workflow(self):
        """Test create valid annual wf"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 12
        data["workflow"]["unit"] = "month"
        data["workflow"]["title"] = "Annually"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    @ddt.data("wrong value", 0, -4)
    def test_create_wrong_repeat_every_workflow(self, value):  # noqa pylint: disable=invalid-name
        """Test case for invalid repeat_every value"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = value
        data["workflow"]["unit"] = "month"
        data["workflow"]["title"] = "Wrong wf"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 400)

    def test_create_wrong_unit_workflow(self):
        """Test case for invalid unit value"""
        data = self.get_workflow_dict()
        data["workflow"]["repeat_every"] = 12
        data["workflow"]["unit"] = "wrong value"
        data["workflow"]["title"] = "Wrong wf"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 400)

    def test_create_task_group(self):
        """Test create task group over api."""
        wf_data = self.get_workflow_dict()
        wf_data["workflow"]["title"] = "Create_task_group"
        wf_response = self.api.post(all_models.Workflow, wf_data)

        data = self.get_task_group_dict(wf_response.json["workflow"])

        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

    # TODO: Api should be able to handle invalid data
    @unittest.skip("Not implemented.")
    def test_create_task_group_invalid_workflow_data(self):  # noqa pylint: disable=invalid-name
        """Test create task group with invalid data."""
        data = self.get_task_group_dict({"id": -1, "context": {"id": -1}})
        response = self.api.post(all_models.TaskGroup, data)
        self.assert400(response)

    @staticmethod
    def get_workflow_dict():
        return {
            "workflow": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "title": "One_time",
                "description": "",
                "unit": None,
                "repeat_every": None,
                "notify_on_change": False,
                "task_group_title": "Task Group 1",
                "notify_custom_message": "",
                "is_verification_needed": True,
                "context": None,
            }
        }

    @staticmethod
    def get_task_group_dict(workflow):
        return {
            "task_group": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "_transient": {},
                "contact": {
                    "id": 1,
                    "href": "/api/people/1",
                    "type": "Person"
                },
                "workflow": {
                    "id": workflow["id"],
                    "href": "/api/workflows/%d" % workflow["id"],
                    "type": "Workflow"
                },
                "context": {
                    "id": workflow["context"]["id"],
                    "href": "/api/contexts/%d" % workflow["context"]["id"],
                    "type": "Context"
                },
                "modal_title": "Create Task Group",
                "title": "Create_task_group",
                "description": "",
            }
        }

    @staticmethod
    def get_task_dict(task_group):
        return {
            "task_group_task": {
                "start_date": "2017-12-25",
                "end_date": "2017-12-31",
                "custom_attributes": {},
                "contact": {
                    "id": 1,
                    "href": "/api/people/1",
                    "type": "Person"
                },
                "task_group": {
                    "id": task_group.id,
                    "href": "/api/task_groups/{}".format(task_group.id),
                    "type": "TaskGroup"
                },
                "context": {
                    "id": task_group.context_id,
                    "href": "/api/contexts/{}".format(task_group.context_id),
                    "type": "Context"
                },
                "title": "Create_task",
                "task_type": "text",
                "description": ""
            }
        }

    @staticmethod
    def get_comment_dict(cycle_task, cycle):
        return {
            "cycle_task_entry": {
                "custom_attributes": {},
                "cycle_task_group_object_task": {
                    "id":
                    cycle_task.id,
                    "href":
                    "/api/cycle_task_group_object_tasks/{}".format(
                        cycle_task.id),
                    "type":
                    "CycleTaskGroupObjectTask"
                },
                "cycle": {
                    "id": cycle.id,
                    "href": "/api/cycles/{}".format(cycle.id),
                    "type": "Cycle"
                },
                "context": {
                    "id": cycle.context_id,
                    "href": "/api/contexts/{}".format(cycle.context_id),
                    "type": "Context"
                },
                "is_declining_review": "",
                "description": "CT comment"
            }
        }

    @ddt.data({}, {"repeat_every": 5, "unit": "month"})
    def test_repeat_multiplier_field(self, data):
        """Check repeat_multiplier is set to 0 after wf creation."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(**data)
        workflow_id = workflow.id
        self.assertEqual(
            0,
            all_models.Workflow.query.get(workflow_id).repeat_multiplier)

    # TODO: Unskip in the patch 2
    @unittest.skip("Will be activated in patch 2")
    def test_change_to_one_time_wf(self):
        """Check repeat_every and unit can be set to Null only together."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                                    unit="day")
        resp = self.api.put(workflow, {"repeat_every": None, "unit": None})
        self.assert200(resp)

    @ddt.data({"repeat_every": 5}, {"unit": "month"})
    def test_change_repeat_every(self, data):
        """Check repeat_every or unit can not be changed once set."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory()
        resp = self.api.put(workflow, data)
        self.assert400(resp)

    def test_not_change_to_one_time_wf(self):
        """Check repeat_every or unit can't be set to Null separately.
    This test will be useful in the 2nd patch, where we allow to change
    WF setup
    """
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                                    unit="day")
        resp = self.api.put(workflow, {"repeat_every": None})
        self.assert400(resp)
        resp = self.api.put(workflow, {"unit": None})
        self.assert400(resp)

    @ddt.data(True, False)
    def test_autogen_verification_flag(self, flag):
        """Check is_verification_needed flag for activate WF action."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
            group = wf_factories.TaskGroupFactory(workflow=workflow)
            wf_factories.TaskGroupTaskFactory(task_group=group)
        data = [{
            "cycle": {
                "autogenerate": True,
                "isOverdue": False,
                "workflow": {
                    "id": workflow.id,
                    "type": "Workflow",
                },
                "context": {
                    "id": workflow.context_id,
                    "type": "Context",
                },
            }
        }]
        resp = self.api.send_request(self.api.client.post,
                                     api_link="/api/cycles",
                                     data=data)
        cycle_id = resp.json[0][1]["cycle"]["id"]
        self.assertEqual(
            flag,
            all_models.Cycle.query.get(cycle_id).is_verification_needed)

    @ddt.data(True, False)
    def test_change_verification_flag_positive(self, flag):  # noqa pylint: disable=invalid-name
        """is_verification_needed flag is changeable for DRAFT workflow."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": not flag})
        self.assert200(resp)
        self.assertEqual(
            all_models.Workflow.query.get(workflow_id).is_verification_needed,
            not flag)

    @ddt.data(True, False)
    def test_change_verification_flag_negative(self, flag):  # noqa pylint: disable=invalid-name
        with freezegun.freeze_time("2017-08-10"):
            with factories.single_commit():
                workflow = wf_factories.WorkflowFactory(
                    unit=all_models.Workflow.WEEK_UNIT,
                    is_verification_needed=flag,
                    repeat_every=1)
                wf_factories.TaskGroupTaskFactory(
                    task_group=wf_factories.TaskGroupFactory(
                        context=factories.ContextFactory(), workflow=workflow),
                    # Two cycles should be created
                    start_date=datetime.date(2017, 8, 3),
                    end_date=datetime.date(2017, 8, 7))
            workflow_id = workflow.id
            self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
            self.generator.activate_workflow(workflow)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.status, all_models.Workflow.ACTIVE)
            resp = self.api.put(workflow, {"is_verification_needed": not flag})
            self.assert400(resp)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.is_verification_needed, flag)

            # End all current cycles
            for cycle in workflow.cycles:
                self.generator.modify_object(cycle, {'is_current': False})
            workflow = all_models.Workflow.query.filter(
                all_models.Workflow.id == workflow_id).first()
            self.assertEqual(workflow.status, all_models.Workflow.INACTIVE)
            resp = self.api.put(workflow, {"is_verification_needed": not flag})
            self.assert400(resp)
            workflow = all_models.Workflow.query.get(workflow_id)
            self.assertEqual(workflow.is_verification_needed, flag)

    @ddt.data(True, False)
    def test_not_change_vf_flag(self, flag):
        """Check is_verification_needed not change on update."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": flag})
        self.assert200(resp)
        self.assertEqual(
            flag,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)

    @ddt.data(True, False, None)
    def test_create_vf_flag(self, flag):
        """Check is_verification_needed flag setup on create."""
        data = self.get_workflow_dict()
        if flag is None:
            data['workflow'].pop('is_verification_needed', None)
        else:
            data['workflow']['is_verification_needed'] = flag
        resp = self.api.post(all_models.Workflow, data)
        self.assertEqual(201, resp.status_code)
        workflow_id = resp.json['workflow']['id']
        self.assertEqual(
            flag if flag is not None else True,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)
Esempio n. 12
0
class TestAuditDeprecated(TestCase):
  """Test for correct working field last_deprecated_date """

  def setUp(self):
    super(TestAuditDeprecated, self).setUp()
    self.api = Api()

  def test_redefine_status(self):
    """Test create audit and change status to Deprecated"""
    audit = factories.AuditFactory()

    with freeze_time("2017-01-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })

    audit_result = all_models.Audit.query.filter(
        all_models.Audit.id == audit.id
    ).one()

    self.assertEquals(audit_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_keep_date_unchanged(self):
    """Test set status audit to Deprecated, and then set status to Planned"""
    audit = factories.AuditFactory()

    with freeze_time("2017-01-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(audit, {
          "status": "Planned"
      })

    audit_result = all_models.Audit.query.filter(
        all_models.Audit.id == audit.id
    ).one()

    self.assertEquals(audit_result.status, "Planned")
    self.assertEquals(audit_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_repeat_deprecated_state(self):
    """Test set status audit to Deprecated, then to Planned,
    then to Deprecated and then to Planned"""
    audit = factories.AuditFactory()

    with freeze_time("2017-01-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(audit, {
          "status": "Planned"
      })
    with freeze_time("2017-02-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })
    with freeze_time("2017-02-26"):
      self.api.modify_object(audit, {
          "status": "Planned"
      })

    audit_result = all_models.Audit.query.filter(
        all_models.Audit.id == audit.id
    ).one()

    self.assertEquals(audit_result.status, "Planned")
    self.assertEquals(audit_result.last_deprecated_date,
                      datetime.date(2017, 2, 25))

  def test_filter_by_deprecated_date(self):
    """Test filter audits by last deprecated date"""
    amount_of_audits = 5
    list_of_ids = []
    with factories.single_commit():
      with freeze_time("2017-01-25"):
        for _ in range(amount_of_audits):
          list_of_ids.append(
              factories.AuditFactory(status="Deprecated").id
          )

    query_request_data = [{
        "object_name": "Audit",
        'filters': {
            'expression': {
                'left': 'Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01-25",
            },
        },
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"])

  def test_sort_by_deprecated_date(self):
    """Test sorting results of filter audits by deprecated date"""
    dict_of_dates = {}
    date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
    with factories.single_commit():
      for date in date_list:
        with freeze_time(date):
          dict_of_dates[factories.AuditFactory(status="Deprecated").id] = date

    sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
    sorted_list_ids = [item[0] for item in sorted_dict]

    query_request_data = [{
        "object_name": "Audit",
        'filters': {
            'expression': {
                'left': 'Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01",
            },
        },
        "order_by": [{"name": "last_deprecated_date"}],
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")

    self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])
Esempio n. 13
0
class TestValidation(TestCase):
  """Test validation query."""

  def setUp(self):
    """Log in before performing queries."""
    # we don't call super as TestCase.setUp clears the DB
    # super(BaseQueryAPITestCase, self).setUp()
    self.client.get("/login")
    self.api = Api()

  def assert_validation(self, query_data):
    self.assert400(self.api.send_request(self.api.client.post,
                                         data=query_data,
                                         api_link="/query"))

  OPERATIONS = ["=", "!=", "~", "!=", ">", "<", ">=", "<="]

  @ddt.data(*OPERATIONS)
  def test_only_left_validations(self, operation):
    self.assert_validation([{
        "object_name": "Snapshot",
        "filters": {
            "expression": {
                "left": "title",
                "op": {"name": operation},
            }
        }
    }])

  @ddt.data(*OPERATIONS)
  def test_only_right_validations(self, operation):
    self.assert_validation([{
        "object_name": "Snapshot",
        "filters": {
            "expression": {
                "right": "value",
                "op": {"name": operation},
            }
        }
    }])

  @ddt.data({}, {"name": "x"})
  def test_invalid_operations(self, operation_dict):
    self.assert_validation([{
        "object_name": "Snapshot",
        "filters": {
            "expression": {
                "right": "value",
                "op": operation_dict
            }
        }
    }])

  NO_OPERATION_DATA = [{
      "object_name": "Snapshot",
      "filters": {"expression": {"right": "value", "left": "title"}}
  }]

  NO_OBJECT_NAME_DATA = [{
      "filters": {
          "expression": {
              "left": "title",
              "op": {"name": "="}
          }
      }
  }]

  @ddt.data(
      [{}],
      NO_OPERATION_DATA,
      NO_OBJECT_NAME_DATA,
  )
  def test_validation(self, query_data):
    self.assert_validation(query_data)
Esempio n. 14
0
class TestPersonResource(TestCase, WithQueryApi):
    """Tests for special people api endpoints."""
    def setUp(self):
        super(TestPersonResource, self).setUp()
        self.client.get("/login")
        self.api = Api()
        self.generator = WorkflowsGenerator()

    @staticmethod
    def _create_users_names_rbac(users):
        """Create name and Creator role for users, created vid PersonFactory"""
        if not users:
            return
        roles = {r.name: r for r in all_models.Role.query.all()}
        for user in users:
            user.name = user.email.split("@")[0]
            rbac_factories.UserRoleFactory(role=roles["Creator"], person=user)

    def assert_profile_get_successful(self, response, expected_datetime):
        """Verify assertions for successful GET profile method"""
        self.assert200(response)
        response_datetime = date_parser.parse(
            response.json["last_seen_whats_new"])
        self.assertEqual(expected_datetime, response_datetime)

    @freeze_time("2018-05-20 12:23:17")
    def test_profile_get_successful(self):
        """Test person_profile GET method successfully achieves correct data"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        response = self.api.client.get("/api/people/{}/profile".format(
            user.id))
        self.assert_profile_get_successful(response, default_date())

    def test_profile_get_no_profile(self):
        """Test person_profile GET method achieves data with missing profile"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        profiles_table = PersonProfile.__table__
        db_request = profiles_table.delete().where(
            profiles_table.c.person_id == user.id)
        db.engine.execute(db_request)
        with freeze_time("2018-05-28 23:30:10"):
            response = self.api.client.get("/api/people/{}/profile".format(
                user.id))
            self.assert_profile_get_successful(response, default_date())

    def test_profile_get_failed(self):
        """Test person_profiles GET method fails

    Now only logged user can request his profile
    """
        with factories.single_commit():
            valid_user = factories.PersonFactory()
            self._create_users_names_rbac([valid_user])

        response = self.client.get("/api/people/{}/profile".format(
            valid_user.id))
        # logged with default user during setUp
        self.assert403(response)
        response = self.api.client.get("/api/people/{}/profile".format(
            valid_user.id))
        # not authorized user
        self.assert403(response)

    @ddt.data("Creator", "Reader", "Editor", "Administrator")
    def test_profile_post_empty_body(self, role_name):
        """Test person_profile POST method with empty body - {}."""
        role = all_models.Role.query.filter(
            all_models.Role.name == role_name).one()
        with factories.single_commit():
            user = factories.PersonFactory()
            rbac_factories.UserRoleFactory(role=role, person=user)
        self.api.set_user(person=user)

        response = self.api.send_request(
            self.api.client.post,
            data={},
            api_link="/api/people/{}/profile".format(user.id))

        self.assert405(response)

    def test_profile_post_unauthorized(self):
        """Test person_profile POST method with empty body - No Access."""
        with factories.single_commit():
            user = factories.PersonFactory()

        response = self.api.send_request(
            self.api.client.post,
            data={},
            api_link="/api/people/{}/profile".format(user.id))
        # not authorized user
        self.assert405(response)

    def assert_profile_put_successful(self, response, correct_response, user,
                                      expected):
        """Verify assertions for successful PUT profile method"""
        self.assert200(response)
        self.assertEqual(response.json, correct_response)
        profile = PersonProfile.query.filter_by(person_id=user.id).first()
        self.assertEqual(profile.last_seen_whats_new,
                         date_parser.parse(expected))

    @ddt.data(["2018-05-20 16:38:17", "2018-05-20 16:38:17"],
              ["2018-07-05T14:11:31Z", "2018-07-05T14:11:31"])
    @ddt.unpack
    def test_profile_put_successful(self, new_date, expected_date):
        """Test person_profile PUT method for setting data and correct response"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        data = {"last_seen_whats_new": new_date}
        correct_response = {"Person": {"id": user.id, "profile": data}}
        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        self.assert_profile_put_successful(response, correct_response, user,
                                           expected_date)

    def test_profile_put_no_profile(self):
        """Test person_profile PUT method for setting data for missing profile"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        new_date = "2018-05-20 22:05:17"
        data = {"last_seen_whats_new": new_date}
        correct_response = {"Person": {"id": user.id, "profile": data}}
        profiles_table = PersonProfile.__table__
        db_request = profiles_table.delete().where(
            profiles_table.c.person_id == user.id)
        db.engine.execute(db_request)
        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        self.assert_profile_put_successful(response, correct_response, user,
                                           new_date)

    def test_profile_put_unauthorized(self):
        """Test person_profiles PUT method fails for unauthorized user"""
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])

        new_date = "2018-05-20 22:05:17"
        data = {"last_seen_whats_new": new_date}
        response = self.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
        # logged with default user during setUp
        self.assert403(response)
        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        # not authorized user
        self.assert403(response)

    @ddt.data({"last_seen_whats_new": "NOT A 123 DAT456A"}, {
        "other_key": "2018-05-20 22:05:17",
        "one_more_key": 42
    })
    def test_profile_put_corrupted_data(self, data):
        """Test person_profiles PUT method fails via incorrect request data

    If request doesn't have "last_seen_whats_new" key or date is incorrect,
      response is code 400 "Bad Request"
    """
        with factories.single_commit():
            user = factories.PersonFactory()
            self._create_users_names_rbac([user])
        self.api.set_user(person=user)

        response = self.api.client.put("/api/people/{}/profile".format(
            user.id),
                                       content_type='application/json',
                                       data=json.dumps(data),
                                       headers=[('X-Requested-By', 'Tests')])
        # missed key in request
        self.assert400(response)

    def test_task_count_empty(self):
        """Test query count without any workflows and tasks."""
        user = all_models.Person.query.first()
        response = self.client.get("/api/people/{}/task_count".format(user.id))
        self.assertEqual(response.json, {
            "open_task_count": 0,
            "has_overdue": False
        })

    @ddt.data(
        (True, [
            ("task 1", "Finished", 3, True, 3),
            ("task 1", "Verified", 2, True, 3),
            ("task 2", "Declined", 2, True, 3),
            ("task 2", "Verified", 1, False, 3),
            ("task 2", "Finished", 2, True, 3),
            ("task 3", "Verified", 1, True, 3),
            ("task 2", "Verified", 0, False, 3),
        ]),
        (False, [
            ("task 1", "Finished", 2, True, 3),
            ("task 2", "In Progress", 2, True, 3),
            ("task 2", "Finished", 1, False, 3),
            ("task 3", "Finished", 0, False, 3),
        ]),
    )
    @ddt.unpack
    def test_task_count(self, is_verification_needed, transitions):
        """Test person task counts.

    This tests checks for correct task counts
     - with inactive workflows and
     - with overdue tasks
     - without overdue tasks
     - with finished overdue tasks

    The four checks are done in a single test due to complex differences
    between tests that make ddt cumbersome and the single test also improves
    integration test performance due to slow workflow setup stage.
    """
        # pylint: disable=too-many-locals

        user = all_models.Person.query.first()
        dummy_user = factories.PersonFactory()
        user_id = user.id
        role_id = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.name == "Task Assignees",
            all_models.AccessControlRole.object_type == "TaskGroupTask",
        ).one().id
        secondary_role_id = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.name == "Task Secondary Assignees",
            all_models.AccessControlRole.object_type == "TaskGroupTask",
        ).one().id

        one_time_workflow = {
            "title":
            "Person resource test workflow",
            "notify_on_change":
            True,
            "description":
            "some test workflow",
            "owners": [create_stub(user)],
            "is_verification_needed":
            is_verification_needed,
            "task_groups": [{
                "title":
                "one time task group",
                "contact":
                create_stub(user),
                "task_group_tasks": [
                    {
                        "title":
                        "task 1",
                        "description":
                        "some task",
                        "access_control_list": [
                            acl_helper.get_acl_json(role_id, user.id),
                            acl_helper.get_acl_json(secondary_role_id, user.id)
                        ],
                        "start_date":
                        date(2017, 5, 5),
                        "end_date":
                        date(2017, 8, 15),
                    },
                    {
                        "title":
                        "task 2",
                        "description":
                        "some task 3",
                        "access_control_list": [
                            acl_helper.get_acl_json(role_id, user.id),
                            acl_helper.get_acl_json(secondary_role_id,
                                                    user.id),
                            acl_helper.get_acl_json(secondary_role_id,
                                                    dummy_user.id)
                        ],
                        "start_date":
                        date(2017, 5, 5),
                        "end_date":
                        date(2017, 9, 16),
                    },
                    {
                        "title":
                        "task 3",
                        "description":
                        "some task 4",
                        "access_control_list": [
                            acl_helper.get_acl_json(role_id, user.id),
                            acl_helper.get_acl_json(role_id, dummy_user.id)
                        ],
                        "start_date":
                        date(2017, 6, 5),
                        "end_date":
                        date(2017, 10, 16),
                    },
                    {
                        "title":
                        "dummy task 4",  # task should not counted
                        "description":
                        "some task 4",
                        "access_control_list":
                        [acl_helper.get_acl_json(role_id, dummy_user.id)],
                        "start_date":
                        date(2017, 6, 5),
                        "end_date":
                        date(2017, 11, 17),
                    },
                    {
                        "title":
                        "dummy task 5",  # task should not counted
                        "description":
                        "some task 4",
                        "access_control_list":
                        [acl_helper.get_acl_json(role_id, dummy_user.id)],
                        "start_date":
                        date(2017, 6, 5),
                        "end_date":
                        date(2017, 11, 18),
                    }
                ],
                "task_group_objects": []
            }]
        }

        inactive_workflow = {
            "title":
            "Activated workflow with archived cycles",
            "notify_on_change":
            True,
            "description":
            "Extra test workflow",
            "owners": [create_stub(user)],
            "task_groups": [{
                "title":
                "Extra task group",
                "contact":
                create_stub(user),
                "task_group_tasks": [{
                    "title":
                    "not counted existing task",
                    "description":
                    "",
                    "access_control_list":
                    [acl_helper.get_acl_json(role_id, user.id)],
                    "start_date":
                    date(2017, 5, 5),
                    "end_date":
                    date(2017, 8, 15),
                }],
                "task_group_objects": []
            }]
        }

        with freeze_time("2017-10-16 05:09:10"):
            self.client.get("/login")
            # Activate normal one time workflow
            _, workflow = self.generator.generate_workflow(one_time_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            tasks = {t.title: t for t in cycle.cycle_task_group_object_tasks}
            _, workflow = self.generator.activate_workflow(workflow)

            # Activate and close the inactive workflow
            _, workflow = self.generator.generate_workflow(inactive_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            _, workflow = self.generator.activate_workflow(workflow)
            self.generator.modify_object(cycle, data={"is_current": False})

        with freeze_time("2017-7-16 07:09:10"):
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 3,
                "has_overdue": False
            })

        with freeze_time("2017-10-16 08:09:10"):  # same day as task 3 end date
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 3,
                "has_overdue": True
            })

            for task, status, count, overdue, my_work_count in transitions:
                self.generator.modify_object(tasks[task],
                                             data={"status": status})
                task_count_response = \
                    self.client.get("/api/people/{}/task_count".format(user_id))
                my_work_count_response = \
                    self.client.get("/api/people/{}/my_work_count".format(user_id))

                self.assertEqual(task_count_response.json, {
                    "open_task_count": count,
                    "has_overdue": overdue
                })

                self.assertEqual(
                    my_work_count_response.json["CycleTaskGroupObjectTask"],
                    my_work_count)

    def test_task_count_multiple_wfs(self):
        """Test task count with both verified and non verified workflows.

    This checks task counts with 4 tasks
        2017, 8, 15  - verification needed
        2017, 11, 18  - verification needed
        2017, 8, 15  - No verification needed
        2017, 11, 18  - No verification needed
    """

        user = all_models.Person.query.first()
        user_id = user.id
        role_id = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.name == "Task Assignees",
            all_models.AccessControlRole.object_type == "TaskGroupTask",
        ).one().id
        workflow_template = {
            "title":
            "verified workflow",
            "owners": [create_stub(user)],
            "is_verification_needed":
            True,
            "task_groups": [{
                "title":
                "one time task group",
                "contact":
                create_stub(user),
                "task_group_tasks": [{
                    "title":
                    "task 1",
                    "description":
                    "some task",
                    "access_control_list":
                    [acl_helper.get_acl_json(role_id, user.id)],
                    "start_date":
                    date(2017, 5, 5),
                    "end_date":
                    date(2017, 8, 15),
                }, {
                    "title":
                    "dummy task 5",
                    "description":
                    "some task 4",
                    "access_control_list":
                    [acl_helper.get_acl_json(role_id, user.id)],
                    "start_date":
                    date(2017, 6, 5),
                    "end_date":
                    date(2017, 11, 18),
                }],
                "task_group_objects": []
            }]
        }

        with freeze_time("2017-10-16 05:09:10"):
            self.client.get("/login")
            verified_workflow = workflow_template.copy()
            verified_workflow["is_verification_needed"] = True
            _, workflow = self.generator.generate_workflow(verified_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            verified_tasks = {
                task.title: task
                for task in cycle.cycle_task_group_object_tasks
            }
            _, workflow = self.generator.activate_workflow(workflow)

            non_verified_workflow = workflow_template.copy()
            non_verified_workflow["is_verification_needed"] = False
            _, workflow = self.generator.generate_workflow(
                non_verified_workflow)
            _, cycle = self.generator.generate_cycle(workflow)
            non_verified_tasks = {
                task.title: task
                for task in cycle.cycle_task_group_object_tasks
            }
            _, workflow = self.generator.activate_workflow(workflow)

        with freeze_time("2017-7-16 07:09:10"):
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 4,
                "has_overdue": False
            })

        with freeze_time("2017-10-16 08:09:10"):
            self.client.get("/login")
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 4,
                "has_overdue": True
            })

            # transition 1, task that needs verification goes to finished state. This
            # transition should not change anything
            self.generator.modify_object(verified_tasks["task 1"],
                                         data={"status": "Finished"})
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 4,
                "has_overdue": True
            })

            # transition 2, task that needs verification goes to verified state. This
            # transition should reduce task count.
            self.generator.modify_object(verified_tasks["task 1"],
                                         data={"status": "Verified"})
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 3,
                "has_overdue": True
            })

            # transition 3, task that does not need verification goes into Finished
            # state. This transition should reduce task count and remove all overdue
            # tasks
            self.generator.modify_object(non_verified_tasks["task 1"],
                                         data={"status": "Finished"})
            response = self.client.get(
                "/api/people/{}/task_count".format(user_id))
            self.assertEqual(response.json, {
                "open_task_count": 2,
                "has_overdue": False
            })

    @ddt.data(("Creator", 403), ("Reader", 403), ("Editor", 200),
              ("Administrator", 200))
    @ddt.unpack
    def test_person_editing(self, role_name, status):
        """{0} should receive {1} status code on edit Person."""
        role = all_models.Role.query.filter(
            all_models.Role.name == role_name).one()
        with factories.single_commit():
            client_user = factories.PersonFactory()
            rbac_factories.UserRoleFactory(role=role, person=client_user)
        self.api.set_user(client_user)
        self.client.get("/login")
        base_email = "*****@*****.**"
        person = factories.PersonFactory(email=base_email)
        person_id = person.id
        new_email = "new_{}".format(base_email)
        resp = self.api.put(person, {"email": new_email})
        self.assertEqual(status, resp.status_code)
        person = all_models.Person.query.get(person_id)
        if status == 200:
            self.assertEqual(new_email, person.email)
        else:
            self.assertEqual(base_email, person.email)
Esempio n. 15
0
class TestWorkflowsApiPost(TestCase):
  """Test class for ggrc workflow api post action."""

  def setUp(self):
    super(TestWorkflowsApiPost, self).setUp()
    self.api = Api()
    self.generator = wf_generator.WorkflowsGenerator()
    self.wf_admin_id = all_models.Person.query.first().id
    with factories.single_commit():
      self.people_ids = [factories.PersonFactory().id for _ in xrange(6)]

  def tearDown(self):
    pass

  def _delete_and_check_related_acl(self, related_model, exp_acl_count,
                                    is_deleted):
    """Delete related model and check remaining ACL count.

    Args:
        related_model: related model class
        exp_acl_count: expected related ACL count after delete operation
        is_deleted: is related object already deleted
    """
    if is_deleted:
      related_count = related_model.query.count()
      self.assertEqual(related_count, 0)
    else:
      related = related_model.query.one()
      response = self.api.delete(related)
      self.assert200(response)

    related_acl_count = all_models.AccessControlList.query.filter(
        all_models.AccessControlList.object_type == related_model.__name__
    ).count()
    self.assertEqual(related_acl_count, 0)

    bg_task_count = all_models.AccessControlList.query.filter(
        all_models.AccessControlList.object_type == "BackgroundTask"
    ).count()

    all_acl_count = all_models.AccessControlList.query.count()
    self.assertEqual(all_acl_count - bg_task_count, exp_acl_count)

  def test_acl_on_object_deletion(self):
    """Test related ACL records removed on related object delete"""
    self._create_propagation_acl_test_data()
    acl_count = all_models.AccessControlList.query.count()
    self.assertNotEqual(acl_count, 0)

    admin = all_models.Person.query.get(1)
    self.api.set_user(admin)

    related_models = (
        (all_models.CycleTaskEntry, 18, False),
        (all_models.TaskGroup, 12, False),
        (all_models.TaskGroupTask, 12, True),
        (all_models.Cycle, 3, False),
        (all_models.CycleTaskGroup, 3, True),
        (all_models.CycleTaskGroupObjectTask, 3, True),
    )
    for related_model, acl_count, is_deleted in related_models:
      self._delete_and_check_related_acl(related_model, acl_count, is_deleted)

  def test_acl_on_workflow_delete(self):
    """Test related ACL records removed on Workflow delete"""
    self._create_propagation_acl_test_data()
    acl_count = all_models.AccessControlList.query.count()
    self.assertNotEqual(acl_count, 0)

    admin = all_models.Person.query.get(1)
    self.api.set_user(admin)
    workflow = all_models.Workflow.query.one()
    response = self.api.delete(workflow)
    self.assert200(response)

    acl_count = all_models.AccessControlList.query.count()
    bg_acl_count = all_models.AccessControlList.query.filter(
        all_models.AccessControlList.object_type == "BackgroundTask"
    ).count()
    self.assertEqual(acl_count, bg_acl_count)

  def test_acl_for_new_related_object(self):
    """Test Workflow ACL propagation for new related objects."""
    data = self.get_workflow_dict()
    acl_map = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Workflow Member'],
    }
    data["workflow"]["access_control_list"] = acl_helper.get_acl_list(acl_map)
    data["workflow"]["unit"] = "week"
    data["workflow"]["repeat_every"] = 1
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

    data = self.get_task_group_dict(response.json["workflow"])
    data["task_group"]["contact"]["id"] = self.people_ids[2]
    data["task_group"]["contact"]["href"] = "/api/people/{}".format(
        self.people_ids[2])
    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

    task_group = all_models.TaskGroup.eager_query().one()
    data = self.get_task_dict(task_group)
    data["task_group_task"]["start_date"] = "2018-01-04"
    data["task_group_task"]["end_date"] = "2018-01-05"
    response = self.api.post(all_models.TaskGroupTask, data)
    self.assertEqual(response.status_code, 201)

    workflow = all_models.Workflow.query.one()
    with freezegun.freeze_time("2018-01-05"):  # Generate 1 cycle
      self.generator.activate_workflow(workflow)

    cycle_task = all_models.CycleTaskGroupObjectTask.query.one()
    cycle = all_models.Cycle.query.one()
    data = self.get_comment_dict(cycle_task, cycle)
    response = self.api.post(all_models.CycleTaskEntry, data)
    self.assertEqual(response.status_code, 201)

    self._check_propagated_acl(3)

  @ddt.data('Admin', 'Workflow Member')
  def test_tg_assignee(self, role_name):
    """Test TaskGroup assignee already has {0} role."""
    data = self.get_workflow_dict()
    init_acl = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES[role_name],
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_acl)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

    data = self.get_task_group_dict(response.json["workflow"])
    data["task_group"]["contact"]["id"] = self.people_ids[1]
    data["task_group"]["contact"]["href"] = "/api/people/{}".format(
        self.people_ids[1])
    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

    workflow = all_models.Workflow.query.one()
    task_group = all_models.TaskGroup.query.one()

    actual_acl = all_models.AccessControlList.eager_query().filter(
        all_models.AccessControlList.person_id == task_group.contact_id,
    ).all()
    self.assertEqual(len(actual_acl), 2)

    expected = {
        role_name: (workflow.type, workflow.id),
        "{} Mapped".format(role_name): (task_group.type, task_group.id)
    }
    actual = {
        acl.ac_role.name: (acl.object_type, acl.object_id)
        for acl in actual_acl
    }
    self.assertDictEqual(expected, actual)

  def test_task_group_assignee_gets_workflow_member(self):  # noqa pylint: disable=invalid-name
    """Test TaskGroup assignee gets WorkflowMember role."""
    data = self.get_workflow_dict()
    init_acl = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Workflow Member'],
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_acl)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

    data = self.get_task_group_dict(response.json["workflow"])
    data["task_group"]["contact"]["id"] = self.people_ids[2]
    data["task_group"]["contact"]["href"] = "/api/people/{}".format(
        self.people_ids[2])
    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

    workflow = all_models.Workflow.query.one()
    task_group = all_models.TaskGroup.query.one()

    parent_acl = all_models.AccessControlList.eager_query().filter(
        all_models.AccessControlList.person_id == task_group.contact_id,
        all_models.AccessControlList.object_type == workflow.type,
        all_models.AccessControlList.object_id == workflow.id
    ).one()
    tg_acl = all_models.AccessControlList.eager_query().filter(
        all_models.AccessControlList.person_id == task_group.contact_id,
        all_models.AccessControlList.object_type == task_group.type,
        all_models.AccessControlList.object_id == task_group.id
    ).one()
    self.assertEqual(parent_acl.ac_role.name, "Workflow Member")
    self.assertEqual(tg_acl.parent_id, parent_acl.id)
    self.assertEqual(tg_acl.ac_role.name, "Workflow Member Mapped")

  def _create_propagation_acl_test_data(self):  # noqa pylint: disable=invalid-name
    """Create objects for Workflow ACL propagation test."""
    with freezegun.freeze_time("2017-08-9"):
      with factories.single_commit():
        workflow = wf_factories.WorkflowFactory(
            title='wf1',
            unit=all_models.Workflow.WEEK_UNIT,
            is_verification_needed=True,
            repeat_every=1)
        wf_factories.TaskGroupTaskFactory(
            title='tgt1',
            task_group=wf_factories.TaskGroupFactory(
                title='tg1',
                context=factories.ContextFactory(),
                workflow=workflow
            ),
            # One cycle should be created
            start_date=datetime.date(2017, 8, 3),
            end_date=datetime.date(2017, 8, 7)
        )
      self.generator.activate_workflow(workflow)
      cycle = all_models.Cycle.query.one()
      cycle_task = all_models.CycleTaskGroupObjectTask.query.one()
      wf_factories.CycleTaskEntryFactory(
          cycle=cycle,
          cycle_task_group_object_task=cycle_task,
          description="Cycle task comment",
      )
      workflow = all_models.Workflow.query.one()
      acl_map = {
          self.people_ids[0]: WF_ROLES['Admin'],
          self.people_ids[1]: WF_ROLES['Workflow Member'],
          self.people_ids[2]: WF_ROLES['Workflow Member'],
      }
      put_params = {'access_control_list': acl_helper.get_acl_list(acl_map)}
      response = self.api.put(workflow, put_params)
      self.assert200(response)

  def _check_propagated_acl(self, roles_count):
    """Check Workflow propagated ACL records.

    Args:
        roles_count: roles' count created in test
    """
    related_objects = (
        (all_models.TaskGroup.query.one().id, all_models.TaskGroup.__name__),
        (all_models.TaskGroupTask.query.one().id,
         all_models.TaskGroupTask.__name__),
        (all_models.Cycle.query.one().id, all_models.Cycle.__name__),
        (all_models.CycleTaskGroup.query.one().id,
         all_models.CycleTaskGroup.__name__),
        (all_models.CycleTaskGroupObjectTask.query.one().id,
         all_models.CycleTaskGroupObjectTask.__name__),
        (all_models.CycleTaskEntry.query.one().id,
         all_models.CycleTaskEntry.__name__)
    )
    related_count = len(related_objects)
    bd_tasks_count = all_models.BackgroundTask.query.count()

    all_acl = [acl for acl in all_models.AccessControlList.eager_query().all()]
    self.assertEqual(
        len(all_acl),
        bd_tasks_count + roles_count + roles_count * related_count
    )

    workflow = all_models.Workflow.query.one()
    parent_acl, related_acl = [], []
    for acl in all_acl:
      if (not acl.parent_id and acl.object_id == workflow.id and
              acl.object_type == workflow.type):
        parent_acl.append(acl)
      else:
        related_acl.append(acl)

    result = defaultdict(set)
    for p_acl in parent_acl:
      for r_acl in related_acl:
        if (r_acl.ac_role.name == '{} Mapped'.format(p_acl.ac_role.name) and
                r_acl.parent_id == p_acl.id and
                r_acl.person_id == p_acl.person_id):
          result[p_acl.id].add((r_acl.object_id, r_acl.object_type))
    self.assertEqual(roles_count, len(result))

  def test_assign_workflow_acl(self):
    """Test propagation Workflow ACL roles on Workflow's update ACL records."""
    self._create_propagation_acl_test_data()
    self._check_propagated_acl(3)

  def test_unassign_workflow_acl(self):
    """Test propagation Workflow ACL roles on person unassigned."""
    self._create_propagation_acl_test_data()
    with freezegun.freeze_time("2017-08-9"):
      workflow = all_models.Workflow.query.one()
      acl_map = {
          self.people_ids[0]: WF_ROLES['Admin'],
          self.people_ids[1]: WF_ROLES['Workflow Member'],
      }
      put_params = {'access_control_list': acl_helper.get_acl_list(acl_map)}
      response = self.api.put(workflow, put_params)
      self.assert200(response)

    self._check_propagated_acl(2)

  def test_post_workflow_with_acl(self):
    """Test PUT workflow with ACL."""
    data = self.get_workflow_dict()

    exp_res = {
        self.wf_admin_id: WF_ROLES['Admin'],
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Workflow Member'],
        self.people_ids[2]: WF_ROLES['Workflow Member'],
        self.people_ids[3]: WF_ROLES['Workflow Member']
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(exp_res)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)
    workflow = all_models.Workflow.eager_query().one()
    act_res = {acl.person_id: acl.ac_role_id
               for acl in workflow.access_control_list}
    self.assertDictEqual(exp_res, act_res)

  def test_update_workflow_acl_people(self):
    """Test PUT workflow with updated ACL."""
    data = self.get_workflow_dict()
    init_map = {
        self.wf_admin_id: WF_ROLES['Admin'],
        self.people_ids[0]: WF_ROLES['Workflow Member'],
    }
    data['workflow']['access_control_list'] = acl_helper.get_acl_list(init_map)
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)
    exp_res = {
        self.people_ids[0]: WF_ROLES['Admin'],
        self.people_ids[1]: WF_ROLES['Admin'],
        self.people_ids[2]: WF_ROLES['Workflow Member'],
        self.people_ids[3]: WF_ROLES['Workflow Member'],
        self.people_ids[4]: WF_ROLES['Workflow Member']
    }
    workflow = all_models.Workflow.eager_query().one()
    put_params = {'access_control_list': acl_helper.get_acl_list(exp_res)}
    response = self.api.put(workflow, put_params)
    self.assert200(response)
    workflow = all_models.Workflow.eager_query().one()
    act_res = {acl.person_id: acl.ac_role_id
               for acl in workflow.access_control_list}
    self.assertDictEqual(exp_res, act_res)

  def test_send_invalid_data(self):
    """Test send invalid data on Workflow post."""
    data = self.get_workflow_dict()
    del data["workflow"]["title"]
    del data["workflow"]["context"]
    response = self.api.post(all_models.Workflow, data)
    self.assert400(response)
    # TODO: check why response.json["message"] is empty

  def test_create_one_time_workflows(self):
    """Test simple create one time Workflow over api."""
    data = self.get_workflow_dict()
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_weekly_workflow(self):
    """Test create valid weekly wf"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 7
    data["workflow"]["unit"] = "day"
    data["workflow"]["title"] = "Weekly"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_annually_workflow(self):
    """Test create valid annual wf"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 12
    data["workflow"]["unit"] = "month"
    data["workflow"]["title"] = "Annually"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  @ddt.data("wrong value", 0, -4)
  def test_create_wrong_repeat_every_workflow(self, value):  # noqa pylint: disable=invalid-name
    """Test case for invalid repeat_every value"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = value
    data["workflow"]["unit"] = "month"
    data["workflow"]["title"] = "Wrong wf"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 400)

  def test_create_wrong_unit_workflow(self):
    """Test case for invalid unit value"""
    data = self.get_workflow_dict()
    data["workflow"]["repeat_every"] = 12
    data["workflow"]["unit"] = "wrong value"
    data["workflow"]["title"] = "Wrong wf"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 400)

  def test_create_task_group(self):
    """Test create task group over api."""
    wf_data = self.get_workflow_dict()
    wf_data["workflow"]["title"] = "Create_task_group"
    wf_response = self.api.post(all_models.Workflow, wf_data)

    data = self.get_task_group_dict(wf_response.json["workflow"])

    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

  @staticmethod
  def get_workflow_dict():
    return {
        "workflow": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "title": "One_time",
            "description": "",
            "unit": None,
            "repeat_every": None,
            "notify_on_change": False,
            "task_group_title": "Task Group 1",
            "notify_custom_message": "",
            "is_verification_needed": True,
            "context": None,
        }
    }

  def get_task_group_dict(self, workflow):
    return {
        "task_group": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "_transient": {},
            "contact": {
                "id": self.wf_admin_id,
                "href": "/api/people/{}".format(self.wf_admin_id),
                "type": "Person"
            },
            "workflow": {
                "id": workflow["id"],
                "href": "/api/workflows/%d" % workflow["id"],
                "type": "Workflow"
            },
            "context": {
                "id": workflow["context"]["id"],
                "href": "/api/contexts/%d" % workflow["context"]["id"],
                "type": "Context"
            },
            "modal_title": "Create Task Group",
            "title": "Create_task_group",
            "description": "",
        }
    }

  def get_task_dict(self, task_group):
    return {
        "task_group_task": {
            "start_date": "2017-12-25",
            "end_date": "2017-12-31",
            "custom_attributes": {},
            "contact": {
                "id": self.wf_admin_id,
                "href": "/api/people/{}".format(self.wf_admin_id),
                "type": "Person"
            },
            "task_group": {
                "id": task_group.id,
                "href": "/api/task_groups/{}".format(task_group.id),
                "type": "TaskGroup"
            },
            "context": {
                "id": task_group.context_id,
                "href": "/api/contexts/{}".format(task_group.context_id),
                "type": "Context"
            },
            "title": "Create_task",
            "task_type": "text",
            "description": ""
        }
    }

  @staticmethod
  def get_comment_dict(cycle_task, cycle):
    return {
        "cycle_task_entry": {
            "custom_attributes": {},
            "cycle_task_group_object_task": {
                "id": cycle_task.id,
                "href": "/api/cycle_task_group_object_tasks/{}".format(
                    cycle_task.id),
                "type": "CycleTaskGroupObjectTask"
            },
            "cycle": {
                "id": cycle.id,
                "href": "/api/cycles/{}".format(cycle.id),
                "type": "Cycle"
            },
            "context": {
                "id": cycle.context_id,
                "href": "/api/contexts/{}".format(cycle.context_id),
                "type": "Context"
            },
            "is_declining_review": "",
            "description": "CT comment"
        }
    }

  @ddt.data({},
            {"repeat_every": 5, "unit": "month"})
  def test_repeat_multiplier_field(self, data):
    """Check repeat_multiplier is set to 0 after wf creation."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(**data)
    workflow_id = workflow.id
    self.assertEqual(
        0, all_models.Workflow.query.get(workflow_id).repeat_multiplier)

  # TODO: Unskip in the patch 2
  @unittest.skip("Will be activated in patch 2")
  def test_change_to_one_time_wf(self):
    """Check repeat_every and unit can be set to Null only together."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                              unit="day")
    resp = self.api.put(workflow, {"repeat_every": None,
                                   "unit": None})
    self.assert200(resp)

  @ddt.data({"repeat_every": 5},
            {"unit": "month"})
  def test_change_repeat_every(self, data):
    """Check repeat_every or unit can not be changed once set."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory()
    resp = self.api.put(workflow, data)
    self.assert400(resp)

  def test_not_change_to_one_time_wf(self):
    """Check repeat_every or unit can't be set to Null separately.
    This test will be useful in the 2nd patch, where we allow to change
    WF setup
    """
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(repeat_every=12,
                                              unit="day")
    resp = self.api.put(workflow, {"repeat_every": None})
    self.assert400(resp)
    resp = self.api.put(workflow, {"unit": None})
    self.assert400(resp)

  @ddt.data(True, False)
  def test_autogen_verification_flag(self, flag):
    """Check is_verification_needed flag for activate WF action."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
      group = wf_factories.TaskGroupFactory(workflow=workflow)
      wf_factories.TaskGroupTaskFactory(task_group=group)
    data = [{
        "cycle": {
            "autogenerate": True,
            "isOverdue": False,
            "workflow": {
                "id": workflow.id,
                "type": "Workflow",
            },
            "context": {
                "id": workflow.context_id,
                "type": "Context",
            },
        }
    }]
    resp = self.api.send_request(
        self.api.client.post,
        api_link="/api/cycles",
        data=data)
    cycle_id = resp.json[0][1]["cycle"]["id"]
    self.assertEqual(
        flag, all_models.Cycle.query.get(cycle_id).is_verification_needed)

  @ddt.data(True, False)
  def test_verification_flag_positive(self, flag):  # noqa pylint: disable=invalid-name
    """is_verification_needed flag is changeable for DRAFT workflow."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": not flag})
    self.assert200(resp)
    self.assertEqual(
        all_models.Workflow.query.get(workflow_id).is_verification_needed,
        not flag)

  @ddt.data(True, False)
  def test_verification_flag_negative(self, flag):
    """Test immutable verification flag on active workflows."""
    with freezegun.freeze_time("2017-08-10"):
      with factories.single_commit():
        workflow = wf_factories.WorkflowFactory(
            unit=all_models.Workflow.WEEK_UNIT,
            is_verification_needed=flag,
            repeat_every=1)
        wf_factories.TaskGroupTaskFactory(
            task_group=wf_factories.TaskGroupFactory(
                context=factories.ContextFactory(),
                workflow=workflow
            ),
            # Two cycles should be created
            start_date=datetime.date(2017, 8, 3),
            end_date=datetime.date(2017, 8, 7))
      workflow_id = workflow.id
      self.assertEqual(workflow.status, all_models.Workflow.DRAFT)
      self.generator.activate_workflow(workflow)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.status, all_models.Workflow.ACTIVE)
      resp = self.api.put(workflow, {"is_verification_needed": not flag})
      self.assert400(resp)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.is_verification_needed, flag)

      # End all current cycles
      for cycle in workflow.cycles:
        self.generator.modify_object(cycle, {'is_current': False})
      workflow = all_models.Workflow.query.filter(
          all_models.Workflow.id == workflow_id).first()
      self.assertEqual(workflow.status, all_models.Workflow.INACTIVE)
      resp = self.api.put(workflow, {"is_verification_needed": not flag})
      self.assert400(resp)
      workflow = all_models.Workflow.query.get(workflow_id)
      self.assertEqual(workflow.is_verification_needed, flag)

  @ddt.data(True, False)
  def test_not_change_vf_flag(self, flag):
    """Check is_verification_needed not change on update."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": flag})
    self.assert200(resp)
    self.assertEqual(
        flag,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)

  @ddt.data(True, False, None)
  def test_create_vf_flag(self, flag):
    """Check is_verification_needed flag setup on create."""
    data = self.get_workflow_dict()
    if flag is None:
      data['workflow'].pop('is_verification_needed', None)
    else:
      data['workflow']['is_verification_needed'] = flag
    resp = self.api.post(all_models.Workflow, data)
    self.assertEqual(201, resp.status_code)
    workflow_id = resp.json['workflow']['id']
    self.assertEqual(
        flag if flag is not None else True,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)
Esempio n. 16
0
class TestCycleTaskDeprecated(TestCase):
  """Test for correct working field last_deprecated_date."""

  def setUp(self):
    super(TestCycleTaskDeprecated, self).setUp()
    self.api = Api()

  def test_redefine_status(self):
    """Test cycle task create and change status to Deprecated."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_keep_date_unchanged(self):
    """Test set status to Deprecated, and then set status to Finished."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

      cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
          all_models.CycleTaskGroupObjectTask.id == cycle_task.id
      ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_repeat_deprecated_state(self):
    """Test updating of last deprecated date by multiply changing of status."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })
    with freeze_time("2017-02-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })
    with freeze_time("2017-02-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 2, 25))

  def test_filter_by_deprecated_date(self):
    """Test filter cycle task by last deprecated date."""
    amount_of_cycle_tasks = 5
    list_of_ids = []
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      with freeze_time("2017-01-25"):
        for _ in range(amount_of_cycle_tasks):
          list_of_ids.append(
              cycle_task_factory(status="Deprecated").id
          )

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01-25",
            },
        },
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(list_of_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])

  def test_sort_by_deprecated_date(self):
    """Test sorting results of filter cycle tasks by deprecated date."""
    dict_of_dates = {}
    date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      for date in date_list:
        with freeze_time(date):
          dict_of_dates[cycle_task_factory(status="Deprecated").id] = date

    sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
    sorted_list_ids = [item[0] for item in sorted_dict]

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01",
            },
        },
        "order_by": [{"name": "last_deprecated_date"}],
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(sorted_list_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])
Esempio n. 17
0
class TestWorkflowsApiPost(TestCase):
    def setUp(self):
        super(TestWorkflowsApiPost, self).setUp()
        self.api = Api()

    def tearDown(self):
        pass

    def test_send_invalid_data(self):
        data = self.get_workflow_dict()
        del data["workflow"]["title"]
        del data["workflow"]["context"]
        response = self.api.post(all_models.Workflow, data)
        self.assert400(response)
        # TODO: check why response.json["message"] is empty

    def test_create_one_time_workflows(self):
        data = self.get_workflow_dict()
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_weekly_workflows(self):
        data = self.get_workflow_dict()
        data["workflow"]["frequency"] = "weekly"
        data["workflow"]["title"] = "Weekly"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_monthly_workflows(self):
        data = self.get_workflow_dict()
        data["workflow"]["frequency"] = "monthly"
        data["workflow"]["title"] = "Monthly"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_quarterly_workflows(self):
        data = self.get_workflow_dict()
        data["workflow"]["frequency"] = "quarterly"
        data["workflow"]["title"] = "Quarterly"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_annually_workflows(self):
        data = self.get_workflow_dict()
        data["workflow"]["frequency"] = "annually"
        data["workflow"]["title"] = "Annually"
        response = self.api.post(all_models.Workflow, data)
        self.assertEqual(response.status_code, 201)

    def test_create_task_group(self):
        wf_data = self.get_workflow_dict()
        wf_data["workflow"]["title"] = "Create_task_group"
        wf_response = self.api.post(all_models.Workflow, wf_data)

        data = self.get_task_group_dict(wf_response.json["workflow"])

        response = self.api.post(all_models.TaskGroup, data)
        self.assertEqual(response.status_code, 201)

    # TODO: Api should be able to handle invalid data
    @unittest.skip("Not implemented.")
    def test_create_task_group_invalid_workflow_data(self):
        data = self.get_task_group_dict({"id": -1, "context": {"id": -1}})
        response = self.api.post(all_models.TaskGroup, data)
        self.assert400(response)

    @staticmethod
    def get_workflow_dict():
        data = {
            "workflow": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "title": "One_time",
                "description": "",
                "frequency": "one_time",
                "notify_on_change": False,
                "task_group_title": "Task Group 1",
                "notify_custom_message": "",
                "is_verification_needed": True,
                "owners": None,
                "context": None,
            }
        }
        return data

    @staticmethod
    def get_task_group_dict(workflow):
        data = {
            "task_group": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "_transient": {},
                "contact": {
                    "id": 1,
                    "href": "/api/people/1",
                    "type": "Person"
                },
                "workflow": {
                    "id": workflow["id"],
                    "href": "/api/workflows/%d" % workflow["id"],
                    "type": "Workflow"
                },
                "context": {
                    "id": workflow["context"]["id"],
                    "href": "/api/contexts/%d" % workflow["context"]["id"],
                    "type": "Context"
                },
                "modal_title": "Create Task Group",
                "title": "Create_task_group",
                "description": "",
            }
        }
        return data

    @ddt.data(True, False)
    def test_autogen_verification_flag(self, flag):
        """Check is_verification_needed flag for activate WF action."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
            group = wf_factories.TaskGroupFactory(workflow=workflow)
            wf_factories.TaskGroupTaskFactory(task_group=group)
        data = [{
            "cycle": {
                "autogenerate": True,
                "isOverdue": False,
                "workflow": {
                    "id": workflow.id,
                    "type": "Workflow",
                },
                "context": {
                    "id": workflow.context_id,
                    "type": "Context",
                },
            }
        }]
        resp = self.api.send_request(self.api.client.post,
                                     api_link="/api/cycles",
                                     data=data)
        cycle_id = resp.json[0][1]["cycle"]["id"]
        self.assertEqual(
            flag,
            all_models.Cycle.query.get(cycle_id).is_verification_needed)

    @ddt.data(True, False)
    def test_change_verification_flag(self, flag):
        """Check is_verification_needed flag isn't changeable."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": not flag})
        self.assert400(resp)
        self.assertEqual(
            flag,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)

    @ddt.data(True, False)
    def test_not_change_vf_flag(self, flag):
        """Check is_verification_needed not change on update."""
        with factories.single_commit():
            workflow = wf_factories.WorkflowFactory(
                is_verification_needed=flag)
        workflow_id = workflow.id
        resp = self.api.put(workflow, {"is_verification_needed": flag})
        self.assert200(resp)
        self.assertEqual(
            flag,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)

    @ddt.data(True, False, None)
    def test_create_vf_flag(self, flag):
        """Check is_verification_needed flag setup on create."""
        data = self.get_workflow_dict()
        if flag is None:
            data['workflow'].pop('is_verification_needed', None)
        else:
            data['workflow']['is_verification_needed'] = flag
        resp = self.api.post(all_models.Workflow, data)
        self.assertEqual(201, resp.status_code)
        workflow_id = resp.json['workflow']['id']
        self.assertEqual(
            flag if flag is not None else True,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)
Esempio n. 18
0
class TestGGRC2857(TestCase, WithQueryApi):

	def setUp(self):
		self.client.get("/login")
		self.api = Api()
		program_creator_id = 1;

		#		acl = [acl_helper.get_acl_json(ac_roles["Program Managers"], program_creator_id)]

		""" Create Program """

		response = self.api.post(all_models.Program, {
			"program": {
				"title": "Program GGRC-2857", 
				"context": None,
				"access_control_list": [] #acl
			},
		})
		self.program_id = response.json.get("program").get("id")
#		print('Program id : %s' % self.program_id)

		""" Create Audit """

		response = self.api.post(all_models.Audit, {
			"audit": {
    			"title": "Program GGRC-2857 audit",
    			'program': {'id': self.program_id, "type": "Program"},
    			"status": "Planned",
    			"context": None,
				"modified_by_id": program_creator_id,
    			"access_control_list": []
			}
		})

		self.audit_id = response.json.get("audit").get("id")
		context = response.json.get("audit").get("context")

#		print('Audit id : %s' % self.audit_id)

		""" Create Assessment """

		response = self.api.post(all_models.Assessment, {
			"assessment": {
				"title": "Assessment GGRC-2857",
				"context": context,
				"recipients": "Assignees,Creators,Verifiers",
				"audit": {
					"id": self.audit_id,
					"href": "/api/audits/" + str(self.audit_id),
					"type": "Audit"
				},
				"access_control_list": [],
			},
		})

		self.assessment_id = response.json.get("assessment").get("id")
#		print('Assessment id : %s' % self.assessment_id)

		""" Create Regulation """

		response = self.api.post(all_models.Regulation, {
			"regulation":{
				"title":"Regulation GGRC-2857",
				"recipients":"Admin,Primary Contacts,Secondary Contacts",
				"status":"Draft",
				"context": None,
				"kind":"Regulation",
				"access_control_list":[],
			},
		})
		self.regulation_id = response.json.get("regulation").get("id")
		regulation_slug = response.json.get("regulation").get("slug")
#		print('Regulation id : %s' % self.regulation_id)

		""" Map Regulation to Audit """
		response = self.api.post(all_models.Relationship, {
			"relationship":{
				"source":{
					"id":self.audit_id,
					"href":"/api/audits/"+ str(self.audit_id),
					"type":"Audit"},
				"destination":{
					"id":self.regulation_id,
					"href":"/api/regulations/" + str(self.regulation_id),
					"type":"Regulation",
				},
				"context": None,
			},			
		})
		self.relationship_id = response.json.get("relationship").get("id")
#		print('Relationship id : %s' % self.relationship_id)

		""" Export Assessment """
		data = [{
			"object_name": "Assessment",
			"filters": {
    			"expression": {},
			},
			"fields": "all",
		}]
		response = self.export_csv(data)
		
		""" Change Assessment """
		imp = (response.data.replace(",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", ",,,,,,,,,,,,,,,,,,,,,,,,"+regulation_slug+",,,,,,,",1)).encode('ascii','ignore')
		self._file = StringIO(imp)

	def tearDown(self):
		asmnt = all_models.Assessment.query.get(self.assessment_id)
		self.api.delete(asmnt)
		regul = all_models.Regulation.query.get(self.regulation_id)
		self.api.delete(regul)
		prog = all_models.Program.query.get(self.program_id)
		self.api.delete(prog)

		return

	@patch("ggrc.gdrive.file_actions.get_gdrive_file",
		new=read_imported_file)
	def test_GGRC2857(self):

		""" Import/Check Assessment """
		data = {"file": (self._file, "test.csv")}
		response = self.send_import_request(data)
		self.assertEqual(response[0]["updated"], 1, msg="Only 1 assessment should be updated")
		
		""" Check Assessment """
		self.snap_types = ["Standard", "Regulation", "Section", "Objective", "Control", "Product", "System", "Process", "AccessGroup", "Clause", "Contract", "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk", "Threat", "Vendor",]
		self.rel_types = ["Audit", "Evidence", "Issue",]

		query_data = []
		relevant = {"object_name": "Assessment", "op": {"name": "relevant"}, "ids": [self.assessment_id]}

		for snap_type in self.snap_types:
			child = self.make_filter_expression(expression=["child_type","=", snap_type])
			filters = {"expression": self.make_filter_expression(expression=[child, "AND", relevant])}
			query_data.append(self._make_query_dict_base("Snapshot", type_="count", filters=filters))

		filters = {"expression": relevant}
		for rel_type in self.rel_types:
			query_data.append(self._make_query_dict_base(rel_type, type_="count", filters=filters))

		response = self.api.send_request(
        	self.api.client.post,
        	data=query_data,
        	api_link="/query"
    	)
		self.assertEqual(response.json[1]["Snapshot"]["count"], 1, msg="Only 1 regulation should be relevant to our assessment")

		""" Check Regulation/Audit """
		query_data = []
		relevant = {"object_name": "Assessment", "op": {"name": "relevant"}, "ids": [self.assessment_id]}
		child = self.make_filter_expression(expression=["child_type","=", "Regulation"])
		filters = {"expression": self.make_filter_expression(expression=[child, "AND", relevant])}
		query_data.append({
				"object_name": "Snapshot",
				"filters": filters,
				"limit": [0, 1],
				"fields": ["child_id", "child_type", "context", "email", "id", "is_latest_revision", "name", "revision", "revisions", "selfLink", "slug", "status", "title", "type", "viewLink", "workflow_state", "archived", "program", "DEFAULT_PEOPLE_LABELS", "object_people", "user_roles"],
			})
		filters = {"expression": relevant}
		query_data.append({
				"object_name": "Audit",
				"filters": filters,
				"limit": [0, 1],
				"fields": ["child_id", "child_type", "context", "email", "id", "is_latest_revision", "name", "revision", "revisions", "selfLink", "slug", "status", "title", "type", "viewLink", "workflow_state", "archived", "program", "DEFAULT_PEOPLE_LABELS", "object_people", "user_roles"],
			})

		relevant = {"object_name": "Audit", "op": {"name": "relevant"}, "ids": [self.audit_id]}
		for snap_type in self.snap_types:
			child = self.make_filter_expression(expression=["child_type","=", snap_type])
			filters = {"expression": self.make_filter_expression(expression=[child, "AND", relevant])}
			query_data.append(self._make_query_dict_base("Snapshot", type_="ids", filters=filters))

		filters = {"expression": relevant}
		query_data.append({
				"object_name": "Issue",
				"filters": filters,
				"type": "ids",
			})

		response = self.api.send_request(
        	self.api.client.post,
        	data=query_data,
        	api_link="/query"
    	)
		
		self.assertEqual(response.json[0]["Snapshot"]["values"][0]["id"], self.relationship_id, msg="Relashionship Id doesn't match with created")
		self.assertEqual(response.json[1]["Audit"]["values"][0]["id"], self.audit_id, msg="Audit Id doesn't match with created")
		
		return
class TestCycleTaskDeprecated(TestCase):
  """Test for correct working field last_deprecated_date."""

  def setUp(self):
    super(TestCycleTaskDeprecated, self).setUp()
    self.api = Api()

  def test_redefine_status(self):
    """Test cycle task create and change status to Deprecated."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_keep_date_unchanged(self):
    """Test set status to Deprecated, and then set status to Finished."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

      cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
          all_models.CycleTaskGroupObjectTask.id == cycle_task.id
      ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_repeat_deprecated_state(self):
    """Test updating of last deprecated date by multiply changing of status."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })
    with freeze_time("2017-02-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })
    with freeze_time("2017-02-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 2, 25))

  def test_filter_by_deprecated_date(self):
    """Test filter cycle task by last deprecated date."""
    amount_of_cycle_tasks = 5
    list_of_ids = []
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      with freeze_time("2017-01-25"):
        for _ in range(amount_of_cycle_tasks):
          list_of_ids.append(
              cycle_task_factory(status="Deprecated").id
          )

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01-25",
            },
        },
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(list_of_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])

  def test_sort_by_deprecated_date(self):
    """Test sorting results of filter cycle tasks by deprecated date."""
    dict_of_dates = {}
    date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      for date in date_list:
        with freeze_time(date):
          dict_of_dates[cycle_task_factory(status="Deprecated").id] = date

    sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
    sorted_list_ids = [item[0] for item in sorted_dict]

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01",
            },
        },
        "order_by": [{"name": "last_deprecated_date"}],
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(sorted_list_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])
Esempio n. 20
0
class TestBulkIssuesSync(TestCase):
    """Base class for bulk issuetracker synchronization tests."""
    def setUp(self):
        """Set up for test methods."""
        super(TestBulkIssuesSync, self).setUp()
        self.api = Api()
        self.gen = generator.ObjectGenerator()

        self.role_people = {
            "Audit Captains":
            factories.PersonFactory(email="*****@*****.**"),
            "Creators": factories.PersonFactory(email="*****@*****.**"),
            "Assignees":
            factories.PersonFactory(email="*****@*****.**"),
            "Verifiers":
            factories.PersonFactory(email="*****@*****.**"),
        }
        self.issue_id = "42"

    def setup_assessments(self, asmnt_count, issue_id=None, enabled=True):
        """Create Audit with couple of Assessments and linked IssueTrackerIssues.

    Args:
        asmnt_count: Count of Assessments in Audit.

    Returns:
        Tuple with Audit id and list of Assessment ids.
    """
        with factories.single_commit():
            audit = factories.AuditFactory()
            audit.add_person_with_role_name(
                self.role_people["Audit Captains"],
                "Audit Captains",
            )
            factories.IssueTrackerIssueFactory(
                enabled=enabled,
                issue_tracked_obj=audit,
                issue_id=issue_id,
                issue_type=constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'],
                component_id=12345,
                hotlist_id=12345,
                issue_priority="P2",
                issue_severity="S2",
            )

            assessment_ids = []
            for _ in range(asmnt_count):
                asmnt = factories.AssessmentFactory(audit=audit)
                factories.RelationshipFactory(source=audit, destination=asmnt)
                for role_name in ["Creators", "Assignees", "Verifiers"]:
                    asmnt.add_person_with_role_name(
                        self.role_people[role_name],
                        role_name,
                    )
                factories.IssueTrackerIssueFactory(
                    enabled=enabled,
                    issue_tracked_obj=asmnt,
                    issue_id=issue_id,
                    title=None,
                )
                assessment_ids.append(asmnt.id)
            return audit.id, assessment_ids

    @staticmethod
    def setup_issues(issue_count, issue_id=None, enabled=True):
        """Create issues with enabled integration."""
        with factories.single_commit():
            issue_ids = []
            for _ in range(issue_count):
                issue = factories.IssueFactory()
                factories.IssueTrackerIssueFactory(
                    enabled=enabled,
                    issue_tracked_obj=issue,
                    issue_id=issue_id,
                    title=None,
                )
                issue_ids.append(issue.id)
            return issue_ids

    def issuetracker_sync_mock(self, sync_func_name):
        """IssueTracker sync method mock."""
        return mock.patch.object(sync_utils,
                                 sync_func_name,
                                 return_value={"issueId": self.issue_id})

    def generate_children_issues_for(self, parent_type, parent_id, child_type):
        """Generate IssueTracker issue for objects with provided type and ids.

    Args:
        obj_type: Type of objects. Now only 'Assessment' supported.
        obj_ids: List with ids of objects.

    Returns:
        Response with result of issues generation.
    """
        with self.issuetracker_sync_mock("create_issue"):
            return self.api.send_request(self.api.client.post,
                                         api_link="/generate_children_issues",
                                         data={
                                             "parent": {
                                                 "type": parent_type,
                                                 "id": parent_id
                                             },
                                             "child_type": child_type,
                                         })

    def generate_issues_for(self, object_info):
        """Generate IssueTracker issues for provided objects."""
        with self.issuetracker_sync_mock("create_issue"):
            return self.api.send_request(
                self.api.client.post,
                api_link="/generate_issues",
                data={
                    "objects": [{
                        "type": type_,
                        "id": id_,
                        "hotlist_ids": hotlist_id,
                        "component_id": component_id,
                    } for type_, id_, hotlist_id, component_id in object_info],
                })

    def update_issues_for(self, object_info):
        """Update IssueTracker issues for provided objects."""
        with self.issuetracker_sync_mock("update_issue"):
            return self.api.send_request(
                self.api.client.post,
                api_link="/update_issues",
                data={
                    "objects": [{
                        "type": type_,
                        "id": id_,
                        "hotlist_ids": hotlist_id,
                        "component_id": component_id,
                    } for type_, id_, hotlist_id, component_id in object_info],
                })

    def assert_obj_issues(self, issuetracker_info, assignee=None):
        """Check correctness of created IssueTracker issues."""
        for type_, id_, hotlist_id, component_id in issuetracker_info:
            obj = inflector.get_model(type_).query.get(id_)
            issue = obj.issuetracker_issue

            self.assertEqual(issue.enabled, 1)
            self.assertEqual(issue.title, obj.title)
            self.assertEqual(issue.component_id, component_id)
            self.assertEqual(issue.hotlist_id, hotlist_id)
            self.assertEqual(
                issue.issue_type,
                constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'])
            self.assertEqual(issue.issue_priority, "P2")
            self.assertEqual(issue.issue_severity, "S2")
            self.assertEqual(issue.assignee, assignee)
            self.assertEqual(issue.cc_list, "")
            self.assertEqual(issue.issue_id, self.issue_id)
            self.assertEqual(issue.issue_url,
                             "http://issue/{}".format(self.issue_id))

    def assert_children_asmnt_issues(self, asmnt_ids):
        """Check if Assessments IssueTracker issues inherit data from Audit."""
        assessments = all_models.Assessment.query.filter(
            all_models.Assessment.id.in_(asmnt_ids))
        for asmnt in assessments:
            issue = asmnt.issuetracker_issue
            parent_issue = asmnt.audit.issuetracker_issue

            self.assertEqual(issue.enabled, 1)
            self.assertEqual(issue.title, asmnt.title)
            self.assertEqual(issue.component_id, parent_issue.component_id)
            self.assertEqual(issue.hotlist_id, parent_issue.hotlist_id)
            self.assertEqual(issue.issue_type, parent_issue.issue_type)
            self.assertEqual(issue.issue_priority, parent_issue.issue_priority)
            self.assertEqual(issue.issue_severity, parent_issue.issue_severity)
            self.assertEqual(issue.assignee, "*****@*****.**")
            self.assertEqual(issue.cc_list, "")
            self.assertEqual(issue.issue_id, self.issue_id)
            self.assertEqual(issue.issue_url,
                             "http://issue/{}".format(self.issue_id))

    def assert_not_updated(self, object_type, object_ids):
        """Check if IssueTracker issues have empty fields.

    Args:
        object_type: Type of objects which issues should be checked.
        object_ids: List with ids for objects which issues should be checked.

    Raise:
        AssertionError if relevant Issues have non-empty base fields.
    """
        issues = all_models.IssuetrackerIssue.query.filter(
            all_models.IssuetrackerIssue.object_type == object_type,
            all_models.IssuetrackerIssue.object_id.in_(object_ids),
        )
        for issue in issues:
            self.assertEqual(issue.issue_id, None)
            self.assertEqual(issue.assignee, None)
            self.assertEqual(issue.cc_list, "")
            self.assertEqual(issue.title, None)
Esempio n. 21
0
class TestValidation(TestCase):
    """Test validation query."""
    def setUp(self):
        """Log in before performing queries."""
        # we don't call super as TestCase.setUp clears the DB
        # super(BaseQueryAPITestCase, self).setUp()
        self.client.get("/login")
        self.api = Api()

    def assert_validation(self, query_data):
        self.assert400(
            self.api.send_request(self.api.client.post,
                                  data=query_data,
                                  api_link="/query"))

    OPERATIONS = ["=", "!=", "~", "!=", ">", "<", ">=", "<="]

    @ddt.data(*OPERATIONS)
    def test_only_left_validations(self, operation):
        self.assert_validation([{
            "object_name": "Snapshot",
            "filters": {
                "expression": {
                    "left": "title",
                    "op": {
                        "name": operation
                    },
                }
            }
        }])

    @ddt.data(*OPERATIONS)
    def test_only_right_validations(self, operation):
        self.assert_validation([{
            "object_name": "Snapshot",
            "filters": {
                "expression": {
                    "right": "value",
                    "op": {
                        "name": operation
                    },
                }
            }
        }])

    @ddt.data({}, {"name": "x"})
    def test_invalid_operations(self, operation_dict):
        self.assert_validation([{
            "object_name": "Snapshot",
            "filters": {
                "expression": {
                    "right": "value",
                    "op": operation_dict
                }
            }
        }])

    NO_OPERATION_DATA = [{
        "object_name": "Snapshot",
        "filters": {
            "expression": {
                "right": "value",
                "left": "title"
            }
        }
    }]

    NO_OBJECT_NAME_DATA = [{
        "filters": {
            "expression": {
                "left": "title",
                "op": {
                    "name": "="
                }
            }
        }
    }]

    @ddt.data(
        [{}],
        NO_OPERATION_DATA,
        NO_OBJECT_NAME_DATA,
    )
    def test_validation(self, query_data):
        self.assert_validation(query_data)
class TestAuditDeprecated(TestCase):
    """Test for correct working field last_deprecated_date """
    def setUp(self):
        super(TestAuditDeprecated, self).setUp()
        self.api = Api()

    def test_redefine_status(self):
        """Test create audit and change status to Deprecated"""
        audit = factories.AuditFactory()

        with freeze_time("2017-01-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})

        audit_result = all_models.Audit.query.filter(
            all_models.Audit.id == audit.id).one()

        self.assertEquals(audit_result.last_deprecated_date,
                          datetime.date(2017, 1, 25))

    def test_keep_date_unchanged(self):
        """Test set status audit to Deprecated, and then set status to Planned"""
        audit = factories.AuditFactory()

        with freeze_time("2017-01-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})

        with freeze_time("2017-01-26"):
            self.api.modify_object(audit, {"status": "Planned"})

        audit_result = all_models.Audit.query.filter(
            all_models.Audit.id == audit.id).one()

        self.assertEquals(audit_result.status, "Planned")
        self.assertEquals(audit_result.last_deprecated_date,
                          datetime.date(2017, 1, 25))

    def test_repeat_deprecated_state(self):
        """Test set status audit to Deprecated, then to Planned,
    then to Deprecated and then to Planned"""
        audit = factories.AuditFactory()

        with freeze_time("2017-01-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})

        with freeze_time("2017-01-26"):
            self.api.modify_object(audit, {"status": "Planned"})
        with freeze_time("2017-02-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})
        with freeze_time("2017-02-26"):
            self.api.modify_object(audit, {"status": "Planned"})

        audit_result = all_models.Audit.query.filter(
            all_models.Audit.id == audit.id).one()

        self.assertEquals(audit_result.status, "Planned")
        self.assertEquals(audit_result.last_deprecated_date,
                          datetime.date(2017, 2, 25))

    def test_filter_by_deprecated_date(self):
        """Test filter audits by last deprecated date"""
        amount_of_audits = 5
        list_of_ids = []
        with factories.single_commit():
            with freeze_time("2017-01-25"):
                for _ in range(amount_of_audits):
                    list_of_ids.append(
                        factories.AuditFactory(status="Deprecated").id)

        query_request_data = [{
            "object_name": "Audit",
            'filters': {
                'expression': {
                    'left': 'Last Deprecated Date',
                    'op': {
                        'name': '='
                    },
                    'right': "2017-01-25",
                },
            },
            'type': 'ids',
        }]

        result = self.api.send_request(self.api.client.post,
                                       data=query_request_data,
                                       api_link="/query")
        self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"])

    def test_sort_by_deprecated_date(self):
        """Test sorting results of filter audits by deprecated date"""
        dict_of_dates = {}
        date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
        with factories.single_commit():
            for date in date_list:
                with freeze_time(date):
                    dict_of_dates[factories.AuditFactory(
                        status="Deprecated").id] = date

        sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
        sorted_list_ids = [item[0] for item in sorted_dict]

        query_request_data = [{
            "object_name": "Audit",
            'filters': {
                'expression': {
                    'left': 'Last Deprecated Date',
                    'op': {
                        'name': '='
                    },
                    'right': "2017-01",
                },
            },
            "order_by": [{
                "name": "last_deprecated_date"
            }],
            'type': 'ids',
        }]

        result = self.api.send_request(self.api.client.post,
                                       data=query_request_data,
                                       api_link="/query")

        self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])
Esempio n. 23
0
class TestWithLastAssessmentDate(TestCase, WithQueryApi):
  """Integration test suite for WithLastComment functionality."""

  def setUp(self):
    super(TestWithLastAssessmentDate, self).setUp()
    self.client.get("/login")
    self.api = Api()
    self.gen = generator.ObjectGenerator()

    self.asmnt_comments = defaultdict(dict)
    with factories.single_commit():
      for _ in range(3):
        asmnt = factories.AssessmentFactory()
        for _ in range(3):
          comment = factories.CommentFactory(
              description=factories.random_str()
          )
          self.asmnt_comments[asmnt.id][comment.id] = comment.description
          factories.RelationshipFactory(source=asmnt, destination=comment)

    query = all_models.Revision.query.filter_by(resource_type="Comment")
    revision_ids = [revision.id for revision in query]
    self.api.send_request(
        self.api.client.post,
        api_link="/admin/compute_attributes",
        data={"revision_ids": revision_ids}
    )

  def test_last_comment_value(self):
    """Test assessment has proper value in last_comment field"""
    assessments = all_models.Assessment.query
    self.assertEqual(assessments.count(), len(self.asmnt_comments))
    for asmnt in assessments:
      last_comment_id = max(self.asmnt_comments[asmnt.id])
      self.assertEqual(
          asmnt.last_comment_id,
          last_comment_id
      )
      self.assertEqual(
          asmnt.last_comment,
          self.asmnt_comments[asmnt.id][last_comment_id]
      )

  def test_last_comment_filter(self):
    """Test filtration by last comment."""
    asmnt = all_models.Assessment.query.first()
    result = self._get_first_result_set(
        self._make_query_dict(
            "Assessment",
            expression=("Last Comment", "=", asmnt.last_comment),
            type_="ids",
        ),
        "Assessment",
    )
    self.assertEqual(result["count"], 1)
    self.assertEqual(result["ids"], [asmnt.id])

  def test_last_comment_order(self):
    """Test sorting by last comment."""
    result = self._get_first_result_set(
        self._make_query_dict(
            "Assessment",
            order_by=[{"name": "Last Comment"}],
            type_="ids"
        ),
        "Assessment",
        "ids",
    )
    asmnts = all_models.Assessment.query
    sorted_asmnts = sorted(asmnts, key=lambda k: k.last_comment)
    self.assertEqual(result, [i.id for i in sorted_asmnts])

  def test_export_last_comment(self):
    """Test export Last Assessment Date."""
    search_request = [{
        "object_name": "Assessment",
        "filters": {
            "expression": {},
        },
        "fields": "all",
    }]
    query = self.export_parsed_csv(search_request)["Assessment"]

    exported_comments = [asmnt["Last Comment"] for asmnt in query]
    db_comments = [a.last_comment for a in all_models.Assessment.query]
    self.assertEqual(exported_comments, db_comments)

  def test_import_last_comment(self):
    """Test Last Assessment Date field read only on import."""
    audit = factories.AuditFactory()
    response = self.import_data(collections.OrderedDict([
        ("object_type", "Assessment"),
        ("Code*", "Asmnt-code"),
        ("Audit", audit.slug),
        ("Assignees", "*****@*****.**"),
        ("Creators", "*****@*****.**"),
        ("Title", "Test title"),
        ("Last Comment", "some comment"),
    ]))
    self._check_csv_response(response, {})
    asmnts = all_models.Assessment.query.filter(
        all_models.Assessment.slug == "Asmnt-code"
    ).all()
    self.assertEqual(len(asmnts), 1)
    self.assertEqual(asmnts[0].last_comment, None)

  def test_ca_create_on_import(self):
    """Test creating last_comment CA when comments imported"""
    audit = factories.AuditFactory()
    response = self.import_data(collections.OrderedDict([
        ("object_type", "Assessment"),
        ("Code*", "Asmnt-code"),
        ("Audit", audit.slug),
        ("Assignees", "*****@*****.**"),
        ("Creators", "*****@*****.**"),
        ("Title", "Test title"),
        ("Comments", "new comment1;;new comment2;;new comment3"),
    ]))
    tasks = self.taskqueue_stub.get_filtered_tasks()
    deferred.run(tasks[0].payload)
    self._check_csv_response(response, {})
    asmnt = all_models.Assessment.query.filter_by(slug="Asmnt-code").first()
    self.assertEqual(asmnt.last_comment, "new comment3")

  def test_ca_update_on_import(self):
    """Test updating of last_comment CA when comments imported"""
    asmnt_id = self.asmnt_comments.keys()[0]
    asmnt_slug = all_models.Assessment.query.get(asmnt_id).slug
    response = self.import_data(collections.OrderedDict([
        ("object_type", "Assessment"),
        ("Code*", asmnt_slug),
        ("Comments", "new comment1;;new comment2;;new comment3"),
    ]))
    tasks = self.taskqueue_stub.get_filtered_tasks()
    deferred.run(tasks[0].payload)
    self._check_csv_response(response, {})
    asmnt = all_models.Assessment.query.filter_by(slug=asmnt_slug).first()
    self.assertEqual(asmnt.last_comment, "new comment3")

  @staticmethod
  def get_model_fulltext(model_name, property, ids):
    """Get fulltext records for model."""
    # pylint: disable=redefined-builtin
    return db.session.query(mysql.MysqlRecordProperty).filter(
        mysql.MysqlRecordProperty.type == model_name,
        mysql.MysqlRecordProperty.property == property,
        mysql.MysqlRecordProperty.key.in_(ids),
    )

  def test_ca_cleanup_on_obj_delete(self):
    """Test cleaning of fulltext and attributes tables on obj delete"""
    asmnt_id = self.asmnt_comments.keys()[0]
    asmnt = all_models.Assessment.query.get(asmnt_id)
    last_comment_records = self.get_model_fulltext(
        "Assessment", "last_comment", [asmnt_id]
    )
    self.assertEqual(last_comment_records.count(), 1)
    last_comment_attrs = self.get_model_ca("Assessment", [asmnt_id])
    self.assertEqual(last_comment_attrs.count(), 1)

    response = self.api.delete(asmnt)
    self.assert200(response)

    last_comment_records = self.get_model_fulltext(
        "Assessment", "last_comment", [asmnt_id]
    )
    self.assertEqual(last_comment_records.count(), 0)
    last_comment_attrs = self.get_model_ca("Assessment", [asmnt_id])
    self.assertEqual(last_comment_attrs.count(), 0)

    # Check that other records weren't affected
    last_comment_records = self.get_model_fulltext(
        "Assessment", "last_comment", self.asmnt_comments.keys()
    )
    self.assertEqual(last_comment_records.count(), 2)
    last_comment_attrs = self.get_model_ca(
        "Assessment", self.asmnt_comments.keys()
    )
    self.assertEqual(last_comment_attrs.count(), 2)
Esempio n. 24
0
class TestPersonResource(TestCase, WithQueryApi):
  """Tests for special people api endpoints."""

  def setUp(self):
    super(TestPersonResource, self).setUp()
    self.client.get("/login")
    self.api = Api()
    self.generator = WorkflowsGenerator()

  @staticmethod
  def _create_users_names_rbac(users):
    """Create name and Creator role for users, created vid PersonFactory"""
    if not users:
      return
    roles = {r.name: r for r in all_models.Role.query.all()}
    for user in users:
      user.name = user.email.split("@")[0]
      rbac_factories.UserRoleFactory(role=roles["Creator"], person=user)

  def assert_profile_get_successful(self, response, expected_datetime):
    """Verify assertions for successful GET profile method"""
    self.assert200(response)
    response_datetime = date_parser.parse(response.json["last_seen_whats_new"])
    self.assertEqual(expected_datetime, response_datetime)

  @freeze_time("2018-05-20 12:23:17")
  def test_profile_get_successful(self):
    """Test person_profile GET method successfully achieves correct data"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    response = self.api.client.get("/api/people/{}/profile".format(user.id))
    self.assert_profile_get_successful(response, default_date())

  def test_profile_get_no_profile(self):
    """Test person_profile GET method achieves data with missing profile"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    profiles_table = PersonProfile.__table__
    db_request = profiles_table.delete().where(
        profiles_table.c.person_id == user.id)
    db.engine.execute(db_request)
    with freeze_time("2018-05-28 23:30:10"):
      response = self.api.client.get("/api/people/{}/profile".format(user.id))
      self.assert_profile_get_successful(response, default_date())

  def test_profile_get_failed(self):
    """Test person_profiles GET method fails

    Now only logged user can request his profile
    """
    with factories.single_commit():
      valid_user = factories.PersonFactory()
      self._create_users_names_rbac([valid_user])

    response = self.client.get(
        "/api/people/{}/profile".format(valid_user.id))
    # logged with default user during setUp
    self.assert403(response)
    response = self.api.client.get(
        "/api/people/{}/profile".format(valid_user.id))
    # not authorized user
    self.assert403(response)

  @ddt.data("Creator", "Reader", "Editor", "Administrator")
  def test_profile_post_empty_body(self, role_name):
    """Test person_profile POST method with empty body - {}."""
    role = all_models.Role.query.filter(
        all_models.Role.name == role_name
    ).one()
    with factories.single_commit():
      user = factories.PersonFactory()
      rbac_factories.UserRoleFactory(role=role, person=user)
    self.api.set_user(person=user)

    response = self.api.send_request(
        self.api.client.post,
        data={},
        api_link="/api/people/{}/profile".format(user.id))

    self.assert405(response)

  def test_profile_post_unauthorized(self):
    """Test person_profile POST method with empty body - No Access."""
    with factories.single_commit():
      user = factories.PersonFactory()

    response = self.api.send_request(
        self.api.client.post,
        data={},
        api_link="/api/people/{}/profile".format(user.id))
    # not authorized user
    self.assert405(response)

  def assert_profile_put_successful(self,
                                    response,
                                    correct_response,
                                    user,
                                    expected):
    """Verify assertions for successful PUT profile method"""
    self.assert200(response)
    self.assertEqual(response.json, correct_response)
    profile = PersonProfile.query.filter_by(person_id=user.id).first()
    self.assertEqual(profile.last_seen_whats_new, date_parser.parse(expected))

  @ddt.data(
      ["2018-05-20 16:38:17", "2018-05-20 16:38:17"],
      ["2018-07-05T14:11:31Z", "2018-07-05T14:11:31"])
  @ddt.unpack
  def test_profile_put_successful(self, new_date, expected_date):
    """Test person_profile PUT method for setting data and correct response"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    data = {"last_seen_whats_new": new_date}
    correct_response = {"Person": {"id": user.id, "profile": data}}
    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    self.assert_profile_put_successful(response,
                                       correct_response,
                                       user,
                                       expected_date)

  def test_profile_put_no_profile(self):
    """Test person_profile PUT method for setting data for missing profile"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    new_date = "2018-05-20 22:05:17"
    data = {"last_seen_whats_new": new_date}
    correct_response = {"Person": {"id": user.id, "profile": data}}
    profiles_table = PersonProfile.__table__
    db_request = profiles_table.delete().where(
        profiles_table.c.person_id == user.id)
    db.engine.execute(db_request)
    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    self.assert_profile_put_successful(response,
                                       correct_response,
                                       user,
                                       new_date)

  def test_profile_put_unauthorized(self):
    """Test person_profiles PUT method fails for unauthorized user"""
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])

    new_date = "2018-05-20 22:05:17"
    data = {"last_seen_whats_new": new_date}
    response = self.client.put("/api/people/{}/profile".format(user.id),
                               content_type='application/json',
                               data=json.dumps(data),
                               headers=[('X-Requested-By', 'Tests')])
    # logged with default user during setUp
    self.assert403(response)
    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    # not authorized user
    self.assert403(response)

  @ddt.data({"last_seen_whats_new": "NOT A 123 DAT456A"},
            {"other_key": "2018-05-20 22:05:17", "one_more_key": 42})
  def test_profile_put_corrupted_data(self, data):
    """Test person_profiles PUT method fails via incorrect request data

    If request doesn't have "last_seen_whats_new" key or date is incorrect,
      response is code 400 "Bad Request"
    """
    with factories.single_commit():
      user = factories.PersonFactory()
      self._create_users_names_rbac([user])
    self.api.set_user(person=user)

    response = self.api.client.put("/api/people/{}/profile".format(user.id),
                                   content_type='application/json',
                                   data=json.dumps(data),
                                   headers=[('X-Requested-By', 'Tests')])
    # missed key in request
    self.assert400(response)

  def test_task_count_empty(self):
    """Test query count without any workflows and tasks."""
    user = all_models.Person.query.first()
    response = self.client.get("/api/people/{}/task_count".format(user.id))
    self.assertEqual(
        response.json,
        {"open_task_count": 0, "has_overdue": False}
    )

  @ddt.data(
      (True, [
          ("task 1", "Finished", 3, True, 3),
          ("task 1", "Verified", 2, True, 3),
          ("task 2", "Declined", 2, True, 3),
          ("task 2", "Verified", 1, False, 3),
          ("task 2", "Finished", 2, True, 3),
          ("task 3", "Verified", 1, True, 3),
          ("task 2", "Verified", 0, False, 3),
      ]),
      (False, [
          ("task 1", "Finished", 2, True, 3),
          ("task 2", "In Progress", 2, True, 3),
          ("task 2", "Finished", 1, False, 3),
          ("task 3", "Finished", 0, False, 3),
      ]),
  )
  @ddt.unpack
  def test_task_count(self, is_verification_needed, transitions):
    """Test person task counts.

    This tests checks for correct task counts
     - with inactive workflows and
     - with overdue tasks
     - without overdue tasks
     - with finished overdue tasks

    The four checks are done in a single test due to complex differences
    between tests that make ddt cumbersome and the single test also improves
    integration test performance due to slow workflow setup stage.
    """
    # pylint: disable=too-many-locals

    user = all_models.Person.query.first()
    dummy_user = factories.PersonFactory()
    user_id = user.id
    role_id = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.name == "Task Assignees",
        all_models.AccessControlRole.object_type == "TaskGroupTask",
    ).one().id
    secondary_role_id = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.name == "Task Secondary Assignees",
        all_models.AccessControlRole.object_type == "TaskGroupTask",
    ).one().id

    one_time_workflow = {
        "title": "Person resource test workflow",
        "notify_on_change": True,
        "description": "some test workflow",
        "owners": [create_stub(user)],
        "is_verification_needed": is_verification_needed,
        "task_groups": [{
            "title": "one time task group",
            "contact": create_stub(user),
            "task_group_tasks": [{
                "title": "task 1",
                "description": "some task",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id),
                    acl_helper.get_acl_json(secondary_role_id, user.id)
                ],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 8, 15),
            }, {
                "title": "task 2",
                "description": "some task 3",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id),
                    acl_helper.get_acl_json(secondary_role_id, user.id),
                    acl_helper.get_acl_json(secondary_role_id, dummy_user.id)
                ],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 9, 16),
            }, {
                "title": "task 3",
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id),
                    acl_helper.get_acl_json(role_id, dummy_user.id)
                ],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 10, 16),
            }, {
                "title": "dummy task 4",  # task should not counted
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, dummy_user.id)],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 11, 17),
            }, {
                "title": "dummy task 5",  # task should not counted
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, dummy_user.id)],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 11, 18),
            }],
            "task_group_objects": []
        }]
    }

    inactive_workflow = {
        "title": "Activated workflow with archived cycles",
        "notify_on_change": True,
        "description": "Extra test workflow",
        "owners": [create_stub(user)],
        "task_groups": [{
            "title": "Extra task group",
            "contact": create_stub(user),
            "task_group_tasks": [{
                "title": "not counted existing task",
                "description": "",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id)],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 8, 15),
            }],
            "task_group_objects": []
        }]
    }

    with freeze_time("2017-10-16 05:09:10"):
      self.client.get("/login")
      # Activate normal one time workflow
      _, workflow = self.generator.generate_workflow(one_time_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      tasks = {t.title: t for t in cycle.cycle_task_group_object_tasks}
      _, workflow = self.generator.activate_workflow(workflow)

      # Activate and close the inactive workflow
      _, workflow = self.generator.generate_workflow(inactive_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      _, workflow = self.generator.activate_workflow(workflow)
      self.generator.modify_object(cycle, data={"is_current": False})

    with freeze_time("2017-7-16 07:09:10"):
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 3, "has_overdue": False}
      )

    with freeze_time("2017-10-16 08:09:10"):  # same day as task 3 end date
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 3, "has_overdue": True}
      )

      for task, status, count, overdue, my_work_count in transitions:
        self.generator.modify_object(tasks[task], data={"status": status})
        task_count_response = \
            self.client.get("/api/people/{}/task_count".format(user_id))
        my_work_count_response = \
            self.client.get("/api/people/{}/my_work_count".format(user_id))

        self.assertEqual(
            task_count_response.json,
            {"open_task_count": count, "has_overdue": overdue}
        )

        self.assertEqual(
            my_work_count_response.json["CycleTaskGroupObjectTask"],
            my_work_count
        )

  def test_task_count_multiple_wfs(self):
    """Test task count with both verified and non verified workflows.

    This checks task counts with 4 tasks
        2017, 8, 15  - verification needed
        2017, 11, 18  - verification needed
        2017, 8, 15  - No verification needed
        2017, 11, 18  - No verification needed
    """

    user = all_models.Person.query.first()
    user_id = user.id
    role_id = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.name == "Task Assignees",
        all_models.AccessControlRole.object_type == "TaskGroupTask",
    ).one().id
    workflow_template = {
        "title": "verified workflow",
        "owners": [create_stub(user)],
        "is_verification_needed": True,
        "task_groups": [{
            "title": "one time task group",
            "contact": create_stub(user),
            "task_group_tasks": [{
                "title": "task 1",
                "description": "some task",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id)],
                "start_date": date(2017, 5, 5),
                "end_date": date(2017, 8, 15),
            }, {
                "title": "dummy task 5",
                "description": "some task 4",
                "access_control_list": [
                    acl_helper.get_acl_json(role_id, user.id)],
                "start_date": date(2017, 6, 5),
                "end_date": date(2017, 11, 18),
            }],
            "task_group_objects": []
        }]
    }

    with freeze_time("2017-10-16 05:09:10"):
      self.client.get("/login")
      verified_workflow = workflow_template.copy()
      verified_workflow["is_verification_needed"] = True
      _, workflow = self.generator.generate_workflow(verified_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      verified_tasks = {
          task.title: task
          for task in cycle.cycle_task_group_object_tasks
      }
      _, workflow = self.generator.activate_workflow(workflow)

      non_verified_workflow = workflow_template.copy()
      non_verified_workflow["is_verification_needed"] = False
      _, workflow = self.generator.generate_workflow(non_verified_workflow)
      _, cycle = self.generator.generate_cycle(workflow)
      non_verified_tasks = {
          task.title: task
          for task in cycle.cycle_task_group_object_tasks
      }
      _, workflow = self.generator.activate_workflow(workflow)

    with freeze_time("2017-7-16 07:09:10"):
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 4, "has_overdue": False}
      )

    with freeze_time("2017-10-16 08:09:10"):
      self.client.get("/login")
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 4, "has_overdue": True}
      )

      # transition 1, task that needs verification goes to finished state. This
      # transition should not change anything
      self.generator.modify_object(
          verified_tasks["task 1"],
          data={"status": "Finished"}
      )
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 4, "has_overdue": True}
      )

      # transition 2, task that needs verification goes to verified state. This
      # transition should reduce task count.
      self.generator.modify_object(
          verified_tasks["task 1"],
          data={"status": "Verified"}
      )
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 3, "has_overdue": True}
      )

      # transition 3, task that does not need verification goes into Finished
      # state. This transition should reduce task count and remove all overdue
      # tasks
      self.generator.modify_object(
          non_verified_tasks["task 1"],
          data={"status": "Finished"}
      )
      response = self.client.get("/api/people/{}/task_count".format(user_id))
      self.assertEqual(
          response.json,
          {"open_task_count": 2, "has_overdue": False}
      )

  @ddt.data(("Creator", 403),
            ("Reader", 403),
            ("Editor", 200),
            ("Administrator", 200))
  @ddt.unpack
  def test_person_editing(self, role_name, status):
    """{0} should receive {1} status code on edit Person."""
    role = all_models.Role.query.filter(
        all_models.Role.name == role_name
    ).one()
    with factories.single_commit():
      client_user = factories.PersonFactory()
      rbac_factories.UserRoleFactory(role=role, person=client_user)
    self.api.set_user(client_user)
    self.client.get("/login")
    base_email = "*****@*****.**"
    person = factories.PersonFactory(email=base_email)
    person_id = person.id
    new_email = "new_{}".format(base_email)
    resp = self.api.put(person, {"email": new_email})
    self.assertEqual(status, resp.status_code)
    person = all_models.Person.query.get(person_id)
    if status == 200:
      self.assertEqual(new_email, person.email)
    else:
      self.assertEqual(base_email, person.email)
Esempio n. 25
0
class TestEvidenceQueries(TestCase):
  """Tests for /query api for Evidence instance filtering."""
  # pylint: disable=invalid-name

  def setUp(self):
    super(TestEvidenceQueries, self).setUp()
    self.api = Api()

  def test_filter_evidence_by_type_url(self):
    """Test filter evidences by evidence type URL."""
    evidence_gdrive = factories.EvidenceFactory(
        title='Simple title',
        kind=all_models.Evidence.URL,
        link='sample.site'
    )
    evidence_url_id = evidence_gdrive.id

    query_request_data = [{
        u'filters': {
            u'expression': {
                u'left': u'type',
                u'op': {u'name': u'='},
                u'right': all_models.Evidence.URL
            }
        },
        u'object_name': u'Evidence',
        u'type': u'values'
    }]
    resp = self.api.send_request(self.api.client.post,
                                 data=query_request_data,
                                 api_link="/query")
    self.assertEqual(1, resp.json[0]["Evidence"]["count"])
    self.assertEqual(evidence_url_id,
                     resp.json[0]["Evidence"]["values"][0]["id"])

  def test_filter_evidence_by_type_gdrive(self):
    """Test filter evidences by evidence type GDRIVE."""
    evidence_gdrive = factories.EvidenceFactory(
        title='Simple title',
        source_gdrive_id='gdrive_id',
        link='sample.site',
        kind=all_models.Evidence.FILE
    )
    evidence_gdrive_id = evidence_gdrive.id
    query_request_data = [{
        u'filters': {
            u'expression': {
                u'left': u'type',
                u'op': {u'name': u'='},
                u'right': all_models.Evidence.FILE
            }
        },
        u'object_name': u'Evidence',
        u'type': u'values'
    }]
    resp = self.api.send_request(self.api.client.post,
                                 data=query_request_data,
                                 api_link="/query")
    self.assertEqual(1, resp.json[0]["Evidence"]["count"])
    self.assertEqual(evidence_gdrive_id,
                     resp.json[0]["Evidence"]["values"][0]["id"])
Esempio n. 26
0
class TestEvidenceQueries(TestCase):
    """Tests for /query api for Evidence instance filtering."""

    # pylint: disable=invalid-name

    def setUp(self):
        super(TestEvidenceQueries, self).setUp()
        self.api = Api()

    def test_filter_evidence_by_type_url(self):
        """Test filter evidences by evidence type URL."""
        evidence_gdrive = factories.EvidenceFactory(
            title='Simple title',
            kind=all_models.Evidence.URL,
            link='sample.site')
        evidence_url_id = evidence_gdrive.id

        query_request_data = [{
            u'filters': {
                u'expression': {
                    u'left': u'type',
                    u'op': {
                        u'name': u'='
                    },
                    u'right': all_models.Evidence.URL
                }
            },
            u'object_name': u'Evidence',
            u'type': u'values'
        }]
        resp = self.api.send_request(self.api.client.post,
                                     data=query_request_data,
                                     api_link="/query")
        self.assertEqual(1, resp.json[0]["Evidence"]["count"])
        self.assertEqual(evidence_url_id,
                         resp.json[0]["Evidence"]["values"][0]["id"])

    def test_filter_evidence_by_type_gdrive(self):
        """Test filter evidences by evidence type GDRIVE."""
        evidence_gdrive = factories.EvidenceFactory(
            title='Simple title',
            source_gdrive_id='gdrive_id',
            link='sample.site',
            kind=all_models.Evidence.FILE)
        evidence_gdrive_id = evidence_gdrive.id
        query_request_data = [{
            u'filters': {
                u'expression': {
                    u'left': u'type',
                    u'op': {
                        u'name': u'='
                    },
                    u'right': all_models.Evidence.FILE
                }
            },
            u'object_name': u'Evidence',
            u'type': u'values'
        }]
        resp = self.api.send_request(self.api.client.post,
                                     data=query_request_data,
                                     api_link="/query")
        self.assertEqual(1, resp.json[0]["Evidence"]["count"])
        self.assertEqual(evidence_gdrive_id,
                         resp.json[0]["Evidence"]["values"][0]["id"])
Esempio n. 27
0
class TestFilterByAuditor(TestCase):
  """ Test for filter by Auditor. """

  def setUp(self):
    super(TestFilterByAuditor, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()
    _, self.auditor = self.generator.generate_person(user_role="Creator")
    auditor_role = all_models.AccessControlRole.query.filter_by(
        name="Auditors").one()
    with factories.single_commit():
      self.audit = factories.AuditFactory(status="In Progress")
      self.audit_id = self.audit.id
      audit_context = factories.ContextFactory()
      self.audit.context = audit_context
      factories.AccessControlListFactory(
          ac_role=auditor_role,
          object=self.audit,
          person=self.auditor
      )
    self.api.set_user(self.auditor)

  def test_query_audits_by_auditor(self):
    """test get audit as query get"""
    objects = self.api.get_query(all_models.Audit, "")
    self.assertEqual(1, len(objects.json["audits_collection"]["audits"]))
    audit_dict = objects.json["audits_collection"]["audits"][0]
    self.assertEqual(self.audit_id, audit_dict["id"])

  def test_filter_audits_by_auditor(self):
    """Test query on audit Global Search.

    This query is the fact query that frontend is sending in global search.
    """
    query_request_data = [
        {
            u'fields': [],
            u'filters': {
                u'expression': {
                    u'left': {
                        u'left': u'status',
                        u'op': {u'name': u'='},
                        u'right': u'Planned'
                    },
                    u'op': {u'name': u'OR'},
                    u'right': {
                        u'left': {
                            u'left': u'status',
                            u'op': {u'name': u'='},
                            u'right': u'In Progress'
                        },
                        u'op': {u'name': u'OR'},
                        u'right': {
                            u'left': {
                                u'left': u'status',
                                u'op': {u'name': u'='},
                                u'right': u'Manager Review'
                            },
                            u'op': {u'name': u'OR'},
                            u'right': {
                                u'left': {
                                    u'left': u'status',
                                    u'op': {u'name': u'='},
                                    u'right': u'Ready for External Review',
                                },
                                u'op': {u'name': u'OR'},
                                u'right': {
                                    u'left': u'status',
                                    u'op': {u'name': u'='},
                                    u'right': u'Completed',
                                }
                            },
                        },
                    },
                },
                u'keys': [u'status'],
                u'order_by': {
                    u'compare': None,
                    u'keys': [],
                    u'order': u'',
                }
            },
            u'limit': [0, 5],
            u'object_name': u'Audit',
            u'permissions': u'read',
            u'type': u'values',
        },
        {
            u'filters': {
                u'expression': {
                    u'ids': [u'150'],
                    u'object_name': u'undefined',
                    u'op': {u'name': u'relevant'}
                },
                u'keys': [],
                u'order_by': {u'compare': None, u'keys': [], u'order': u''}
            },
            u'object_name': u'Audit',
            u'type': u'ids',
        },
    ]
    resp = self.api.send_request(self.api.client.post,
                                 data=query_request_data,
                                 api_link="/query")
    self.assertEqual(1, resp.json[0]["Audit"]["count"])
    self.assertEqual(self.audit_id, resp.json[0]["Audit"]["values"][0]["id"])
Esempio n. 28
0
class TestWithLastCommentCycleTask(TestCase, WithQueryApi):
  """
      Integration test suite for WithLastComment functionality
      for Cycle Tasks.
  """
  def setUp(self):
    super(TestWithLastCommentCycleTask, self).setUp()
    self.client.get("/login")
    self.api = Api()

  def compute_attributes(self):
    """Method for computed_attributes job"""
    query = all_models.Revision.query.filter_by(resource_type="Comment")
    revision_ids = [revision.id for revision in query]
    self.api.send_request(
        self.api.client.post,
        api_link="/admin/compute_attributes",
        data={"revision_ids": revision_ids}
    )

  @staticmethod
  def get_model_fulltext(model_name, property, ids):
    """Get fulltext records for model."""
    # pylint: disable=redefined-builtin
    return db.session.query(mysql.MysqlRecordProperty).filter(
        mysql.MysqlRecordProperty.type == model_name,
        mysql.MysqlRecordProperty.property == property,
        mysql.MysqlRecordProperty.key.in_(ids),
    )

  def test_last_comment_value(self):
    """Test proper value in last_comment field"""
    with factories.single_commit():
      c_task = wf_factories.CycleTaskGroupObjectTaskFactory()
      c_task_id = c_task.id
      comment_1 = factories.CommentFactory(description=factories.random_str())
      comment_2 = factories.CommentFactory(description=factories.random_str())
      comment_2_id = comment_2.id
      factories.RelationshipFactory(source=c_task, destination=comment_1)
      factories.RelationshipFactory(source=c_task, destination=comment_2)

    self.compute_attributes()
    comment_2 = all_models.Comment.query.get(comment_2_id)
    c_task = all_models.CycleTaskGroupObjectTask.query.get(c_task_id)

    self.assertEqual(c_task.last_comment, comment_2.description)

  def test_last_comment_filter(self):
    """Test filtration by last comment."""
    with factories.single_commit():
      for _ in range(2):
        c_task = wf_factories.CycleTaskGroupObjectTaskFactory()
        comment = factories.CommentFactory(
            description=factories.random_str()
        )
        factories.RelationshipFactory(source=c_task, destination=comment)

    self.compute_attributes()

    c_task = all_models.CycleTaskGroupObjectTask.query.first()
    result = self._get_first_result_set(
        self._make_query_dict(
            "CycleTaskGroupObjectTask",
            expression=("Last Comment", "=", c_task.last_comment),
            type_="ids",
        ),
        "CycleTaskGroupObjectTask",
    )

    self.assertEqual(result["count"], 1)
    self.assertEqual(result["ids"], [c_task.id])

  def test_ca_cleanup_on_obj_delete(self):
    """Test cleaning of fulltext and attributes tables on obj delete"""
    with factories.single_commit():
      for _ in range(2):
        c_task = wf_factories.CycleTaskGroupObjectTaskFactory()
        comment = factories.CommentFactory(
            description=factories.random_str()
        )
        factories.RelationshipFactory(source=c_task, destination=comment)

    self.compute_attributes()

    c_task = all_models.CycleTaskGroupObjectTask.query.first()

    last_comment_records = self.get_model_fulltext(
        "CycleTaskGroupObjectTask", "last_comment", [c_task.id]
    )
    last_comment_attrs = self.get_model_ca(
        "CycleTaskGroupObjectTask",
        [c_task.id]
    )
    self.assertEqual(last_comment_records.count(), 1)
    self.assertEqual(last_comment_attrs.count(), 1)

    response = self.api.delete(c_task)
    self.assert200(response)

    last_comment_records = self.get_model_fulltext(
        "CycleTaskGroupObjectTask", "last_comment", [c_task.id]
    )

    last_comment_attrs = self.get_model_ca(
        "CycleTaskGroupObjectTask",
        [c_task.id]
    )
    self.assertEqual(last_comment_attrs.count(), 0)
    self.assertEqual(last_comment_records.count(), 0)

    # Check that other records weren't affected
    task_ids = [task.id for task in
                all_models.CycleTaskGroupObjectTask.query.all()]

    last_comment_records = self.get_model_fulltext(
        "CycleTaskGroupObjectTask", "last_comment", task_ids
    )
    last_comment_attrs = self.get_model_ca(
        "CycleTaskGroupObjectTask",
        task_ids,
    )

    self.assertEqual(last_comment_records.count(), 1)
    self.assertEqual(last_comment_attrs.count(), 1)
Esempio n. 29
0
class TestWorkflowsApiPost(TestCase):

  def setUp(self):
    super(TestWorkflowsApiPost, self).setUp()
    self.api = Api()

  def tearDown(self):
    pass

  def test_send_invalid_data(self):
    data = self.get_workflow_dict()
    del data["workflow"]["title"]
    del data["workflow"]["context"]
    response = self.api.post(all_models.Workflow, data)
    self.assert400(response)
    # TODO: check why response.json["message"] is empty

  def test_create_one_time_workflows(self):
    data = self.get_workflow_dict()
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_weekly_workflows(self):
    data = self.get_workflow_dict()
    data["workflow"]["frequency"] = "weekly"
    data["workflow"]["title"] = "Weekly"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_monthly_workflows(self):
    data = self.get_workflow_dict()
    data["workflow"]["frequency"] = "monthly"
    data["workflow"]["title"] = "Monthly"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_quarterly_workflows(self):
    data = self.get_workflow_dict()
    data["workflow"]["frequency"] = "quarterly"
    data["workflow"]["title"] = "Quarterly"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_annually_workflows(self):
    data = self.get_workflow_dict()
    data["workflow"]["frequency"] = "annually"
    data["workflow"]["title"] = "Annually"
    response = self.api.post(all_models.Workflow, data)
    self.assertEqual(response.status_code, 201)

  def test_create_task_group(self):
    wf_data = self.get_workflow_dict()
    wf_data["workflow"]["title"] = "Create_task_group"
    wf_response = self.api.post(all_models.Workflow, wf_data)

    data = self.get_task_group_dict(wf_response.json["workflow"])

    response = self.api.post(all_models.TaskGroup, data)
    self.assertEqual(response.status_code, 201)

  # TODO: Api should be able to handle invalid data
  @unittest.skip("Not implemented.")
  def test_create_task_group_invalid_workflow_data(self):
    data = self.get_task_group_dict({"id": -1, "context": {"id": -1}})
    response = self.api.post(all_models.TaskGroup, data)
    self.assert400(response)

  @staticmethod
  def get_workflow_dict():
    data = {
        "workflow": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "title": "One_time",
            "description": "",
            "frequency": "one_time",
            "notify_on_change": False,
            "task_group_title": "Task Group 1",
            "notify_custom_message": "",
            "is_verification_needed": True,
            "owners": None,
            "context": None,
        }
    }
    return data

  @staticmethod
  def get_task_group_dict(workflow):
    data = {
        "task_group": {
            "custom_attribute_definitions": [],
            "custom_attributes": {},
            "_transient": {},
            "contact": {
                "id": 1,
                "href": "/api/people/1",
                "type": "Person"
            },
            "workflow": {
                "id": workflow["id"],
                "href": "/api/workflows/%d" % workflow["id"],
                "type": "Workflow"
            },
            "context": {
                "id": workflow["context"]["id"],
                "href": "/api/contexts/%d" % workflow["context"]["id"],
                "type": "Context"
            },
            "modal_title": "Create Task Group",
            "title": "Create_task_group",
            "description": "",
        }
    }
    return data

  @ddt.data(True, False)
  def test_autogen_verification_flag(self, flag):
    """Check is_verification_needed flag for activate WF action."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
      group = wf_factories.TaskGroupFactory(workflow=workflow)
      wf_factories.TaskGroupTaskFactory(task_group=group)
    data = [{
        "cycle": {
            "autogenerate": True,
            "isOverdue": False,
            "workflow": {
                "id": workflow.id,
                "type": "Workflow",
            },
            "context": {
                "id": workflow.context_id,
                "type": "Context",
            },
        }
    }]
    resp = self.api.send_request(
        self.api.client.post,
        api_link="/api/cycles",
        data=data)
    cycle_id = resp.json[0][1]["cycle"]["id"]
    self.assertEqual(
        flag,
        all_models.Cycle.query.get(cycle_id).is_verification_needed)

  @ddt.data(True, False)
  def test_change_verification_flag(self, flag):
    """Check is_verification_needed flag isn't changeable."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": not flag})
    self.assert400(resp)
    self.assertEqual(
        flag,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)

  @ddt.data(True, False)
  def test_not_change_vf_flag(self, flag):
    """Check is_verification_needed not change on update."""
    with factories.single_commit():
      workflow = wf_factories.WorkflowFactory(is_verification_needed=flag)
    workflow_id = workflow.id
    resp = self.api.put(workflow, {"is_verification_needed": flag})
    self.assert200(resp)
    self.assertEqual(
        flag,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)

  @ddt.data(True, False, None)
  def test_create_vf_flag(self, flag):
    """Check is_verification_needed flag setup on create."""
    data = self.get_workflow_dict()
    if flag is None:
      data['workflow'].pop('is_verification_needed', None)
    else:
      data['workflow']['is_verification_needed'] = flag
    resp = self.api.post(all_models.Workflow, data)
    self.assertEqual(201, resp.status_code)
    workflow_id = resp.json['workflow']['id']
    self.assertEqual(
        flag if flag is not None else True,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)
Esempio n. 30
0
class TestBulkIssuesSync(TestCase):
  """Base class for bulk issuetracker synchronization tests."""

  def setUp(self):
    """Set up for test methods."""
    super(TestBulkIssuesSync, self).setUp()
    self.api = Api()
    self.gen = generator.ObjectGenerator()

    self.role_people = {
        "Audit Captains": factories.PersonFactory(email="*****@*****.**"),
        "Creators": factories.PersonFactory(email="*****@*****.**"),
        "Assignees": factories.PersonFactory(email="*****@*****.**"),
        "Verifiers": factories.PersonFactory(email="*****@*****.**"),
    }
    self.issue_id = "42"

  def setup_assessments(self, asmnt_count, issue_id=None, enabled=True):
    """Create Audit with couple of Assessments and linked IssueTrackerIssues.

    Args:
        asmnt_count: Count of Assessments in Audit.

    Returns:
        Tuple with Audit id and list of Assessment ids.
    """
    with factories.single_commit():
      audit = factories.AuditFactory()
      audit.add_person_with_role_name(
          self.role_people["Audit Captains"],
          "Audit Captains",
      )
      factories.IssueTrackerIssueFactory(
          enabled=enabled,
          issue_tracked_obj=audit,
          issue_id=issue_id,
          issue_type=constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'],
          component_id=12345,
          hotlist_id=12345,
          issue_priority="P2",
          issue_severity="S2",
      )

      assessment_ids = []
      for _ in range(asmnt_count):
        asmnt = factories.AssessmentFactory(audit=audit)
        factories.RelationshipFactory(source=audit, destination=asmnt)
        for role_name in ["Creators", "Assignees", "Verifiers"]:
          asmnt.add_person_with_role_name(
              self.role_people[role_name],
              role_name,
          )
        factories.IssueTrackerIssueFactory(
            enabled=enabled,
            issue_tracked_obj=asmnt,
            issue_id=issue_id,
            title=None,
        )
        assessment_ids.append(asmnt.id)
      return audit.id, assessment_ids

  @staticmethod
  def setup_issues(issue_count, issue_id=None, enabled=True):
    """Create issues with enabled integration."""
    with factories.single_commit():
      issue_ids = []
      for _ in range(issue_count):
        issue = factories.IssueFactory()
        factories.IssueTrackerIssueFactory(
            enabled=enabled,
            issue_tracked_obj=issue,
            issue_id=issue_id,
            title=None,
        )
        issue_ids.append(issue.id)
      return issue_ids

  def issuetracker_sync_mock(self, sync_func_name):
    """IssueTracker sync method mock."""
    return mock.patch.object(
        sync_utils,
        sync_func_name,
        return_value={"issueId": self.issue_id}
    )

  def generate_children_issues_for(self, parent_type, parent_id, child_type):
    """Generate IssueTracker issue for objects with provided type and ids.

    Args:
        obj_type: Type of objects. Now only 'Assessment' supported.
        obj_ids: List with ids of objects.

    Returns:
        Response with result of issues generation.
    """
    with self.issuetracker_sync_mock("create_issue"):
      return self.api.send_request(
          self.api.client.post,
          api_link="/generate_children_issues",
          data={
              "parent": {"type": parent_type, "id": parent_id},
              "child_type": child_type,
          }
      )

  def generate_issues_for(self, object_info):
    """Generate IssueTracker issues for provided objects."""
    with self.issuetracker_sync_mock("create_issue"):
      return self.api.send_request(
          self.api.client.post,
          api_link="/generate_issues",
          data={
              "objects": [{
                  "type": type_,
                  "id": id_,
                  "hotlist_ids": hotlist_id,
                  "component_id": component_id,
              } for type_, id_, hotlist_id, component_id in object_info],
          }
      )

  def update_issues_for(self, object_info):
    """Update IssueTracker issues for provided objects."""
    with self.issuetracker_sync_mock("update_issue"):
      return self.api.send_request(
          self.api.client.post,
          api_link="/update_issues",
          data={
              "objects": [{
                  "type": type_,
                  "id": id_,
                  "hotlist_ids": hotlist_id,
                  "component_id": component_id,
              } for type_, id_, hotlist_id, component_id in object_info],
          }
      )

  def assert_obj_issues(self, issuetracker_info, assignee=None):
    """Check correctness of created IssueTracker issues."""
    for type_, id_, hotlist_id, component_id in issuetracker_info:
      obj = inflector.get_model(type_).query.get(id_)
      issue = obj.issuetracker_issue

      self.assertEqual(issue.enabled, 1)
      self.assertEqual(issue.title, obj.title)
      self.assertEqual(issue.component_id, component_id)
      self.assertEqual(issue.hotlist_id, hotlist_id)
      self.assertEqual(
          issue.issue_type,
          constants.DEFAULT_ISSUETRACKER_VALUES['issue_type']
      )
      self.assertEqual(issue.issue_priority, "P2")
      self.assertEqual(issue.issue_severity, "S2")
      self.assertEqual(issue.assignee, assignee)
      self.assertEqual(issue.cc_list, "")
      self.assertEqual(issue.issue_id, self.issue_id)
      self.assertEqual(
          issue.issue_url,
          "http://issue/{}".format(self.issue_id)
      )

  def assert_children_asmnt_issues(self, asmnt_ids):
    """Check if Assessments IssueTracker issues inherit data from Audit."""
    assessments = all_models.Assessment.query.filter(
        all_models.Assessment.id.in_(asmnt_ids)
    )
    for asmnt in assessments:
      issue = asmnt.issuetracker_issue
      parent_issue = asmnt.audit.issuetracker_issue

      self.assertEqual(issue.enabled, 1)
      self.assertEqual(issue.title, asmnt.title)
      self.assertEqual(issue.component_id, parent_issue.component_id)
      self.assertEqual(issue.hotlist_id, parent_issue.hotlist_id)
      self.assertEqual(issue.issue_type, parent_issue.issue_type)
      self.assertEqual(issue.issue_priority, parent_issue.issue_priority)
      self.assertEqual(issue.issue_severity, parent_issue.issue_severity)
      self.assertEqual(issue.assignee, "*****@*****.**")
      self.assertEqual(issue.cc_list, "")
      self.assertEqual(issue.issue_id, self.issue_id)
      self.assertEqual(
          issue.issue_url,
          "http://issue/{}".format(self.issue_id)
      )

  def assert_not_updated(self, object_type, object_ids):
    """Check if IssueTracker issues have empty fields.

    Args:
        object_type: Type of objects which issues should be checked.
        object_ids: List with ids for objects which issues should be checked.

    Raise:
        AssertionError if relevant Issues have non-empty base fields.
    """
    issues = all_models.IssuetrackerIssue.query.filter(
        all_models.IssuetrackerIssue.object_type == object_type,
        all_models.IssuetrackerIssue.object_id.in_(object_ids),
    )
    for issue in issues:
      self.assertEqual(issue.issue_id, None)
      self.assertEqual(issue.assignee, None)
      self.assertEqual(issue.cc_list, "")
      self.assertEqual(issue.title, None)