Exemplo n.º 1
0
class TestDelete(TestCase, WithQueryApi):
    """Test objects deletion."""
    def setUp(self):
        super(TestDelete, self).setUp()
        self.client.get("/login")
        self.api = Api()

    def test_delete(self):
        """Deletion is synchronous and triggers compute_attributes."""
        control = factories.ControlFactory()

        result = self.api.delete(control)

        controls = db.session.query(all_models.Control).all()
        background_tasks = db.session.query(all_models.BackgroundTask).all()

        self.assert200(result)
        self.assertEqual(len(controls), 0)
        self.assertEqual(len(background_tasks), 1)
        self.assertTrue(
            background_tasks[0].name.startswith("compute_attributes"))

    def test_delete_http400(self):
        """Deletion returns HTTP400 if BadRequest is raised."""
        with factories.single_commit():
            audit = factories.AuditFactory()
            factories.AssessmentFactory(audit=audit)

        result = self.api.delete(audit)

        self.assert400(result)
        self.assertEqual(
            result.json["message"],
            "This request will break a mandatory relationship from "
            "assessments to audits.")
Exemplo n.º 2
0
class TestDelete(TestCase, WithQueryApi):
  """Test objects deletion."""

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

  def test_delete(self):
    """Deletion is synchronous and triggers compute_attributes."""
    control = factories.ControlFactory()

    result = self.api.delete(control)

    controls = db.session.query(all_models.Control).all()
    background_tasks = db.session.query(all_models.BackgroundTask).all()

    self.assert200(result)
    self.assertEqual(len(controls), 0)
    self.assertEqual(len(background_tasks), 1)
    self.assertTrue(background_tasks[0].name.startswith("compute_attributes"))

  def test_delete_http400(self):
    """Deletion returns HTTP400 if BadRequest is raised."""
    with factories.single_commit():
      audit = factories.AuditFactory()
      factories.AssessmentFactory(audit=audit)

    result = self.api.delete(audit)

    self.assert400(result)
    self.assertEqual(result.json["message"],
                     "This request will break a mandatory relationship from "
                     "assessments to audits.")
Exemplo n.º 3
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
  """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assessor, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """
  def setUp(self):
    super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()

    _, self.reader = self.generator.generate_person(
        user_role="Reader"
    )
    audit = factories.AuditFactory()
    assessment = factories.AssessmentFactory(audit=audit)
    object_person_rel = factories.RelationshipFactory(
        source=assessment,
        destination=self.reader
    )
    factories.RelationshipAttrFactory(
        relationship_id=object_person_rel.id,
        attr_name="AssigneeType",
        attr_value="Assessor"
    )

    factories.RelationshipFactory(source=audit, destination=assessment)
    document = factories.DocumentFactory()
    document_id = document.id
    doc_rel = factories.RelationshipFactory(source=assessment,
                                            destination=document)
    doc_rel_id = doc_rel.id

    self.api.set_user(self.reader)
    self.document = all_models.Document.query.get(document_id)
    self.doc_relationship = all_models.Relationship.query.get(doc_rel_id)

  def test_delete_action(self):
    """Test permissions for delete action on Document"""
    resp = self.api.delete(self.document)
    self.assert200(resp)
    self.assertFalse(all_models.Document.query.filter(
        all_models.Document.id == self.document.id).all())

  def test_unmap_action(self):
    """Test permissions for unmap action on Document"""
    resp = self.api.delete(self.doc_relationship)
    self.assert200(resp)
    self.assertFalse(all_models.Relationship.query.filter(
        all_models.Relationship.id == self.doc_relationship.id).all())
Exemplo n.º 4
0
class TestReader(TestCase):
    """Test that some objects cannot be deleted by anyone."""
    def setUp(self):
        TestCase.setUp(self)
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.init_users()
        self.init_objects()

    def init_users(self):
        """ Init users needed by the test cases """
        users = [("creator", "Creator"), ("reader", "Reader"),
                 ("editor", "Editor"), ("admin", "Administrator")]
        self.users = {}
        for (name, role) in users:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role=role)
            self.users[name] = user

    def init_objects(self):
        """Creates the objects used by all the tests"""
        self.api.set_user(self.users["admin"])
        _, person = self.object_generator.generate_person()

        self.objects = [person]

    def test_undeletable_objects(self):
        """No user shoud be allowed to delete these objects."""
        for role, user in self.users.iteritems():
            self.api.set_user(user)
            for obj in self.objects:
                response = self.api.delete(obj)
                self.assertEqual(response.status_code, 403,
                                 "{} can delete {}".format(role, obj.type))
Exemplo n.º 5
0
class TestAssigneeRBAC(TestRBAC):
  """TestAssigneeRBAC tests if users get correct permissions on objects
  where he is has assignee role"""
  def setUp(self):
    super(TestAssigneeRBAC, self).setUp()
    self.api = Api()
    self.set_up_people()
    self.assignee_roles = {
        role_name: role_id
        for role_id, role_name in get_custom_roles_for("Assessment").items()
        if role_name in ["Assignees", "Creators", "Verifiers"]
    }

  def test_mapped_regulations_read(self):
    """Test if creators can CRUD mapped Regulations and Objective snapshots."""
    self.api.set_user(self.people.get("Editor"))
    with factories.single_commit():
      audit = factories.AuditFactory()
      assessment = factories.AssessmentFactory(audit=audit)
      factories.AccessControlPersonFactory(
          ac_list=assessment.acr_name_acl_map["Creators"],
          person=self.people.get("Editor"),
      )
      factories.AccessControlPersonFactory(
          ac_list=assessment.acr_name_acl_map["Assignees"],
          person=self.people.get("Creator"),
      )
      factories.RelationshipFactory(source=audit, destination=assessment)
      control = factories.ControlFactory()
      objective = factories.ObjectiveFactory()
      regulation = factories.RegulationFactory()
      snapshots = self._create_snapshots(
          audit, [control, objective, regulation]
      )
      for snapshot in snapshots:
        factories.RelationshipFactory(source=audit, destination=snapshot)
      factories.RelationshipFactory(
          source=snapshots[0], destination=snapshots[1]
      )
      factories.RelationshipFactory(
          source=snapshots[2], destination=snapshots[0]
      )
      factories.RelationshipFactory(
          source=assessment, destination=snapshots[0]
      )

    self.api.set_user(self.people.get("Creator"))
    for snapshot in snapshots:
      db.session.add(snapshot)
      response = self.api.get(type(snapshot), snapshot.id)
      self.assertEqual(
          response.status_code, 200,
          "Cannot GET mapped object. Received {}".format(response.status)
      )
      db.session.add(snapshot)
      response = self.api.delete(snapshot)
      self.assertEqual(
          response.status_code, 403,
          "Can DELETE mapped object. Received {}".format(response.status)
      )
Exemplo n.º 6
0
class TestReader(TestCase):
  """Test that some objects cannot be deleted by anyone."""

  def setUp(self):
    super(TestReader, self).setUp()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.init_users()
    self.init_objects()

  def init_users(self):
    """ Init users needed by the test cases """
    users = [("creator", "Creator"), ("reader", "Reader"),
             ("editor", "Editor"), ("admin", "Administrator")]
    self.users = {}
    for (name, role) in users:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=role)
      self.users[name] = user

  def init_objects(self):
    """Creates the objects used by all the tests"""
    self.api.set_user(self.users["admin"])
    _, person = self.object_generator.generate_person()

    self.objects = [person]

  def test_undeletable_objects(self):
    """No user shoud be allowed to delete these objects."""
    for role, user in self.users.iteritems():
      self.api.set_user(user)
      for obj in self.objects:
        response = self.api.delete(obj)
        self.assertEqual(response.status_code, 403,
                         "{} can delete {}".format(role, obj.type))
Exemplo n.º 7
0
class TestDelete(TestCase, WithQueryApi):
    """Test objects deletion."""
    def setUp(self):
        super(TestDelete, self).setUp()
        self.client.get("/login")
        self.api = Api()

    def test_delete(self):
        """Deletion is synchronous and triggers compute_attributes."""
        project = factories.ProjectFactory()

        with mock.patch(
                "ggrc.models.background_task.create_task", ) as create_task:
            result = self.api.delete(project)
            projects = db.session.query(all_models.Project).all()
            event_id = db.session.query(func.max(
                all_models.Event.id)).first()[0]

            self.assert200(result)
            self.assertEqual(len(projects), 0)
            self.assertEqual(
                db.session.query(all_models.BackgroundTask).count(), 0)
            create_task.assert_called_once_with(
                name="compute_attributes",
                url="/_background_tasks/compute_attributes",
                parameters={
                    "revision_ids": None,
                    "event_id": event_id
                },
                method="POST",
                queued_callback=views.compute_attributes)

    @unittest.skip("Audit deletion is handled in separate handler now."
                   " Test should be updated to use other models.")
    def test_delete_http400(self):
        """Deletion returns HTTP400 if BadRequest is raised."""
        with factories.single_commit():
            audit = factories.AuditFactory()
            factories.AssessmentTemplateFactory(audit=audit)

        result = self.api.delete(audit)

        self.assert400(result)
        self.assertEqual(
            result.json["message"],
            "This request will break a mandatory relationship from "
            "assessment_templates to audits.")
Exemplo n.º 8
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
    """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assessor, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """
    def setUp(self):
        super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
        self.api = Api()
        self.generator = ObjectGenerator()

        _, self.reader = self.generator.generate_person(user_role="Reader")
        audit = factories.AuditFactory()
        assessment = factories.AssessmentFactory(audit=audit)
        object_person_rel = factories.RelationshipFactory(
            source=assessment, destination=self.reader)
        factories.RelationshipAttrFactory(relationship_id=object_person_rel.id,
                                          attr_name="AssigneeType",
                                          attr_value="Assessor")

        factories.RelationshipFactory(source=audit, destination=assessment)
        document = factories.DocumentFactory()
        document_id = document.id
        doc_rel = factories.RelationshipFactory(source=assessment,
                                                destination=document)
        doc_rel_id = doc_rel.id

        self.api.set_user(self.reader)
        self.document = all_models.Document.query.get(document_id)
        self.doc_relationship = all_models.Relationship.query.get(doc_rel_id)

    def test_delete_action(self):
        """Test permissions for delete action on Document"""
        resp = self.api.delete(self.document)
        self.assert200(resp)
        self.assertFalse(
            all_models.Document.query.filter(
                all_models.Document.id == self.document.id).all())

    def test_unmap_action(self):
        """Test permissions for unmap action on Document"""
        resp = self.api.delete(self.doc_relationship)
        self.assert200(resp)
        self.assertFalse(
            all_models.Relationship.query.filter(
                all_models.Relationship.id == self.doc_relationship.id).all())
Exemplo n.º 9
0
class TestAssigneeRBAC(TestRBAC):
    """TestAssigneeRBAC tests if users get correct permissions on objects
  where he is has assignee role"""
    def setUp(self):
        super(TestAssigneeRBAC, self).setUp()
        self.api = Api()
        self.set_up_people()
        self.assignee_roles = {
            role_name: role_id
            for role_id, role_name in get_custom_roles_for(
                "Assessment").items()
            if role_name in ["Assignees", "Creators", "Verifiers"]
        }

    def test_mapped_regulations_read(self):
        """Test if creators can CRUD mapped Regulations and Objective snapshots."""
        self.api.set_user(self.people.get("Editor"))
        with factories.single_commit():
            audit = factories.AuditFactory()
            assessment = factories.AssessmentFactory(audit=audit)
            factories.AccessControlPersonFactory(
                ac_list=assessment.acr_name_acl_map["Creators"],
                person=self.people.get("Editor"),
            )
            factories.AccessControlPersonFactory(
                ac_list=assessment.acr_name_acl_map["Assignees"],
                person=self.people.get("Creator"),
            )
            factories.RelationshipFactory(source=audit, destination=assessment)
            control = factories.ControlFactory()
            objective = factories.ObjectiveFactory()
            regulation = factories.RegulationFactory()
            snapshots = self._create_snapshots(
                audit, [control, objective, regulation])
            for snapshot in snapshots:
                factories.RelationshipFactory(source=audit,
                                              destination=snapshot)
            factories.RelationshipFactory(source=snapshots[0],
                                          destination=snapshots[1])
            factories.RelationshipFactory(source=snapshots[2],
                                          destination=snapshots[0])
            factories.RelationshipFactory(source=assessment,
                                          destination=snapshots[0])

        self.api.set_user(self.people.get("Creator"))
        for snapshot in snapshots:
            db.session.add(snapshot)
            response = self.api.get(type(snapshot), snapshot.id)
            self.assertEqual(
                response.status_code, 200,
                "Cannot GET mapped object. Received {}".format(
                    response.status))
            db.session.add(snapshot)
            response = self.api.delete(snapshot)
            self.assertEqual(
                response.status_code, 403,
                "Can DELETE mapped object. Received {}".format(
                    response.status))
Exemplo n.º 10
0
class TestCollection(TestCase, WithQueryApi):
    """Test for collection assessment objects."""
    def setUp(self):
        super(TestCollection, self).setUp()
        self.client.get("/login")
        self.clear_data()
        self.expected_ids = []
        self.api = Api()
        self.generator = ObjectGenerator()
        assessments = [factories.AssessmentFactory() for _ in range(10)]
        random.shuffle(assessments)
        for idx, assessment in enumerate(assessments):
            comment = factories.CommentFactory(description=str(idx))
            factories.RelationshipFactory(source=assessment,
                                          destination=comment)
            self.expected_ids.append(assessment.id)

    @data(True, False)
    def test_order_by_test(self, desc):
        """Order by fultext attr"""
        query = self._make_query_dict("Assessment",
                                      order_by=[{
                                          "name": "comment",
                                          "desc": desc
                                      }])
        expected_ids = self.expected_ids
        if desc:
            expected_ids = expected_ids[::-1]
        results = self._get_first_result_set(query, "Assessment", "values")
        self.assertEqual(expected_ids, [i['id'] for i in results])

    @data("Assessor", "Creator", "Verifier")
    def test_delete_assessment_by_role(self, role_name):
        """Delete assessment not allowed for based on Assignee Type."""
        with factories.single_commit():
            assessment = factories.AssessmentFactory()
            context = factories.ContextFactory(related_object=assessment)
            assessment.context = context
            person = factories.PersonFactory()
            object_person_rel = factories.RelationshipFactory(
                source=assessment, destination=person)
            factories.RelationshipAttrFactory(
                relationship_id=object_person_rel.id,
                attr_name="AssigneeType",
                attr_value=role_name,
            )
        assessment_id = assessment.id
        role = all_models.Role.query.filter(
            all_models.Role.name == "Creator").first()
        self.generator.generate_user_role(person, role, context)
        self.api.set_user(person)
        assessment = all_models.Assessment.query.get(assessment_id)
        resp = self.api.delete(assessment)
        self.assert403(resp)
        self.assertTrue(
            all_models.Assessment.query.filter(
                all_models.Assessment.id == assessment_id).one())
Exemplo n.º 11
0
class TestDelete(TestCase, WithQueryApi):
  """Test objects deletion."""

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

  def test_delete(self):
    """Deletion is synchronous and triggers compute_attributes."""
    project = factories.ProjectFactory()

    with mock.patch(
        "ggrc.models.background_task.create_task",
    ) as create_task:
      result = self.api.delete(project)
      projects = db.session.query(all_models.Project).all()
      event_id = db.session.query(func.max(all_models.Event.id)).first()[0]

      self.assert200(result)
      self.assertEqual(len(projects), 0)
      self.assertEqual(db.session.query(all_models.BackgroundTask).count(), 0)
      create_task.assert_called_once_with(
          name="compute_attributes",
          url="/_background_tasks/compute_attributes",
          parameters={"revision_ids": None, "event_id": event_id},
          method="POST",
          queued_callback=views.compute_attributes
      )

  @unittest.skip("Audit deletion is handled in separate handler now."
                 " Test should be updated to use other models.")
  def test_delete_http400(self):
    """Deletion returns HTTP400 if BadRequest is raised."""
    with factories.single_commit():
      audit = factories.AuditFactory()
      factories.AssessmentTemplateFactory(audit=audit)

    result = self.api.delete(audit)

    self.assert400(result)
    self.assertEqual(result.json["message"],
                     "This request will break a mandatory relationship from "
                     "assessment_templates to audits.")
Exemplo n.º 12
0
class TestCollection(TestCase, WithQueryApi):

  """Test for collection assessment objects."""

  def setUp(self):
    super(TestCollection, self).setUp()
    self.client.get("/login")
    self.clear_data()
    self.expected_ids = []
    self.api = Api()
    self.generator = ObjectGenerator()
    assessments = [factories.AssessmentFactory() for _ in range(10)]
    random.shuffle(assessments)
    for idx, assessment in enumerate(assessments):
      comment = factories.CommentFactory(description=str(idx))
      factories.RelationshipFactory(source=assessment, destination=comment)
      self.expected_ids.append(assessment.id)

  @data(True, False)
  def test_order_by_test(self, desc):
    """Order by fultext attr"""
    query = self._make_query_dict(
        "Assessment", order_by=[{"name": "comment", "desc": desc}]
    )
    expected_ids = self.expected_ids
    if desc:
      expected_ids = expected_ids[::-1]
    results = self._get_first_result_set(query, "Assessment", "values")
    self.assertEqual(expected_ids, [i['id'] for i in results])

  @data("Assessor", "Creator", "Verifier")
  def test_delete_assessment_by_role(self, role_name):
    """Delete assessment not allowed for based on Assignee Type."""
    with factories.single_commit():
      assessment = factories.AssessmentFactory()
      context = factories.ContextFactory(related_object=assessment)
      assessment.context = context
      person = factories.PersonFactory()
      object_person_rel = factories.RelationshipFactory(
          source=assessment, destination=person)
      factories.RelationshipAttrFactory(
          relationship_id=object_person_rel.id,
          attr_name="AssigneeType",
          attr_value=role_name,
      )
    assessment_id = assessment.id
    role = all_models.Role.query.filter(
        all_models.Role.name == "Creator"
    ).first()
    self.generator.generate_user_role(person, role, context)
    self.api.set_user(person)
    assessment = all_models.Assessment.query.get(assessment_id)
    resp = self.api.delete(assessment)
    self.assert403(resp)
    self.assertTrue(all_models.Assessment.query.filter(
        all_models.Assessment.id == assessment_id).one())
class TestPersonProfilePermissions(TestCase):
    """Test PersonProfile."""
    def setUp(self):
        super(TestPersonProfilePermissions, self).setUp()
        self.generator = Generator()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.init_users()

    def init_users(self):
        """Init user with different roles."""
        users = [("reader", "Reader"), ("editor", "Editor"),
                 ("admin", "Administrator"), ("creator", "Creator")]
        self.users = {}
        for (name, role) in users:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role=role)
            self.users[name] = user

    @ddt.data("reader", "editor", "admin", "creator")
    def test_permissions(self, name):
        """Test permissions for user roles."""
        user = all_models.Person.query.get(self.users[name].id)
        profile_id = user.profile.id
        self.api.set_user(self.users[name])
        response = self.api.get(all_models.PersonProfile, profile_id)
        self.assert200(response)

        new_date = "2018-05-20 22:05:17"
        response = self.api.put(
            user.profile, {
                "people_profiles": {
                    "id": profile_id,
                    "last_seen_whats_new": new_date,
                },
            })
        self.assert200(response)

        response = self.api.delete(user.profile, profile_id)
        if name == "admin":
            self.assert200(response)
        else:
            self.assert403(response)

        res = self.api.get(all_models.PersonProfile, None)
        api_profiles = res.json["people_profiles_collection"][
            "people_profiles"]
        api_profile_id = api_profiles[0]["id"]

        if name == "admin":
            self.assertEqual(len(api_profiles), 4)
        else:
            self.assertEqual(len(api_profiles), 1)
            self.assertEqual(profile_id, api_profile_id)
Exemplo n.º 14
0
class TestPersonProfilePermissions(TestCase):
  """Test PersonProfile."""

  def setUp(self):
    super(TestPersonProfilePermissions, self).setUp()
    self.generator = Generator()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.init_users()

  def init_users(self):
    """Init user with different roles."""
    users = [("reader", "Reader"),
             ("editor", "Editor"),
             ("admin", "Administrator"),
             ("creator", "Creator")]
    self.users = {}
    for (name, role) in users:
      _, user = self.object_generator.generate_person(
          data={"name": name},
          user_role=role
      )
      self.users[name] = user

  @ddt.data("reader", "editor", "admin", "creator")
  def test_permissions(self, name):
    """Test permissions for user roles."""
    user = all_models.Person.query.get(self.users[name].id)
    profile = all_models.PersonProfile.query.join(
        all_models.PersonProfile.person
    ).filter_by(
        email=user.email
    ).one()
    self.api.set_user(self.users[name])
    response = self.api.get(all_models.PersonProfile, profile.id)
    self.assert200(response)

    new_date = "2018-05-20 22:05:17"
    response = self.api.put(profile, {
        "people_profiles": {
            "id": profile.id,
            "last_seen_whats_new": new_date,
        },
    })
    self.assert200(response)

    response = self.api.delete(profile)
    if name == "admin":
      self.assert200(response)
    else:
      self.assert403(response)
Exemplo n.º 15
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
  """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assignee, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """

  def setUp(self):
    super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()

    _, self.reader = self.generator.generate_person(
        user_role="Reader"
    )
    audit = factories.AuditFactory()
    assessment = factories.AssessmentFactory(audit=audit)
    ac_role = all_models.AccessControlRole.query.filter_by(
        object_type=assessment.type, name="Assignees"
    ).first()
    factories.AccessControlListFactory(
        ac_role=ac_role,
        object=assessment,
        person=self.reader
    )
    factories.RelationshipFactory(source=audit, destination=assessment)
    evidence = factories.EvidenceUrlFactory()
    evidence_id = evidence.id
    evid_rel = factories.RelationshipFactory(source=assessment,
                                             destination=evidence)
    evid_rel_id = evid_rel.id

    self.api.set_user(self.reader)
    self.evidence = all_models.Evidence.query.get(evidence_id)
    self.evid_relationship = all_models.Relationship.query.get(evid_rel_id)

  def test_delete_action(self):
    """Test permissions for delete action on Evidence

    Allow only Global Admin to delete Documents.
    """
    resp = self.api.delete(self.evidence)
    self.assert403(resp)
    self.assertEquals(len(all_models.Evidence.query.filter(
        all_models.Evidence.id == self.evidence.id).all()), 1)
Exemplo n.º 16
0
class TestPermissionsOnAssessmentRelatedAssignables(TestCase):
  """Test check Reader permissions for Assessment related assignables

  Global Reader once assigned to Assessment as Assignee, should have
  permissions to read/update/delete URLs(Documents) related to this Assessment
  """

  def setUp(self):
    super(TestPermissionsOnAssessmentRelatedAssignables, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()

    _, self.reader = self.generator.generate_person(
        user_role="Reader"
    )
    audit = factories.AuditFactory()
    assessment = factories.AssessmentFactory(audit=audit)
    factories.AccessControlPersonFactory(
        ac_list=assessment.acr_name_acl_map["Assignees"],
        person=self.reader,
    )
    factories.RelationshipFactory(source=audit, destination=assessment)
    evidence = factories.EvidenceUrlFactory()
    evidence_id = evidence.id
    evid_rel = factories.RelationshipFactory(source=assessment,
                                             destination=evidence)
    evid_rel_id = evid_rel.id

    self.api.set_user(self.reader)
    self.evidence = all_models.Evidence.query.get(evidence_id)
    self.evid_relationship = all_models.Relationship.query.get(evid_rel_id)

  def test_delete_action(self):
    """Test permissions for delete action on Evidence

    Allow only Global Admin to delete Documents.
    """
    resp = self.api.delete(self.evidence)
    self.assert200(resp)
    self.assertEquals(len(all_models.Evidence.query.filter(
        all_models.Evidence.id == self.evidence.id).all()), 0)
Exemplo n.º 17
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.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)
Exemplo n.º 18
0
class TestAccessControlRole(TestCase):
    """TestAccessControlRole"""
    def setUp(self):
        super(TestAccessControlRole, self).setUp()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.people = {}
        for name in ["Creator", "Reader", "Editor"]:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role=name)
            self.people[name] = user

    def _post_role(self):
        """Helper function for POSTing roles"""
        name = random_str(prefix="Access Control Role - ")
        return self.api.post(
            AccessControlRole, {
                "access_control_role": {
                    "name": name,
                    "object_type": "Control",
                    "context": None,
                    "read": True
                },
            })

    def test_create(self):
        """Test Access Control Role creation"""
        response = self._post_role()
        assert response.status_code == 201, \
            "Failed to create a new access control role, response was {}".format(
                response.status)

        id_ = response.json['access_control_role']['id']
        role = AccessControlRole.query.filter(
            AccessControlRole.id == id_).first()
        assert role.read == 1, \
            "Read permission not correctly saved {}".format(role.read)
        assert role.update == 1, \
            "Update permission not correctly saved {}".format(role.update)
        assert role.delete == 1, \
            "Update permission not correctly saved {}".format(role.delete)

    def test_only_admin_can_post(self):
        """Only admin users should be able to POST access control roles"""
        for name in ("Creator", "Reader", "Editor"):
            person = self.people.get(name)
            self.api.set_user(person)
            response = self._post_role()
            assert response.status_code == 403, \
                "Non admins should get forbidden error when POSTing role. {}".format(
                    response.status)

    @ddt.data(
        ("name", "New ACR"),
        ("read", False),
        ("mandatory", False),
        ("non_editable", False),
    )
    @ddt.unpack
    def test_modify_non_editable_role(self, field_name, field_value):
        """Test if user can modify non-editable role"""
        # Primary Contacts role of Control is non-editable
        ac_role = AccessControlRole.query.filter_by(
            object_type="Control",
            name="Primary Contacts",
        ).first()

        response = self.api.put(ac_role, {field_name: field_value})
        assert response.status_code == 403, \
            "Forbidden error should be thrown when non-editable " \
            "role {} updated.".format(ac_role.name)

    def test_delete_non_editable_role(self):
        """Test if user can delete non-editable role"""
        # Primary Contacts role of Control is non-editable
        ac_role = AccessControlRole.query.filter_by(
            object_type="Control",
            name="Primary Contacts",
        ).first()

        response = self.api.delete(ac_role)
        assert response.status_code == 403, \
            "Forbidden error should be thrown when non-editable " \
            "role {} deleted.".format(ac_role.name)
Exemplo n.º 19
0
class TestAccessControlRole(TestCase):
  """TestAccessControlRole"""

  def setUp(self):
    self.clear_data()
    super(TestAccessControlRole, self).setUp()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.people = {}
    for name in ["Creator", "Reader", "Editor"]:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=name)
      self.people[name] = user

  def _post_role(self):
    """Helper function for POSTing roles"""
    name = random_str(prefix="Access Control Role - ")
    return self.api.post(AccessControlRole, {
        "access_control_role": {
            "name": name,
            "object_type": "Control",
            "context": None,
            "read": True
        },
    })

  def test_create(self):
    """Test Access Control Role creation"""
    response = self._post_role()
    assert response.status_code == 201, \
        "Failed to create a new access control role, response was {}".format(
            response.status)

    id_ = response.json['access_control_role']['id']
    role = AccessControlRole.query.filter(AccessControlRole.id == id_).first()
    assert role.read == 1, \
        "Read permission not correctly saved {}".format(role.read)
    assert role.update == 1, \
        "Update permission not correctly saved {}".format(role.update)
    assert role.delete == 1, \
        "Update permission not correctly saved {}".format(role.delete)

  @ddt.data(
      {"mandatory": True, "exp_response": MANDATORY_ROLE_RESPONSE},
      {"mandatory": False, "exp_response": NON_MANDATORY_ROLE_RESPONSE},
  )
  @ddt.unpack
  def test_mandatory_delete(self, mandatory, exp_response):
    """Test set empty field via import if acr mandatory is {mandatory}"""
    with factories.single_commit():
      user = factories.PersonFactory()
      control = factories.ControlFactory()
      role = factories.AccessControlRoleFactory(
          name=ROLE_NAME,
          object_type="Control",
          mandatory=mandatory,
      )
      role_id = role.id
      factories.AccessControlListFactory(
          person=user,
          ac_role_id=role.id,
          object=control,
      )
    response = self.import_data(OrderedDict([
        ("object_type", "Control"),
        ("Code*", control.slug),
        (ROLE_NAME, "--"),
    ]))
    self._check_csv_response(response, exp_response)
    db_data = defaultdict(set)
    for acl in all_models.Control.query.get(control.id).access_control_list:
      db_data[acl.ac_role_id].add(acl.person_id)
    if mandatory:
      cur_user = all_models.Person.query.filter_by(
          email="*****@*****.**").first()
      self.assertEqual(set([cur_user.id]), db_data[role_id])
    else:
      self.assertFalse(db_data[role_id])

  def test_only_admin_can_post(self):
    """Only admin users should be able to POST access control roles"""
    for name in ("Creator", "Reader", "Editor"):
      person = self.people.get(name)
      self.api.set_user(person)
      response = self._post_role()
      assert response.status_code == 403, \
          "Non admins should get forbidden error when POSTing role. {}".format(
              response.status)

  @ddt.data(
      ("name", "New ACR"),
      ("read", False),
      ("mandatory", False),
      ("non_editable", False),
  )
  @ddt.unpack
  def test_modify_non_editable_role(self, field_name, field_value):
    """Test if user can modify non-editable role"""
    # Primary Contacts role of Control is non-editable
    ac_role = AccessControlRole.query.filter_by(
        object_type="Control",
        name="Primary Contacts",
    ).first()

    response = self.api.put(ac_role, {field_name: field_value})
    assert response.status_code == 403, \
        "Forbidden error should be thrown when non-editable " \
        "role {} updated.".format(ac_role.name)

  def test_delete_non_editable_role(self):
    """Test if user can delete non-editable role"""
    # Primary Contacts role of Control is non-editable
    ac_role = AccessControlRole.query.filter_by(
        object_type="Control",
        name="Primary Contacts",
    ).first()

    response = self.api.delete(ac_role)
    assert response.status_code == 403, \
        "Forbidden error should be thrown when non-editable " \
        "role {} deleted.".format(ac_role.name)
Exemplo n.º 20
0
class TestAccessControlRole(TestCase):
  """TestAccessControlRole"""

  def setUp(self):
    self.clear_data()
    super(TestAccessControlRole, self).setUp()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.people = {}
    for name in ["Creator", "Reader", "Editor"]:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=name)
      self.people[name] = user

  def _post_role(self, name=None, object_type="Control"):
    """Helper function for POSTing roles"""
    if name is None:
      name = random_str(prefix="Access Control Role - ")
    return self.api.post(AccessControlRole, {
        "access_control_role": {
            "name": name,
            "object_type": object_type,
            "context": None,
            "read": True
        },
    })

  def test_create_after_objects(self):
    """Test eager creation of ACLs on existing objects with new ACR."""
    risk_id = factories.RiskFactory().id
    role_name = "New Custom Role"
    self._post_role(name=role_name, object_type="Risk")
    risk = all_models.Risk.query.get(risk_id)
    self.assertIn(role_name, risk.acr_name_acl_map.keys())
    self.assertIsNotNone(risk.acr_name_acl_map[role_name])

  def test_create(self):
    """Test Access Control Role creation"""
    response = self._post_role(object_type="Risk")
    assert response.status_code == 201, \
        "Failed to create a new access control role, response was {}".format(
            response.status)

    id_ = response.json['access_control_role']['id']
    role = AccessControlRole.query.filter(AccessControlRole.id == id_).first()
    assert role.read == 1, \
        "Read permission not correctly saved {}".format(role.read)
    assert role.update == 1, \
        "Update permission not correctly saved {}".format(role.update)
    assert role.delete == 1, \
        "Update permission not correctly saved {}".format(role.delete)

  @ddt.data(
      {"mandatory": True, "exp_response": MANDATORY_ROLE_RESPONSE},
      {"mandatory": False, "exp_response": NON_MANDATORY_ROLE_RESPONSE},
  )
  @ddt.unpack
  def test_mandatory_delete(self, mandatory, exp_response):
    """Test set empty field via import if acr mandatory is {mandatory}"""
    role = factories.AccessControlRoleFactory(
        name=ROLE_NAME,
        object_type="Risk",
        mandatory=mandatory,
    )
    with factories.single_commit():
      user = factories.PersonFactory()
      risk = factories.RiskFactory()
      role_id = role.id
      factories.AccessControlPersonFactory(
          ac_list=risk.acr_name_acl_map[ROLE_NAME],
          person=user,
      )
    response = self.import_data(OrderedDict([
        ("object_type", "Risk"),
        ("Code*", risk.slug),
        (ROLE_NAME, "--"),
    ]))
    self._check_csv_response(response, exp_response)
    db_data = defaultdict(set)
    risk = all_models.Risk.query.get(risk.id)
    for person, acl in risk.access_control_list:
      db_data[acl.ac_role_id].add(person.id)
    if mandatory:
      cur_user = all_models.Person.query.filter_by(
          email="*****@*****.**").first()
      self.assertEqual(set([cur_user.id]), db_data[role_id])
    else:
      self.assertFalse(db_data[role_id])

  def test_only_admin_can_post(self):
    """Only admin users should be able to POST access control roles"""
    for name in ("Creator", "Reader", "Editor"):
      person = self.people.get(name)
      self.api.set_user(person)
      response = self._post_role()
      assert response.status_code == 403, \
          "Non admins should get forbidden error when POSTing role. {}".format(
              response.status)

  @ddt.data(
      ("name", "New ACR"),
      ("read", False),
      ("mandatory", False),
      ("non_editable", False),
  )
  @ddt.unpack
  def test_modify_non_editable_role(self, field_name, field_value):
    """Test if user can modify non-editable role"""
    # Primary Contacts role of Control is non-editable
    ac_role = AccessControlRole.query.filter_by(
        object_type="Control",
        name="Control Operators",
    ).first()

    response = self.api.put(ac_role, {field_name: field_value})
    assert response.status_code == 403, \
        "Forbidden error should be thrown when non-editable " \
        "role {} updated.".format(ac_role.name)

  def test_delete_non_editable_role(self):
    """Test if user can delete non-editable role"""
    # Primary Contacts role of Control is non-editable
    ac_role = AccessControlRole.query.filter_by(
        object_type="Control",
        name="Control Operators",
    ).first()

    response = self.api.delete(ac_role)
    assert response.status_code == 403, \
        "Forbidden error should be thrown when non-editable " \
        "role {} deleted.".format(ac_role.name)

  @ddt.data("Control")
  def test_create_from_ggrcq(self, object_type):
    """Test that create action only for GGRCQ."""
    with self.api.as_external():
      response = self._post_role(object_type=object_type)
      self.assertEqual(response.status_code, 201)

  @ddt.data("Control")
  def test_create_from_ggrc(self, object_type):
    """Test create action not allowed for GGRC."""
    response = self._post_role(object_type=object_type)
    self.assertEqual(response.status_code, 405)

  @ddt.data("Control")
  def test_modify_from_ggrcq(self, object_type):
    """Test that modify action only for GGRCQ."""
    with factories.single_commit():
      acr_id = factories.AccessControlRoleFactory(object_type=object_type).id

    with self.api.as_external():
      acr = all_models.AccessControlRole.query.get(acr_id)
      response = self.api.put(acr, {"name": "new acr"})
      self.assertEqual(response.status_code, 200)

  @ddt.data("Control")
  def test_modify_from_ggrc(self, object_type):
    """Test modify action not allowed for GGRC."""
    with factories.single_commit():
      acr = factories.AccessControlRoleFactory(object_type=object_type)

    response = self.api.put(acr, {"name": "new acr"})
    self.assertEqual(response.status_code, 405)

  @ddt.data("Control")
  def test_delete_from_ggrcq(self, object_type):
    """Test that modify action only for GGRCQ."""
    with factories.single_commit():
      acr_id = factories.AccessControlRoleFactory(object_type=object_type).id

    with self.api.as_external():
      acr = all_models.AccessControlRole.query.get(acr_id)
      response = self.api.delete(acr)
      self.assertEqual(response.status_code, 200)

  @ddt.data("Control")
  def test_delete_from_ggrc(self, object_type):
    """Test modify action not allowed for GGRC."""
    with factories.single_commit():
      acr = factories.AccessControlRoleFactory(object_type=object_type)

    response = self.api.delete(acr)
    self.assertEqual(response.status_code, 405)
Exemplo n.º 21
0
class TestPermissionsLoading(TestMemcacheBase):
  """Test user permissions loading."""

  def setUp(self):
    super(TestPermissionsLoading, self).setUp()
    self.api = Api()
    self.generator = generator.ObjectGenerator()

    _, self.user = self.generator.generate_person(user_role="Creator")
    _, self.user1 = self.generator.generate_person(user_role="Creator")
    self.api.set_user(self.user)
    self.user_id = self.user.id
    self.user1_id = self.user1.id

  def set_dummy_permissions_in_cache(self, *user_ids):
    """Set dummy permissions for users in memcache.
    This will reset already existing set."""
    cached_keys = set()
    for user_id in user_ids:
      cached_keys.add("permissions:{}".format(user_id))
    self.memcache_client.set("permissions:list", cached_keys)

  def test_permissions_loading(self):
    """Test if permissions created only once for GET requests."""
    control_id = factories.ControlFactory().id
    with mock.patch(
        "ggrc_basic_permissions.store_results_into_memcache",
        side_effect=ggrc_basic_permissions.store_results_into_memcache
    ) as store_perm:
      self.api.get(all_models.Control, control_id)
      store_perm.assert_called_once()
      store_perm.call_count = 0

      # On second GET permissions should be loaded from memcache
      # but not created from scratch.
      self.api.get(all_models.Control, control_id)
      store_perm.assert_not_called()

  def test_post_object_with_acl(self):
    """Permissions are recalculated only for assigned people on POST."""
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()

    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
        },
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertIn("permissions:{}".format(self.user1_id), cached_keys)

  def test_delete_object_with_acl(self):
    """Permissions are recalculated only for affected people on DELETE."""
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()

    response = self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
        },
    })
    program = all_models.Program.query.get(response.json["program"]["id"])
    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    self.api.delete(program)
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertIn("permissions:{}".format(self.user1_id), cached_keys)

  def test_add_acl(self):
    """Permissions are recalculated only for assigned people on PUT."""
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()

    response = self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
        },
    })
    program = all_models.Program.query.get(response.json["program"]["id"])
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertNotIn("permissions:{}".format(self.user1_id), cached_keys)

    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    self.api.put(program, {
        "access_control_list": [{
            "ac_role_id": pa_role.id,
            "person": {
                "type": "Person",
                "id": self.user_id,
            }
        }, {
            "ac_role_id": pa_role.id,
            "person": {
                "type": "Person",
                "id": self.user1_id,
            }
        }],
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertNotIn("permissions:{}".format(self.user1_id), cached_keys)

  def test_remove_acl(self):
    """Permissions are recalculated only for unassigned people on PUT."""
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()

    response = self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }, {
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user1_id,
                }
            }],
        },
    })
    program = all_models.Program.query.get(response.json["program"]["id"])
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertNotIn("permissions:{}".format(self.user1_id), cached_keys)

    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    self.api.put(program, {
        "access_control_list": [{
            "ac_role_id": pa_role.id,
            "person": {
                "type": "Person",
                "id": self.user_id,
            }
        }]
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertNotIn("permissions:{}".format(self.user1_id), cached_keys)

  def test_mapping(self):
    """Perm dict should be recalculated for affected users on map/unmap."""
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()
    oa_role = all_models.AccessControlRole.query.filter_by(
        name="Admin",
        object_type="Objective",
    ).one()

    response = self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
        },
    })

    program = all_models.Program.query.get(response.json["program"]["id"])
    response = self.api.post(all_models.Objective, {
        "objective": {
            "access_control_list": [{
                "ac_role_id": oa_role.id,
                "person": {
                    "id": self.user_id,
                    "type": "Person",
                }
            }],
            "title": "Objective title",
            "context": None,
        }
    })
    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    response = self.api.post(all_models.Relationship, {
        "relationship": {
            "source": {"id": program.id, "type": "Program"},
            "destination": {
                "id": response.json["objective"]["id"],
                "type": "Objective"
            },
            "context": None,
        },
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertIn("permissions:{}".format(self.user1_id), cached_keys)

    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    relationship = all_models.Relationship.query.get(
        response.json["relationship"]["id"])
    self.api.delete(relationship)
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertIn("permissions:{}".format(self.user1_id), cached_keys)

  def test_add_comment(self):
    """Permissions dict should be flushed for affected users on add comment."""
    aa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Assessment",
        all_models.AccessControlRole.name == "Assignees"
    ).first()
    ac_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Audit",
        all_models.AccessControlRole.name == "Audit Captains"
    ).first()
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()

    response = self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
        },
    })
    response = self.api.post(all_models.Audit, {
        "audit": {
            "program": {
                "id": response.json["program"]["id"],
                "type": "Program"
            },
            "access_control_list": [{
                "ac_role_id": ac_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user1_id,
                }
            }],
            "context": None,
            "title": "Some title"
        }
    })
    response = self.api.post(all_models.Assessment, {
        "assessment": {
            "audit": {
                "id": response.json["audit"]["id"],
                "type": "Audit"
            },
            "access_control_list": [{
                "ac_role_id": aa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user1_id,
                }
            }],
            "context": None,
            "title": "Some title"
        }
    })
    assessment = all_models.Assessment.query.get(
        response.json["assessment"]["id"]
    )
    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    request_data = [{
        "comment": {
            "description": "<p>{}</p>".format("test"),
            "context": None,
            "assignee_type": "Assignees,Verifiers,Creators",
        },
    }]

    # logged user will be set as comment admin
    response = self.api.post(all_models.Comment, request_data)
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertIn("permissions:{}".format(self.user1_id), cached_keys)

    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    self.api.set_user(self.user1)
    self.api.put(assessment, {
        "actions": {"add_related": [{
            "id": response.json[0][1]["comment"]["id"],
            "type": "Comment"
        }]},
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertNotIn("permissions:{}".format(self.user1_id), cached_keys)

  def test_add_evidence(self):
    """Perm dict should be flushed for affected users on add evidence."""
    aa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Assessment",
        all_models.AccessControlRole.name == "Assignees"
    ).first()
    ac_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Audit",
        all_models.AccessControlRole.name == "Audit Captains"
    ).first()
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()
    ea_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Evidence",
        all_models.AccessControlRole.name == "Admin"
    ).first()

    response = self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
        },
    })
    response = self.api.post(all_models.Audit, {
        "audit": {
            "program": {
                "id": response.json["program"]["id"],
                "type": "Program"
            },
            "access_control_list": [{
                "ac_role_id": ac_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
            "context": None,
            "title": "Some title"
        }
    })
    response = self.api.post(all_models.Assessment, {
        "assessment": {
            "audit": {
                "id": response.json["audit"]["id"],
                "type": "Audit"
            },
            "access_control_list": [{
                "ac_role_id": aa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
            "context": None,
            "title": "Some title"
        }
    })
    assessment = all_models.Assessment.query.get(
        response.json["assessment"]["id"]
    )
    response = self.api.post(all_models.Evidence, {
        "evidence": {
            "access_control_list": [{
                "ac_role_id": ea_role.id,
                "person": {
                    "id": self.user_id,
                    "type": "Person",
                }
            }],
            "link": factories.random_str(),
            "title": factories.random_str(),
            "context": None,
        }
    })
    self.set_dummy_permissions_in_cache(self.user_id, self.user1_id)
    self.api.put(assessment, {
        "actions": {"add_related": [{
            "id": response.json["evidence"]["id"],
            "type": "Evidence"
        }]},
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)
    self.assertIn("permissions:{}".format(self.user1_id), cached_keys)

  def test_edit_object_title(self):
    """Permissions shouldn't be recalculated on PUT if no acls were changed."""
    pa_role = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Program",
        all_models.AccessControlRole.name == "Program Managers"
    ).first()

    response = self.api.post(all_models.Program, {
        "program": {
            "title": "Program title",
            "context": None,
            "access_control_list": [{
                "ac_role_id": pa_role.id,
                "person": {
                    "type": "Person",
                    "id": self.user_id,
                }
            }],
        },
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertNotIn("permissions:{}".format(self.user_id), cached_keys)

    self.api.get(all_models.Program, response.json["program"]["id"])
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertIn("permissions:{}".format(self.user_id), cached_keys)

    program = all_models.Program.query.get(response.json["program"]["id"])
    self.api.put(program, {
        "title": "Program title 1"
    })
    cached_keys = self.memcache_client.get("permissions:list")
    self.assertIn("permissions:{}".format(self.user_id), cached_keys)
Exemplo n.º 22
0
class TestDisabledIssueIntegration(ggrc.TestCase):
  """Tests for IssueTracker integration functionality with disabled sync."""

  # pylint: disable=invalid-name

  def setUp(self):
    # pylint: disable=super-on-old-class
    super(TestDisabledIssueIntegration, self).setUp()
    self.api = Api()
    self.client.get("/login")

  @mock.patch("ggrc.integrations.issues.Client.create_issue")
  def test_issue_creation(self, mock_create_issue):
    """Test creating Issue object with disabled integration."""
    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      response = self.api.post(all_models.Issue, {
          "issue": {
              "title": "test title",
              "context": None,
              "issue_tracker": {
                  "enabled": False,
              }
          },
      })
    mock_create_issue.assert_not_called()
    self.assertEqual(response.status_code, 201)
    issue_id = response.json.get("issue").get("id")
    issue_tracker_issue = models.IssuetrackerIssue.get_issue("Issue",
                                                             issue_id)
    self.assertIsNone(issue_tracker_issue)

  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_issue_deletion(self, mock_update_issue):
    """Test deleting Issue object with disabled integration for issue."""
    iti = factories.IssueTrackerIssueFactory(
        enabled=False,
        issue_tracked_obj=factories.IssueFactory()
    )
    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      self.api.delete(iti.issue_tracked_obj)
    mock_update_issue.assert_not_called()

  @ddt.data(
      {"description": "new description", "issue_tracker": {"enabled": False}},
      {"test_plan": "new test plan", "issue_tracker": {"enabled": False}},
      {"issue_tracker": {"component_id": "123", "enabled": False}},
      {"issue_tracker": {"hotlist_id": "321", "enabled": False}},
      {"issue_tracker": {"issue_priority": "P2", "enabled": False}},
      {"issue_tracker": {"issue_severity": "S2", "enabled": False}},
  )
  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_update_issue_object(self, issue_attrs, mock_update_issue):
    """Test updating issue object with disabled integration for issue."""
    iti = factories.IssueTrackerIssueFactory(
        enabled=False,
        issue_tracked_obj=factories.IssueFactory()
    )
    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      self.api.put(iti.issue_tracked_obj, issue_attrs)
    mock_update_issue.assert_not_called()

  @mock.patch("ggrc.integrations.issues.Client.create_issue",
              side_effect=[integrations_errors.Error, {"issueId": "issueId"}])
  @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
  def test_issue_recreation(self, mock_create_issue):
    """Test retrying to turn on integration after failed creation."""
    # Arrange data.
    component_id = "1234"
    hotlist_id = "4321"
    issue_type = "Default Issue type"
    issue_priority = "P2"
    issue_severity = "S1"
    title = "test title"
    issue_tracker_attrs = {
        "enabled": True,
        "component_id": int(component_id),
        "hotlist_id": int(hotlist_id),
        "issue_type": issue_type,
        "issue_priority": issue_priority,
        "issue_severity": issue_severity,
    }

    # Perform actions and assert results.
    with mock.patch.object(integration_utils, "exclude_auditor_emails",
                           return_value={u"*****@*****.**", }):

      # Try to create issue. create_issue should raise exception here.
      response = self.api.post(all_models.Issue, {
          "issue": {
              "title": title,
              "context": None,
              "issue_tracker": issue_tracker_attrs
          },
      })

      issue_id = response.json.get("issue").get("id")
      issue_tracker_issue = models.IssuetrackerIssue.get_issue("Issue",
                                                               issue_id)
      self.assertIsNone(issue_tracker_issue.issue_id)
      self.assertIsNone(issue_tracker_issue.issue_url)

      # Try to turn on integration on already created issue.
      self.api.put(
          issue_tracker_issue.issue_tracked_obj,
          {"issue_tracker": issue_tracker_attrs}
      )

      issue_id = issue_tracker_issue.issue_tracked_obj.id
      issue_tracker_issue = models.IssuetrackerIssue.get_issue("Issue",
                                                               issue_id)
      self.assertEqual(issue_tracker_issue.issue_url, "http://issue/issueId")

  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_adding_comment_to_issue(self, update_issue_mock):
    """Test not adding comment to issue when issue tracker disabled."""
    iti = factories.IssueTrackerIssueFactory(
        enabled=False,
        issue_tracked_obj=factories.IssueFactory()
    )
    comment = factories.CommentFactory(description="test comment")

    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      self.api.post(all_models.Relationship, {
          "relationship": {
              "source": {"id": iti.issue_tracked_obj.id, "type": "Issue"},
              "destination": {"id": comment.id, "type": "comment"},
              "context": None
          },
      })
    update_issue_mock.assert_not_called()
Exemplo n.º 23
0
class TestReader(TestCase):
    """ Test reader role """
    def setUp(self):
        super(TestReader, self).setUp()
        self.generator = Generator()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.init_users()

    def init_users(self):
        """ Init users needed by the test cases """
        users = [("reader", "Reader"), ("admin", "Administrator"),
                 ("creator", "Creator")]
        self.users = {}
        for (name, role) in users:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role=role)
            self.users[name] = user

    def test_admin_page_access(self):
        """Only admin can use admin section"""
        for role, code in (("reader", 403), ("admin", 200)):
            self.api.set_user(self.users[role])
            self.assertEqual(self.api.client.get("/admin").status_code, code)

    def test_reader_can_crud(self):
        """ Test Basic create/read,update/delete operations """
        self.api.set_user(self.users["reader"])
        all_errors = []
        base_models = set([
            "Control", "DataAsset", "Contract", "Policy", "Regulation",
            "Standard", "Document", "Facility", "Market", "Objective",
            "OrgGroup", "Vendor", "Product", "Clause", "System", "Process",
            "Project", "AccessGroup", "Metric"
        ])
        for model_singular in base_models:
            try:
                model = get_model(model_singular)
                table_singular = model._inflector.table_singular
                table_plural = model._inflector.table_plural
                # Test POST creation
                response = self.api.post(
                    model,
                    {
                        table_singular: {
                            "title": model_singular,
                            "context": None,
                            "documents_reference_url": "ref",
                            "link":
                            "https://example.com",  # ignored except for Document
                            "contact": {
                                "type": "Person",
                                "id": self.users["reader"].id,
                            },
                        },
                    })
                if response.status_code != 201:
                    all_errors.append("{} post creation failed {} {}".format(
                        model_singular, response.status, response.data))
                    continue

                obj_id = response.json.get(table_singular).get("id")

                # Test GET when owner
                response = self.api.get(model, obj_id)
                if response.status_code != 200:
                    all_errors.append("{} can't GET object {}".format(
                        model_singular, response.status))
                    continue

                # Test GET collection when owner
                response = self.api.get_collection(model, obj_id)
                collection = response.json.get(
                    "{}_collection".format(table_plural)).get(table_plural)
                if not collection:
                    all_errors.append(
                        "{} cannot retrieve object even if owner (collection)".
                        format(model_singular))
                    continue
            except:
                all_errors.append("{} exception thrown".format(model_singular))
                raise
        self.assertEqual(all_errors, [])

    def test_reader_search(self):
        """ Test if reader can see the correct object while using search api """
        self.api.set_user(self.users['admin'])
        self.api.post(all_models.Regulation, {
            "regulation": {
                "title": "Admin regulation",
                "context": None
            },
        })
        self.api.set_user(self.users['reader'])
        response = self.api.post(all_models.Policy, {
            "policy": {
                "title": "reader Policy",
                "context": None
            },
        })
        response, _ = self.api.search("Regulation,Policy")
        entries = response.json["results"]["entries"]
        self.assertEqual(len(entries), 2)
        response, _ = self.api.search("Regulation,Policy", counts=True)
        self.assertEqual(response.json["results"]["counts"]["Policy"], 1)
        self.assertEqual(response.json["results"]["counts"]["Regulation"], 1)

    def _get_count(self, obj):
        """ Return the number of counts for the given object from search """
        response, _ = self.api.search(obj, counts=True)
        return response.json["results"]["counts"].get(obj)

    def test_reader_should_see_users(self):
        """ Test if creator can see all the users in the system """
        self.api.set_user(self.users['admin'])
        admin_count = self._get_count("Person")
        self.api.set_user(self.users['reader'])
        reader_count = self._get_count("Person")
        self.assertEqual(admin_count, reader_count)

    def test_relationships_access(self):
        """Check if reader can access relationship objects"""
        self.api.set_user(self.users['admin'])
        _, obj_0 = self.generator.generate(all_models.Regulation, "regulation",
                                           {
                                               "regulation": {
                                                   "title": "Test regulation",
                                                   "context": None
                                               },
                                           })
        _, obj_1 = self.generator.generate(
            all_models.Regulation, "regulation", {
                "regulation": {
                    "title": "Test regulation 2",
                    "context": None
                },
            })
        response, rel = self.generator.generate(
            all_models.Relationship, "relationship", {
                "relationship": {
                    "source": {
                        "id": obj_0.id,
                        "type": "Regulation"
                    },
                    "destination": {
                        "id": obj_1.id,
                        "type": "Regulation"
                    },
                    "context": None
                },
            })
        relationship_id = rel.id
        self.assertEqual(response.status_code, 201)
        self.api.set_user(self.users['reader'])
        response = self.api.get_collection(all_models.Relationship,
                                           relationship_id)
        self.assertEqual(response.status_code, 200)
        num = len(response.json["relationships_collection"]["relationships"])
        self.assertEqual(num, 1)

    def test_creation_of_mappings(self):
        """Check if reader can't create mappings"""
        self.generator.api.set_user(self.users["admin"])
        _, control = self.generator.generate(all_models.Control, "control", {
            "control": {
                "title": "Test Control",
                "context": None
            },
        })
        self.generator.api.set_user(self.users['reader'])
        _, program = self.generator.generate(all_models.Program, "program", {
            "program": {
                "title": "Test Program",
                "context": None
            },
        })

        response, _ = self.generator.generate(
            all_models.Relationship, "relationship", {
                "relationship": {
                    "destination": {
                        "id": program.id,
                        "type": "Program"
                    },
                    "source": {
                        "id": control.id,
                        "type": "Control"
                    },
                    "context": {
                        "id": program.context.id,
                        "type": "context"
                    }
                },
            })
        self.assertEqual(response.status_code, 403)

    @ddt.data("creator", "reader")
    def test_unmap_people(self, user_role):
        """Test that global reader/creator can't unmap people from program"""
        user = self.users[user_role]
        with factories.single_commit():
            program = factories.ProgramFactory()
            mapped_person = factories.ObjectPersonFactory(
                personable=program, person=user, context=program.context)
        self.api.set_user(user)
        db.session.add(mapped_person)
        response = self.api.delete(mapped_person)
        self.assertEqual(response.status_code, 403)

    def test_read_evidence_revision(self):
        """Global Read can read Evidence revision content"""
        user = self.users["reader"]
        link = "google.com"
        evidence = factories.EvidenceUrlFactory(link=link)
        evidence_id = evidence.id
        self.api.set_user(user)
        resp = self.api.client.get(
            "/api/revisions?resource_type={}&resource_id={}".format(
                evidence.type, evidence_id))
        rev_content = resp.json["revisions_collection"]["revisions"][0][
            "content"]
        self.assertTrue(rev_content)
        self.assertEquals(link, rev_content["link"])
Exemplo n.º 24
0
class TestReader(TestCase):
  """ Test reader role """

  def setUp(self):
    super(TestReader, self).setUp()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.init_users()

  def init_users(self):
    """ Init users needed by the test cases """
    users = [("reader", "Reader"),
             ("admin", "Administrator"),
             ("creator", "Creator")]
    self.users = {}
    for (name, role) in users:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=role)
      self.users[name] = user

    self.users["external"] = self.object_generator.generate_person(
        data={"email": "*****@*****.**"})[1]

  def test_admin_page_access(self):
    """Only admin can use admin requirement"""
    for role, code in (("reader", 403), ("admin", 200)):
      self.api.set_user(self.users[role])
      self.assertEqual(self.api.client.get("/admin").status_code, code)

  def test_reader_can_crud(self):
    """ Test Basic create/read,update/delete operations """
    self.api.set_user(self.users["reader"])
    all_errors = []
    base_models = set([
        "DataAsset", "Contract",
        "Policy", "Regulation", "Standard", "Document", "Facility",
        "Market", "Objective", "OrgGroup", "Vendor", "Product",
        "System", "Process", "Project", "AccessGroup",
        "Metric", "TechnologyEnvironment", "ProductGroup", "KeyReport",
        "AccountBalance",
    ])
    for model_singular in base_models:
      try:
        model = get_model(model_singular)
        table_singular = model._inflector.table_singular
        table_plural = model._inflector.table_plural
        # Test POST creation
        response, _ = self.object_generator.generate_object(
            model,
            data={
                table_singular: {
                    "title": model_singular,
                    "context": None,
                    "documents_reference_url": "ref",
                    "link": "https://example.com",  # only for Document
                    "contact": {
                        "type": "Person",
                        "id": self.users["reader"].id,
                    }
                },
            }
        )

        if response.status_code != 201:
          all_errors.append("{} post creation failed {} {}".format(
              model_singular, response.status, response.data))
          continue

        obj_id = response.json.get(table_singular).get("id")

        # Test GET when owner
        response = self.api.get(model, obj_id)
        if response.status_code != 200:
          all_errors.append("{} can't GET object {}".format(
              model_singular, response.status))
          continue

        # Test GET collection when owner
        response = self.api.get_collection(model, obj_id)
        collection = response.json.get(
            "{}_collection".format(table_plural)).get(table_plural)
        if not collection:
          all_errors.append(
              "{} cannot retrieve object even if owner (collection)".format(
                  model_singular))
          continue
      except:
        all_errors.append("{} exception thrown".format(model_singular))
        raise
    self.assertEqual(all_errors, [])

  def test_reader_search(self):
    """ Test if reader can see the correct object while using search api """
    self.api.set_user(self.users['admin'])
    self.api.post(all_models.Regulation, {
        "regulation": {"title": "Admin regulation", "context": None},
    })
    self.api.set_user(self.users['reader'])
    response = self.api.post(all_models.Policy, {
        "policy": {"title": "reader Policy", "context": None},
    })
    response, _ = self.api.search("Regulation,Policy")
    entries = response.json["results"]["entries"]
    self.assertEqual(len(entries), 2)
    response, _ = self.api.search("Regulation,Policy", counts=True)
    self.assertEqual(response.json["results"]["counts"]["Policy"], 1)
    self.assertEqual(response.json["results"]["counts"]["Regulation"], 1)

  def _get_count(self, obj):
    """ Return the number of counts for the given object from search """
    response, _ = self.api.search(obj, counts=True)
    return response.json["results"]["counts"].get(obj)

  def test_reader_should_see_users(self):
    """ Test if creator can see all the users in the system """
    self.api.set_user(self.users['admin'])
    admin_count = self._get_count("Person")
    self.api.set_user(self.users['reader'])
    reader_count = self._get_count("Person")
    self.assertEqual(admin_count, reader_count)

  def test_relationships_access(self):
    """Check if reader can access relationship objects"""
    self.api.set_user(self.users['admin'])
    _, first_regulation = self.object_generator.generate_object(
        all_models.Regulation,
        data={"regulation": {"title": "Test regulation", "context": None}}
    )
    _, second_regulation = self.object_generator.generate_object(
        all_models.Regulation,
        data={"regulation": {"title": "Test regulation 2", "context": None}}
    )
    response, rel = self.object_generator.generate_relationship(
        first_regulation, second_regulation
    )
    self.assertStatus(response, 201)
    self.api.set_user(self.users['reader'])
    response = self.api.get_collection(all_models.Relationship, rel.id)
    self.assert200(response)
    num = len(response.json["relationships_collection"]["relationships"])
    self.assertEqual(num, 1)

  def test_creation_of_mappings(self):
    """Check if reader can't create mappings"""
    self.object_generator.api.set_user(self.users["external"])
    _, control = self.object_generator.generate_object(
        all_models.Control,
        data={"control": {"title": "Test Control", "context": None}}
    )

    self.object_generator.api.set_user(self.users['reader'])
    _, program = self.object_generator.generate_object(
        all_models.Program,
        data={"program": {"title": "Test Program", "context": None}}
    )

    response, _ = self.object_generator.generate_relationship(
        control, program, program.context
    )
    self.assert403(response)

  @ddt.data("creator", "reader")
  def test_unmap_people(self, user_role):
    """Test that global reader/creator can't unmap people from program"""
    user = self.users[user_role]
    with factories.single_commit():
      program = factories.ProgramFactory()
      mapped_person = factories.ObjectPersonFactory(
          personable=program, person=user, context=program.context
      )
    self.api.set_user(user)
    db.session.add(mapped_person)
    response = self.api.delete(mapped_person)
    self.assert403(response)

  def test_read_evidence_revision(self):
    """Global Read can read Evidence revision content"""
    user = self.users["reader"]
    link = "google.com"
    evidence = factories.EvidenceUrlFactory(link=link)
    evidence_id = evidence.id
    self.api.set_user(user)
    resp = self.api.client.get(
        "/api/revisions?resource_type={}&resource_id={}".format(evidence.type,
                                                                evidence_id))
    rev_content = resp.json["revisions_collection"]["revisions"][0]["content"]
    self.assertTrue(rev_content)
    self.assertEquals(link, rev_content["link"])
Exemplo n.º 25
0
class TestReviewStatusUpdate(TestCase):
    """Base TestCase class automatic review status update."""
    def setUp(self):
        super(TestReviewStatusUpdate, self).setUp()
        self.api = Api()
        self.api.client.get("/login")
        self.generator = generator.ObjectGenerator()

    @ddt.data(
        ("title", "new title"),
        ("description", "new description"),
        ("test_plan", "new test_plan"),
        ("notes", "new notes"),
        ("fraud_related", 1),
        ("key_control", 1),
        ("start_date", "2020-01-01"),
        ("status", "Active"),
        ("kind", get_kind_data),
        ("means", get_mean_data),
        ("verify_frequency", get_verify_frequency_data),
        ("assertions", get_assertions_data),
        ("categories", get_categories_data),
    )
    @ddt.unpack
    def test_reviewable_attributes(self, attr_to_modify, new_value):
        """If attribute '{0}' modified move review to Unreviewed state"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id
        reviewable = review.reviewable

        self.api.modify_object(reviewable, {
            attr_to_modify:
            new_value() if callable(new_value) else new_value
        })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_gca(self):
        """if GCA of reviewable is changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="control",
                             title="rich_test_gca",
                             attribute_type="Rich Text")
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_reference_url(self):
        """If reference url is updated state should not updated"""
        with factories.single_commit():
            control = factories.ControlFactory()
            doc = factories.DocumentReferenceUrlFactory(
                title="Simple title",
                link="some_url.com",
                description="mega description",
                parent_obj={
                    "id": control.id,
                    "type": "Control"
                })
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id

        self.api.modify_object(doc, {"link": "new_link.com"})
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_acl_roles(self):
        """Update of reviewable ACL shouldn't change review status"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id

        ac_role_id = all_models.AccessControlRole.query.filter_by(
            name="Primary Contacts", object_type="Control").one().id

        user_id = all_models.Person.query.filter_by(
            email="*****@*****.**").one().id

        self.api.modify_object(
            control, {
                "access_control_list": [{
                    "ac_role_id": ac_role_id,
                    "person": {
                        "id": user_id
                    },
                }],
            })
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_comments(self):
        """Add comment to reviewable shouldn't update review state"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id

        self.generator.generate_comment(control,
                                        "Verifiers",
                                        "some comment",
                                        send_notification="false")

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_mapping_non_snapshotable(self):
        """Map non-snapshotable shouldn't change review status"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
            review_id = review.id

        factories.RelationshipFactory(source=control,
                                      destination=factories.IssueFactory())

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    @ddt.data("Standard", "Regulation", "Requirement", "Objective", "Control",
              "Product", "System", "Process", "AccessGroup", "Contract",
              "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk",
              "Threat", "Vendor")
    def test_map_snapshotable(self, snapshotable):
        """Map '{}' should change review status"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
            review_id = review.id

        self.generator.generate_relationship(
            source=control,
            destination=factories.get_model_factory(snapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_unmap_snapshotable(self):
        """Unmap snapshotable should change review status"""
        control = factories.ControlFactory()
        resp, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.UNREVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        review_id = review.id

        _, rel = self.generator.generate_relationship(
            source=control,
            destination=factories.ProductFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    @ddt.data(
        "Assessment",
        "Issue",
        "Program",
        "Project",
        "Audit",
        "RiskAssessment",
        "AssessmentTemplate",
        "Person",
    )
    def test_map_nonsnapshotable(self, nonsnapshotable):
        """Map '{}' shouldn't change review status"""
        control = factories.ControlFactory()
        _, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.REVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        review_id = review.id

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.generator.generate_relationship(
            source=control,
            destination=factories.get_model_factory(nonsnapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_unmap_nonsnapshotable(self):
        """Unmap nonsnapshotable shouldn't change review status"""
        control = factories.ControlFactory()
        resp, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.REVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        review_id = review.id
        _, rel = self.generator.generate_relationship(
            source=control,
            destination=factories.ProgramFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_proposal_apply(self):
        """Reviewable object changed via proposal -> review.state-> UNREVIEWED"""
        control = factories.ControlFactory()
        _, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.UNREVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )

        review_id = review.id

        proposal_content = {
            "fields": {
                "title": "new title"
            },
        }
        proposal = factories.ProposalFactory(instance=control,
                                             content=proposal_content,
                                             agenda="agenda content")
        self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED})

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)
Exemplo n.º 26
0
class TestReviewApi(TestCase):
    """Base TestCase class proposal api tests."""
    def setUp(self):
        super(TestReviewApi, self).setUp()
        self.api = Api()
        self.api.client.get("/login")
        self.generator = generator.ObjectGenerator()

    def test_simple_get(self):
        """Test simple get"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                email_message="test email message",
                notification_type="email",
                reviewable=control,
                status=all_models.Review.STATES.UNREVIEWED,
            )
        resp = self.api.get(all_models.Review, review.id)
        self.assert200(resp)
        self.assertIn("review", resp.json)
        resp_review = resp.json["review"]
        self.assertEqual(all_models.Review.STATES.UNREVIEWED,
                         resp_review["status"])
        self.assertEqual(all_models.Review.NotificationTypes.EMAIL_TYPE,
                         resp_review["notification_type"])
        self.assertEqual("test email message", resp_review["email_message"])

    def test_collection_get(self):
        """Test simple collection get"""
        with factories.single_commit():
            review1 = factories.ReviewFactory(
                status=all_models.Review.STATES.UNREVIEWED)
            review2 = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED)

        resp = self.api.get_collection(all_models.Review,
                                       [review1.id, review2.id])
        self.assert200(resp)
        self.assertIn("reviews_collection", resp.json)
        self.assertIn("reviews", resp.json["reviews_collection"])
        self.assertEquals(2, len(resp.json["reviews_collection"]["reviews"]))

    def test_create_review(self):
        """Create review via API, check that single relationship is created"""
        control = factories.ControlFactory()
        control_id = control.id
        resp = self.api.post(
            all_models.Review,
            {
                "review": {
                    "reviewable": {
                        "type": control.type,
                        "id": control.id,
                    },
                    "context": None,
                    "notification_type": "email",
                    "status": all_models.Review.STATES.UNREVIEWED,
                    "access_control_list": build_reviewer_acl()
                },
            },
        )
        self.assertEqual(201, resp.status_code)
        review_id = resp.json["review"]["id"]
        review = all_models.Review.query.get(review_id)
        self.assertEqual(all_models.Review.STATES.UNREVIEWED, review.status)
        self.assertEqual(control.type, review.reviewable_type)
        self.assertEqual(control_id, review.reviewable_id)

        control_review_rel_count = all_models.Relationship.query.filter(
            all_models.Relationship.source_id == review.id,
            all_models.Relationship.source_type == review.type,
            all_models.Relationship.destination_id == control_id,
            all_models.Relationship.destination_type == control.type,
        ).union(
            all_models.Relationship.query.filter(
                all_models.Relationship.destination_id == review.id,
                all_models.Relationship.destination_type == review.type,
                all_models.Relationship.source_id == control_id,
                all_models.Relationship.source_type == control.type,
            )).count()
        self.assertEqual(1, control_review_rel_count)

    def test_delete_review(self):
        """Test delete review via API"""
        with factories.single_commit():
            control = factories.ControlFactory()
            control_id = control.id
            review = factories.ReviewFactory(reviewable=control)
            review_id = review.id
        resp = self.api.delete(review)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        control = all_models.Control.query.get(control_id)

        self.assertIsNone(review)
        self.assertEquals(0, len(control.related_objects(_types=["Review"])))

    def test_last_reviewed(self):
        """last_reviewed_by, last_reviewed_by should be set if reviewed"""
        control = factories.ControlFactory()
        resp, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.UNREVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        review_id = review.id
        resp = self.api.put(
            review,
            {
                "status": all_models.Review.STATES.REVIEWED,
            },
        )
        self.assert200(resp)
        self.assertIsNotNone(resp.json["review"]["last_reviewed_by"])
        self.assertIsNotNone(resp.json["review"]["last_reviewed_at"])

        review = all_models.Review.query.get(review_id)
        self.assertIsNotNone(review.last_reviewed_by)
        self.assertIsNotNone(review.last_reviewed_at)

    def test_reviewable_revisions(self):
        """Check that proper revisions are created"""
        control = factories.ControlFactory()
        resp, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.UNREVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        control_id = control.id
        reviewable = review.reviewable

        control_revisions = all_models.Revision.query.filter_by(
            resource_id=control_id, resource_type=control.type).order_by(
                all_models.Revision.created_at, ).all()
        self.assertEquals(2, len(control_revisions))
        self.assertEquals(all_models.Review.STATES.UNREVIEWED,
                          control_revisions[0].content["review_status"])
        self.assertEquals(all_models.Review.STATES.UNREVIEWED,
                          control_revisions[1].content["review_status"])
        resp = self.api.put(
            review,
            {
                "status": all_models.Review.STATES.REVIEWED,
            },
        )
        self.assert200(resp)

        control_revisions = all_models.Revision.query.filter_by(
            resource_id=control_id, resource_type=control.type).order_by(
                all_models.Revision.created_at, ).all()
        self.assertEquals(3, len(control_revisions))
        self.assertEquals(all_models.Review.STATES.REVIEWED,
                          control_revisions[2].content["review_status"])

        resp = self.api.put(reviewable,
                            {"description": "some new description"})
        self.assert200(resp)

        control_revisions = all_models.Revision.query.filter_by(
            resource_id=control_id, resource_type=control.type).order_by(
                all_models.Revision.created_at, ).all()
        self.assertEquals(4, len(control_revisions))
        self.assertEquals(all_models.Review.STATES.UNREVIEWED,
                          control_revisions[3].content["review_status"])
Exemplo n.º 27
0
class TestPermissionsOnAssessmentTemplate(TestCase):
  """ Test check permissions for ProgramEditor on

  get and post assessment_temaplte action"""

  def setUp(self):
    super(TestPermissionsOnAssessmentTemplate, self).setUp()
    self.api = Api()
    self.generator = ObjectGenerator()
    _, program = self.generator.generate_object(all_models.Program)
    program_id = program.id
    _, self.editor = self.generator.generate_person(
        user_role="Creator"
    )
    role = perms.all_models.Role.query.filter(
        perms.all_models.Role.name == "ProgramEditor"
    ).first()
    self.generator.generate_user_role(
        self.editor,
        role,
        all_models.Program.query.get(program_id)
    )
    _, audit = self.generator.generate_object(
        all_models.Audit,
        {
            "title": "Audit",
            "program": {"id": program_id},
            "status": "Planned"
        },
    )
    audit_id = audit.id

    generated_at = self.generator.generate_object(
        all_models.AssessmentTemplate,
        {
            "title": "Template",
            "_NON_RELEVANT_OBJ_TYPES": {},
            "_objectTypes": {},
            "audit": {"id": audit.id},
            "audit_title": audit.title,
            "people_value": [],
            "default_people": {
                "assessors": "Object Owners",
                "verifiers": "Object Owners",
            },
            "context": {"id": audit.context.id},
        }
    )
    self.assessment_template_resp, assessment_template = generated_at
    assessment_template_id = assessment_template.id
    self.api.set_user(self.editor)
    self.perms_data = self.api.client.get("/permissions").json
    self.audit = all_models.Audit.query.get(audit_id)
    self.assessment_template = all_models.AssessmentTemplate.query.get(
        assessment_template_id)

  def test_post_action(self):
    """Test create action on AssessmentTemplate created by api"""
    data = [{
        "assessment_template": {
            "_NON_RELEVANT_OBJ_TYPES": {},
            "_objectTypes": {},
            "audit": {"id": self.audit.id},
            "audit_title": self.audit.title,
            "people_value": [],
            "default_people": {
                "assessors": "Object Owners",
                "verifiers": "Object Owners",
            },
            "context": {"id": self.audit.context.id},
            "title": "123",
        }
    }]
    self.api.set_user(self.editor)
    resp = self.api.post(all_models.AssessmentTemplate, data)
    self.assert200(resp)

  def test_get_action(self):
    """Test read action on AssessmentTemplate created by api"""
    resp = self.api.get(all_models.AssessmentTemplate,
                        self.assessment_template.id)
    self.assert200(resp)

  def test_put_action(self):
    """Test update action on AssessmentTemplate created by api"""
    to_update = copy.deepcopy(self.assessment_template_resp.json)
    new_title = "new_{}".format(self.assessment_template.title)
    to_update['assessment_template']['title'] = new_title
    resp = self.api.put(self.assessment_template, to_update)
    self.assert200(resp)
    assessment_tmpl = all_models.AssessmentTemplate.query.get(
        self.assessment_template.id
    )
    self.assertEqual(new_title, assessment_tmpl.title)

  def test_delete_action(self):
    """Test delete action on AssessmentTemplate created by api"""
    resp = self.api.delete(self.assessment_template)
    self.assert200(resp)
    self.assertFalse(all_models.AssessmentTemplate.query.filter(
        all_models.AssessmentTemplate == self.assessment_template.id).all())
Exemplo n.º 28
0
class TestCreatorProgram(TestCase):
  """Set up necessary objects and test Creator role with Program roles"""

  def setUp(self):
    super(TestCreatorProgram, self).setUp()
    self.generator = Generator()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.init_users()
    self.init_roles()
    self.init_test_cases()
    self.objects = {}

  def init_test_cases(self):
    """ Create a dict of all possible test cases """
    self.test_cases = {
        "notmapped": {
            "objects": {
                "program": {
                    "get": 403,
                    "put": 403,
                    "delete": 403
                },
                "mapped_object": {
                    "get": 403,
                    "put": 403,
                    "delete": 403
                },
                "unrelated": {
                    "get": 403,
                    "put": 403,
                    "delete": 403,
                    "map": 403,
                }
            },
        },
        "mapped": {
            "objects": {
                "program": {
                    "get": 403,
                    "put": 403,
                    "delete": 403
                },
                "mapped_object": {
                    "get": 403,
                    "put": 403,
                    "delete": 403
                },
                "unrelated": {
                    "get": 403,
                    "put": 403,
                    "delete": 403,
                    "map": 403,
                }
            }
        },
        "ProgramReader": {
            "program_role": "ProgramReader",
            "objects": {
                "program": {
                    "get": 200,
                    "put": 403,
                    "delete": 403
                },
                "mapped_object": {
                    "get": 200,
                    "put": 403,
                    "delete": 403
                },
                "unrelated": {
                    "get": 403,
                    "put": 403,
                    "delete": 403,
                    "map": 403,
                }
            }
        },
        "ProgramOwner": {
            "program_role": "ProgramOwner",
            "objects": {
                "program": {
                    "get": 200,
                    "put": 200,
                    "delete": 200
                },
                "mapped_object": {
                    "get": 200,
                    "put": 200,
                    "delete": 200,
                },
                "unrelated": {
                    "get": 403,
                    "put": 403,
                    "delete": 403,
                    "map": 403,
                }
            }
        },
        "ProgramEditor": {
            "program_role": "ProgramEditor",
            "objects": {
                "program": {
                    "get": 200,
                    "put": 200,
                    "delete": 200
                },
                "mapped_object": {
                    "get": 200,
                    "put": 200,
                    "delete": 200
                },
                "unrelated": {
                    "get": 403,
                    "put": 403,
                    "delete": 403,
                    "map": 403,
                }
            }
        },
    }

  def init_roles(self):
    """ Create a delete request for the given object """
    response = self.api.get_query(all_models.Role, "")
    self.roles = {}
    for role in response.json.get("roles_collection").get("roles"):
      self.roles[role.get("name")] = role

  def init_users(self):
    """ Create users used by test cases """
    users = [
        ("creator", "Creator"),
        ("notmapped", "Creator"),
        ("mapped", "Creator"),
        ("ProgramReader", "Creator"),
        ("ProgramEditor", "Creator"),
        ("ProgramOwner", "Creator")]
    self.people = {}
    for (name, role) in users:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role=role)
      self.people[name] = user

  def delete(self, obj):
    """ Create a delete request for the given object """
    return self.api.delete(obj).status_code

  def get(self, obj):
    """ Create a get request for the given object """
    return self.api.get(obj.__class__, obj.id).status_code

  def put(self, obj):
    """ Create a put request for the given object """
    response = self.api.get(obj.__class__, obj.id)
    if response.status_code == 200:
      return self.api.put(obj, response.json).status_code
    else:
      return response.status_code

  def map(self, dest):
    """ Map src to dest """
    response = self.api.post(all_models.Relationship, {
        "relationship": {"source": {
            "id": self.objects["program"].id,
            "type": self.objects["program"].type,
        }, "destination": {
            "id": dest.id,
            "type": dest.type
        }, "context": None},
    })
    return response.status_code

  def init_objects(self, test_case_name):
    """ Create a Program and a Mapped object for a given test case """
    # Create a program
    test_case = self.test_cases[test_case_name]
    creator = self.people.get('creator')
    self.api.set_user(creator)
    random_title = factories.random_str()
    response = self.api.post(all_models.Program, {
        "program": {"title": random_title, "context": None},
    })
    self.assertEqual(response.status_code, 201)
    context_id = response.json.get("program").get("context").get("id")
    program_id = response.json.get("program").get("id")

    # Use admin owner role to map it with system
    acr_id = all_models.AccessControlRole.query.filter_by(
        object_type="System",
        name="Admin"
    ).first().id
    self.objects["program"] = all_models.Program.query.get(program_id)

    # Create an object:
    for obj in ("mapped_object", "unrelated"):
      random_title = factories.random_str()
      response = self.api.post(all_models.System, {
          "system": {
              "title": random_title,
              "context": None,
              "access_control_list": [{
                  "person": {
                      "id": creator.id,
                      "type": "Person",
                  },
                  "ac_role_id": acr_id,
                  "context": None
              }],
          },
      })
      self.assertEqual(response.status_code, 201)
      system_id = response.json.get("system").get("id")
      self.objects[obj] = all_models.System.query.get(system_id)

    # Map Object to Program
    response = self.api.post(all_models.Relationship, {
        "relationship": {"source": {
            "id": program_id,
            "type": "Program"
        }, "destination": {
            "id": self.objects["mapped_object"].id,
            "type": "System"
        }, "context": None},
    })
    self.assertEqual(response.status_code, 201)

    # Map people to Program:
    if test_case_name != "notmapped":
      person = self.people.get(test_case_name)
      response = self.api.post(all_models.ObjectPerson, {"object_person": {
          "person": {
              "id": person.id,
              "type": "Person",
              "href": "/api/people/{}".format(person.id),
          }, "personable": {
              "type": "Program",
              "href": "/api/programs/{}".format(program_id),
              "id": program_id,
          }, "context": {
              "type": "Context",
              "id": context_id,
              "href": "/api/contexts/{}".format(context_id)
          }}})

    # Add roles to mapped users:
    if "program_role" in test_case:
      person = self.people.get(test_case_name)
      role = self.roles[test_case["program_role"]]
      response = self.api.post(all_models.UserRole, {"user_role": {
          "person": {
              "id": person.id,
              "type": "Person",
              "href": "/api/people/{}".format(person.id),
          }, "role": {
              "type": "Role",
              "href": "/api/roles/{}".format(role["id"]),
              "id": role["id"],
          }, "context": {
              "type": "Context",
              "id": context_id,
              "href": "/api/contexts/{}".format(context_id)
          }}})
      self.assertEqual(response.status_code, 201)

  def test_creator_program_roles(self):
    """ Test creator role with all program scoped roles """
    # Check permissions based on test_cases:
    errors = []
    for test_case in self.test_cases:
      self.init_objects(test_case)
      person = self.people.get(test_case)
      objects = self.test_cases.get(test_case).get('objects')
      self.api.set_user(person)
      for obj in ("unrelated", "mapped_object", "program"):
        actions = objects[obj]
        for action in ("map", "get", "put", "delete"):
          # reset sesion:
          db.session.commit()
          if action not in actions:
            continue
          func = getattr(self, action)
          res = func(self.objects[obj])
          if res != actions[action]:
            errors.append(
                "{}: Tried {} on {}, but received {} instead of {}".format(
                    test_case, action, obj, res, actions[action]))
      # Try mapping
    self.assertEqual(errors, [])
Exemplo n.º 29
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)
Exemplo n.º 30
0
class TestPermissionsCacheFlushing(TestMemcacheBase):
  """Test user permissions loading."""

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

  @staticmethod
  def load_perms(user_id, new_perms):
    """Emulate procedure to load permissions
    """

    with mock.patch(
        'ggrc_basic_permissions._load_permissions_from_database',
        return_value=new_perms
    ):

      mock_user = mock.Mock()
      mock_user.id = user_id

      return ggrc_basic_permissions.load_permissions_for(mock_user)

  def test_memcache_flushing(self):
    """Test if memcache is properly cleaned on object creation

      Procedure to test functionality:
      1) load and permissions for specific user and store them in memcahe
      2) emulate new object creation, which cleans permissions in memcache
      3) make request which tries to get cache for permissions from memcache

      Also, it's assumed that 2 or more GGRC workers are running
    """

    client = cache_utils.get_cache_manager().cache_object.memcache_client
    client.flush_all()

    # load perms and store them in memcache
    self.load_perms(11, {"11": "a"})

    # emulate situation when a new object is created
    # this procedure cleans memcache in the end
    cache_utils.clear_permission_cache()

    # emulate work of worker #1 - get permissions for our user
    # the first step - check permissions in memcache
    ggrc_basic_permissions.query_memcache(client, "permissions:11")
    # step 2 - load permissions from DB and save then into memcahe
    # this step is omitted

    # load permission on behalf of worker #2, before step 2 of worker #1
    result = self.load_perms(11, {"11": "b"})

    # ensure that new permissions were returned instead of old ones
    self.assertEquals(result, {"11": "b"})

  def test_permissions_flush_not_flush_on_simple_post(self):
    """Test that permissions in memcache are cleaned after POST request."""
    user = self.create_user_with_role("Creator")
    self.api.set_user(user)
    self.api.client.get("/permissions")

    perm_ids = self.memcache_client.get("permissions:list")
    self.assertEqual(perm_ids, {"permissions:{}".format(user.id)})

    response = self.api.post(
        all_models.Objective,
        {"objective": {"title": "Test Objective", "context": None}}
    )
    self.assert_status(response, 201)

    perm_ids = self.memcache_client.get("permissions:list")
    self.assertIn("permissions:{}".format(user.id), perm_ids)

  def test_permissions_not_flush_on_simple_put(self):
    """Test that permissions in memcache are cleaned after PUT request."""
    with factories.single_commit():
      user = self.create_user_with_role("Creator")
      objective = factories.ObjectiveFactory()
      objective_id = objective.id
      objective.add_person_with_role_name(user, "Admin")

    self.api.set_user(user)
    self.api.client.get("/permissions")

    perm_ids = self.memcache_client.get("permissions:list")
    self.assertEqual(perm_ids, {"permissions:{}".format(user.id)})

    objective = all_models.Objective.query.get(objective_id)
    response = self.api.put(objective, {"title": "new title"})
    self.assert200(response)

    perm_ids = self.memcache_client.get("permissions:list")
    self.assertIn("permissions:{}".format(user.id), perm_ids)

  def test_permissions_flush_on_delete(self):
    """Test that permissions in memcache are cleaned after DELETE request."""
    with factories.single_commit():
      user = self.create_user_with_role("Creator")
      objective = factories.ObjectiveFactory()
      objective.add_person_with_role_name(user, "Admin")
      objective_id = objective.id

    self.api.set_user(user)
    self.api.client.get("/permissions")

    perm_ids = self.memcache_client.get("permissions:list")
    self.assertEqual(perm_ids, {"permissions:{}".format(user.id)})

    objective = all_models.Objective.query.get(objective_id)
    response = self.api.delete(objective)
    self.assert200(response)

    perm_ids = self.memcache_client.get("permissions:list")
    self.assertEqual(perm_ids, set())
Exemplo n.º 31
0
class TestIssueMapping(TestCase):
  """Test Issue mapping"""

  def setup_roles(self):
    """Setup necessary roles needed by the tests"""
    query = all_models.Role.query
    acr_query = all_models.AccessControlRole.query
    self.roles = {
        'creator': query.filter_by(name="Creator").first(),
        'auditors': acr_query.filter_by(name="Auditors").first(),
        'program_editors': acr_query.filter_by(
            name="Program Editors").first()
    }

  def setup_users(self):
    """Creates two creator users"""
    self.users = {}
    for user_name in ('auditor', 'programeditor'):
      user = factories.PersonFactory()
      rbac_factories.UserRoleFactory(
          role=self.roles['creator'],
          person=user)
      self.users[user_name] = user

  def setup_audits(self):
    """Create an audit and an archived audit"""
    self.audits = {
        False: self.create_audit(archived=False),
        True: self.create_audit(archived=True)
    }

  def setup_snapshots_and_issue(self):
    """Create snapshot & issue objects"""
    self.snapshots = {}
    self.issues = {}
    self.control = factories.ControlFactory()
    for is_archived in (False, True):
      audit = self.audits[is_archived]
      self.snapshots[is_archived] = self._create_snapshots(
          audit,
          [self.control],
      )[0]
      factories.RelationshipFactory(
          source=audit,
          destination=self.snapshots[is_archived],
      )

      # Create an issue
      issue = factories.IssueFactory()
      self.issues[is_archived] = issue
      # Map issue to audit
      factories.RelationshipFactory(
          source=audit,
          destination=issue,
          context=audit.context
      )

  def create_audit(self, archived=False):
    """Create an audit object and fix the it's context"""
    audit = factories.AuditFactory(archived=archived)
    factories.RelationshipFactory(
        source=audit,
        destination=audit.program,
    )
    # Add auditor & program editor roles
    factories.AccessControlListFactory(
        ac_role=self.roles['auditors'],
        object=audit,
        person=self.users['auditor']
    )
    factories.AccessControlListFactory(
        ac_role=self.roles['program_editors'],
        object=audit.program,
        person=self.users['programeditor']
    )

    return audit

  def setUp(self):
    """Prepare data needed to run the tests"""
    super(TestIssueMapping, self).setUp()
    self.api = Api()
    self.setup_roles()
    self.setup_users()
    self.setup_audits()
    self.setup_snapshots_and_issue()

  @data(
      # user_name, is_archived
      ('auditor', True),
      ('programeditor', True),
      ('auditor', False),
      ('programeditor', False),
  )
  @unpack
  def test_mapping_to_issue(self, user_name, is_archived):
    """Test mapping snapshots to issue for {0} ({1})"""
    user = self.users[user_name]
    payload = _get_map_dict(
        self.snapshots[is_archived],
        self.issues[is_archived])
    self.api.set_user(user)

    # Try to map to audit
    response = self.api.post(all_models.Relationship, payload)
    self.assertStatus(response, 201)

    rel_id = response.json['relationship']['id']
    relationship = all_models.Relationship.query.filter_by(id=rel_id).first()
    response = self.api.delete(relationship)
    self.assertStatus(response, 200)
Exemplo n.º 32
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
Exemplo n.º 33
0
class TestWorkflowCycleStatePropagation(TestCase):
  """Test case for cycle task to cycle task group status propagation"""

  def setUp(self):
    super(TestWorkflowCycleStatePropagation, self).setUp()
    self.api = Api()
    self.generator = WorkflowsGenerator()
    self.object_generator = ObjectGenerator()

    self.weekly_wf = {
        "title": "weekly thingy",
        "description": "start this many a time",
        "unit": "week",
        "repeat_every": 1,
        "task_groups": [{
            "title": "weekly task group",
            "task_group_tasks": [{
                "title": "weekly task 1",
                "start_date": dtm.date(2016, 6, 10),
                "end_date": dtm.date(2016, 6, 13),
            }, {
                "title": "weekly task 1",
                "start_date": dtm.date(2016, 6, 10),
                "end_date": dtm.date(2016, 6, 13),
            }]},
        ]
    }

  def test_weekly_state_transitions_assigned_inprogress(self):
    """Test that starting one cycle task changes cycle task group"""

    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(self.weekly_wf)
      self.generator.activate_workflow(wf)

      ctg = db.session.query(CycleTaskGroup).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()[0]
      self.assertEqual(ctg.status, "Assigned")

      cycle_tasks = db.session.query(CycleTaskGroupObjectTask).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()
      first_ct, second_ct = cycle_tasks

      for cycle_task in cycle_tasks:
        self.assertEqual(cycle_task.status, "Assigned")

      # Move one task to In Progress
      _, first_ct = self.generator.modify_object(
          first_ct, {"status": "In Progress"})

      self.assertEqual(first_ct.status, "In Progress")
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)
      self.assertEqual(ctg.status, "In Progress")

      # Undo operation
      _, first_ct = self.generator.modify_object(
          first_ct, {"status": "Assigned"})

      self.assertEqual(first_ct.status, "Assigned")
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)
      self.assertEqual(ctg.status, "Assigned")

      # Move both to in progress
      for cycle_task in cycle_tasks:
        self.generator.modify_object(
            cycle_task, {"status": "In Progress"})

      ctg = db.session.query(CycleTaskGroup).get(ctg.id)
      self.assertEqual(ctg.status, "In Progress")

      # Undo one cycle task
      _, first_ct = self.generator.modify_object(
          first_ct, {"status": "Assigned"})
      second_ct = db.session.query(CycleTaskGroupObjectTask).get(second_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(first_ct.status, "Assigned")
      self.assertEqual(second_ct.status, "In Progress")
      self.assertEqual(ctg.status, "In Progress")

      # Undo second cycle task
      _, second_ct = self.generator.modify_object(
          second_ct, {"status": "Assigned"})
      first_ct = db.session.query(CycleTaskGroupObjectTask).get(first_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(first_ct.status, "Assigned")
      self.assertEqual(second_ct.status, "Assigned")
      self.assertEqual(ctg.status, "Assigned")

  def test_weekly_state_transitions_inprogress_finished(self):
    """Test In Progress to Finished transitions"""

    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(self.weekly_wf)
      self.generator.activate_workflow(wf)

      ctg = db.session.query(CycleTaskGroup).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()[0]

      cycle_tasks = db.session.query(CycleTaskGroupObjectTask).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()
      first_ct, second_ct = cycle_tasks

      # Move both tasks to In Progress
      for cycle_task in cycle_tasks:
        self.generator.modify_object(
            cycle_task, {"status": "In Progress"})

      # Test that moving one task to finished doesn't finish entire cycle
      _, first_ct = self.generator.modify_object(
          first_ct, {"status": "Finished"})
      second_ct = db.session.query(CycleTaskGroupObjectTask).get(second_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(first_ct.status, "Finished")
      self.assertEqual(second_ct.status, "In Progress")
      self.assertEqual(ctg.status, "In Progress")

      # Test moving second task to Finished - entire cycle should be finished
      _, second_ct = self.generator.modify_object(
          second_ct, {"status": "Finished"})
      first_ct = db.session.query(CycleTaskGroupObjectTask).get(first_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(second_ct.status, "Finished")
      self.assertEqual(first_ct.status, "Finished")
      self.assertEqual(ctg.status, "Finished")

      # Undo one task, cycle should be In Progress
      _, first_ct = self.generator.modify_object(
          first_ct, {"status": "In Progress"})
      second_ct = db.session.query(CycleTaskGroupObjectTask).get(second_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(first_ct.status, "In Progress")
      self.assertEqual(second_ct.status, "Finished")
      self.assertEqual(ctg.status, "In Progress")

  def test_weekly_state_transitions_finished_verified(self):
    """Test Finished to Verified transitions"""

    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(self.weekly_wf)
      self.generator.activate_workflow(wf)

      ctg = db.session.query(CycleTaskGroup).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()[0]

      cycle_tasks = db.session.query(CycleTaskGroupObjectTask).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()
      first_ct, second_ct = cycle_tasks

      # Move both tasks to In Progress
      for cycle_task in cycle_tasks:
        self.generator.modify_object(
            cycle_task, {"status": "In Progress"})
        self.generator.modify_object(
            cycle_task, {"status": "Finished"})

      ctg = db.session.query(CycleTaskGroup).get(ctg.id)
      self.assertEqual(ctg.status, "Finished")

      for cycle_task in cycle_tasks:
        cycle_task = db.session.query(CycleTaskGroupObjectTask).get(
            cycle_task.id)
        self.assertEqual(cycle_task.status, "Finished")

      # Verify first CT
      _, first_ct = self.generator.modify_object(
          first_ct, {"status": "Verified"})

      second_ct = db.session.query(CycleTaskGroupObjectTask).get(second_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(first_ct.status, "Verified")
      self.assertEqual(second_ct.status, "Finished")
      self.assertEqual(ctg.status, "Finished")

      # Verify second CT
      _, second_ct = self.generator.modify_object(
          second_ct, {"status": "Verified"})

      first_ct = db.session.query(CycleTaskGroupObjectTask).get(first_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(first_ct.status, "Verified")
      self.assertEqual(second_ct.status, "Verified")
      self.assertEqual(ctg.status, "Verified")

  def test_weekly_state_transitions_finished_declined(self):
    """Test Finished to Declined transitions"""

    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(self.weekly_wf)
      self.generator.activate_workflow(wf)

      ctg = db.session.query(CycleTaskGroup).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()[0]

      cycle_tasks = db.session.query(CycleTaskGroupObjectTask).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()
      first_ct, second_ct = cycle_tasks

      # Move both tasks to In Progress
      for cycle_task in cycle_tasks:
        self.generator.modify_object(
            cycle_task, {"status": "In Progress"})
        self.generator.modify_object(
            cycle_task, {"status": "Finished"})

      ctg = db.session.query(CycleTaskGroup).get(ctg.id)
      self.assertEqual(ctg.status, "Finished")

      # Decline first CT
      _, first_ct = self.generator.modify_object(
          first_ct, {"status": "Declined"})

      second_ct = db.session.query(CycleTaskGroupObjectTask).get(second_ct.id)
      ctg = db.session.query(CycleTaskGroup).get(ctg.id)

      self.assertEqual(first_ct.status, "Declined")
      self.assertEqual(second_ct.status, "Finished")
      self.assertEqual(ctg.status, "In Progress")

  def test_deleted_task_state_transitions(self):
    """Test In Progress to Finished transition after task is deleted"""

    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(self.weekly_wf)
      self.generator.activate_workflow(wf)

      ctg = db.session.query(CycleTaskGroup).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()[0]
      first_ct, second_ct = db.session.query(CycleTaskGroupObjectTask).join(
          Cycle).join(Workflow).filter(Workflow.id == wf.id).all()

      # Move first task to In Progress
      self.generator.modify_object(first_ct, {"status": "In Progress"})
      self.generator.modify_object(first_ct, {"status": "Finished"})
      # Delete second task
      response = self.generator.api.delete(second_ct)
      self.assert200(response)

      ctg = db.session.query(CycleTaskGroup).get(ctg.id)
      self.assertEqual(ctg.status, "Finished")

  def test_cycle_change_on_ct_status_transition(self):
    """Test cycle is_current change on task Finished to In Progress transition
    """
    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(self.weekly_wf)
      self.generator.activate_workflow(wf)

    ctg = db.session.query(
        CycleTaskGroup
    ).join(
        Cycle
    ).join(
        Workflow
    ).filter(
        Workflow.id == wf.id
    ).one()
    c_id = ctg.cycle.id
    first_ct, second_ct = db.session.query(CycleTaskGroupObjectTask).join(
        Cycle).join(Workflow).filter(Workflow.id == wf.id).all()
    self.api.put(first_ct, {"status": "Verified"})
    self.api.put(second_ct, {"status": "Verified"})
    # cycle now should have is_current == False
    cycle = db.session.query(Cycle).get(c_id)

    self.assertEqual(cycle.is_current, False)

    # Move second task back to In Progress
    self.api.put(second_ct, {"status": "In Progress"})
    # cycle now should have is_current == True

    cycle = db.session.query(Cycle).get(ctg.cycle.id)
    self.assertEqual(cycle.is_current, True)

  @staticmethod
  def _get_obj(model, title):
    return db.session.query(model).filter(model.title == title).first()

  def test_cycle_task_group_dates(self):
    """Test status and dates when task status is changed """
    wf_data = {
        "title": "test workflow",
        "unit": "week",
        "repeat_every": 1,
        "task_groups": [{
            "title": "test group",
            "task_group_tasks": [{
                "title": "task1",
                "start_date": dtm.date(2016, 6, 10),
                "end_date": dtm.date(2016, 6, 14),
            }, {
                "title": "task2",
                "start_date": dtm.date(2016, 6, 13),
                "end_date": dtm.date(2016, 6, 15),
            }]
        }]
    }

    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(wf_data)
      self.generator.activate_workflow(wf)

      # check task group status and dates
      tg = self._get_obj(CycleTaskGroup, "test group")
      self.assertEqual(tg.end_date, dtm.date(2016, 6, 15))
      self.assertEqual(tg.next_due_date, dtm.date(2016, 6, 14))
      self.assertEqual(tg.status, "Assigned")

      # move task1 to Verified
      task1 = self._get_obj(CycleTaskGroupObjectTask, "task1")
      self.api.put(task1, {"status": "In Progress"})
      self.api.put(task1, {"status": "Finished"})
      self.api.put(task1, {"status": "Verified"})

      # # check task group status and dates
      tg = self._get_obj(CycleTaskGroup, "test group")
      self.assertEqual(tg.end_date, dtm.date(2016, 6, 15))
      self.assertEqual(tg.next_due_date, dtm.date(2016, 6, 15))
      self.assertEqual(tg.status, "In Progress")

      # move task2 to Verified
      task2 = self._get_obj(CycleTaskGroupObjectTask, "task2")
      self.api.put(task2, {"status": "In Progress"})
      self.api.put(task2, {"status": "Finished"})
      self.api.put(task2, {"status": "Verified"})

      # # check task group status and dates
      tg = self._get_obj(CycleTaskGroup, "test group")
      self.assertIsNone(tg.next_due_date)
      self.assertEqual(tg.status, "Verified")

  def test_empty_group_status(self):
    """Test status and dates when task group is empty """
    wf_data = {
        "title": "test workflow",
        "unit": "week",
        "repeat_every": 1,
        "task_groups": [{
            "title": "test group1",
            "task_group_tasks": [{
                "title": "task1",
                "start_date": dtm.date(2016, 6, 10),
                "end_date": dtm.date(2016, 6, 13),
            }]
        }, {
            # second task group prevents from moving workflow to history
            "title": "test group2",
            "task_group_tasks": [{
                "title": "task2",
                "start_date": dtm.date(2016, 6, 14),
                "end_date": dtm.date(2016, 6, 16),
            }]
        }]
    }

    with freeze_time("2016-6-10 13:00:00"):  # Friday, 6/10/2016
      _, wf = self.generator.generate_workflow(wf_data)
      self.generator.activate_workflow(wf)

      # check task group status and dates
      tg = self._get_obj(CycleTaskGroup, "test group1")
      self.assertEqual(tg.end_date, dtm.date(2016, 6, 13))
      self.assertEqual(tg.next_due_date, dtm.date(2016, 6, 13))
      self.assertEqual(tg.status, "Assigned")

      # move task2 to Verified
      task2 = self._get_obj(CycleTaskGroupObjectTask, "task2")
      self.api.put(task2, {"status": "In Progress"})
      self.api.put(task2, {"status": "Finished"})
      self.api.put(task2, {"status": "Verified"})

      # check task group status
      cycle = self._get_obj(Cycle, "test workflow")
      self.assertEqual(cycle.status, "In Progress")

      # delete task1
      task = self._get_obj(CycleTaskGroupObjectTask, "task1")
      self.api.delete(task)

      # # check task group status and dates
      tg = self._get_obj(CycleTaskGroup, "test group1")
      self.assertIsNone(tg.end_date)
      self.assertIsNone(tg.next_due_date)
      self.assertEqual(tg.status, "Deprecated")

      # # check cycle status
      cycle = self._get_obj(Cycle, "test workflow")
      self.assertEqual(cycle.status, "Verified")
Exemplo n.º 34
0
class TestIssueMapping(TestCase):
    """Test Issue mapping"""
    def setup_roles(self):
        """Setup necessary roles needed by the tests"""
        query = all_models.Role.query
        self.roles = {
            'creator': query.filter_by(name="Creator").first(),
            'auditor': query.filter_by(name="Auditor").first(),
            'program_editor': query.filter_by(name="ProgramEditor").first()
        }

    def setup_users(self):
        """Creates two creator users"""
        self.users = {}
        for user_name in ('auditor', 'programeditor'):
            user = factories.PersonFactory()
            rbac_factories.UserRoleFactory(role=self.roles['creator'],
                                           person=user)
            self.users[user_name] = user

    def setup_audits(self):
        """Create an audit and an archived audit"""
        self.audits = {
            False: self.create_audit(archived=False),
            True: self.create_audit(archived=True)
        }

    def setup_snapshots_and_issue(self):
        """Create snapshot & issue objects"""
        self.snapshots = {}
        self.issues = {}
        self.control = factories.ControlFactory()
        revision = all_models.Revision.query.filter(
            all_models.Revision.resource_type == self.control.type).first()
        for is_archived in (False, True):
            audit = self.audits[is_archived]
            # Create a snapshot
            self.snapshots[is_archived] = factories.SnapshotFactory(
                child_id=revision.resource_id,
                child_type=revision.resource_type,
                revision=revision,
                parent=audit,
                context=audit.context,
            )
            # Create an issue
            issue = factories.IssueFactory()
            self.issues[is_archived] = issue
            # Map issue to audit
            factories.RelationshipFactory(source=audit,
                                          destination=issue,
                                          context=audit.context)

    def create_audit(self, archived=False):
        """Create an audit object and fix the it's context"""
        audit = factories.AuditFactory(archived=archived)

        # Add auditor & program editor roles
        rbac_factories.UserRoleFactory(context=audit.context,
                                       role=self.roles['auditor'],
                                       person=self.users['auditor'])
        rbac_factories.UserRoleFactory(context=audit.program.context,
                                       role=self.roles['program_editor'],
                                       person=self.users['programeditor'])

        return audit

    def setUp(self):
        """Prepare data needed to run the tests"""
        self.api = Api()
        self.setup_roles()
        self.setup_users()
        self.setup_audits()
        self.setup_snapshots_and_issue()

    @data(
        # user_name, is_archived
        ('auditor', True),
        ('programeditor', True),
        ('auditor', False),
        ('programeditor', False),
    )
    @unpack
    def test_mapping_to_issue(self, user_name, is_archived):
        """Test mapping snapshots to issue"""
        user = self.users[user_name]
        payload = _get_map_dict(self.snapshots[is_archived],
                                self.issues[is_archived])
        self.api.set_user(user)

        # Try to map to audit
        response = self.api.post(all_models.Relationship, payload)
        self.assertStatus(response, 201)

        rel_id = response.json['relationship']['id']
        relationship = all_models.Relationship.query.filter_by(
            id=rel_id).first()
        response = self.api.delete(relationship)
        self.assertStatus(response, 200)
Exemplo n.º 35
0
class TestIssueIntegration(ggrc.TestCase):
    """Test set for IssueTracker integration functionality."""

    # pylint: disable=invalid-name

    def setUp(self):
        # pylint: disable=super-on-old-class
        super(TestIssueIntegration, self).setUp()
        self.api = Api()
        self.client.get("/login")

    @mock.patch("ggrc.integrations.issues.Client.create_issue",
                return_value={"issueId": "issueId"})
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_create_issue_tracker_info(self, mock_create_issue):
        """Test creation issue tracker issue for Issue object."""
        component_id = "1234"
        hotlist_id = "4321"
        issue_type = "Default Issue type"
        issue_priority = "P2"
        issue_severity = "S1"
        title = "test title"

        with mock.patch.object(integration_utils,
                               "exclude_auditor_emails",
                               return_value={
                                   u"*****@*****.**",
                               }):
            response = self.api.post(
                all_models.Issue, {
                    "issue": {
                        "title": title,
                        "context": None,
                        "issue_tracker": {
                            "enabled": True,
                            "component_id": int(component_id),
                            "hotlist_id": int(hotlist_id),
                            "issue_type": issue_type,
                            "issue_priority": issue_priority,
                            "issue_severity": issue_severity,
                        }
                    },
                })
            mock_create_issue.assert_called_once()
            self.assertEqual(response.status_code, 201)
            issue_id = response.json.get("issue").get("id")
            issue_tracker_issue = models.IssuetrackerIssue.get_issue(
                "Issue", issue_id)
            self.assertTrue(issue_tracker_issue.enabled)
            self.assertEqual(issue_tracker_issue.title, title)
            self.assertEqual(issue_tracker_issue.component_id, component_id)
            self.assertEqual(issue_tracker_issue.hotlist_id, hotlist_id)
            self.assertEqual(issue_tracker_issue.issue_type, issue_type)
            self.assertEqual(issue_tracker_issue.issue_priority,
                             issue_priority)
            self.assertEqual(issue_tracker_issue.issue_severity,
                             issue_severity)

    def test_exclude_auditor(self):
        """Test 'exclude_auditor_emails' util."""
        audit = factories.AuditFactory()
        factories.AccessControlListFactory(
            ac_role=factories.AccessControlRoleFactory(name="Auditors"),
            person=factories.PersonFactory(email="*****@*****.**"),
            object_id=audit.id,
            object_type="Audit")

        result = integration_utils.exclude_auditor_emails(
            ["*****@*****.**", "*****@*****.**"])
        self.assertEqual(result, {
            "*****@*****.**",
        })

    @ddt.data(
        ({
            "description": "new description"
        }, {
            "comment": "Issue Description has been updated.\nnew description"
        }),
        ({
            "test_plan": "new test plan"
        }, {
            "comment":
            "Issue Remediation Plan has been updated.\nnew test plan"
        }),
        ({
            "issue_tracker": {
                "component_id": "123",
                "enabled": True
            }
        }, {
            "component_id": 123
        }),
        ({
            "issue_tracker": {
                "hotlist_id": "321",
                "enabled": True
            }
        }, {
            "hotlist_ids": [
                321,
            ]
        }),
        ({
            "issue_tracker": {
                "issue_priority": "P2",
                "enabled": True
            }
        }, {
            "priority": "P2"
        }),
        ({
            "issue_tracker": {
                "issue_severity": "S2",
                "enabled": True
            }
        }, {
            "severity": "S2"
        }),
        ({
            "issue_tracker": {
                "enabled": False
            }
        }, {
            "comment":
            "Changes to this GGRC object will no longer be "
            "tracked within this bug."
        }),
    )
    @ddt.unpack
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue(self, issue_attrs, expected_query,
                          mock_update_issue):
        """Test updating issue tracker issue."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.put(iti.issue_tracked_obj, issue_attrs)
        mock_update_issue.assert_called_with(iti.issue_id, expected_query)

    @ddt.data(
        {"notes": "new notes"},
        {"end_date": "2018-07-15"},
        {"start_date": "2018-07-15"},
    )
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue_with_untracked_fields(self, issue_attrs,
                                                mock_update_issue):
        """Test updating issue with fields which shouldn't be sync."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.put(iti.issue_tracked_obj, issue_attrs)
        mock_update_issue.assert_not_called()

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_issue_tracker_error(self, update_issue_mock):
        """Test that issue tracker does not change state
       in case receiving an error."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        update_issue_mock.side_effect = integrations_errors.HttpError("data")
        issue_attrs = {
            "issue_tracker": {
                "enabled": True,
                "hotlist_id": "123",
                "issue_id": iti.issue_id,
            }
        }
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True),\
            mock.patch.object(all_models.IssuetrackerIssue,
                              "create_or_update_from_dict") as update_info_mock:
            self.api.put(iti.issue_tracked_obj, issue_attrs)

        # Check that "enabled" flag hasn't been changed.
        self.assertTrue("enabled" not in update_info_mock.call_args[0][1])

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_delete_issue(self, mock_update_issue):
        """Test updating issue tracker issue when issue in GGRC has been deleted"""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        expected_query = {
            "comment":
            "GGRC object has been deleted. GGRC changes "
            "will no longer be tracked within this bug."
        }
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.delete(iti.issue_tracked_obj)
        mock_update_issue.assert_called_with(iti.issue_id, expected_query)

    @mock.patch.object(params_builder.BaseIssueTrackerParamsBuilder,
                       "get_ggrc_object_url",
                       return_value="http://issue_url.com")
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_adding_comment_to_issue(self, update_issue_mock,
                                     url_builder_mock):
        """Test adding comment to issue."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        comment = factories.CommentFactory(description="test comment")

        expected_result = {
            "comment":
            u"A new comment is added by 'Example User' to the 'Issue': "
            u"'test comment'.\nUse the following to link to get more "
            u"information from the GGRC 'Issue'. Link - "
            u"http://issue_url.com"
        }

        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.post(
                all_models.Relationship, {
                    "relationship": {
                        "source": {
                            "id": iti.issue_tracked_obj.id,
                            "type": "Issue"
                        },
                        "destination": {
                            "id": comment.id,
                            "type": "comment"
                        },
                        "context": None
                    },
                })
        url_builder_mock.assert_called_once()
        update_issue_mock.assert_called_with(iti.issue_id, expected_result)
Exemplo n.º 36
0
class TestIssueIntegration(ggrc.TestCase):
  """Test set for IssueTracker integration functionality."""

  # pylint: disable=invalid-name

  def setUp(self):
    # pylint: disable=super-on-old-class
    super(TestIssueIntegration, self).setUp()
    self.api = Api()
    self.client.get("/login")

  @mock.patch("ggrc.integrations.issues.Client.create_issue",
              return_value={"issueId": "issueId"})
  @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
  def test_create_issue_tracker_info(self, mock_create_issue):
    """Test creation issue tracker issue for Issue object."""
    component_id = "1234"
    hotlist_id = "4321"
    issue_type = "Default Issue type"
    issue_priority = "P2"
    issue_severity = "S1"
    title = "test title"

    with mock.patch.object(integration_utils, "exclude_auditor_emails",
                           return_value={u"*****@*****.**", }):
      response = self.api.post(all_models.Issue, {
          "issue": {
              "title": title,
              "context": None,
              "issue_tracker": {
                  "enabled": True,
                  "component_id": int(component_id),
                  "hotlist_id": int(hotlist_id),
                  "issue_type": issue_type,
                  "issue_priority": issue_priority,
                  "issue_severity": issue_severity,
              }
          },
      })
      mock_create_issue.assert_called_once()
      self.assertEqual(response.status_code, 201)
      issue_id = response.json.get("issue").get("id")
      issue_tracker_issue = models.IssuetrackerIssue.get_issue("Issue",
                                                               issue_id)
      self.assertTrue(issue_tracker_issue.enabled)
      self.assertEqual(issue_tracker_issue.title, title)
      self.assertEqual(issue_tracker_issue.component_id, component_id)
      self.assertEqual(issue_tracker_issue.hotlist_id, hotlist_id)
      self.assertEqual(issue_tracker_issue.issue_type, issue_type)
      self.assertEqual(issue_tracker_issue.issue_priority, issue_priority)
      self.assertEqual(issue_tracker_issue.issue_severity, issue_severity)

  def test_exclude_auditor(self):
    """Test 'exclude_auditor_emails' util."""
    audit = factories.AuditFactory()
    factories.AccessControlListFactory(
        ac_role=factories.AccessControlRoleFactory(name="Auditors"),
        person=factories.PersonFactory(email="*****@*****.**"),
        object_id=audit.id,
        object_type="Audit"
    )

    result = integration_utils.exclude_auditor_emails(["*****@*****.**",
                                                       "*****@*****.**"])
    self.assertEqual(result, {"*****@*****.**", })

  @ddt.data(
      ({"description": "new description"},
       {"comment": "Issue Description has been updated.\nnew description"}),
      ({"test_plan": "new test plan"},
       {"comment": "Issue Remediation Plan has been updated.\nnew test plan"}),
      ({"issue_tracker": {"component_id": "123", "enabled": True}},
       {"component_id": 123}),
      ({"issue_tracker": {"hotlist_id": "321", "enabled": True}},
       {"hotlist_ids": [321, ]}),
      ({"issue_tracker": {"issue_priority": "P2", "enabled": True}},
       {"priority": "P2"}),
      ({"issue_tracker": {"issue_severity": "S2", "enabled": True}},
       {"severity": "S2"}),
      ({"issue_tracker": {"enabled": False, "hotlist_ids": [999, ]}},
       {"comment": "Changes to this GGRC object will no longer be "
                   "tracked within this bug."}),
  )
  @ddt.unpack
  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_update_issue(self, issue_attrs, expected_query, mock_update_issue):
    """Test updating issue tracker issue."""
    iti = factories.IssueTrackerIssueFactory(
        enabled=True,
        issue_tracked_obj=factories.IssueFactory()
    )
    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      self.api.put(iti.issue_tracked_obj, issue_attrs)
    mock_update_issue.assert_called_with(iti.issue_id, expected_query)

  @ddt.data(
      {"notes": "new notes"},
      {"end_date": "2018-07-15"},
      {"start_date": "2018-07-15"},
  )
  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_update_issue_with_untracked_fields(self, issue_attrs,
                                              mock_update_issue):
    """Test updating issue with fields which shouldn't be sync."""
    iti = factories.IssueTrackerIssueFactory(
        enabled=True,
        issue_tracked_obj=factories.IssueFactory()
    )
    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      self.api.put(iti.issue_tracked_obj, issue_attrs)
    mock_update_issue.assert_not_called()

  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_issue_tracker_error(self, update_issue_mock):
    """Test that issue tracker does not change state
       in case receiving an error."""
    iti = factories.IssueTrackerIssueFactory(
        enabled=True,
        issue_tracked_obj=factories.IssueFactory()
    )
    update_issue_mock.side_effect = integrations_errors.HttpError("data")
    issue_attrs = {
        "issue_tracker": {
            "enabled": True,
            "hotlist_id": "123",
            "issue_id": iti.issue_id,

        }
    }
    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True),\
        mock.patch.object(all_models.IssuetrackerIssue,
                          "create_or_update_from_dict") as update_info_mock:
      self.api.put(iti.issue_tracked_obj, issue_attrs)

    # Check that "enabled" flag hasn't been changed.
    self.assertTrue("enabled" not in update_info_mock.call_args[0][1])

  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_delete_issue(self, mock_update_issue):
    """Test updating issue tracker issue when issue in GGRC has been deleted"""
    iti = factories.IssueTrackerIssueFactory(
        enabled=True,
        issue_tracked_obj=factories.IssueFactory()
    )
    expected_query = {"comment": "GGRC object has been deleted. GGRC changes "
                                 "will no longer be tracked within this bug."}
    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      self.api.delete(iti.issue_tracked_obj)
    mock_update_issue.assert_called_with(iti.issue_id, expected_query)

  @mock.patch.object(params_builder.BaseIssueTrackerParamsBuilder,
                     "get_ggrc_object_url",
                     return_value="http://issue_url.com")
  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  def test_adding_comment_to_issue(self, update_issue_mock, url_builder_mock):
    """Test adding comment to issue."""
    iti = factories.IssueTrackerIssueFactory(
        enabled=True,
        issue_tracked_obj=factories.IssueFactory()
    )
    comment = factories.CommentFactory(description="test comment")

    expected_result = {
        "comment": u"A new comment is added by 'Example User' to the 'Issue': "
                   u"'test comment'.\nUse the following to link to get more "
                   u"information from the GGRC 'Issue'. Link - "
                   u"http://issue_url.com"
    }

    with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
      self.api.post(all_models.Relationship, {
          "relationship": {
              "source": {"id": iti.issue_tracked_obj.id, "type": "Issue"},
              "destination": {"id": comment.id, "type": "comment"},
              "context": None
          },
      })
    url_builder_mock.assert_called_once()
    update_issue_mock.assert_called_with(iti.issue_id, expected_result)

  @mock.patch("ggrc.integrations.issues.Client.update_issue")
  @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
  def test_mapping_document(self, update_issue_mock):
    """Test map document action on issue.

    Issue in Issue tracker shouldn't be updated when reference url has been
    added to issue.
    """
    iti = factories.IssueTrackerIssueFactory(
        enabled=True,
        issue_tracked_obj=factories.IssueFactory()
    )
    document = factories.DocumentFactory()
    response = self.api.put(
        iti.issue_tracked_obj,
        {
            "actions": {
                "add_related": [{"id": document.id, "type": "Document", }, ]
            }
        }
    )
    self.assert200(response)

    relationship = all_models.Relationship.query.filter(
        all_models.Relationship.source_type == "Issue",
        all_models.Relationship.source_id == response.json["issue"]["id"],
    ).order_by(all_models.Relationship.id.desc()).first()

    self.assertEqual(relationship.destination_id, document.id)
    self.assertEqual(relationship.source_id, iti.issue_tracked_obj.id)

    # Check that issue in Issue Tracker hasn't been updated.
    update_issue_mock.assert_not_called()
Exemplo n.º 37
0
class TestReviewStatusUpdate(TestCase):
  """Base TestCase class automatic review status update."""

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

    self.generator = generator.ObjectGenerator()

  def test_gca(self):
    """if GCA of reviewable is changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="rich_test_gca",
          attribute_type="Rich Text"
      )
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id
    reviewable = review.reviewable

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_value": "new_value",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_update_gca(self):
    """if existing GCA value changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="rich_test_gca",
          attribute_type="Rich Text"
      )
      risk = factories.RiskFactory()

      risk.custom_attribute_values = [{
          "attribute_value": "starting_value",
          "custom_attribute_id": gca.id
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id
    reviewable = review.reviewable

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_value": "new_value",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  @ddt.data("custom attr", "slug", "self")
  def test_gca_with_varying_titles(self, title):
    """if GCA with any title is changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title=title,
          attribute_type="Rich Text"
      )
      risk = factories.RiskFactory()

      risk.custom_attribute_values = [{
          "attribute_value": "starting_value",
          "custom_attribute_id": gca.id
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id
    reviewable = review.reviewable

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_value": "new_value",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_map_person_gca(self):
    """if Map:Person GCA value added review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="map_test_gca",
          attribute_type="Map:Person"
      )

      user_id = all_models.Person.query.filter_by(
          email="*****@*****.**"
      ).one().id

      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )

    review_id = review.id
    reviewable = review.reviewable
    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_object_id": user_id,
                "attribute_value": "Person",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_update_map_person_gca(self):
    """if existing Map:Person GCA value changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="map_test_gca",
          attribute_type="Map:Person"
      )

      first_user_id = all_models.Person.query.filter_by(
          email="*****@*****.**"
      ).one().id
      second_user_id = factories.PersonFactory().id

      risk = factories.RiskFactory()
      risk.custom_attribute_values = [{
          "attribute_object_id": first_user_id,
          "custom_attribute_id": gca.id,
          "attribute_value": "Person"
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )

    review_id = review.id
    reviewable = review.reviewable
    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_object_id": second_user_id,
                "attribute_value": "Person",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_delete_map_person_gca(self):
    """if existing Map:Person GCA value deleted review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="map_test_gca",
          attribute_type="Map:Person"
      )

      user_id = all_models.Person.query.filter_by(
          email="*****@*****.**"
      ).one().id

      risk = factories.RiskFactory()
      risk.custom_attribute_values = [{
          "attribute_object_id": user_id,
          "custom_attribute_id": gca.id,
          "attribute_value": "Person"
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )

    review_id = review.id
    reviewable = review.reviewable
    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_object_id": None,
                "attribute_object": None,
                "attribute_value": "Person",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_reference_url(self):
    """If reference url is updated state should not updated"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      doc = factories.DocumentReferenceUrlFactory(
          title="Simple title",
          link="some_url.com",
          description="mega description",
          parent_obj={
              "id": risk.id,
              "type": "Risk"
          }
      )
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id

    self.api.modify_object(doc, {"link": "new_link.com"})
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_acl_roles(self):
    """Update of reviewable ACL shouldn't change review status"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id

    ac_role_id = all_models.AccessControlRole.query.filter_by(
        name="Admin", object_type="Risk"
    ).one().id

    user_id = all_models.Person.query.filter_by(
        email="*****@*****.**"
    ).one().id

    self.api.modify_object(
        risk, {
            "access_control_list":
            [{
                "ac_role_id": ac_role_id,
                "person": {
                    "id": user_id
                },
            }],
        }
    )
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_comments(self):
    """Add comment to reviewable shouldn't update review state"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id

    self.generator.generate_comment(
        risk, "Verifiers", "some comment", send_notification="false"
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_mapping_non_snapshotable(self):
    """Map non-snapshotable shouldn't change review status"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
      review_id = review.id

    factories.RelationshipFactory(
        source=risk, destination=factories.IssueFactory()
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  @ddt.data(
      "Standard",
      "Regulation",
      "Requirement",
      "Objective",
      "Control",
      "Product",
      "System",
      "Process",
      "AccessGroup",
      "Contract",
      "DataAsset",
      "Facility",
      "Market",
      "OrgGroup",
      "Policy",
      "Risk",
      "Threat",
      "Vendor"
  )
  def test_map_snapshotable(self, snapshotable):
    """Map '{}' should change review status"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
      review_id = review.id

    self.generator.generate_relationship(
        source=risk,
        destination=factories.get_model_factory(snapshotable)(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_unmap_snapshotable(self):
    """Unmap snapshotable should change review status"""
    self.api.login_as_normal()

    risk = factories.RiskFactory()
    resp, review = generate_review_object(risk)
    review_id = review.id

    _, rel = self.generator.generate_relationship(
        source=risk,
        destination=factories.ProductFactory(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    resp = self.api.modify_object(
        review, {"status": all_models.Review.STATES.REVIEWED}
    )
    self.assert200(resp)

    resp = self.api.delete(rel)
    self.assert200(resp)
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  @ddt.data(
      "Assessment",
      "Issue",
      "Program",
      "Project",
      "Audit",
      "RiskAssessment",
      "AssessmentTemplate",
      "Person",
  )
  def test_map_nonsnapshotable(self, nonsnapshotable):
    """Map '{}' shouldn't change review status"""
    risk = factories.RiskFactory()
    _, review = generate_review_object(
        risk, state=all_models.Review.STATES.REVIEWED)
    review_id = review.id

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.generator.generate_relationship(
        source=risk,
        destination=factories.get_model_factory(nonsnapshotable)(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_unmap_nonsnapshotable(self):
    """Unmap nonsnapshotable shouldn't change review status"""
    self.api.login_as_normal()

    risk = factories.RiskFactory()
    resp, review = generate_review_object(
        risk, state=all_models.Review.STATES.REVIEWED)
    review_id = review.id
    _, rel = self.generator.generate_relationship(
        source=risk,
        destination=factories.ProgramFactory(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    resp = self.api.modify_object(
        review, {"status": all_models.Review.STATES.REVIEWED}
    )
    self.assert200(resp)
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    resp = self.api.delete(rel)
    self.assert200(resp)
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_proposal_apply(self):
    """Reviewable object changed via proposal -> review.state-> UNREVIEWED"""
    risk = factories.RiskFactory()
    _, review = generate_review_object(risk)

    review_id = review.id

    proposal_content = {
        "fields": {
            "title": "new title"
        },
    }
    proposal = factories.ProposalFactory(
        instance=risk, content=proposal_content, agenda="agenda content"
    )
    self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED})

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_review_status_update(self):
    """Test updating folder preserves review status"""
    risk = factories.RiskFactory()
    factories.ReviewFactory(
        reviewable=risk,
        status=all_models.Review.STATES.REVIEWED,
    )
    self.api.put(risk, {"folder": factories.random_str()})
    risk = all_models.Risk.query.get(risk.id)
    self.assertEqual(risk.review.status, all_models.Review.STATES.REVIEWED)
Exemplo n.º 38
0
class TestIssueIntegration(ggrc.TestCase):
    """Test set for IssueTracker integration functionality."""
    DEFAULT_ISSUE_ATTRS = {
        "title": "title1",
        "context": None,
        "status": "Draft",
        "enabled": True,
        "component_id": 1234,
        "hotlist_id": 4321,
        "issue_id": TICKET_ID,
        "issue_type": "Default Issue Type",
        "issue_priority": "P2",
        "issue_severity": "S1",
    }

    DEFAULT_TICKET_ATTRS = {
        "component_id": 1234,
        "hotlist_id": 4321,
        "issue_id": TICKET_ID,
        "status": "new",
        "issue_type": "Default Issue type",
        "issue_priority": "P1",
        "issue_severity": "S2",
        "title": "test title",
        "verifier": "*****@*****.**",
        "assignee": "*****@*****.**",
        "ccs": ["*****@*****.**"],
    }

    # pylint: disable=invalid-name

    def setUp(self):
        # pylint: disable=super-on-old-class
        super(TestIssueIntegration, self).setUp()
        self.api = Api()
        self.client.get("/login")

    @mock.patch("ggrc.integrations.issues.Client.create_issue",
                return_value={"issueId": "issueId"})
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_create_issue_tracker_info(self, mock_create_issue):
        """Test creation issue tracker issue for Issue object."""
        component_id = "1234"
        hotlist_id = "4321"
        issue_type = "Default Issue type"
        issue_priority = "P2"
        issue_severity = "S1"
        title = "test title"

        with mock.patch.object(integration_utils,
                               "exclude_auditor_emails",
                               return_value={
                                   u"*****@*****.**",
                               }):
            response = self.api.post(
                all_models.Issue, {
                    "issue": {
                        "title": title,
                        "context": None,
                        "issue_tracker": {
                            "enabled": True,
                            "component_id": int(component_id),
                            "hotlist_id": int(hotlist_id),
                            "issue_type": issue_type,
                            "issue_priority": issue_priority,
                            "issue_severity": issue_severity,
                        }
                    },
                })
            mock_create_issue.assert_called_once()
            self.assertEqual(response.status_code, 201)
            issue_id = response.json.get("issue").get("id")
            issue_tracker_issue = models.IssuetrackerIssue.get_issue(
                "Issue", issue_id)
            self.assertTrue(issue_tracker_issue.enabled)
            self.assertEqual(issue_tracker_issue.title, title)
            self.assertEqual(issue_tracker_issue.component_id, component_id)
            self.assertEqual(issue_tracker_issue.hotlist_id, hotlist_id)
            self.assertEqual(issue_tracker_issue.issue_type, issue_type)
            self.assertEqual(issue_tracker_issue.issue_priority,
                             issue_priority)
            self.assertEqual(issue_tracker_issue.issue_severity,
                             issue_severity)

    def test_exclude_auditor(self):
        """Test 'exclude_auditor_emails' util."""
        audit = factories.AuditFactory()
        person = factories.PersonFactory(email="*****@*****.**")
        audit.add_person_with_role_name(person, "Auditors")
        db.session.commit()

        result = integration_utils.exclude_auditor_emails(
            ["*****@*****.**", "*****@*****.**"])
        self.assertEqual(result, {
            "*****@*****.**",
        })

    @ddt.data(
        ({
            "description": "new description"
        }, {
            "comment": "Issue Description has been updated.\nnew description"
        }),
        ({
            "test_plan": "new test plan"
        }, {
            "comment":
            "Issue Remediation Plan has been updated.\nnew test plan"
        }),
        ({
            "issue_tracker": {
                "component_id": "123",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "component_id": 123
        }),
        ({
            "issue_tracker": {
                "hotlist_id": "321",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "hotlist_ids": [
                321,
            ]
        }),
        ({
            "issue_tracker": {
                "issue_priority": "P2",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "priority": "P2"
        }),
        ({
            "issue_tracker": {
                "issue_severity": "S2",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "severity": "S2"
        }),
        ({
            "issue_tracker": {
                "enabled": False,
                "hotlist_ids": [
                    999,
                ],
                "issue_id": TICKET_ID
            }
        }, {
            "comment":
            "Changes to this GGRC object will no longer be "
            "tracked within this bug."
        }),
        ({
            "issue_tracker": {
                "title": "test_iti_title",
                "enabled": True,
                "issue_id": TICKET_ID
            }
        }, {
            "title": "test_iti_title"
        }),
    )
    @ddt.unpack
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue(self, issue_attrs, expected_query,
                          mock_update_issue):
        """Test updating issue tracker issue."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True,
            issue_id=TICKET_ID,
            issue_tracked_obj=factories.IssueFactory())

        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.put(iti.issue_tracked_obj, issue_attrs)
        mock_update_issue.assert_called_with(iti.issue_id, expected_query)

    @ddt.data(
        {"notes": "new notes"},
        {"end_date": "2018-07-15"},
        {"start_date": "2018-07-15"},
    )
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue_with_untracked_fields(self, issue_attrs,
                                                mock_update_issue):
        """Test updating issue with fields which shouldn't be sync."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.put(iti.issue_tracked_obj, issue_attrs)
        mock_update_issue.assert_not_called()

    def request_payload_builder(self, issue_attrs):
        """Build payload for POST request to Issue Tracker"""
        payload_attrs = dict(self.DEFAULT_ISSUE_ATTRS, **issue_attrs)
        payload = {
            "issue": {
                "title": payload_attrs["title"],
                "context": payload_attrs["context"],
                "status": payload_attrs["status"],
                "issue_tracker": {
                    "enabled": payload_attrs["enabled"],
                    "component_id": payload_attrs["component_id"],
                    "hotlist_id": payload_attrs["hotlist_id"],
                    "issue_id": payload_attrs["issue_id"],
                    "issue_type": payload_attrs["issue_type"],
                    "issue_priority": payload_attrs["issue_priority"],
                    "issue_severity": payload_attrs["issue_severity"],
                    "title": payload_attrs["title"],
                }
            }
        }
        return payload

    def put_request_payload_builder(self, issue_attrs):
        """Build payload for PUT request to Issue Tracker"""
        payload_attrs = dict(self.DEFAULT_ISSUE_ATTRS, **issue_attrs)
        payload = {
            "issue_tracker": {
                "enabled": payload_attrs["enabled"],
                "component_id": payload_attrs["component_id"],
                "hotlist_id": payload_attrs["hotlist_id"],
                "issue_id": payload_attrs["issue_id"],
                "issue_type": payload_attrs["issue_type"],
                "issue_priority": payload_attrs["issue_priority"],
                "issue_severity": payload_attrs["issue_severity"],
                "title": payload_attrs["title"],
            }
        }
        return payload

    def response_payload_builder(self, ticket_attrs):
        """Build payload for response from Issue Tracker via get_issue method"""
        payload_attrs = dict(self.DEFAULT_TICKET_ATTRS, **ticket_attrs)
        payload = {
            "issueState": {
                "component_id": payload_attrs["component_id"],
                "hotlist_id": payload_attrs["hotlist_id"],
                "issue_id": payload_attrs["issue_id"],
                "status": payload_attrs["status"],
                "issue_type": payload_attrs["issue_type"],
                "issue_priority": payload_attrs["issue_priority"],
                "issue_severity": payload_attrs["issue_severity"],
                "title": payload_attrs["title"],
                "verifier": payload_attrs["verifier"],
                "assignee": payload_attrs["assignee"],
                "ccs": payload_attrs["ccs"],
            }
        }
        return payload

    def check_issuetracker_issue_fields(self, obj, issue_tracker_issue,
                                        issue_attrs,
                                        issue_tracker_ticket_attrs):
        """Checks issuetracker_issue were updated correctly.

    Make assertions to check if issue tracker fields were updated according
    our business logic.
    For Issue model we should get title, component_id, hotlist_id,
    priority, severity, issue_id and issue_type from GGRC and status from
    Issue Tracker.
    """

        self.assertTrue(issue_tracker_issue.enabled)

        # According to our business logic these attributes should be taken
        # from issue information
        self.assertEqual(issue_tracker_issue.title,
                         issue_attrs["issue"]["title"])
        self.assertEqual(int(issue_tracker_issue.component_id),
                         issue_attrs["issue"]["issue_tracker"]["component_id"])
        self.assertEqual(int(issue_tracker_issue.hotlist_id),
                         issue_attrs["issue"]["issue_tracker"]["hotlist_id"])
        self.assertEqual(
            issue_tracker_issue.issue_priority,
            issue_attrs["issue"]["issue_tracker"]["issue_priority"])
        self.assertEqual(
            issue_tracker_issue.issue_severity,
            issue_attrs["issue"]["issue_tracker"]["issue_severity"])
        self.assertEqual(int(issue_tracker_issue.issue_id),
                         issue_attrs["issue"]["issue_tracker"]["issue_id"])
        self.assertEqual(issue_tracker_issue.issue_type,
                         issue_attrs["issue"]["issue_tracker"]["issue_type"])

        # These attributes should be taken from ticket information
        ticket_status = issue_tracker_ticket_attrs["issueState"]["status"]
        ticket_mapped_status = ISSUE_STATUS_MAPPING[ticket_status]
        self.assertEqual(obj.status, ticket_mapped_status)

    @ddt.data(
        ({
            "title": "first_title"
        }, {
            "title": "other_title"
        }),
        ({
            "issue_type": "type1"
        }, {
            "issue_type": "process"
        }),
        ({
            "issue_severity": "S0"
        }, {
            "issue_severity": "S1"
        }),
        ({
            "issue_priority": "P0"
        }, {
            "issue_priority": "P1"
        }),
        ({
            "hotlist_id": 1234
        }, {
            "hotlist_id": 4321
        }),
        ({
            "component_id": 1234
        }, {
            "component_id": 4321
        }),
        ({
            "status": "Draft"
        }, {
            "status": "fixed"
        }),
    )
    @ddt.unpack
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_new_issue_linking(self, issue_attrs, ticket_attrs, update_mock):
        """Test linking new Issue to IssueTracker ticket sets correct fields"""
        issue_request_payload = self.request_payload_builder(issue_attrs)
        response_payload = self.response_payload_builder(ticket_attrs)
        with mock.patch("ggrc.integrations.issues.Client.get_issue",
                        return_value=response_payload) as get_mock:
            with mock.patch.object(integration_utils,
                                   "exclude_auditor_emails",
                                   return_value={
                                       u"*****@*****.**",
                                   }):
                response = self.api.post(all_models.Issue,
                                         issue_request_payload)
            get_mock.assert_called_once()
        update_mock.assert_called_once()

        self.assertEqual(response.status_code, 201)
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        issue = all_models.Issue.query.filter_by(id=issue_id).first()
        self.check_issuetracker_issue_fields(issue, issue_tracker_issue,
                                             issue_request_payload,
                                             response_payload)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_people_merge_after_linking(self, update_mock):
        """Test people roles were updated while linking new ticket"""
        ticket_attrs = {
            "verifier": "*****@*****.**",
            "assignee": "*****@*****.**",
            "ccs": ["*****@*****.**", "*****@*****.**"],
        }
        with factories.single_commit():
            factories.PersonFactory(email="*****@*****.**")
            factories.PersonFactory(email="*****@*****.**")
            for email in ["*****@*****.**", "*****@*****.**"]:
                factories.PersonFactory(email=email)

        issue_request_payload = self.request_payload_builder({})
        response_payload = self.response_payload_builder(ticket_attrs)
        with mock.patch("ggrc.integrations.issues.Client.get_issue",
                        return_value=response_payload) as get_mock:
            with mock.patch.object(integration_utils,
                                   "exclude_auditor_emails",
                                   return_value={
                                       u"*****@*****.**",
                                   }):
                response = self.api.post(all_models.Issue,
                                         issue_request_payload)
            get_mock.assert_called_once()
        update_mock.assert_called_once()

        self.assertEqual(response.status_code, 201)
        issue_id = response.json.get("issue").get("id")
        issue = all_models.Issue.query.filter_by(id=issue_id).first()

        admins = [
            person.email for person in issue.get_persons_for_rolename("Admin")
        ]
        primary = [
            person.email
            for person in issue.get_persons_for_rolename("Primary Contacts")
        ]
        secondary = [
            person.email
            for person in issue.get_persons_for_rolename("Secondary Contacts")
        ]
        # assert ticket roles were added to Issue
        self.assertIn("*****@*****.**", admins)
        self.assertIn("*****@*****.**", primary)
        for person in ["*****@*****.**", "*****@*****.**"]:
            self.assertIn(person, secondary)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_existing_issue_link(self, update_mock):
        """Test Issue link to another ticket """
        iti = factories.IssueTrackerIssueFactory(
            enabled=True,
            issue_id=TICKET_ID,
            issue_tracked_obj=factories.IssueFactory())
        new_ticket_id = TICKET_ID + 1
        new_data = {"issue_id": new_ticket_id}
        issue_request_payload = self.put_request_payload_builder(new_data)
        response_payload = self.response_payload_builder(new_data)

        with mock.patch("ggrc.integrations.issues.Client.get_issue",
                        return_value=response_payload) as get_mock:
            with mock.patch.object(integration_utils,
                                   "exclude_auditor_emails",
                                   return_value={
                                       u"*****@*****.**",
                                   }):
                response = self.api.put(iti.issue_tracked_obj,
                                        issue_request_payload)
            get_mock.assert_called_once()

        self.assert200(response)

        # check if data was changed in our DB
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertEqual(int(issue_tracker_issue.issue_id), new_ticket_id)

        # check detach comment was sent
        detach_comment_template = params_builder.IssueParamsBuilder.DETACH_TMPL
        comment = detach_comment_template.format(new_ticket_id=new_ticket_id)
        expected_args = (TICKET_ID, {"status": "OBSOLETE", "comment": comment})
        self.assertEqual(expected_args, update_mock.call_args[0])

    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_already_linked_ticket(self):
        """Test Issue without IT couldn't be linked to already linked ticket"""
        with factories.single_commit():
            factories.IssueTrackerIssueFactory(
                enabled=True,
                issue_id=TICKET_ID,
                issue_tracked_obj=factories.IssueFactory())
            new_issue = factories.IssueFactory()

        issue_data = {"issue_id": TICKET_ID}
        issue_request_payload = self.put_request_payload_builder(issue_data)

        response = self.api.put(new_issue, issue_request_payload)
        self.assert200(response)
        self.assertTrue(response.json["issue"]["issue_tracker"]["_warnings"])
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertFalse(issue_tracker_issue)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_creating_new_ticket_for_linked_issue(self, update_mock):
        """Test create new ticket for already linked issue"""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True,
            issue_id=TICKET_ID,
            issue_tracked_obj=factories.IssueFactory())
        new_data = {"issue_id": ''}
        issue_request_payload = self.put_request_payload_builder(new_data)

        with mock.patch.object(integration_utils,
                               "exclude_auditor_emails",
                               return_value={
                                   u"*****@*****.**",
                               }):
            with mock.patch("ggrc.integrations.issues.Client.create_issue",
                            return_value={"issueId":
                                          TICKET_ID + 1}) as create_mock:
                response = self.api.put(iti.issue_tracked_obj,
                                        issue_request_payload)

        self.assert200(response)

        # Detach comment should be sent to previous ticket
        update_mock.assert_called_once()
        self.assertEqual(TICKET_ID, update_mock.call_args[0][0])
        create_mock.assert_called_once()

        # check if data was changed in our DB
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertNotEqual(int(issue_tracker_issue.issue_id), TICKET_ID)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_issue_tracker_error(self, update_issue_mock):
        """Test issue tracker errors.

    Issue in Issue tracker doesn't change state
    in case receiving an error.
    """
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        update_issue_mock.side_effect = integrations_errors.HttpError("data")
        issue_attrs = {
            "issue_tracker": {
                "enabled": True,
                "hotlist_id": "123",
                "issue_id": iti.issue_id,
            }
        }
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True),\
            mock.patch.object(all_models.IssuetrackerIssue,
                              "create_or_update_from_dict") as update_info_mock:
            self.api.put(iti.issue_tracked_obj, issue_attrs)

        # Check that "enabled" flag hasn't been changed.
        self.assertTrue("enabled" not in update_info_mock.call_args[0][1])

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_delete_issue(self, mock_update_issue):
        """Test updating issue tracker issue when issue in GGRC has been deleted"""
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        expected_query = {
            "comment":
            "GGRC object has been deleted. GGRC changes "
            "will no longer be tracked within this bug."
        }
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.delete(iti.issue_tracked_obj)
        mock_update_issue.assert_called_with(iti.issue_id, expected_query)

    @ddt.data("test comment", "  \n\ntest comment\n\n" "  \n\n  \n\n")
    @mock.patch.object(params_builder.BaseIssueTrackerParamsBuilder,
                       "get_ggrc_object_url",
                       return_value="http://issue_url.com")
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_adding_comment_to_issue(self, desc, update_issue_mock,
                                     url_builder_mock):
        """Test adding comment to issue."""
        role = all_models.Role.query.filter(
            all_models.Role.name == "Administrator").one()
        with factories.single_commit():
            client_user = factories.PersonFactory(name="Test User")
            rbac_factories.UserRoleFactory(role=role, person=client_user)
        self.api.set_user(client_user)
        self.client.get("/login")
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        comment = factories.CommentFactory(description=desc)
        builder_class = params_builder.BaseIssueTrackerParamsBuilder
        expected_result = {
            "comment":
            builder_class.COMMENT_TMPL.format(
                author=client_user.name,
                comment="test comment",
                model="Issue",
                link="http://issue_url.com",
            )
        }

        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.post(
                all_models.Relationship, {
                    "relationship": {
                        "source": {
                            "id": iti.issue_tracked_obj.id,
                            "type": "Issue"
                        },
                        "destination": {
                            "id": comment.id,
                            "type": "comment"
                        },
                        "context": None
                    },
                })
        url_builder_mock.assert_called_once()
        update_issue_mock.assert_called_with(iti.issue_id, expected_result)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_mapping_document(self, update_issue_mock):
        """Test map document action on issue.

    Issue in Issue tracker shouldn't be updated when reference url has been
    added to issue.
    """
        iti = factories.IssueTrackerIssueFactory(
            enabled=True, issue_tracked_obj=factories.IssueFactory())
        document = factories.DocumentFactory()
        response = self.api.put(
            iti.issue_tracked_obj, {
                "actions": {
                    "add_related": [
                        {
                            "id": document.id,
                            "type": "Document",
                        },
                    ]
                }
            })
        self.assert200(response)

        relationship = all_models.Relationship.query.filter(
            all_models.Relationship.source_type == "Issue",
            all_models.Relationship.source_id == response.json["issue"]["id"],
        ).order_by(all_models.Relationship.id.desc()).first()

        self.assertEqual(relationship.destination_id, document.id)
        self.assertEqual(relationship.source_id, iti.issue_tracked_obj.id)

        # Check that issue in Issue Tracker hasn't been updated.
        update_issue_mock.assert_not_called()
class TestProposalRelationship(TestCase):
  """Test relationship for proposals."""

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

  @staticmethod
  def proposal_relationships(obj):
    """Get relationships between any Proposal and object.

    Args:
        obj: Instance of Proposalable object.

    Returns:
        Query which return relationship ids.
    """
    return db.session.query(all_models.Relationship.id).filter(
        sa.or_(
            sa.and_(
                all_models.Relationship.source_type == 'Proposal',
                all_models.Relationship.destination_type == obj.type,
            ),
            sa.and_(
                all_models.Relationship.source_type == obj.type,
                all_models.Relationship.destination_type == 'Proposal',
            )
        )
    )

  def create_proposal_for(self, obj):
    """Create Proposal for obj.

    Args:
        obj: Instance of Proposalable object.

    Returns:
        Response with result of Proposal creation.
    """
    response = self.api.post(
        all_models.Proposal,
        {
            "proposal": {
                "instance": {
                    "id": obj.id,
                    "type": obj.type,
                },
                "full_instance_content": obj.log_json(),
                "context": None,
            }
        }
    )
    self.assertEqual(201, response.status_code)
    return response

  @ddt.data("Risk", "Control")
  def test_create(self, model_name):
    """Test if relationship between {} and Proposal is created."""
    obj = factories.get_model_factory(model_name)()
    self.create_proposal_for(obj)
    self.assertEqual(1, self.proposal_relationships(obj).count())

  def test_create_on_post_only(self):
    """Test if proposal relationship is created on post only."""
    control = factories.ControlFactory()
    response = self.create_proposal_for(control)
    post_rels = self.proposal_relationships(control).all()

    proposal = all_models.Proposal.query.get(response.json["proposal"]["id"])
    # Invalidate ACR cache manually as after first post
    # it will in detached state
    flask.g.global_ac_roles = None
    response = self.api.put(
        proposal,
        {
            "proposal": {
                "status": all_models.Proposal.STATES.APPLIED,
                "apply_reason": "test"
            }
        }
    )
    self.assert200(response)
    put_rels = self.proposal_relationships(control).all()
    self.assertEqual(post_rels, put_rels)

  def test_rel_remove_parent(self):
    """Test if relationship will be removed if parent instance is removed."""
    control = factories.ControlFactory()
    self.create_proposal_for(control)
    self.assertEqual(1, self.proposal_relationships(control).count())

    response = self.api.delete(control)
    self.assert200(response)
    self.assertEqual(0, self.proposal_relationships(control).count())

  def test_rel_remove_proposal(self):
    """Test if relationship will be removed if proposal is removed."""
    control = factories.ControlFactory()
    response = self.create_proposal_for(control)
    self.assertEqual(1, self.proposal_relationships(control).count())

    proposal = all_models.Proposal.query.get(response.json["proposal"]["id"])
    response = self.api.delete(proposal)
    self.assert200(response)
    self.assertEqual(0, self.proposal_relationships(control).count())
Exemplo n.º 40
0
class TestReviewApi(TestCase):
  """Base TestCase class proposal api tests."""

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

  def test_simple_get(self):
    """Test simple get"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          email_message="test email message",
          notification_type="email",
          reviewable=risk,
          status=all_models.Review.STATES.UNREVIEWED,
      )
    resp = self.api.get(all_models.Review, review.id)
    self.assert200(resp)
    self.assertIn("review", resp.json)
    resp_review = resp.json["review"]
    self.assertEqual(all_models.Review.STATES.UNREVIEWED,
                     resp_review["status"])
    self.assertEqual(all_models.Review.NotificationTypes.EMAIL_TYPE,
                     resp_review["notification_type"])
    self.assertEqual("test email message",
                     resp_review["email_message"])

  def test_collection_get(self):
    """Test simple collection get"""
    with factories.single_commit():
      review1 = factories.ReviewFactory(
          status=all_models.Review.STATES.UNREVIEWED
      )
      review2 = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED
      )

    resp = self.api.get_collection(all_models.Review,
                                   [review1.id, review2.id])
    self.assert200(resp)
    self.assertIn("reviews_collection", resp.json)
    self.assertIn("reviews", resp.json["reviews_collection"])
    self.assertEquals(2, len(resp.json["reviews_collection"]["reviews"]))

  def test_create_review(self):
    """Create review via API, check that single relationship is created"""
    program = factories.ProgramFactory()
    program_id = program.id
    resp = self.api.post(
        all_models.Review,
        {
            "review": {
                "reviewable": {
                    "type": program.type,
                    "id": program.id,
                },
                "context": None,
                "notification_type": "email",
                "status": all_models.Review.STATES.UNREVIEWED,
                "access_control_list": build_reviewer_acl()
            },
        },
    )
    self.assertEqual(201, resp.status_code)
    review_id = resp.json["review"]["id"]
    review = all_models.Review.query.get(review_id)
    self.assertEqual(all_models.Review.STATES.UNREVIEWED, review.status)
    self.assertEqual(program.type, review.reviewable_type)
    self.assertEqual(program_id, review.reviewable_id)

    control_review_rel_count = all_models.Relationship.query.filter(
        all_models.Relationship.source_id == review.id,
        all_models.Relationship.source_type == review.type,
        all_models.Relationship.destination_id == program_id,
        all_models.Relationship.destination_type == program.type,
    ).union(
        all_models.Relationship.query.filter(
            all_models.Relationship.destination_id == review.id,
            all_models.Relationship.destination_type == review.type,
            all_models.Relationship.source_id == program_id,
            all_models.Relationship.source_type == program.type,
        )
    ).count()
    self.assertEqual(1, control_review_rel_count)

  def test_delete_review(self):
    """Test delete review via API"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      risk_id = risk.id
      review = factories.ReviewFactory(reviewable=risk)
      review_id = review.id
    resp = self.api.delete(review)
    self.assert200(resp)
    review = all_models.Review.query.get(review_id)
    risk = all_models.Risk.query.get(risk_id)

    self.assertIsNone(review)
    self.assertEquals(0, len(risk.related_objects(_types=["Review"])))

  def test_last_reviewed(self):
    """last_reviewed_by, last_reviewed_by should be set if reviewed"""
    risk = factories.RiskFactory()
    resp, review = self.generator.generate_object(
        all_models.Review,
        {
            "reviewable": {
                "type": risk.type,
                "id": risk.id,
            },
            "context": None,
            "status": all_models.Review.STATES.UNREVIEWED,
            "access_control_list": build_reviewer_acl(),
            "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE
        },
    )
    review_id = review.id
    resp = self.api.put(
        review,
        {
            "status": all_models.Review.STATES.REVIEWED,
        },
    )
    self.assert200(resp)
    self.assertIsNotNone(resp.json["review"]["last_reviewed_by"])
    self.assertIsNotNone(resp.json["review"]["last_reviewed_at"])

    review = all_models.Review.query.get(review_id)
    self.assertIsNotNone(review.last_reviewed_by)
    self.assertIsNotNone(review.last_reviewed_at)

  def test_reviewable_revisions(self):
    """Check that proper revisions are created"""
    program = factories.ProgramFactory()
    resp, review = self.generator.generate_object(
        all_models.Review,
        {
            "reviewable": {
                "type": program.type,
                "id": program.id,
            },
            "context": None,
            "status": all_models.Review.STATES.UNREVIEWED,
            "access_control_list": build_reviewer_acl(),
            "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE
        },
    )
    program_id = program.id
    reviewable = review.reviewable

    program_revisions = all_models.Revision.query.filter_by(
        resource_id=program_id,
        resource_type=program.type
    ).order_by(
        all_models.Revision.id,
    ).all()
    self.assertEquals(2, len(program_revisions))
    self.assertEquals(all_models.Review.STATES.UNREVIEWED,
                      program_revisions[0].content["review_status"])
    self.assertEquals(all_models.Review.STATES.UNREVIEWED,
                      program_revisions[1].content["review_status"])
    resp = self.api.put(
        review,
        {
            "status": all_models.Review.STATES.REVIEWED,
        },
    )
    self.assert200(resp)

    program_revisions = all_models.Revision.query.filter_by(
        resource_id=program_id,
        resource_type=program.type
    ).order_by(
        all_models.Revision.id,
    ).all()
    self.assertEquals(3, len(program_revisions))
    self.assertEquals(all_models.Review.STATES.REVIEWED,
                      program_revisions[2].content["review_status"])

    resp = self.api.put(
        reviewable,
        {
            "description": "some new description"
        }
    )
    self.assert200(resp)

    program_revisions = all_models.Revision.query.filter_by(
        resource_id=program_id,
        resource_type=program.type
    ).order_by(
        all_models.Revision.id,
    ).all()
    self.assertEquals(4, len(program_revisions))
    self.assertEquals(all_models.Review.STATES.UNREVIEWED,
                      program_revisions[3].content["review_status"])
Exemplo n.º 41
0
class TestCreatorAudit(TestCase):
    """Set up necessary objects and test Creator role with Audit roles"""
    def setUp(self):
        super(TestCreatorAudit, self).setUp()
        self.generator = Generator()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.init_users()
        self.init_roles()
        self.init_test_cases()
        self.objects = {}

    def init_test_cases(self):
        """Create a dict of all possible test cases."""
        self.test_cases = {
            "Auditor": {
                "audit_role": "Auditor",
                "objects": {
                    "audit": {
                        "get": 200,
                        "put": 403,
                        "delete": 403
                    },
                    "mapped_Issue": {
                        "get": 200,
                        "put": 200,
                        "delete": 200
                    },
                    "unrelated_Issue": {
                        "get": 403,
                        "put": 403,
                        "delete": 403,
                        "map": 403,
                    },
                    "mapped_Assessment": {
                        "get": 200,
                        "put": 200,
                        "delete": 200
                    },
                    "unrelated_Assessment": {
                        "get": 403,
                        "put": 403,
                        "delete": 403,
                        "map": 403,
                    }
                }
            },
        }

    def init_roles(self):
        """Create a delete request for the given object."""
        response = self.api.get_query(all_models.Role, "")
        self.roles = {}
        for role in response.json.get("roles_collection").get("roles"):
            self.roles[role.get("name")] = role

    def init_users(self):
        """Create users used by test cases."""
        self.people = {}
        for name in ["creator", "notmapped", "mapped", "Auditor"]:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role="Creator")
            self.people[name] = user

        _, user = self.object_generator.generate_person(
            data={"name": "editor"}, user_role="Editor")
        self.people["editor"] = user

    def delete(self, obj):
        """Create a delete request for the given object.

    Args:
        obj (model instance): target object to delete
    Returns:
        int: http response status code
    """
        return self.api.delete(obj).status_code

    def get(self, obj):
        """Create a get request for the given object.

    Args:
        obj (model instance): target object to get
    Returns:
        int: http response status code
    """
        return self.api.get(obj.__class__, obj.id).status_code

    def put(self, obj):
        """Create a put request for the given object.

    Args:
        obj (model instance): target object to put
    Returns:
        int: http response status code
    """
        response = self.api.get(obj.__class__, obj.id)
        if response.status_code == 200:
            return self.api.put(obj, response.json).status_code
        else:
            return response.status_code

    def map(self, dest):
        """Map audit to dest.

    Args:
        dest (model instance): target object to map to the audit
    Returns:
        int: http response status code
    """
        response = self.api.post(
            all_models.Relationship, {
                "relationship": {
                    "source": {
                        "id": self.objects["audit"].id,
                        "type": self.objects["audit"].type,
                    },
                    "destination": {
                        "id": dest.id,
                        "type": dest.type
                    },
                    "context": None
                },
            })
        return response.status_code

    def init_objects(self, test_case_name):
        """Create a Program, an Audit, and a Mapped object for the test case.

    Args:
        test_case_name (string): test case to init for
    """
        # Create a program
        dummy_audit = factories.AuditFactory()
        unrelated_audit = {
            "type": "Audit",
            "context_id": dummy_audit.context.id,
            "id": dummy_audit.id,
        }
        test_case = self.test_cases[test_case_name]
        editor = self.people.get('editor')
        self.api.set_user(editor)
        random_title = factories.random_str()
        response = self.api.post(all_models.Program, {
            "program": {
                "title": random_title,
                "context": None
            },
        })
        self.assertEqual(response.status_code, 201)
        program_id = response.json.get("program").get("id")
        self.objects["program"] = all_models.Program.query.get(program_id)
        response = self.api.post(
            all_models.Audit, {
                "audit": {
                    "title": random_title + " audit",
                    'program': {
                        'id': program_id
                    },
                    "status": "Planned",
                    "context": None
                }
            })
        self.assertEqual(response.status_code, 201)
        context = response.json.get("audit").get("context")
        audit_id = response.json.get("audit").get("id")
        self.objects["audit"] = all_models.Audit.query.get(audit_id)
        audits = {
            "mapped": {
                "type": "Audit",
                "context_id": context["id"],
                "id": audit_id,
            },
            "unrelated": unrelated_audit,
        }

        for prefix, audit_dict in audits.items():
            random_title = factories.random_str()

            response = self.api.post(all_models.Issue, {
                "issue": {
                    "title": random_title,
                    "context": None,
                },
            })
            self.assertEqual(response.status_code, 201)
            issue_id = response.json.get("issue").get("id")
            self.objects[prefix +
                         "_Issue"] = all_models.Issue.query.get(issue_id)

            response = self.api.post(
                all_models.Assessment, {
                    "assessment": {
                        "title": random_title,
                        "context": {
                            "type": "Context",
                            "id": audit_dict["context_id"],
                        },
                        "audit": audit_dict,
                    },
                })
            self.assertEqual(response.status_code, 201)
            assessment_id = response.json.get("assessment").get("id")
            self.objects[prefix + "_Assessment"] = \
                all_models.Assessment.query.get(assessment_id)

        self.assertEqual(self.map(self.objects["mapped_Issue"]), 201)
        self.assertEqual(self.map(self.objects["mapped_Assessment"]), 201)

        # Add roles to mapped users:
        if "audit_role" in test_case:
            person = self.people.get(test_case_name)
            role = self.roles[test_case["audit_role"]]
            response = self.api.post(
                all_models.UserRole, {
                    "user_role": {
                        "person": {
                            "id": person.id,
                            "type": "Person",
                            "href": "/api/people/{}".format(person.id),
                        },
                        "role": {
                            "type": "Role",
                            "href": "/api/roles/{}".format(role["id"]),
                            "id": role["id"],
                        },
                        "context": {
                            "type": "Context",
                            "id": context.get("id"),
                            "href": "/api/contexts/{}".format(
                                context.get("id"))
                        }
                    }
                })
            self.assertEqual(response.status_code, 201)

    def test_creator_audit_roles(self):
        """ Test creator role with all audit scoped roles """
        # Check permissions based on test_cases:
        errors = []
        for test_case in self.test_cases:
            self.init_objects(test_case)
            person = self.people.get(test_case)
            objects = self.test_cases.get(test_case).get('objects')
            self.api.set_user(person)
            for obj, actions in objects.iteritems():
                for action in ("map", "get", "put", "delete"):
                    if action not in actions:
                        continue
                    # reset sesion:
                    db.session.commit()
                    func = getattr(self, action)
                    res = func(self.objects[obj])
                    if res != actions[action]:
                        errors.append(
                            "{}: Tried {} on {}, but received {} instead of {}"
                            .format(test_case, action, obj, res,
                                    actions[action]))

        self.assertEqual(errors, [])
Exemplo n.º 42
0
class TestCreatorAudit(TestCase):
  """Set up necessary objects and test Creator role with Audit roles"""

  def setUp(self):
    super(TestCreatorAudit, self).setUp()
    self.generator = Generator()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.init_users()
    self.init_roles()
    self.init_test_cases()
    self.objects = {}

  def init_test_cases(self):
    """Create a dict of all possible test cases."""
    self.test_cases = {
        "Auditor": {
            "audit_role": "Auditor",
            "objects": {
                "audit": {
                    "get": 200,
                    "put": 403,
                    "delete": 403
                },
                "mapped_Issue": {
                    "get": 200,
                    "put": 200,
                    "delete": 200
                },
                "unrelated_Issue": {
                    "get": 403,
                    "put": 403,
                    "delete": 403,
                    "map": 403,
                },
                "mapped_Assessment": {
                    "get": 200,
                    "put": 200,
                    "delete": 200
                },
                "unrelated_Assessment": {
                    "get": 403,
                    "put": 403,
                    "delete": 403,
                    "map": 403,
                }
            }
        },
    }

  def init_roles(self):
    """Create a delete request for the given object."""
    response = self.api.get_query(all_models.Role, "")
    self.roles = {}
    for role in response.json.get("roles_collection").get("roles"):
      self.roles[role.get("name")] = role

  def init_users(self):
    """Create users used by test cases."""
    self.people = {}
    for name in ["creator", "notmapped", "mapped", "Auditor"]:
      _, user = self.object_generator.generate_person(
          data={"name": name}, user_role="Creator")
      self.people[name] = user

    _, user = self.object_generator.generate_person(
        data={"name": "editor"}, user_role="Editor")
    self.people["editor"] = user

  def delete(self, obj):
    """Create a delete request for the given object.

    Args:
        obj (model instance): target object to delete
    Returns:
        int: http response status code
    """
    return self.api.delete(obj).status_code

  def get(self, obj):
    """Create a get request for the given object.

    Args:
        obj (model instance): target object to get
    Returns:
        int: http response status code
    """
    return self.api.get(obj.__class__, obj.id).status_code

  def put(self, obj):
    """Create a put request for the given object.

    Args:
        obj (model instance): target object to put
    Returns:
        int: http response status code
    """
    response = self.api.get(obj.__class__, obj.id)
    if response.status_code == 200:
      return self.api.put(obj, response.json).status_code
    else:
      return response.status_code

  def map(self, dest):
    """Map audit to dest.

    Args:
        dest (model instance): target object to map to the audit
    Returns:
        int: http response status code
    """
    response = self.api.post(all_models.Relationship, {
        "relationship": {"source": {
            "id": self.objects["audit"].id,
            "type": self.objects["audit"].type,
        }, "destination": {
            "id": dest.id,
            "type": dest.type
        }, "context": None},
    })
    return response.status_code

  def init_objects(self, test_case_name):
    """Create a Program, an Audit, and a Mapped object for the test case.

    Args:
        test_case_name (string): test case to init for
    """
    # Create a program
    dummy_audit = factories.AuditFactory()
    unrelated_audit = {
        "type": "Audit",
        "context_id": dummy_audit.context.id,
        "id": dummy_audit.id,
    }
    test_case = self.test_cases[test_case_name]
    editor = self.people.get('editor')
    self.api.set_user(editor)
    random_title = factories.random_str()
    response = self.api.post(all_models.Program, {
        "program": {"title": random_title, "context": None},
    })
    self.assertEqual(response.status_code, 201)
    program_id = response.json.get("program").get("id")
    self.objects["program"] = all_models.Program.query.get(program_id)
    response = self.api.post(all_models.Audit, {
        "audit": {
            "title": random_title + " audit",
            'program': {'id': program_id},
            "status": "Planned",
            "context": None
        }
    })
    self.assertEqual(response.status_code, 201)
    context = response.json.get("audit").get("context")
    audit_id = response.json.get("audit").get("id")
    self.objects["audit"] = all_models.Audit.query.get(audit_id)
    audits = {
        "mapped": {
            "type": "Audit",
            "context_id": context["id"],
            "id": audit_id,
        },
        "unrelated": unrelated_audit,
    }

    for prefix, audit_dict in audits.items():
      random_title = factories.random_str()

      response = self.api.post(all_models.Issue, {
          "issue": {
              "title": random_title,
              "context": {
                  "type": "Context",
                  "id": audit_dict["context_id"],
              },
              "audit": audit_dict,
          },
      })
      self.assertEqual(response.status_code, 201)
      issue_id = response.json.get("issue").get("id")
      self.objects[prefix + "_Issue"] = all_models.Issue.query.get(issue_id)

      response = self.api.post(all_models.Assessment, {
          "assessment": {
              "title": random_title,
              "context": {
                  "type": "Context",
                  "id": audit_dict["context_id"],
              },
              "audit": audit_dict,
          },
      })
      self.assertEqual(response.status_code, 201)
      assessment_id = response.json.get("assessment").get("id")
      self.objects[prefix + "_Assessment"] = \
          all_models.Assessment.query.get(assessment_id)

    self.assertEqual(self.map(self.objects["mapped_Issue"]), 201)
    self.assertEqual(self.map(self.objects["mapped_Assessment"]), 201)

    # Add roles to mapped users:
    if "audit_role" in test_case:
      person = self.people.get(test_case_name)
      role = self.roles[test_case["audit_role"]]
      response = self.api.post(all_models.UserRole, {"user_role": {
          "person": {
              "id": person.id,
              "type": "Person",
              "href": "/api/people/{}".format(person.id),
          }, "role": {
              "type": "Role",
              "href": "/api/roles/{}".format(role["id"]),
              "id": role["id"],
          }, "context": {
              "type": "Context",
              "id": context.get("id"),
              "href": "/api/contexts/{}".format(context.get("id"))
          }}})
      self.assertEqual(response.status_code, 201)

  def test_creator_audit_roles(self):
    """ Test creator role with all audit scoped roles """
    # Check permissions based on test_cases:
    errors = []
    for test_case in self.test_cases:
      self.init_objects(test_case)
      person = self.people.get(test_case)
      objects = self.test_cases.get(test_case).get('objects')
      self.api.set_user(person)
      for obj, actions in objects.iteritems():
        for action in ("map", "get", "put", "delete"):
          if action not in actions:
            continue
          # reset sesion:
          db.session.commit()
          func = getattr(self, action)
          res = func(self.objects[obj])
          if res != actions[action]:
            errors.append(
                "{}: Tried {} on {}, but received {} instead of {}".format(
                    test_case, action, obj, res, actions[action]))

    self.assertEqual(errors, [])
Exemplo n.º 43
0
class TestCollection(TestCase, WithQueryApi):
    """Test for collection assessment objects."""
    def setUp(self):
        super(TestCollection, self).setUp()
        self.client.get("/login")
        self.clear_data()
        self.api = Api()
        self.generator = ObjectGenerator()

    @ddt.data(True, False)
    def test_order_by_test(self, desc):
        """Order by fultext attr"""
        expected_ids = []
        with factories.single_commit():
            assessments = [factories.AssessmentFactory() for _ in range(10)]
        random.shuffle(assessments)
        with factories.single_commit():
            for idx, assessment in enumerate(assessments):
                comment = factories.CommentFactory(description=str(idx))
                factories.RelationshipFactory(source=assessment,
                                              destination=comment)
                expected_ids.append(assessment.id)
        query = self._make_query_dict("Assessment",
                                      order_by=[{
                                          "name": "comment",
                                          "desc": desc
                                      }])
        if desc:
            expected_ids = expected_ids[::-1]
        results = self._get_first_result_set(query, "Assessment", "values")
        self.assertEqual(expected_ids, [i['id'] for i in results])

    @ddt.data("Assessor", "Creator", "Verifier")
    def test_delete_assessment_by_role(self, role_name):
        """Delete assessment not allowed for based on Assignee Type."""
        with factories.single_commit():
            assessment = factories.AssessmentFactory()
            context = factories.ContextFactory(related_object=assessment)
            assessment.context = context
            person = factories.PersonFactory()
            object_person_rel = factories.RelationshipFactory(
                source=assessment, destination=person)
            factories.RelationshipAttrFactory(
                relationship_id=object_person_rel.id,
                attr_name="AssigneeType",
                attr_value=role_name,
            )
        assessment_id = assessment.id
        role = all_models.Role.query.filter(
            all_models.Role.name == "Creator").first()
        self.generator.generate_user_role(person, role, context)
        self.api.set_user(person)
        assessment = all_models.Assessment.query.get(assessment_id)
        resp = self.api.delete(assessment)
        self.assert403(resp)
        self.assertTrue(
            all_models.Assessment.query.filter(
                all_models.Assessment.id == assessment_id).one())

    @ddt.data(
        (all_models.Assessment.REWORK_NEEDED, True),
        (all_models.Assessment.DONE_STATE, True),
        (all_models.Assessment.FINAL_STATE, True),
        (all_models.Assessment.START_STATE, False),
    )
    @ddt.unpack
    def test_update_status_need_rework(self, status, is_valid):
        """Update assessment state from need rework to valid or invalid states."""
        with factories.single_commit():
            assessment = factories.AssessmentFactory(
                status=all_models.Assessment.REWORK_NEEDED)
        assessment_id = assessment.id
        resp = self.api.put(assessment, {"status": status})
        if is_valid:
            self.assert200(resp)
            check_status = status
        else:
            self.assert400(resp)
            check_status = all_models.Assessment.REWORK_NEEDED
        self.assertEqual(check_status,
                         all_models.Assessment.query.get(assessment_id).status)
Exemplo n.º 44
0
class TestProposalRelationship(TestCase):
  """Test relationship for proposals."""

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

  @staticmethod
  def proposal_relationships(obj):
    """Get relationships between any Proposal and object.

    Args:
        obj: Instance of Proposalable object.

    Returns:
        Query which return relationship ids.
    """
    return db.session.query(all_models.Relationship.id).filter(
        sa.or_(
            sa.and_(
                all_models.Relationship.source_type == 'Proposal',
                all_models.Relationship.destination_type == obj.type,
            ),
            sa.and_(
                all_models.Relationship.source_type == obj.type,
                all_models.Relationship.destination_type == 'Proposal',
            )
        )
    )

  def create_proposal_for(self, obj):
    """Create Proposal for obj.

    Args:
        obj: Instance of Proposalable object.

    Returns:
        Response with result of Proposal creation.
    """
    response = self.api.post(
        all_models.Proposal,
        {
            "proposal": {
                "instance": {
                    "id": obj.id,
                    "type": obj.type,
                },
                "full_instance_content": obj.log_json(),
                "context": None,
            }
        }
    )
    self.assertEqual(201, response.status_code)
    return response

  @ddt.data("Risk", "Control")
  def test_create(self, model_name):
    """Test if relationship between {} and Proposal is created."""
    obj = factories.get_model_factory(model_name)()
    self.create_proposal_for(obj)
    self.assertEqual(1, self.proposal_relationships(obj).count())

  def test_create_on_post_only(self):
    """Test if proposal relationship is created on post only."""
    control = factories.ControlFactory()
    response = self.create_proposal_for(control)
    post_rels = self.proposal_relationships(control).all()

    proposal = all_models.Proposal.query.get(response.json["proposal"]["id"])
    # Invalidate ACR cache manually as after first post
    # it will in detached state
    flask.g.global_ac_roles = None
    response = self.api.put(
        proposal,
        {
            "proposal": {
                "status": all_models.Proposal.STATES.APPLIED,
                "apply_reason": "test"
            }
        }
    )
    self.assert200(response)
    put_rels = self.proposal_relationships(control).all()
    self.assertEqual(post_rels, put_rels)

  def test_rel_remove_parent(self):
    """Test if relationship will be removed if parent instance is removed."""
    control = factories.ControlFactory()
    self.create_proposal_for(control)
    self.assertEqual(1, self.proposal_relationships(control).count())

    response = self.api.delete(control)
    self.assert200(response)
    self.assertEqual(0, self.proposal_relationships(control).count())

  def test_rel_remove_proposal(self):
    """Test if relationship will be removed if proposal is removed."""
    control = factories.ControlFactory()
    response = self.create_proposal_for(control)
    self.assertEqual(1, self.proposal_relationships(control).count())

    proposal = all_models.Proposal.query.get(response.json["proposal"]["id"])
    response = self.api.delete(proposal)
    self.assert200(response)
    self.assertEqual(0, self.proposal_relationships(control).count())
Exemplo n.º 45
0
class TestDisabledIssueIntegration(ggrc.TestCase):
    """Tests for IssueTracker integration functionality with disabled sync."""

    # pylint: disable=invalid-name

    def setUp(self):
        # pylint: disable=super-on-old-class
        super(TestDisabledIssueIntegration, self).setUp()
        self.api = Api()
        self.client.get("/login")

    @mock.patch("ggrc.integrations.issues.Client.create_issue")
    def test_issue_creation(self, mock_create_issue):
        """Test creating Issue object with disabled integration."""
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            response = self.api.post(
                all_models.Issue, {
                    "issue": {
                        "title": "test title",
                        "context": None,
                        "issue_tracker": {
                            "enabled": False,
                        }
                    },
                })
        mock_create_issue.assert_not_called()
        self.assertEqual(response.status_code, 201)
        issue_id = response.json.get("issue").get("id")
        issue_tracker_issue = models.IssuetrackerIssue.get_issue(
            "Issue", issue_id)
        self.assertIsNone(issue_tracker_issue)

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_issue_deletion(self, mock_update_issue):
        """Test deleting Issue object with disabled integration for issue."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=False, issue_tracked_obj=factories.IssueFactory())
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.delete(iti.issue_tracked_obj)
        mock_update_issue.assert_not_called()

    @ddt.data(
        {
            "description": "new description",
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "enabled": False
            }
        },
        {
            "test_plan": "new test plan",
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "component_id": "123",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "hotlist_id": "321",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "issue_priority": "P2",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "issue_severity": "S2",
                "enabled": False
            }
        },
        {
            "issue_tracker": {
                "issue_id": TICKET_ID,
                "title": "title1",
                "enabled": False
            }
        },
    )
    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_update_issue_object(self, issue_attrs, mock_update_issue):
        """Test updating issue object with disabled integration for issue."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=False,
            issue_id=TICKET_ID,
            issue_tracked_obj=factories.IssueFactory())
        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.put(iti.issue_tracked_obj, issue_attrs)
        mock_update_issue.assert_not_called()

    @mock.patch(
        "ggrc.integrations.issues.Client.create_issue",
        side_effect=[integrations_errors.Error, {
            "issueId": "issueId"
        }])
    @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True)
    def test_issue_recreation(self, mock_create_issue):
        """Test retrying to turn on integration after failed creation."""
        # Arrange data.
        component_id = "1234"
        hotlist_id = "4321"
        issue_type = "Default Issue type"
        issue_priority = "P2"
        issue_severity = "S1"
        title = "test title"
        issue_tracker_attrs = {
            "enabled": True,
            "component_id": int(component_id),
            "hotlist_id": int(hotlist_id),
            "issue_type": issue_type,
            "issue_priority": issue_priority,
            "issue_severity": issue_severity,
        }

        # Perform actions and assert results.
        with mock.patch.object(integration_utils,
                               "exclude_auditor_emails",
                               return_value={
                                   u"*****@*****.**",
                               }):

            # Try to create issue. create_issue should raise exception here.
            response = self.api.post(
                all_models.Issue, {
                    "issue": {
                        "title": title,
                        "context": None,
                        "issue_tracker": issue_tracker_attrs
                    },
                })

            issue_id = response.json.get("issue").get("id")
            issue_tracker_issue = models.IssuetrackerIssue.get_issue(
                "Issue", issue_id)
            self.assertIsNone(issue_tracker_issue.issue_id)
            self.assertIsNone(issue_tracker_issue.issue_url)

            # Try to turn on integration on already created issue.
            self.api.put(issue_tracker_issue.issue_tracked_obj,
                         {"issue_tracker": issue_tracker_attrs})

            issue_id = issue_tracker_issue.issue_tracked_obj.id
            issue_tracker_issue = models.IssuetrackerIssue.get_issue(
                "Issue", issue_id)
            self.assertEqual(issue_tracker_issue.issue_url,
                             "http://issue/issueId")

    @mock.patch("ggrc.integrations.issues.Client.update_issue")
    def test_adding_comment_to_issue(self, update_issue_mock):
        """Test not adding comment to issue when issue tracker disabled."""
        iti = factories.IssueTrackerIssueFactory(
            enabled=False, issue_tracked_obj=factories.IssueFactory())
        comment = factories.CommentFactory(description="test comment")

        with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True):
            self.api.post(
                all_models.Relationship, {
                    "relationship": {
                        "source": {
                            "id": iti.issue_tracked_obj.id,
                            "type": "Issue"
                        },
                        "destination": {
                            "id": comment.id,
                            "type": "comment"
                        },
                        "context": None
                    },
                })
        update_issue_mock.assert_not_called()

    def test_prepare_update_json(self):
        """Test prepare_update_json method for Issue."""
        with factories.single_commit():
            issue = factories.IssueFactory()
            iti = factories.IssueTrackerIssueFactory(
                enabled=True,
                issue_tracked_obj=issue,
                title='title',
                component_id=123,
                hotlist_id=321,
                issue_type="PROCESS",
                issue_priority="P3",
                issue_severity="S3",
            )
        without_info = issue_integration.prepare_issue_update_json(issue)
        issue_info = issue.issue_tracker
        with_info = issue_integration.prepare_issue_update_json(
            issue, issue_info)

        expected_info = {
            'component_id': 123,
            'severity': u'S3',
            'title': iti.title,
            'hotlist_ids': [
                321,
            ],
            'priority': u'P3',
            'type': u'PROCESS',
        }
        self.assertEqual(expected_info, with_info)
        self.assertEqual(without_info, with_info)
Exemplo n.º 46
0
class TestCreatorProgram(TestCase):
    """Set up necessary objects and test Creator role with Program roles"""
    def setUp(self):
        super(TestCreatorProgram, self).setUp()
        self.generator = Generator()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.init_users()
        self.init_roles()
        self.init_test_cases()
        self.objects = {}

    def init_test_cases(self):
        """ Create a dict of all possible test cases """
        self.test_cases = {
            "notmapped": {
                "objects": {
                    "program": {
                        "get": 403,
                        "put": 403,
                        "delete": 403
                    },
                    "mapped_object": {
                        "get": 403,
                        "put": 403,
                        "delete": 403
                    },
                    "unrelated": {
                        "get": 403,
                        "put": 403,
                        "delete": 403,
                        "map": 403,
                    }
                },
            },
            "mapped": {
                "objects": {
                    "program": {
                        "get": 403,
                        "put": 403,
                        "delete": 403
                    },
                    "mapped_object": {
                        "get": 403,
                        "put": 403,
                        "delete": 403
                    },
                    "unrelated": {
                        "get": 403,
                        "put": 403,
                        "delete": 403,
                        "map": 403,
                    }
                }
            },
            "ProgramReader": {
                "program_role": "Program Readers",
                "objects": {
                    "program": {
                        "get": 200,
                        "put": 403,
                        "delete": 403
                    },
                    "mapped_object": {
                        "get": 200,
                        "put": 403,
                        "delete": 403
                    },
                    "unrelated": {
                        "get": 403,
                        "put": 403,
                        "delete": 403,
                        "map": 403,
                    }
                }
            },
            "ProgramManager": {
                "program_role": "Program Managers",
                "objects": {
                    "program": {
                        "get": 200,
                        "put": 200,
                        "delete": 200
                    },
                    "mapped_object": {
                        "get": 200,
                        "put": 200,
                        "delete": 200,
                    },
                    "unrelated": {
                        "get": 403,
                        "put": 403,
                        "delete": 403,
                        "map": 403,
                    }
                }
            },
            "ProgramEditor": {
                "program_role": "Program Editors",
                "objects": {
                    "program": {
                        "get": 200,
                        "put": 200,
                        "delete": 200
                    },
                    "mapped_object": {
                        "get": 200,
                        "put": 200,
                        "delete": 200
                    },
                    "unrelated": {
                        "get": 403,
                        "put": 403,
                        "delete": 403,
                        "map": 403,
                    }
                }
            },
        }

    def init_roles(self):
        """ Create a delete request for the given object """
        ac_roles = all_models.AccessControlRole.query.all()
        self.ac_roles = {}
        for ac_role in ac_roles:
            self.ac_roles[ac_role.name] = ac_role.id

    def init_users(self):
        """ Create users used by test cases """
        users = [("creator", "Creator"), ("notmapped", "Creator"),
                 ("mapped", "Creator"), ("ProgramReader", "Creator"),
                 ("ProgramEditor", "Creator"), ("ProgramManager", "Creator")]
        self.people = {}
        for (name, role) in users:
            _, user = self.object_generator.generate_person(data={
                "name":
                name,
                "email":
                name + "@example.com"
            },
                                                            user_role=role)
            self.people[name] = user

    def delete(self, obj):
        """ Create a delete request for the given object """
        return self.api.delete(obj).status_code

    def get(self, obj):
        """ Create a get request for the given object """
        return self.api.get(obj.__class__, obj.id).status_code

    def put(self, obj):
        """ Create a put request for the given object """
        response = self.api.get(obj.__class__, obj.id)
        if response.status_code == 200:
            return self.api.put(obj, response.json).status_code
        else:
            return response.status_code

    def map(self, dest):
        """ Map src to dest """
        response = self.api.post(
            all_models.Relationship, {
                "relationship": {
                    "source": {
                        "id": self.objects["program"].id,
                        "type": self.objects["program"].type,
                    },
                    "destination": {
                        "id": dest.id,
                        "type": dest.type
                    },
                    "context": None
                },
            })
        return response.status_code

    def init_objects(self, test_case_name):
        """ Create a Program and a Mapped object for a given test case """
        # Create a program
        test_case = self.test_cases[test_case_name]
        creator = self.people.get('creator')
        self.api.set_user(creator)
        random_title = factories.random_str()
        person = self.people.get(test_case_name)
        acl = [
            acl_helper.get_acl_json(self.ac_roles["Program Managers"],
                                    creator.id)
        ]
        if "program_role" in test_case:
            ac_role_id = self.ac_roles[test_case["program_role"]]
            acl.append(acl_helper.get_acl_json(ac_role_id, person.id))
        response = self.api.post(
            all_models.Program, {
                "program": {
                    "title": random_title,
                    "context": None,
                    "access_control_list": acl
                },
            })
        self.assertEqual(response.status_code, 201,
                         "Creator can't create program")
        context_id = response.json.get("program").get("context").get("id")
        program_id = response.json.get("program").get("id")

        # Use admin owner role to map it with system
        acr_id = all_models.AccessControlRole.query.filter_by(
            object_type="System", name="Admin").first().id
        self.objects["program"] = all_models.Program.query.get(program_id)

        # Create an object:
        for obj in ("mapped_object", "unrelated"):
            random_title = factories.random_str()
            response = self.api.post(
                all_models.System, {
                    "system": {
                        "title":
                        random_title,
                        "context":
                        None,
                        "access_control_list":
                        [acl_helper.get_acl_json(acr_id, creator.id)],
                    },
                })
            self.assertEqual(response.status_code, 201,
                             "Creator can't create object")
            system_id = response.json.get("system").get("id")
            self.objects[obj] = all_models.System.query.get(system_id)

        # Map Object to Program
        response = self.api.post(
            all_models.Relationship, {
                "relationship": {
                    "source": {
                        "id": program_id,
                        "type": "Program"
                    },
                    "destination": {
                        "id": self.objects["mapped_object"].id,
                        "type": "System"
                    },
                    "context": None
                },
            })
        self.assertEqual(response.status_code, 201,
                         "Creator can't map object to program")

        # Map people to Program:
        if test_case_name != "notmapped":
            person = self.people.get(test_case_name)
            response = self.api.post(
                all_models.ObjectPerson, {
                    "object_person": {
                        "person": {
                            "id": person.id,
                            "type": "Person",
                            "href": "/api/people/{}".format(person.id),
                        },
                        "personable": {
                            "type": "Program",
                            "href": "/api/programs/{}".format(program_id),
                            "id": program_id,
                        },
                        "context": {
                            "type": "Context",
                            "id": context_id,
                            "href": "/api/contexts/{}".format(context_id)
                        }
                    }
                })

    def test_creator_program_roles(self):
        """ Test creator role with all program scoped roles """
        # Check permissions based on test_cases:
        errors = []
        for test_case in self.test_cases:
            self.init_objects(test_case)
            person = self.people.get(test_case)
            objects = self.test_cases.get(test_case).get('objects')
            self.api.set_user(person)
            for obj in ("unrelated", "mapped_object", "program"):
                actions = objects[obj]
                for action in ("map", "get", "put", "delete"):
                    # reset sesion:
                    db.session.commit()
                    if action not in actions:
                        continue
                    func = getattr(self, action)
                    res = func(self.objects[obj])
                    if res != actions[action]:
                        errors.append(
                            "{}: Tried {} on {}, but received {} instead of {}"
                            .format(test_case, action, obj, res,
                                    actions[action]))
            # Try mapping
        self.assertEqual(errors, [])
Exemplo n.º 47
0
class TestAccessControlRole(TestCase):
    """TestAccessControlRole"""
    def setUp(self):
        self.clear_data()
        super(TestAccessControlRole, self).setUp()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.people = {}
        for name in ["Creator", "Reader", "Editor"]:
            _, user = self.object_generator.generate_person(
                data={"name": name}, user_role=name)
            self.people[name] = user

    def _post_role(self, name=None, object_type="Control"):
        """Helper function for POSTing roles"""
        if name is None:
            name = random_str(prefix="Access Control Role - ")
        return self.api.post(
            AccessControlRole, {
                "access_control_role": {
                    "name": name,
                    "object_type": object_type,
                    "context": None,
                    "read": True
                },
            })

    def test_create_after_objects(self):
        """Test eager creation of ACLs on existing objects with new ACR."""
        program_id = factories.ProgramFactory().id
        role_name = "New Custom Role"
        self._post_role(name=role_name, object_type="Program")
        program = all_models.Program.query.get(program_id)
        self.assertIn(role_name, program.acr_name_acl_map.keys())
        self.assertIsNotNone(program.acr_name_acl_map[role_name])

    def test_create(self):
        """Test Access Control Role creation"""
        response = self._post_role(object_type="Program")
        assert response.status_code == 201, \
            "Failed to create a new access control role, response was {}".format(
                response.status)

        id_ = response.json['access_control_role']['id']
        role = AccessControlRole.query.filter(
            AccessControlRole.id == id_).first()
        assert role.read == 1, \
            "Read permission not correctly saved {}".format(role.read)
        assert role.update == 1, \
            "Update permission not correctly saved {}".format(role.update)
        assert role.delete == 1, \
            "Update permission not correctly saved {}".format(role.delete)

    @ddt.data(
        {
            "mandatory": True,
            "exp_response": MANDATORY_ROLE_RESPONSE
        },
        {
            "mandatory": False,
            "exp_response": NON_MANDATORY_ROLE_RESPONSE
        },
    )
    @ddt.unpack
    def test_mandatory_delete(self, mandatory, exp_response):
        """Test set empty field via import if acr mandatory is {mandatory}"""
        role = factories.AccessControlRoleFactory(
            name=ROLE_NAME,
            object_type="Program",
            mandatory=mandatory,
        )
        with factories.single_commit():
            user = factories.PersonFactory()
            program = factories.ProgramFactory()
            role_id = role.id
            factories.AccessControlPersonFactory(
                ac_list=program.acr_name_acl_map[ROLE_NAME],
                person=user,
            )
        response = self.import_data(
            OrderedDict([
                ("object_type", "Program"),
                ("Code*", program.slug),
                (ROLE_NAME, "--"),
            ]))
        self._check_csv_response(response, exp_response)
        db_data = defaultdict(set)
        program = all_models.Program.query.get(program.id)
        for person, acl in program.access_control_list:
            db_data[acl.ac_role_id].add(person.id)
        if mandatory:
            cur_user = all_models.Person.query.filter_by(
                email="*****@*****.**").first()
            self.assertEqual(set([cur_user.id]), db_data[role_id])
        else:
            self.assertFalse(db_data[role_id])

    def test_only_admin_can_post(self):
        """Only admin users should be able to POST access control roles"""
        for name in ("Creator", "Reader", "Editor"):
            person = self.people.get(name)
            self.api.set_user(person)
            response = self._post_role()
            assert response.status_code == 403, \
                "Non admins should get forbidden error when POSTing role. {}".format(
                    response.status)

    @ddt.data(
        ("name", "New ACR"),
        ("read", False),
        ("mandatory", False),
        ("non_editable", False),
    )
    @ddt.unpack
    def test_modify_non_editable_role(self, field_name, field_value):
        """Test if user can modify non-editable role"""
        # Primary Contacts role of Control is non-editable
        ac_role = AccessControlRole.query.filter_by(
            object_type="Control",
            name="Control Operators",
        ).first()

        response = self.api.put(ac_role, {field_name: field_value})
        assert response.status_code == 403, \
            "Forbidden error should be thrown when non-editable " \
            "role {} updated.".format(ac_role.name)

    def test_delete_non_editable_role(self):
        """Test if user can delete non-editable role"""
        # Primary Contacts role of Control is non-editable
        ac_role = AccessControlRole.query.filter_by(
            object_type="Control",
            name="Control Operators",
        ).first()

        response = self.api.delete(ac_role)
        assert response.status_code == 403, \
            "Forbidden error should be thrown when non-editable " \
            "role {} deleted.".format(ac_role.name)

    @ddt.data("Control")
    def test_create_from_ggrcq(self, object_type):
        """Test that create action only for GGRCQ."""
        with self.api.as_external():
            response = self._post_role(object_type=object_type)
            self.assertEqual(response.status_code, 201)

    @ddt.data("Control")
    def test_create_from_ggrc(self, object_type):
        """Test create action not allowed for GGRC."""
        response = self._post_role(object_type=object_type)
        self.assertEqual(response.status_code, 405)

    @ddt.data("Control")
    def test_modify_from_ggrcq(self, object_type):
        """Test that modify action only for GGRCQ."""
        with factories.single_commit():
            acr_id = factories.AccessControlRoleFactory(
                object_type=object_type).id

        with self.api.as_external():
            acr = all_models.AccessControlRole.query.get(acr_id)
            response = self.api.put(acr, {"name": "new acr"})
            self.assertEqual(response.status_code, 200)

    @ddt.data("Control")
    def test_modify_from_ggrc(self, object_type):
        """Test modify action not allowed for GGRC."""
        with factories.single_commit():
            acr = factories.AccessControlRoleFactory(object_type=object_type)

        response = self.api.put(acr, {"name": "new acr"})
        self.assertEqual(response.status_code, 405)

    @ddt.data("Control")
    def test_delete_from_ggrcq(self, object_type):
        """Test that modify action only for GGRCQ."""
        with factories.single_commit():
            acr_id = factories.AccessControlRoleFactory(
                object_type=object_type).id

        with self.api.as_external():
            acr = all_models.AccessControlRole.query.get(acr_id)
            response = self.api.delete(acr)
            self.assertEqual(response.status_code, 200)

    @ddt.data("Control")
    def test_delete_from_ggrc(self, object_type):
        """Test modify action not allowed for GGRC."""
        with factories.single_commit():
            acr = factories.AccessControlRoleFactory(object_type=object_type)

        response = self.api.delete(acr)
        self.assertEqual(response.status_code, 405)

    @ddt.data(
        {
            "name": "Test 1",
            "update": False,
            "read": False,
            "delete": True
        },
        {
            "name": "Test 2",
            "update": True,
            "read": False,
            "delete": False
        },
        {
            "name": "Test 3",
            "update": True,
            "read": False,
            "delete": True
        },
    )
    @ddt.unpack
    def test_create_with_wrong_options(self, name, update, read, delete):
        """ Test if user create ACR with wrong options."""
        options = [{
            'access_control_role': {
                'modal_title': 'Add Custom Role to type Regulation',
                'object_type': 'Regulation',
                'parent_type': 'Regulation',
                'context': {
                    'id': None
                },
                'delete': delete,
                'update': update,
                'read': read,
                'name': name
            }
        }]
        response = self.api.post(AccessControlRole, options)
        self.assert400(response)
class TestReviewStatusUpdate(TestCase):
    """Base TestCase class automatic review status update."""
    def setUp(self):
        super(TestReviewStatusUpdate, self).setUp()
        self.api = Api()

        self.generator = generator.ObjectGenerator()

    def test_gca(self):
        """if GCA of reviewable is changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="rich_test_gca",
                             attribute_type="Rich Text")
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_update_gca(self):
        """if existing GCA value changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="rich_test_gca",
                             attribute_type="Rich Text")
            program = factories.ProgramFactory()

            program.custom_attribute_values = [{
                "attribute_value": "starting_value",
                "custom_attribute_id": gca.id
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    @ddt.data("custom attr", "slug", "self")
    def test_gca_with_varying_titles(self, title):
        """if GCA with any title is changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title=title,
                             attribute_type="Rich Text")
            program = factories.ProgramFactory()

            program.custom_attribute_values = [{
                "attribute_value": "starting_value",
                "custom_attribute_id": gca.id
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_map_person_gca(self):
        """if Map:Person GCA value added review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="map_test_gca",
                             attribute_type="Map:Person")

            user_id = all_models.Person.query.filter_by(
                email="*****@*****.**").one().id

            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)

        review_id = review.id
        reviewable = review.reviewable
        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_object_id": user_id,
                    "attribute_value": "Person",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_update_map_person_gca(self):
        """if existing Map:Person GCA value changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="map_test_gca",
                             attribute_type="Map:Person")

            first_user_id = all_models.Person.query.filter_by(
                email="*****@*****.**").one().id
            second_user_id = factories.PersonFactory().id

            program = factories.ProgramFactory()
            program.custom_attribute_values = [{
                "attribute_object_id": first_user_id,
                "custom_attribute_id": gca.id,
                "attribute_value": "Person"
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)

        review_id = review.id
        reviewable = review.reviewable
        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_object_id": second_user_id,
                    "attribute_value": "Person",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_delete_map_person_gca(self):
        """if existing Map:Person GCA value deleted review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="map_test_gca",
                             attribute_type="Map:Person")

            user_id = all_models.Person.query.filter_by(
                email="*****@*****.**").one().id

            program = factories.ProgramFactory()
            program.custom_attribute_values = [{
                "attribute_object_id": user_id,
                "custom_attribute_id": gca.id,
                "attribute_value": "Person"
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)

        review_id = review.id
        reviewable = review.reviewable
        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_object_id": None,
                    "attribute_object": None,
                    "attribute_value": "Person",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_reference_url(self):
        """If reference url is updated state should not updated"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            doc = factories.DocumentReferenceUrlFactory(
                title="Simple title",
                link="some_url.com",
                description="mega description",
                parent_obj={
                    "id": program.id,
                    "type": "Program"
                })
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id

        self.api.modify_object(doc, {"link": "new_link.com"})
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_acl_roles(self):
        """Update of reviewable ACL shouldn't change review status"""
        with factories.single_commit():
            threat = factories.ThreatFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=threat)
        review_id = review.id

        ac_role_id = all_models.AccessControlRole.query.filter_by(
            name="Primary Contacts", object_type="Threat").one().id

        user_id = all_models.Person.query.filter_by(
            email="*****@*****.**").one().id

        self.api.modify_object(
            threat, {
                "access_control_list": [{
                    "ac_role_id": ac_role_id,
                    "person": {
                        "id": user_id
                    },
                }],
            })
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_comments(self):
        """Add comment to reviewable shouldn't update review state"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id

        self.generator.generate_comment(program,
                                        "Verifiers",
                                        "some comment",
                                        send_notification="false")

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_mapping_non_snapshotable(self):
        """Map non-snapshotable shouldn't change review status"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
            review_id = review.id

        factories.RelationshipFactory(source=program,
                                      destination=factories.IssueFactory())

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    @ddt.data("Standard", "Regulation", "Requirement", "Objective", "Control",
              "Product", "System", "Process", "AccessGroup", "Contract",
              "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk",
              "Threat", "Vendor")
    def test_map_snapshotable(self, snapshotable):
        """Map '{}' should change review status"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
            review_id = review.id

        self.generator.generate_relationship(
            source=program,
            destination=factories.get_model_factory(snapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_unmap_snapshotable(self):
        """Unmap snapshotable should change review status"""
        program = factories.ProgramFactory()
        resp, review = generate_review_object(program)
        review_id = review.id

        _, rel = self.generator.generate_relationship(
            source=program,
            destination=factories.ProductFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    @ddt.data(
        "Assessment",
        "Issue",
        "Program",
        "Project",
        "Audit",
        "RiskAssessment",
        "AssessmentTemplate",
        "Person",
    )
    def test_map_nonsnapshotable(self, nonsnapshotable):
        """Map '{}' shouldn't change review status"""
        program = factories.ProgramFactory()
        _, review = generate_review_object(
            program, state=all_models.Review.STATES.REVIEWED)
        review_id = review.id

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.generator.generate_relationship(
            source=program,
            destination=factories.get_model_factory(nonsnapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_unmap_nonsnapshotable(self):
        """Unmap nonsnapshotable shouldn't change review status"""
        program = factories.ProgramFactory()
        resp, review = generate_review_object(
            program, state=all_models.Review.STATES.REVIEWED)
        review_id = review.id
        _, rel = self.generator.generate_relationship(
            source=program,
            destination=factories.ProgramFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_proposal_apply(self):
        """Reviewable object changed via proposal -> review.state-> UNREVIEWED"""
        program = factories.ProgramFactory()
        _, review = generate_review_object(program)

        review_id = review.id

        proposal_content = {
            "fields": {
                "title": "new title"
            },
        }
        proposal = factories.ProposalFactory(instance=program,
                                             content=proposal_content,
                                             agenda="agenda content")
        self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED})

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_review_status_update(self):
        """Test updating folder preserves review status"""
        threat = factories.ThreatFactory()
        factories.ReviewFactory(
            reviewable=threat,
            status=all_models.Review.STATES.REVIEWED,
        )
        self.api.put(threat, {"folder": factories.random_str()})
        program = all_models.Threat.query.get(threat.id)
        self.assertEqual(program.review.status,
                         all_models.Review.STATES.REVIEWED)
Exemplo n.º 49
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)
Exemplo n.º 50
0
class TestPermissionsOnAssessmentTemplate(TestCase):
    """ Test check permissions for ProgramEditor on

  get and post assessment_temaplte action"""
    def setUp(self):
        super(TestPermissionsOnAssessmentTemplate, self).setUp()
        self.api = Api()
        self.generator = ObjectGenerator()
        _, program = self.generator.generate_object(all_models.Program)
        program_id = program.id
        _, self.editor = self.generator.generate_person(user_role="Creator")
        role = perms.all_models.Role.query.filter(
            perms.all_models.Role.name == "ProgramEditor").first()
        self.generator.generate_user_role(
            self.editor, role, all_models.Program.query.get(program_id))
        _, audit = self.generator.generate_object(
            all_models.Audit,
            {
                "title": "Audit",
                "program": {
                    "id": program_id
                },
                "status": "Planned"
            },
        )
        audit_id = audit.id

        generated_at = self.generator.generate_object(
            all_models.AssessmentTemplate, {
                "title": "Template",
                "_NON_RELEVANT_OBJ_TYPES": {},
                "_objectTypes": {},
                "audit": {
                    "id": audit.id
                },
                "audit_title": audit.title,
                "people_value": [],
                "default_people": {
                    "assignees": "Admin",
                    "verifiers": "Admin",
                },
                "context": {
                    "id": audit.context.id
                },
            })
        self.assessment_template_resp, assessment_template = generated_at
        assessment_template_id = assessment_template.id
        self.api.set_user(self.editor)
        self.perms_data = self.api.client.get("/permissions").json
        self.audit = all_models.Audit.query.get(audit_id)
        self.assessment_template = all_models.AssessmentTemplate.query.get(
            assessment_template_id)

    def test_post_action(self):
        """Test create action on AssessmentTemplate created by api"""
        data = [{
            "assessment_template": {
                "_NON_RELEVANT_OBJ_TYPES": {},
                "_objectTypes": {},
                "audit": {
                    "id": self.audit.id
                },
                "audit_title": self.audit.title,
                "people_value": [],
                "default_people": {
                    "assignees": "Admin",
                    "verifiers": "Admin",
                },
                "context": {
                    "id": self.audit.context.id
                },
                "title": "123",
            }
        }]
        self.api.set_user(self.editor)
        resp = self.api.post(all_models.AssessmentTemplate, data)
        self.assert200(resp)

    def test_get_action(self):
        """Test read action on AssessmentTemplate created by api"""
        resp = self.api.get(all_models.AssessmentTemplate,
                            self.assessment_template.id)
        self.assert200(resp)

    def test_put_action(self):
        """Test update action on AssessmentTemplate created by api"""
        to_update = copy.deepcopy(self.assessment_template_resp.json)
        new_title = "new_{}".format(self.assessment_template.title)
        to_update['assessment_template']['title'] = new_title
        resp = self.api.put(self.assessment_template, to_update)
        self.assert200(resp)
        assessment_tmpl = all_models.AssessmentTemplate.query.get(
            self.assessment_template.id)
        self.assertEqual(new_title, assessment_tmpl.title)

    def test_delete_action(self):
        """Test delete action on AssessmentTemplate created by api"""
        resp = self.api.delete(self.assessment_template)
        self.assert200(resp)
        self.assertFalse(
            all_models.AssessmentTemplate.query.filter(
                all_models.AssessmentTemplate ==
                self.assessment_template.id).all())
Exemplo n.º 51
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)
Exemplo n.º 52
0
class TestCollection(TestCase, WithQueryApi):

  """Test for collection assessment objects."""

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

  @ddt.data(True, False)
  def test_order_by_test(self, desc):
    """Order by fultext attr"""
    expected_ids = []
    with factories.single_commit():
      assessments = [factories.AssessmentFactory() for _ in range(10)]
    random.shuffle(assessments)
    with factories.single_commit():
      for idx, assessment in enumerate(assessments):
        comment = factories.CommentFactory(description=str(idx))
        factories.RelationshipFactory(source=assessment, destination=comment)
        expected_ids.append(assessment.id)
    query = self._make_query_dict(
        "Assessment", order_by=[{"name": "comment", "desc": desc}]
    )
    if desc:
      expected_ids = expected_ids[::-1]
    results = self._get_first_result_set(query, "Assessment", "values")
    self.assertEqual(expected_ids, [i['id'] for i in results])

  @ddt.data("Assignees", "Creators", "Verifiers")
  def test_delete_assessment_by_role(self, role_name):
    """Delete assessment not allowed for based on Assignee Type."""
    with factories.single_commit():
      assessment = factories.AssessmentFactory()
      context = factories.ContextFactory(related_object=assessment)
      assessment.context = context
      person = factories.PersonFactory()
      ac_role = all_models.AccessControlRole.query.filter_by(
          object_type=assessment.type,
          name=role_name
      ).first()
      factories.AccessControlListFactory(
          person=person,
          ac_role=ac_role,
          object=assessment
      )
    assessment_id = assessment.id
    role = all_models.Role.query.filter(
        all_models.Role.name == "Creator"
    ).first()
    self.generator.generate_user_role(person, role, context)
    self.api.set_user(person)
    assessment = all_models.Assessment.query.get(assessment_id)
    resp = self.api.delete(assessment)
    self.assert403(resp)
    self.assertTrue(all_models.Assessment.query.filter(
        all_models.Assessment.id == assessment_id).one())

  @ddt.data(
      (all_models.Assessment.REWORK_NEEDED, True),
      (all_models.Assessment.DONE_STATE, True),
      (all_models.Assessment.FINAL_STATE, True),
      (all_models.Assessment.START_STATE, False),
  )
  @ddt.unpack
  def test_update_status_need_rework(self, status, is_valid):
    """Update assessment state from need rework to valid or invalid states."""
    with factories.single_commit():
      assessment = factories.AssessmentFactory(
          status=all_models.Assessment.REWORK_NEEDED
      )
    assessment_id = assessment.id
    resp = self.api.put(assessment, {"status": status})
    if is_valid:
      self.assert200(resp)
      check_status = status
    else:
      self.assert400(resp)
      check_status = all_models.Assessment.REWORK_NEEDED
    self.assertEqual(
        check_status, all_models.Assessment.query.get(assessment_id).status)