Ejemplo n.º 1
0
class TestTitledMixin(TestCase):
    """Test cases for Labeled mixin"""
    def setUp(self):
        super(TestTitledMixin, self).setUp()
        self.api = Api()
        self.api.login_as_normal()

    def test_post_no_title(self):
        """Test object creation request without title key"""
        response = self.api.post(all_models.Product,
                                 {'product': {
                                     "description": "desc"
                                 }})

        self.assert400(response)
        self.assertEqual(response.json, "'title' must be specified")

    def test_post_title_is_null(self):
        """Test object creation request title=null"""
        response = self.api.post(
            all_models.Product,
            {'product': {
                "description": "desc",
                "title": None
            }})

        self.assert400(response)
        self.assertEqual(response.json, "'title' must be specified")

    @ddt.data(
        ('a', 'a'),
        ('  a  ', 'a'),
        ('', ''),
        ('  ', ''),
    )
    @ddt.unpack
    def test_post_title_is_valid(self, title, expected):
        """Test object creation request title={0!r}"""
        response = self.api.post(
            all_models.Product,
            {'product': {
                "description": "desc",
                "title": title
            }})

        self.assertStatus(response, 201)
        product = all_models.Product.query.get(response.json['product']['id'])
        self.assertEqual(product.title, expected)
Ejemplo n.º 2
0
class TestTitledMixin(TestCase):
  """Test cases for Labeled mixin"""

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

  def test_post_no_title(self):
    """Test object creation request without title key"""
    response = self.api.post(all_models.Product,
                             {'product': {"description": "desc"}})

    self.assert400(response)
    self.assertEqual(response.json, "'title' must be specified")

  def test_post_title_is_null(self):
    """Test object creation request title=null"""
    response = self.api.post(
        all_models.Product,
        {'product': {"description": "desc", "title": None}}
    )

    self.assert400(response)
    self.assertEqual(response.json, "'title' must be specified")

  @ddt.data(
      ('a', 'a'),
      ('  a  ', 'a'),
      ('', ''),
      ('  ', ''),
  )
  @ddt.unpack
  def test_post_title_is_valid(self, title, expected):
    """Test object creation request title={0!r}"""
    response = self.api.post(
        all_models.Product,
        {'product': {"description": "desc", "title": title}}
    )

    self.assertStatus(response, 201)
    product = all_models.Product.query.get(response.json['product']['id'])
    self.assertEqual(product.title, expected)
Ejemplo n.º 3
0
class BaseTestProposalApi(TestCase):
    """Base TestCase class proposal apip tests."""
    def setUp(self):
        super(BaseTestProposalApi, self).setUp()
        self.api = Api()
        self.client.get("/login")

    def create_proposal(self, instance, **context):
        """Create proposal."""
        data = context.copy()
        data["instance"] = {"id": instance.id, "type": instance.type}
        resp = self.api.post(all_models.Proposal, {"proposal": data})
        self.assertEqual(201, resp.status_code)
        return resp

    def update_proposal_status(self, proposal, status, resp_status, **context):
        """Update proposal status via api."""
        data = {"status": status}
        data.update(context)
        resp = self.api.put(proposal, {"proposal": data})
        self.assertEqual(resp_status, resp.status_code)
        return resp

    def decline_proposal(self, proposal, resp_status=200, **context):
        return self.update_proposal_status(proposal, proposal.STATES.DECLINED,
                                           resp_status, **context)

    def apply_proposal(self, proposal, resp_status=200, **context):
        return self.update_proposal_status(proposal, proposal.STATES.APPLIED,
                                           resp_status, **context)

    @staticmethod
    def revision_query_for(obj):
        return all_models.Revision.query.filter(
            all_models.Revision.resource_type == obj.type,
            all_models.Revision.resource_id == obj.id)

    def latest_revision_for(self, obj):
        return self.revision_query_for(obj).order_by(
            all_models.Revision.id.desc()).first()

    @contextlib.contextmanager
    def number_obj_revisions_for(self, obj, increase_on=1):
        """Context manager,

    checks the number of logged revisions after nested operations."""
        revision_query = self.revision_query_for(obj)
        start_count = revision_query.count()
        yield
        expected = start_count + increase_on
        current = revision_query.count()
        msg = ("Object change isn't logged correctly: "
               "expected number {expected} is not equal to {current}.")
        self.assertEqual(expected, current,
                         msg.format(expected=expected, current=current))
Ejemplo n.º 4
0
class TestArchivedAuditObjectCreation(TestCase):
  """Test creation permissions in audit"""

  def setUp(self):
    """Prepare data needed to run the tests"""
    TestCase.clear_data()
    self.api = Api()
    self.client.get("/login")
    self.archived_audit = factories.AuditFactory(
        archived=True
    )
    self.archived_audit.context = factories.ContextFactory(
        name="Audit context",
        related_object=self.archived_audit,
    )
    self.audit = factories.AuditFactory()
    self.assessment = factories.AssessmentFactory()

  @data(
      (all_models.Assessment, 403),
      (all_models.AssessmentTemplate, 403),
      (all_models.Issue, 201),
      (all_models.Relationship, 403),
  )
  @unpack
  def test_object_creation(self, obj, archived_status):
    """Test object creation in audit and archived audit"""
    audit = self.audit.id, self.audit.context.id
    archived_audit = self.archived_audit.id, self.archived_audit.context.id
    assessment_id = self.assessment.id
    response = self.api.post(
        obj, _create_obj_dict(obj, audit[0], audit[1], assessment_id))
    assert response.status_code == 201, \
        "201 not returned for {} on audit, received {} instead".format(
            obj._inflector.model_singular, response.status_code)

    response = self.api.post(obj, _create_obj_dict(
        obj, archived_audit[0], archived_audit[1], assessment_id))
    assert response.status_code == archived_status, \
        "403 not raised for {} on archived audit, received {} instead".format(
            obj._inflector.model_singular, response.status_code)
Ejemplo n.º 5
0
class TestArchivedAuditObjectCreation(TestCase):
  """Test creation permissions in audit"""

  def setUp(self):
    """Prepare data needed to run the tests"""
    TestCase.clear_data()
    self.api = Api()
    self.client.get("/login")
    self.archived_audit = factories.AuditFactory(
        archived=True
    )
    self.archived_audit.context = factories.ContextFactory(
        name="Audit context",
        related_object=self.archived_audit,
    )
    self.audit = factories.AuditFactory()
    self.assessment = factories.AssessmentFactory()

  @data(
      (all_models.Assessment, 403),
      (all_models.AssessmentTemplate, 403),
      (all_models.Issue, 201),
      (all_models.Relationship, 403),
  )
  @unpack
  def test_object_creation(self, obj, archived_status):
    """Test object creation in audit and archived audit"""
    audit = self.audit.id, self.audit.context.id
    archived_audit = self.archived_audit.id, self.archived_audit.context.id
    assessment_id = self.assessment.id
    response = self.api.post(
        obj, _create_obj_dict(obj, audit[0], audit[1], assessment_id))
    assert response.status_code == 201, \
        "201 not returned for {} on audit, received {} instead".format(
            obj._inflector.model_singular, response.status_code)

    response = self.api.post(obj, _create_obj_dict(
        obj, archived_audit[0], archived_audit[1], assessment_id))
    assert response.status_code == archived_status, \
        "403 not raised for {} on archived audit, received {} instead".format(
            obj._inflector.model_singular, response.status_code)
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)
Ejemplo n.º 7
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)
Ejemplo n.º 8
0
 def test_create_from_ggrc(self, definition_type, title):
     """Test create definition not allowed for GGRC."""
     api = Api()
     payload = [{
         "custom_attribute_definition": {
             "attribute_type": "Text",
             "context": {
                 "id": None
             },
             "definition_type": definition_type,
             "helptext": "Some text",
             "mandatory": False,
             "modal_title": "Modal title",
             "placeholder": "Placeholder",
             "title": title
         }
     }]
     response = api.post(all_models.CustomAttributeDefinition, payload)
     self.assertEqual(response.status_code, 405)
Ejemplo n.º 9
0
 def test_create_from_ggrc(self, definition_type, title):
   """Test create definition not allowed for GGRC."""
   api = Api()
   payload = [
       {
           "custom_attribute_definition": {
               "attribute_type": "Text",
               "context": {"id": None},
               "definition_type": definition_type,
               "helptext": "Some text",
               "mandatory": False,
               "modal_title": "Modal title",
               "placeholder": "Placeholder",
               "title": title
           }
       }
   ]
   response = api.post(all_models.CustomAttributeDefinition, payload)
   self.assertEqual(response.status_code, 405)
Ejemplo n.º 10
0
  def test_create_from_ggrcq(self, definition_type, title):
    """Test create definition only for GGRCQ."""
    api = Api()
    payload = [
        {
            "custom_attribute_definition": {
                "attribute_type": "Text",
                "context": {"id": None},
                "definition_type": definition_type,
                "helptext": "",
                "mandatory": False,
                "modal_title": "Title",
                "placeholder": "",
                "title": title
            }
        }
    ]

    with api.as_external():
      response = api.post(all_models.CustomAttributeDefinition, payload)
      self.assertEqual(response.status_code, 200)
Ejemplo n.º 11
0
    def test_create_from_ggrcq(self, definition_type, title):
        """Test create definition only for GGRCQ."""
        api = Api()
        payload = [{
            "custom_attribute_definition": {
                "attribute_type": "Text",
                "context": {
                    "id": None
                },
                "definition_type": definition_type,
                "helptext": "",
                "mandatory": False,
                "modal_title": "Title",
                "placeholder": "",
                "title": title
            }
        }]

        with api.as_external():
            response = api.post(all_models.CustomAttributeDefinition, payload)
            self.assertEqual(response.status_code, 200)
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
class TestCreator(TestCase):
  """ TestCreator """

  def setUp(self):
    super(TestCreator, 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 = [("creator", "Creator"), ("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 test_admin_page_access(self):
    """Permissions to admin page."""
    for role, code in (("creator", 403), ("admin", 200)):
      self.api.set_user(self.users[role])
      self.assertEqual(self.api.client.get("/admin").status_code, code)

  def test_creator_can_crud(self):
    """ Test Basic create/read,update/delete operations """
    self.api.set_user(self.users["creator"])
    creator_id = self.users["creator"].id
    audit_id = factories.AuditFactory().id
    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": creator_id,
                },
                "audit": {  # this is ignored on everything but Issues
                    "id": audit_id,
                    "type": "Audit",
                }
            },
        })
        if response.status_code != 201:
          all_errors.append("{} post creation failed {} {}".format(
              model_singular, response.status, response.data))
          continue

        # Test GET when not owner
        obj_id = response.json.get(table_singular).get("id")
        response = self.api.get(model, obj_id)
        if response.status_code != 403:  # we are not onwers yet
          all_errors.append(
              "{} can retrieve object if not owner".format(model_singular))
          continue
        response = self.api.get_collection(model, obj_id)
        collection = response.json.get(
            "{}_collection".format(table_plural)).get(table_plural)
        if collection:
          all_errors.append(
              "{} can retrieve object if not owner (collection)"
              .format(model_singular))
          continue

        # Test GET when owner
        acr = all_models.AccessControlRole.query.filter_by(
            object_type=model_singular,
            name="Admin"
        ).first()
        factories.AccessControlListFactory(
            object_id=obj_id,
            object_type=model_singular,
            ac_role=acr,
            person_id=creator_id
        )
        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_creator_search(self):
    """Test if creator can see the correct object while using the 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['creator'])
    acr_id = all_models.AccessControlRole.query.filter_by(
        object_type="Policy",
        name="Admin"
    ).first().id
    response = self.api.post(all_models.Policy, {
        "policy": {
            "title": "Creator Policy",
            "context": None,
            "access_control_list": [
                acl_helper.get_acl_json(acr_id, self.users["creator"].id)],
        },
    })
    response.json.get("policy").get("id")
    response, _ = self.api.search("Regulation,Policy")
    entries = response.json["results"]["entries"]
    self.assertEqual(len(entries), 1)
    self.assertEqual(entries[0]["type"], "Policy")
    response, _ = self.api.search("Regulation,Policy", counts=True)
    self.assertEqual(response.json["results"]["counts"]["Policy"], 1)
    self.assertEqual(
        response.json["results"]["counts"].get("Regulation"), None)

  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_creator_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['creator'])
    creator_count = self._get_count("Person")
    self.assertEqual(admin_count, creator_count)

  def test_relationships_access(self):
    """Check if creator cannot 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['creator'])
    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, 0)

  def test_revision_access(self):
    """Check if creator can access the right revision objects."""

    def gen(title, extra_data=None):
      """Generates section."""
      section_content = {"title": title, "context": None}
      if extra_data:
        section_content.update(**extra_data)
      return self.generator.generate(all_models.Section, "section", {
          "section": section_content
      })[1]

    def check(obj, expected):
      """Check that how many revisions of an object current user can see."""
      response = self.api.get_query(
          all_models.Revision,
          "resource_type={}&resource_id={}".format(obj.type, obj.id)
      )
      self.assertEqual(response.status_code, 200)
      self.assertEqual(
          len(response.json['revisions_collection']['revisions']),
          expected
      )

    self.api.set_user(self.users["admin"])
    obj_1 = gen("Test Section 1")

    self.api.set_user(self.users["creator"])
    acr_id = all_models.AccessControlRole.query.filter_by(
        object_type="Section",
        name="Admin"
    ).first().id
    linked_acl = {
        "access_control_list": [
            acl_helper.get_acl_json(acr_id, self.users["creator"].id)],
    }
    check(obj_1, 0)
    obj_2 = gen("Test Section 2", linked_acl)
    obj2_acl = obj_2.access_control_list[0]
    check(obj_2, 1)
    check(obj2_acl, 1)

  @ddt.data("creator", "admin")
  def test_count_type_in_accordion(self, glob_role):
    """Return count of Persons in DB for side accordion."""
    self.api.set_user(self.users[glob_role])
    ocordion_api_person_count_link = (
        "/search?"
        "q=&types=Program%2CWorkflow_All%2C"
        "Audit%2CAssessment%2CIssue%2CRegulation%2C"
        "Policy%2CStandard%2CContract%2CClause%2CSection%2CControl%2C"
        "Objective%2CPerson%2COrgGroup%2CVendor%2CAccessGroup%2CSystem%2C"
        "Process%2CDataAsset%2CProduct%2CProject%2CFacility%2C"
        "Market%2CRisk%2CThreat&counts_only=true&"
        "extra_columns=Workflow_All%3DWorkflow%2C"
        "Workflow_Active%3DWorkflow%2CWorkflow_Draft%3D"
        "Workflow%2CWorkflow_Inactive%3DWorkflow&contact_id=1&"
        "extra_params=Workflow%3Astatus%3DActive%3BWorkflow_Active"
        "%3Astatus%3DActive%3BWorkflow_Inactive%3Astatus%3D"
        "Inactive%3BWorkflow_Draft%3Astatus%3DDraft"
    )
    resp = self.api.client.get(ocordion_api_person_count_link)
    self.assertIn("Person", resp.json["results"]["counts"])
    self.assertEqual(all_models.Person.query.count(),
                     resp.json["results"]["counts"]["Person"])

  @ddt.data(
      ("/api/revisions?resource_type={}&resource_id={}", 1),
      ("/api/revisions?source_type={}&source_id={}", 0),
      ("/api/revisions?destination_type={}&destination_id={}", 1),
  )
  @ddt.unpack
  def test_changelog_access(self, link, revision_count):
    """Test accessing changelog under GC user who is assigned to object"""
    with factories.single_commit():
      audit = factories.AuditFactory()
      asmnt = factories.AssessmentFactory(audit=audit)
      asmnt_id = asmnt.id
      factories.RelationshipFactory(source=audit, destination=asmnt)
      verifier_role = all_models.AccessControlRole.query.filter_by(
          object_type="Assessment",
          name="Verifiers",
      ).first()
      factories.AccessControlListFactory(
          person=self.users["creator"],
          ac_role=verifier_role,
          object=asmnt,
      )

    self.api.set_user(self.users["creator"])
    response = self.api.client.get(link.format("Assessment", asmnt_id))
    self.assert200(response)
    self.assertEqual(
        len(response.json.get("revisions_collection", {}).get("revisions")),
        revision_count
    )

  @ddt.data(all_models.ControlCategory, all_models.ControlAssertion)
  def test_permissions_for_categories(self, category_model):
    """Test get collection for {0}."""
    self.api.set_user(self.users["creator"])
    resp = self.api.get_collection(category_model, None)
    plural_name = category_model._inflector.table_plural
    key_name = "{}_collection".format(plural_name)
    self.assertIn(key_name, resp.json)
    self.assertIn(plural_name, resp.json[key_name])
    collection = resp.json[key_name][plural_name]
    self.assertTrue(collection, "Collection shouldn't be empty")
Ejemplo n.º 14
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")]
        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):
        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",
        ])
        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,
                            "reference_url": "ref",
                            "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 len(collection) == 0:
                    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)
Ejemplo n.º 15
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"])
Ejemplo n.º 16
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()
class TestPermissions(TestCase):
    """Test checks permissions for proposals."""
    def setUp(self):
        super(TestPermissions, self).setUp()
        self.api = Api()
        roles = {r.name: r for r in all_models.Role.query.all()}
        ac_roles = {
            r.name: r
            for r in all_models.AccessControlRole.query.all()
        }
        with factories.single_commit():
            self.control = factories.ControlFactory()
            acrs = {
                "ACL_Reader":
                factories.AccessControlRoleFactory(name="ACL_Reader",
                                                   object_type="Control",
                                                   update=0),
                "ACL_Editor":
                factories.AccessControlRoleFactory(name="ACL_Editor",
                                                   object_type="Control"),
            }
            self.program = factories.ProgramFactory()
            self.program.context.related_object = self.program
            self.relationship = factories.RelationshipFactory(
                source=self.program,
                destination=self.control,
                context=self.program.context,
            )
            self.people = {
                "Creator": factories.PersonFactory(),
                "Reader": factories.PersonFactory(),
                "Editor": factories.PersonFactory(),
                "Administrator": factories.PersonFactory(),
                "ACL_Reader": factories.PersonFactory(),
                "ACL_Editor": factories.PersonFactory(),
                "Program Editors": factories.PersonFactory(),
                "Program Managers": factories.PersonFactory(),
                "Program Readers": factories.PersonFactory(),
            }
            for role_name in ["Creator", "Reader", "Editor", "Administrator"]:
                rbac_factories.UserRoleFactory(role=roles[role_name],
                                               person=self.people[role_name])
            for role_name in [
                    "Program Editors", "Program Managers", "Program Readers"
            ]:
                person = self.people[role_name]
                rbac_factories.UserRoleFactory(role=roles["Creator"],
                                               person=person)
                factories.AccessControlListFactory(
                    ac_role=ac_roles[role_name],
                    object=self.program,
                    person=self.people[role_name])
            self.proposal = factories.ProposalFactory(
                instance=self.control,
                content={
                    "access_control_list": {},
                    "custom_attribute_values": {},
                    "fields": {},
                    "mapping_fields": {},
                    "mapping_list_fields": {},
                })
            for role_name in ["ACL_Reader", "ACL_Editor"]:
                rbac_factories.UserRoleFactory(role=roles["Creator"],
                                               person=self.people[role_name])
                factories.AccessControlListFactory(
                    ac_role=acrs[role_name],
                    object=self.control,
                    person=self.people[role_name])
            proposal_model.set_acl_to_all_proposals_for(self.control)

    @ddt.data(
        ("Creator", 403),
        ("Reader", 200),
        ("Editor", 200),
        ("ACL_Reader", 200),
        ("ACL_Editor", 200),
        ("Administrator", 200),
        ("Program Editors", 200),
        ("Program Managers", 200),
        ("Program Readers", 200),
    )
    @ddt.unpack
    def test_permissions_on_get(self, role_name, status):
        """Test get proposals for {0}."""
        proposal_id = self.proposal.id
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api.get(all_models.Proposal, proposal_id)
        self.assertEqual(status, resp.status_code)

    def api_proposal_status_change(self, proposal_id, status):
        return self.api.put(all_models.Proposal.query.get(proposal_id),
                            {"proposal": {
                                "status": status
                            }})

    @ddt.data(("Creator", 403), ("Reader", 403), ("Editor", 200),
              ("Administrator", 200), ("ACL_Reader", 403), ("ACL_Editor", 200),
              ("Program Editors", 200), ("Program Managers", 200),
              ("Program Readers", 403))
    @ddt.unpack
    def test_permissions_on_apply(self, role_name, status):
        """Test apply proposals for {0}."""
        proposal_id = self.proposal.id
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api_proposal_status_change(
            proposal_id, all_models.Proposal.STATES.APPLIED)
        self.assertEqual(status, resp.status_code)

    @ddt.data(
        ("Creator", 403),
        ("Reader", 403),
        ("Editor", 200),
        ("ACL_Reader", 403),
        ("ACL_Editor", 200),
        ("Administrator", 200),
        ("Program Editors", 200),
        ("Program Managers", 200),
        ("Program Readers", 403),
    )
    @ddt.unpack
    def test_permissions_on_decline(self, role_name, status):
        """Test decline proposals for {0}."""
        proposal_id = self.proposal.id
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api_proposal_status_change(
            proposal_id, all_models.Proposal.STATES.DECLINED)
        self.assertEqual(status, resp.status_code)

    @ddt.data(
        ("Creator", 403),
        ("Reader", 201),
        ("Editor", 201),
        ("ACL_Reader", 201),
        ("ACL_Editor", 201),
        ("Administrator", 201),
        ("Program Editors", 201),
        ("Program Managers", 201),
        ("Program Readers", 201),
    )
    @ddt.unpack
    def test_permissions_on_create(self, role_name, status):
        """Test create proposal for {0}."""
        data = {
            "proposal": {
                "instance": {
                    "id": self.control.id,
                    "type": self.control.type,
                },
                "full_instance_content": {
                    "title": "new_title"
                },
                "agenda": "update cav",
                "context": None,
            }
        }
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api.post(all_models.Proposal, data)
        self.assertEqual(status, resp.status_code)
Ejemplo n.º 18
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"])
Ejemplo n.º 19
0
class BaseTestProposalApi(TestCase):
  """Base TestCase class proposal apip tests."""

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

  def create_proposal(self, instance, **context):
    """Create proposal."""
    data = context.copy()
    data["instance"] = {"id": instance.id, "type": instance.type}
    resp = self.api.post(all_models.Proposal, {"proposal": data})
    self.assertEqual(201, resp.status_code)
    return resp

  def update_proposal_status(self, proposal, status, resp_status, **context):
    """Update proposal status via api."""
    data = {"status": status}
    data.update(context)
    resp = self.api.put(proposal, {"proposal": data})
    self.assertEqual(resp_status, resp.status_code)
    return resp

  def decline_proposal(self, proposal, resp_status=200, **context):
    return self.update_proposal_status(proposal,
                                       proposal.STATES.DECLINED,
                                       resp_status,
                                       **context)

  def apply_proposal(self, proposal, resp_status=200, **context):
    return self.update_proposal_status(proposal,
                                       proposal.STATES.APPLIED,
                                       resp_status,
                                       **context)

  @staticmethod
  def revision_query_for(obj):
    return all_models.Revision.query.filter(
        all_models.Revision.resource_type == obj.type,
        all_models.Revision.resource_id == obj.id
    )

  def latest_revision_for(self, obj):
    return self.revision_query_for(
        obj
    ).order_by(
        all_models.Revision.id.desc()
    ).first()

  @contextlib.contextmanager
  def number_obj_revisions_for(self, obj, increase_on=1):
    """Context manager,

    checks the number of logged revisions after nested operations."""
    revision_query = self.revision_query_for(obj)
    start_count = revision_query.count()
    yield
    expected = start_count + increase_on
    current = revision_query.count()
    msg = ("Object change isn't logged correctly: "
           "expected number {expected} is not equal to {current}.")
    self.assertEqual(expected,
                     current,
                     msg.format(expected=expected, current=current))
Ejemplo n.º 20
0
class TestDocument(TestCase):
  """Document test cases"""
  # pylint: disable=invalid-name

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

  def test_get_parent_obj_control_type(self):
    """Test mapping parent of Control type"""
    control = factories.ControlFactory()
    document = factories.DocumentFileFactory(
        parent_obj={
            'id': control.id,
            'type': 'Control'
        })
    expected_control = document.related_objects(_types=[control.type]).pop()
    self.assertEqual(expected_control, control)

  def test_parent_obj_validation_is_id_presents(self):
    """Validation parent_obj id should present."""
    with self.assertRaises(exceptions.ValidationError):
      factories.DocumentFileFactory(
          parent_obj={
              'type': 'Control'
          })

  def test_parent_obj_validation_is_type_presents(self):
    """Validation parent_obj type should present."""
    control = factories.ControlFactory()
    with self.assertRaises(exceptions.ValidationError):
      factories.DocumentFileFactory(
          parent_obj={
              'id': control.id
          })

  def test_parent_obj_validation_wrong_type(self):
    """Validation parent_obj type.

    Type should be in 'Control', 'Issue', 'RiskAssessment'.
    """
    control = factories.ControlFactory()
    with self.assertRaises(exceptions.ValidationError):
      factories.DocumentFileFactory(
          parent_obj={
              'id': control.id,
              'type': 'Program'
          })

  def test_update_title(self):
    """Test update document title."""
    create_title = "test_title"
    update_title = "update_test_title"
    document = factories.DocumentFactory(title=create_title)
    response = self.api.put(document, {"title": update_title})
    self.assert200(response)
    self.assertEqual(all_models.Document.query.get(document.id).title,
                     update_title)

  def create_document_by_type(self, kind):
    """Create document with sent type."""
    data = {
        "title": "test_title",
        "link": "test_link",
    }
    if kind is not None:
      data["kind"] = kind
    kind = kind or all_models.Document.REFERENCE_URL
    resp, doc = self.gen.generate_object(
        all_models.Document,
        data
    )
    self.assertTrue(
        all_models.Document.query.filter(
            all_models.Document.id == resp.json["document"]["id"],
            all_models.Document.kind == kind,
        ).all()
    )
    return (resp, doc)

  def test_create_reference_url(self):
    """Test create reference url."""
    self.create_document_by_type(all_models.Document.REFERENCE_URL)

  def test_create_reference_url_default(self):
    """Test create reference url(default)."""
    self.create_document_by_type(None)

  def test_create_evidence(self):
    """Test create evidence."""
    self.create_document_by_type(all_models.Document.FILE)

  def test_create_invalid_type(self):
    """Test validation kind."""
    data = {
        "kind": 3,
        "title": "test_title",
        "link": "test_link",
        "owners": [self.gen.create_stub(all_models.Person.query.first())],
    }
    obj_name = all_models.Document._inflector.table_singular
    obj = all_models.Document()
    obj_dict = self.gen.obj_to_dict(obj, obj_name)
    obj_dict[obj_name].update(data)
    resp = self.api.post(all_models.Document, obj_dict)
    self.assert400(resp)
    self.assertEqual('"Invalid value for attribute kind. '
                     'Expected options are `FILE`, '
                     '`REFERENCE_URL`"',
                     resp.data)

  def test_header_on_expected_error(self):
    """During authorization flow we have the expected 'Unauthorized'.

    To allow FE ignore the error popup we need to set
    'X-Expected-Error' header
    """
    control = factories.ControlFactory()
    response = self.api.post(all_models.Document, [{
        "document": {
            "kind": all_models.Document.FILE,
            "source_gdrive_id": "some link",
            "link": "some link",
            "title": "some title",
            "context": None,
            "parent_obj": {
                "id": control.id,
                "type": "Control"
            }
        }
    }])
    self.assertEqual(response.status_code, 401)
    self.assertIn('X-Expected-Error', response.headers)

  def test_header_on_unexpected_error(self):
    """During authorization flow we have the expected 'Unauthorized'.

    If error is unexpected we need to make sure that 'X-Expected-Error'
    header is not set.
    """
    # pylint: disable=unused-argument
    def side_effect_function(*args, **kwargs):
      raise Unauthorized("Unable to get valid credentials")

    with mock.patch("ggrc.gdrive.file_actions.get_gdrive_file_link") as mocked:
      mocked.side_effect = side_effect_function
      control = factories.ControlFactory()
      response = self.api.post(all_models.Document, [{
          "document": {
              "kind": all_models.Document.FILE,
              "source_gdrive_id": "some link",
              "link": "some link",
              "title": "some title",
              "context": None,
              "parent_obj": {
                  "id": control.id,
                  "type": "Control"
              }
          }
      }])
    self.assertEqual(response.status_code, 401)
    self.assertNotIn('X-Expected-Error', response.headers)

  def test_header_on_expected_error_batch(self):
    """During authorization flow we have the expected 'Unauthorized'.

    To allow FE ignore popup we need to set 'X-Expected-Error' header
    """
    # pylint: disable=unused-argument
    def side_effect_function(*args, **kwargs):
      raise GdriveUnauthorized("Unable to get valid credentials")

    with mock.patch("ggrc.gdrive.file_actions.get_gdrive_file_link") as mocked:
      mocked.side_effect = side_effect_function
      control = factories.ControlFactory()

      doc1 = {
          "document": {
              "kind": all_models.Document.FILE,
              "source_gdrive_id": "some link",
              "link": "some link",
              "title": "some title",
              "context": None,
              "parent_obj": {
                  "id": control.id,
                  "type": "Control"
              }
          }
      }
      doc2 = {
          "document": {
              "kind": all_models.Document.REFERENCE_URL,
              "link": "some link",
              "title": "some title",
              "context": None,
          }
      }

    response = self.api.post(all_models.Document, [doc1, doc2])
    self.assertEqual(response.status_code, 401)
    self.assertIn('X-Expected-Error', response.headers)

  def test_create_document_by_api(self,
                                  kind=all_models.Document.REFERENCE_URL):
    """Test crete document via POST"""
    document_data = dict(
        title='Simple title',
        kind=kind,
        link='some_url.com',
        description='mega description'
    )
    _, document = self.gen.generate_object(
        all_models.Document,
        document_data
    )

    result = all_models.Document.query.filter(
        all_models.Document.id == document.id).one()

    self.assertEqual(result.title, 'Simple title')
    self.assertEqual(result.kind, kind)
    self.assertEqual(result.link, 'some_url.com')
    self.assertEqual(result.description, 'mega description')

  @mock.patch('ggrc.gdrive.file_actions.get_gdrive_file_link',
              dummy_gdrive_response_link)
  def test_create_document_file_by_api(self, kind=all_models.Document.FILE):
    """Test crete document.FILE via POST"""
    document_data = dict(
        title='Simple title',
        kind=kind,
        source_gdrive_id='1234',
        description='mega description'
    )
    _, document = self.gen.generate_object(
        all_models.Document,
        document_data
    )

    result = all_models.Document.query.filter(
        all_models.Document.id == document.id).one()

    self.assertEqual(result.slug, 'DOCUMENT-{}'.format(result.id))
    self.assertEqual(result.title, 'Simple title')
    self.assertEqual(result.kind, kind)
    self.assertEqual(result.link, 'http://mega.doc')
    self.assertEqual(result.description, 'mega description')
    self.assertEqual(result.status, all_models.Document.START_STATE)

  def test_document_ref_url_type_with_parent(self):
    """Document of REFERENCE_URL type mapped to parent if parent specified"""
    control = factories.ControlFactory()
    document = factories.DocumentReferenceUrlFactory(
        description='mega description',
        parent_obj={
            'id': control.id,
            'type': 'Control'
        }
    )
    rel_evidences = control.related_objects(_types=[document.type])
    self.assertEqual(document, rel_evidences.pop())

  def test_document_make_admin_endpoint(self):
    """Test /api/document/make_admin endpoint

    should add current user as document admin
    """

    _, editor = self.gen.generate_person(
        user_role="Creator"
    )

    doc = factories.DocumentFileFactory(gdrive_id="123")
    doc_id = doc.id
    self.api.set_user(editor)
    request_data = json.dumps(dict(gdrive_ids=["123", "456"]))
    response = self.api.client.post("/api/document/make_admin",
                                    data=request_data,
                                    content_type="application/json")

    updated = [obj for obj in response.json if obj["updated"]]
    not_updated = [obj for obj in response.json if not obj["updated"]]

    self.assertEquals(len(updated), 1)
    self.assertEquals(updated[0]["object"]["id"], doc_id)
    self.assertEquals(len(not_updated), 1)

    doc = all_models.Document.query.filter_by(id=doc_id).one()
    self.assertEquals(len(doc.access_control_list), 1)
    control_user = all_models.Person.query.get(editor.id)
    self.assertIn(control_user.id,
                  [acr.person_id for acr in doc.access_control_list])

  def test_api_documents_exist(self):
    """Test /api/document/documents_exist"""
    with factories.single_commit():
      doc1 = factories.DocumentFileFactory(gdrive_id="123")
      doc1_id = doc1.id
      factories.DocumentFileFactory(gdrive_id="456")
    endpoint_uri = "/api/document/documents_exist"
    request_data1 = json.dumps(dict(gdrive_ids=["123", "456"]))
    response1 = self.api.client.post(endpoint_uri, data=request_data1,
                                     content_type="application/json")

    self.assertEquals(len(response1.json), 2)
    self.assertTrue(all([r["exists"] for r in response1.json]))

    request_data2 = json.dumps(dict(gdrive_ids=["123", "999"]))
    response2 = self.api.client.post(endpoint_uri, data=request_data2,
                                     content_type="application/json")
    self.assertEquals(len(response2.json), 2)
    existing = [obj for obj in response2.json if obj["exists"]]
    not_existing = [obj for obj in response2.json if not obj["exists"]]
    self.assertEquals(len(existing), 1)
    self.assertEquals(len(not_existing), 1)
    self.assertEquals(existing[0]["object"]["id"], doc1_id)

  def test_add_to_parent_folder(self):
    """If parent has folder => add document to that folder"""
    method_to_patch = 'ggrc.gdrive.file_actions.add_gdrive_file_folder'
    with mock.patch(method_to_patch) as mocked:
      mocked.return_value = 'http://mega.doc'
      with factories.single_commit():
        control = factories.ControlFactory(folder="gdrive_folder_id")
        factories.DocumentFileFactory(
            source_gdrive_id="source_gdrive_id",
            parent_obj={
                "id": control.id,
                "type": "Control"
            }
        )
    mocked.assert_called_with("source_gdrive_id", "gdrive_folder_id")

  def test_add_to_parent_folder_relationship(self):
    """If parent has folder => add document to that folder mapped via rel"""
    method_to_patch = 'ggrc.gdrive.file_actions.add_gdrive_file_folder'
    with mock.patch(method_to_patch) as mocked:
      mocked.return_value = 'http://mega.doc'
      with factories.single_commit():
        control = factories.ControlFactory(folder="gdrive_folder_id")
        control_id = control.id
        doc = factories.DocumentFileFactory(
            source_gdrive_id="source_gdrive_id",
            link='some link'
        )
        doc_id = doc.id

      response = self.api.post(all_models.Relationship, {
          "relationship": {
              "source": {"id": control_id, "type": control.type},
              "destination": {"id": doc_id, "type": doc.type},
              "context": None
          },
      })

    self.assertStatus(response, 201)
    mocked.assert_called_with("source_gdrive_id", "gdrive_folder_id")

  def test_add_to_parent_folder_not_specified(self):
    """If parent has not folder => just save gdrive link"""
    with mock.patch('ggrc.gdrive.file_actions.get_gdrive_file_link') as mocked:
      mocked.return_value = 'http://mega.doc'
      with factories.single_commit():
        control = factories.ControlFactory()
        factories.DocumentFileFactory(
            source_gdrive_id="source_gdrive_id",
            parent_obj={
                "id": control.id,
                "type": "Control"
            }
        )
    mocked.assert_called_with("source_gdrive_id")
Ejemplo n.º 21
0
class TestEnableDisableNotifications(TestCase):
  """Test enable / disable notifications by user with
  specific global role.
  """
  def setUp(self):
    super(TestEnableDisableNotifications, self).setUp()
    self.api = Api()

  @ddt.data("Reader", "Creator", "Editor", "Administrator")
  def test_default_notif_settings(self, role_name):
    """Test setting 'Daily email digest' checkbox to False
    by the user with global role {0}."""
    with factories.single_commit():
      name = "Test Name"
      email = "*****@*****.**"
      person = factories.PersonFactory(name=name, email=email)
      role = all_models.Role.query.filter(
          all_models.Role.name == role_name
      ).one()
      rbac_factories.UserRoleFactory(role=role,
                                     person=person)
    person = all_models.Person.query.get(person.id)
    self.api.set_user(person=person)
    response = self.api.post(
        all_models.NotificationConfig,
        data={
            "notification_config": {
                "person_id": person.id,
                "notif_type": "Email_Digest",
                "enable_flag": True,
                "context": {
                    "id": None,
                    "type": "Context"
                }
            }
        },
    )
    self.assertEqual(response.status_code, 201)

  @ddt.data("Reader", "Creator", "Editor", "Administrator")
  def test_get_notif_settings(self, role_name):
    """Tests notification configs list is returned after
    it has been established by the user with role {0}."""
    with factories.single_commit():
      name = "Test Name"
      email = "*****@*****.**"
      person = factories.PersonFactory(name=name, email=email)
      role = all_models.Role.query.filter(
          all_models.Role.name == role_name
      ).one()
      rbac_factories.UserRoleFactory(role=role,
                                     person=person)
    person = all_models.Person.query.get(person.id)
    self.api.set_user(person=person)
    response = self.api.post(
        all_models.NotificationConfig,
        data={
            "notification_config": {
                "person_id": person.id,
                "notif_type": "Email_Digest",
                "enable_flag": True,
                "context": {
                    "id": None,
                    "type": "Context"
                }
            }
        },
    )
    self.assertEqual(response.status_code, 201)
    response = self.api.get_query(all_models.NotificationConfig,
                                  "person_id=%s" % person.id)
    result_configs_list = response.json['notification_configs_collection']
    self.assertTrue(result_configs_list['notification_configs'] != [])
Ejemplo 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()
Ejemplo 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")]
    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):
    return
    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):
    return
    """ Test Basic create/read,update/delete operations """
    self.api.set_user(self.users["reader"])
    all_errors = []
    base_models = set([
        "Control", "Assessment", "DataAsset", "Contract",
        "Policy", "Regulation", "Standard", "Document", "Facility",
        "Market", "Objective", "OrgGroup", "Vendor", "Product",
        "Clause", "System", "Process", "Issue", "Project", "AccessGroup",
    ])
    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,
                "reference_url": "ref",
                "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 len(collection) == 0:
          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):
    return
    """ 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},
    })
    obj_id = response.json.get("policy").get("id")
    self.api.post(all_models.ObjectOwner, {"object_owner": {
        "person": {
            "id": self.users['reader'].id,
            "type": "Person",
        }, "ownable": {
            "type": "Policy",
            "id": obj_id,
        }, "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):
    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)
Ejemplo n.º 24
0
class TestDocument(TestCase):
  """Document test cases"""
  # pylint: disable=invalid-name

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

  def test_update_title(self):
    """Test update document title."""
    create_title = "test_title"
    update_title = "update_test_title"
    document = factories.DocumentFactory(title=create_title)
    response = self.api.put(document, {"title": update_title})
    self.assert200(response)
    self.assertEqual(all_models.Document.query.get(document.id).title,
                     update_title)

  def create_document_by_type(self, doc_type):
    """Create docuemtn with sent type."""
    data = {
        "title": "test_title",
        "link": "test_link",
    }
    if doc_type is not None:
        data["document_type"] = doc_type
    doc_type = doc_type or all_models.Document.URL
    resp, doc = self.gen.generate_object(
        all_models.Document,
        data
    )
    self.assertTrue(
        all_models.Document.query.filter(
            all_models.Document.id == resp.json["document"]['id'],
            all_models.Document.document_type == doc_type,
        ).all()
    )
    return (resp, doc)

  def test_create_url(self):
    """Test create url."""
    self.create_document_by_type(all_models.Document.URL)

  def test_create_url_default(self):
    """Test create url(default)."""
    self.create_document_by_type(None)

  def test_create_evidence(self):
    """Test create evidence."""
    self.create_document_by_type(all_models.Document.ATTACHMENT)

  def test_create_invalid_type(self):
    """Test validation document_type."""
    data = {
        "document_type": 3,
        "title": "test_title",
        "link": "test_link",
        "owners": [self.gen.create_stub(all_models.Person.query.first())],
    }
    obj_name = all_models.Document._inflector.table_singular
    obj = all_models.Document()
    obj_dict = self.gen.obj_to_dict(obj, obj_name)
    obj_dict[obj_name].update(data)
    resp = self.api.post(all_models.Document, obj_dict)
    self.assert400(resp)
    self.assertEqual('"Invalid value for attribute document_type. '
                     'Expected options are `URL`, `EVIDENCE`."',
                     resp.data)
Ejemplo n.º 25
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",
            }]
        }

    def test_async_request_state_transitions(self):
        """Test asynchronous transitions"""
        # Due to complexity of the test and the actual need for all variables
        # pylint: disable=too-many-locals

        tgt_roles = role.get_ac_roles_for("TaskGroupTask")

        queue = Queue.Queue()
        wf = self.generator.generate_workflow(self.weekly_wf)[1]
        context_id = wf.context.id

        tg_id = all_models.TaskGroup.query.first().id
        obj_count = 10  # actual thread count is 20, 10 tgt + 10 tgo

        with factories.single_commit():
            person_id = factories.PersonFactory().id
            controls = [
                factories.ControlFactory().id for _ in range(obj_count)
            ]

        def create_tgo(context_id, tg_id, control_id):
            queue.put(
                self.api.post(all_models.TaskGroupObject, [{
                    "task_group_object": {
                        "context": {
                            "id": context_id,
                            "type": "Context"
                        },
                        "task_group": {
                            "id": tg_id,
                            "type": "TaskGroup"
                        },
                        "object": {
                            "id": control_id,
                            "type": "Control"
                        },
                    },
                }]))

        def create_tgt(context_id, tg_id, tgt_roles, person_id):
            queue.put(
                self.api.post(all_models.TaskGroupTask, [{
                    "task_group_task": {
                        "response_options": [],
                        "start_date":
                        "2018-03-29",
                        "end_date":
                        "2018-04-05T00:23:41.000Z",
                        "minStartDate":
                        "2018-03-29T00:23:41.576Z",
                        "access_control_list": [{
                            "ac_role_id":
                            tgt_roles["Task Assignees"].id,
                            "person": {
                                "id": person_id,
                                "type": "Person"
                            }
                        }],
                        "contact": {
                            "id": person_id,
                            "type": "Person"
                        },
                        "task_group": {
                            "id": tg_id,
                            "type": "TaskGroup"
                        },
                        "context": {
                            "id": context_id,
                            "type": "Context"
                        },
                        "sort_index":
                        "1",
                        "modal_title":
                        "Create New Task",
                        "title":
                        "Dummy task title",
                        "task_type":
                        "text",
                        "description":
                        "",
                        "slug":
                        "",
                    }
                }]))

        # Move all tasks to In Progress
        threads = []
        for control_id in controls:
            threads.append(
                Thread(target=create_tgo,
                       args=(context_id, tg_id, control_id)))
            threads.append(
                Thread(target=create_tgt,
                       args=(context_id, tg_id, tgt_roles, person_id)))

        for t in threads:
            t.start()
        for t in threads:
            t.join()

        while not queue.empty():
            response = queue.get()
            self.assert200(response, response.data)

        internal_acl_count = all_models.AccessControlList.query.filter(
            all_models.AccessControlList.parent_id.isnot(None)).count()
        self.assertEqual(
            internal_acl_count,
            (1 + 2 * obj_count) * 2,
            # wf role on 1 task group + number of tgo and tgt
            # times 2 is for all relationships that belong to each object
        )
Ejemplo n.º 26
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)
Ejemplo n.º 27
0
class TestReader(TestCase):
    """Test Assignable RBAC"""
    def setUp(self):
        super(TestReader, self).setUp()
        self.audit_id = factories.AuditFactory().id
        self.generator = Generator()
        self.api = Api()
        self.object_generator = ObjectGenerator()
        self.init_users()
        self.init_assignable()

    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_assignable(self):
        """Creates the assignable object used by all the tests"""
        self.api.set_user(self.users["editor"])
        response = self.api.post(
            all_models.Assessment, {
                "assessment": {
                    "title": "Assessment",
                    "context": None,
                    "audit": {
                        "id": self.audit_id,
                        "type": "Audit"
                    }
                }
            })
        obj_id = response.json.get("assessment").get("id")
        self.assertEqual(response.status_code, 201,
                         "Error setting up Assessment")
        self.obj_json = response.json
        self.obj = all_models.Assessment.query.get(obj_id)

    def _add_creator(self, asmnt, user):
        """Helper method for creating assignees on an object"""
        acr = all_models.AccessControlRole.query.filter(
            all_models.AccessControlRole.object_type == "Assessment",
            all_models.AccessControlRole.name == "Creators",
        ).first()
        return self.api.put(
            asmnt, {
                "access_control_list": [{
                    "ac_role_id": acr.id,
                    "person": {
                        "id": user.id
                    },
                    "type": "AccessControlList",
                }]
            })

    def test_basic_with_no_assignee(self):
        """Editor creates an Assessment, but doesn't assign Reader/Creator as
       assignee. Reader should have Read access, Creator should have no access
    """

        # Reader should have read access, but shouldn't be allowed to edit or
        # create another assingee
        self.api.set_user(self.users["reader"])
        response = self.api.get(all_models.Assessment, self.obj.id)
        self.assertEqual(response.status_code, 200)
        response = self.api.put(self.obj, self.obj_json)
        self.assertEqual(response.status_code, 403)
        response = self._add_creator(self.obj, self.users["reader"])
        self.assertEqual(response.status_code, 403)

        # Creator should have no access. We skip the put request because we can't
        # get the object etag.
        self.api.set_user(self.users["creator"])
        response = self.api.get(all_models.Assessment, self.obj.id)
        self.assertEqual(response.status_code, 403)
        response = self._add_creator(self.obj, self.users["reader"])
        self.assertEqual(response.status_code, 403)

    def test_basic_with_assignee(self):
        """Test if Reader/Creator have CRUD access once they become assignees"""

        # Admin adds reader as an assignee
        self.api.set_user(self.users["admin"])
        response = self._add_creator(self.obj, self.users["reader"])
        self.assertEqual(response.status_code, 200)

        # Reader is now allowed to update the object
        self.api.set_user(self.users["reader"])
        response = self.api.get(all_models.Assessment, self.obj.id)
        self.assertEqual(response.status_code, 200)
        response = self.api.put(self.obj, response.json)
        self.assertEqual(response.status_code, 200)

        # Reader adds creator as an assignee
        response = self._add_creator(self.obj, self.users["creator"])
        self.assertEqual(response.status_code, 200)

        # Creator now has CRUD access
        self.api.set_user(self.users["creator"])
        response = self.api.get(all_models.Assessment, self.obj.id)
        self.assertEqual(response.status_code, 200)
        response = self.api.put(self.obj, response.json)

        # Creator should even be allowed to add new assignees
        response = self._add_creator(self.obj, self.users["admin"])
        self.assertEqual(response.status_code, 200)

    def test_read_of_mapped_objects(self):
        """Test if assignees get Read access on all mapped objects"""

        # Editor creates a System object and maps it to the assignable object
        self.api.set_user(self.users["editor"])
        response = self.api.post(
            all_models.System,
            {"system": {
                "title": "System",
                "context": None,
            }})
        system_id = response.json.get("system").get("id")
        system = all_models.System.query.get(system_id)
        self.api.post(
            all_models.Relationship, {
                "relationship": {
                    "source": {
                        "id": self.obj.id,
                        "type": "Assessment"
                    },
                    "destination": {
                        "id": system_id,
                        "type": "System"
                    },
                    "context": None
                },
            })

        # Since creator is not an assignee she should not have access to any of the
        # two objects
        self.api.set_user(self.users["creator"])
        response = self.api.get(all_models.Assessment, self.obj.id)
        self.assertEqual(response.status_code, 403)
        response = self.api.get(all_models.System, system_id)
        self.assertEqual(response.status_code, 403)

        # Editor adds creator as an assignee
        self.api.set_user(self.users["editor"])
        response = self._add_creator(self.obj, self.users["creator"])
        self.assertEqual(response.status_code, 200)

        # Creator should now have read access on the mapped object
        self.api.set_user(self.users["creator"])
        response = self.api.get(all_models.System, system_id)
        self.assertEqual(response.status_code, 200)

        # But he should still not be allowed to update
        response = self.api.put(system, response.json)
        self.assertEqual(response.status_code, 403)
Ejemplo 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, [])
Ejemplo n.º 29
0
class TestWfNotifsGenerator(TestCase):
  """Test wf cycle tasks notifications generation."""
  def setUp(self):
    """Set up."""
    super(TestWfNotifsGenerator, self).setUp()
    self.api = Api()
    self.wf_generator = WorkflowsGenerator()
    self.object_generator = ObjectGenerator()
    Notification.query.delete()

    with freeze_time("2015-05-01 14:29:00"):
      wf_slug = "wf1"
      with factories.single_commit():
        wf = wf_factories.WorkflowFactory(slug=wf_slug)
        task_group = wf_factories.TaskGroupFactory(workflow=wf)
        wf_factories.TaskGroupTaskFactory(
            task_group=task_group,
            title='task1',
            start_date=datetime.now(),
            end_date=datetime.now() + timedelta(7)
        )
      data = workflow_api.get_cycle_post_dict(wf)
      self.api.post(all_models.Cycle, data)
      wf = all_models.Workflow.query.filter_by(slug=wf_slug).one()
      self.cycle = all_models.Cycle.query.filter_by(workflow_id=wf.id).one()
      self.ctask = all_models.CycleTaskGroupObjectTask.query.filter_by(
          cycle_id=self.cycle.id).first()

  def test_ctasks_notifs_generator_daily_digest(self):
    """Test cycle tasks notifications generation job."""
    with freeze_time("2015-05-01 14:29:00"):
      self.assert_notifications_for_object(self.cycle, "manual_cycle_created")
      self.assert_notifications_for_object(self.ctask,
                                           "manual_cycle_created",
                                           "cycle_task_due_in",
                                           "cycle_task_due_today",
                                           "cycle_task_overdue")

      # Move task to Finished
      self.wf_generator.modify_object(
          self.ctask, data={"status": "Verified"})
      generate_cycle_tasks_notifs()
      self.assert_notifications_for_object(self.cycle,
                                           "all_cycle_tasks_completed",
                                           "manual_cycle_created")

      # Undo finish
      self.wf_generator.modify_object(
          self.ctask, data={"status": "In Progress"})
      generate_cycle_tasks_notifs()
      self.assert_notifications_for_object(self.cycle, "manual_cycle_created")
      self.assert_notifications_for_object(self.ctask,
                                           "cycle_task_due_in",
                                           "cycle_task_due_today",
                                           "cycle_task_overdue")

      self.wf_generator.modify_object(
          self.ctask, data={"status": "Declined"})
      self.assert_notifications_for_object(self.ctask,
                                           "cycle_task_due_in",
                                           "cycle_task_due_today",
                                           "cycle_task_overdue",
                                           "cycle_task_declined")

  @ddt.data(("2015-05-01 14:29:00", ("all_cycle_tasks_completed",
                                     "manual_cycle_created")),
            ("2015-05-02 07:29:00", ("all_cycle_tasks_completed",
                                     "manual_cycle_created")),
            ("2015-05-02 14:29:00", ("all_cycle_tasks_completed",
                                     "manual_cycle_created")),
            ("2015-05-03 07:29:00", ("manual_cycle_created",)))
  @ddt.unpack
  def test_cycle_task_update_timelines(self, _datetime, notifications):
    """Test cycle task has been updated:
    1) the day before job is called;
    2) the same day job is called before 08:00 AM UTC;
    3) the same day job is called after 08:00 AM UTC;
    4) two days before job is called.
    """
    with freeze_time("2015-05-01 14:29:00"):
      # Move task to Finished
      self.wf_generator.modify_object(
          self.ctask, data={"status": "Verified"})
    with freeze_time(_datetime):
      generate_cycle_tasks_notifs()
      self.assert_notifications_for_object(self.cycle, *notifications)

  def test_ctasks_notifs_generator_daily_digest_called_twice(self):
    """No duplicated notifications should be generated"""
    with freeze_time("2015-05-01 14:29:00"):
      generate_cycle_tasks_notifs()
      self.assert_notifications_for_object(self.cycle, "manual_cycle_created")
      self.assert_notifications_for_object(self.ctask,
                                           "manual_cycle_created",
                                           "cycle_task_due_in",
                                           "cycle_task_due_today",
                                           "cycle_task_overdue")

      # Move task to Finished
      self.wf_generator.modify_object(
          self.ctask, data={"status": "Verified"})
      generate_cycle_tasks_notifs()
      generate_cycle_tasks_notifs()
      self.assert_notifications_for_object(self.cycle,
                                           "all_cycle_tasks_completed",
                                           "manual_cycle_created")

  def test_ctasks_notifs_generator_cron_job(self):
    """Test cycle tasks notifications generation cron job."""
    with freeze_time("2015-05-2 08:00:00"):
      generate_cycle_tasks_notifs()
      self.assert_notifications_for_object(self.cycle, "manual_cycle_created")
      self.assert_notifications_for_object(self.ctask,
                                           "manual_cycle_created",
                                           "cycle_task_due_in",
                                           "cycle_task_due_today",
                                           "cycle_task_overdue")
Ejemplo n.º 30
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())
Ejemplo 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)
Ejemplo n.º 32
0
class TestReader(TestCase):
  """Test Assignable RBAC"""

  def setUp(self):
    super(TestReader, self).setUp()
    self.audit_id = factories.AuditFactory().id
    self.generator = Generator()
    self.api = Api()
    self.object_generator = ObjectGenerator()
    self.init_users()
    self.init_assignable()

  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_assignable(self):
    """Creates the assignable object used by all the tests"""
    self.api.set_user(self.users["editor"])
    response = self.api.post(all_models.Assessment, {
        "assessment": {
            "title": "Assessment",
            "context": None,
            "audit": {
                "id": self.audit_id,
                "type": "Audit"
            }
        }
    })
    obj_id = response.json.get("assessment").get("id")
    self.assertEqual(response.status_code, 201, "Error setting up Assessment")
    self.obj_json = response.json
    self.obj = all_models.Assessment.query.get(obj_id)

  def _add_creator(self, asmnt, user):
    """Helper method for creating assignees on an object"""
    acr = all_models.AccessControlRole.query.filter(
        all_models.AccessControlRole.object_type == "Assessment",
        all_models.AccessControlRole.name == "Creators",
    ).first()
    return self.api.put(asmnt, {
        "access_control_list": [acl_helper.get_acl_json(acr.id, user.id)]
    })

  def test_basic_with_no_assignee(self):
    """Editor creates an Assessment, but doesn't assign Reader/Creator as
       assignee. Reader should have Read access, Creator should have no access
    """

    # Reader should have read access, but shouldn't be allowed to edit or
    # create another assingee
    self.api.set_user(self.users["reader"])
    response = self.api.get(all_models.Assessment, self.obj.id)
    self.assertEqual(response.status_code, 200)
    response = self.api.put(self.obj, self.obj_json)
    self.assertEqual(response.status_code, 403)
    response = self._add_creator(self.obj, self.users["reader"])
    self.assertEqual(response.status_code, 403)

    # Creator should have no access. We skip the put request because we can't
    # get the object etag.
    self.api.set_user(self.users["creator"])
    response = self.api.get(all_models.Assessment, self.obj.id)
    self.assertEqual(response.status_code, 403)
    response = self._add_creator(self.obj, self.users["reader"])
    self.assertEqual(response.status_code, 403)

  def test_basic_with_assignee(self):
    """Test if Reader/Creator have CRUD access once they become assignees"""

    # Admin adds reader as an assignee
    self.api.set_user(self.users["admin"])
    response = self._add_creator(self.obj, self.users["reader"])
    self.assertEqual(response.status_code, 200)

    # Reader is now allowed to update the object
    self.api.set_user(self.users["reader"])
    response = self.api.get(all_models.Assessment, self.obj.id)
    self.assertEqual(response.status_code, 200)
    response = self.api.put(self.obj, response.json)
    self.assertEqual(response.status_code, 200)

    # Reader adds creator as an assignee
    response = self._add_creator(self.obj, self.users["creator"])
    self.assertEqual(response.status_code, 200)

    # Creator now has CRUD access
    self.api.set_user(self.users["creator"])
    response = self.api.get(all_models.Assessment, self.obj.id)
    self.assertEqual(response.status_code, 200)
    response = self.api.put(self.obj, response.json)

    # Creator should even be allowed to add new assignees
    response = self._add_creator(self.obj, self.users["admin"])
    self.assertEqual(response.status_code, 200)

  def test_read_of_mapped_objects(self):
    """Test if assignees get Read access on all mapped objects"""

    # Editor creates a System object and maps it to the assignable object
    self.api.set_user(self.users["editor"])
    response = self.api.post(all_models.System, {
        "system": {
            "title": "System",
            "context": None,
        }
    })
    system_id = response.json.get("system").get("id")
    system = all_models.System.query.get(system_id)
    self.api.post(all_models.Relationship, {
        "relationship": {"source": {
            "id": self.obj.id,
            "type": "Assessment"
        }, "destination": {
            "id": system_id,
            "type": "System"
        }, "context": None},
    })

    # Since creator is not an assignee she should not have access to any of the
    # two objects
    self.api.set_user(self.users["creator"])
    response = self.api.get(all_models.Assessment, self.obj.id)
    self.assertEqual(response.status_code, 403)
    response = self.api.get(all_models.System, system_id)
    self.assertEqual(response.status_code, 403)

    # Editor adds creator as an assignee
    self.api.set_user(self.users["editor"])
    response = self._add_creator(self.obj, self.users["creator"])
    self.assertEqual(response.status_code, 200)

    # Creator should now have read access on the mapped object
    self.api.set_user(self.users["creator"])
    response = self.api.get(all_models.System, system_id)
    self.assertEqual(response.status_code, 403)

    # But he should still not be allowed to update
    response = self.api.put(system, response.json)
    self.assertEqual(response.status_code, 403)
Ejemplo n.º 33
0
class TestAssessmentGeneration(TestCase):
    """Test assessment generation"""
    def setUp(self):
        super(TestAssessmentGeneration, self).setUp()
        self.api = Api()

        self.audit = factories.AuditFactory()
        self.control = factories.ControlFactory(test_plan="Control Test Plan")
        revision = Revision.query.filter(
            Revision.resource_id == self.control.id, Revision.resource_type ==
            self.control.__class__.__name__).order_by(
                Revision.id.desc()).first()
        self.snapshot = factories.SnapshotFactory(
            parent=self.audit,
            child_id=self.control.id,
            child_type=self.control.__class__.__name__,
            revision_id=revision.id)

    def assessment_post(self, template=None):
        """Helper function to POST an assessment"""
        assessment_dict = {
            "_generated": True,
            "audit": {
                "id": self.audit.id,
                "type": "Audit"
            },
            "object": {
                "id": self.snapshot.id,
                "type": "Snapshot"
            },
            "context": {
                "id": self.audit.context.id,
                "type": "Context"
            },
            "title": "Temp title"
        }
        if template:
            assessment_dict["template"] = {
                "id": template.id,
                "type": "AssessmentTemplate"
            }

        return self.api.post(Assessment, {"assessment": assessment_dict})

    def test_autogenerated_title(self):
        """Test autogenerated assessment title"""
        control_title = self.control.title
        audit_title = self.audit.title
        response = self.assessment_post()
        title = response.json["assessment"]["title"]
        self.assertIn(audit_title, title)
        self.assertIn(control_title, title)

    def test_template_test_plan(self):
        """Test if generating assessments from template sets default test plan"""
        template = factories.AssessmentTemplateFactory(
            test_plan_procedure=False,
            procedure_description="Assessment Template Test Plan")
        response = self.assessment_post(template)
        self.assertEqual(response.json["assessment"]["test_plan"],
                         template.procedure_description)

    def test_control_test_plan(self):
        """Test test_plan from control"""
        test_plan = self.control.test_plan
        template = factories.AssessmentTemplateFactory(
            test_plan_procedure=True)
        response = self.assessment_post(template)
        self.assertEqual(response.json["assessment"]["test_plan"], test_plan)
Ejemplo n.º 34
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())
Ejemplo 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)
Ejemplo n.º 36
0
class TestAccessControlList(TestCase):
  """TestAccessControlList"""

  def setUp(self):
    super(TestAccessControlList, self).setUp()
    self.api = Api()
    self.person = factories.PersonFactory(name="My Person")
    self.control = factories.ControlFactory()
    self.acr = factories.AccessControlRoleFactory(
        object_type="Control",
        read=True
    )
    self.second_acr = factories.AccessControlRoleFactory(
        object_type="Control",
        read=True
    )
    self.acl = factories.AccessControlListFactory(
        object=self.control,
        ac_role_id=self.acr.id,
        person=self.person
    )

  def _post_control(self, id_, person_id, collection=False):
    """Helper function for posting a control"""
    title = random_str(prefix="Control - ")
    control = {
        "control": {
            "title": title,
            "type": "Control",
            "context": None,
            "access_control_list": [
                _acl_json(id_, person_id)
            ]
        },
    }
    response = self.api.post(
        all_models.Control, [control] if collection else control)
    assert response.status_code == 200 or response.status_code == 201, \
        "Control with acl not created successfully {}".format(response.status)

    if collection:
      return response.json[0][1]
    return response.json

  def test_object_roles(self):
    """Test if roles are fetched with the object"""
    id_, person_id = self.acr.id, self.person.id
    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)

    assert "access_control_list" in response.json["control"], \
        "Access Control List not a property in {}".format(
            response.json["control"].keys())

    ac_list = response.json["control"]["access_control_list"]
    assert len(ac_list) == 1, "{}".format(len(ac_list))

    assert ac_list[0]["ac_role_id"] == id_, \
        "ac_role_id not properly set {}".format(ac_list[0].get("ac_role_id"))
    assert ac_list[0]["person"]["id"] == person_id, \
        "Person stub not properly set {}".format(ac_list[0]["person"])

  def test_post_object_roles(self):
    """Test if roles are stored correctly when POSTed with the object"""
    id_, person_id = self.acr.id, self.person.id
    response = self._post_control(id_, person_id)

    acl = response["control"]["access_control_list"]
    _acl_asserts(acl, id_, person_id)

  def test_acl_revision_content(self):
    """Test if the access control list is added to revisions"""
    id_, person_id = self.acr.id, self.person.id
    response = self._post_control(id_, person_id)
    control_id = response["control"]["id"]
    rev = all_models.Revision.query.filter(
        all_models.Revision.resource_id == control_id,
        all_models.Revision.resource_type == "Control"
    ).first()

    acl = rev.content["access_control_list"]
    _acl_asserts(acl, id_, person_id)

  def test_put_object_roles(self):
    """Test if PUTing object roles saves them correctly"""
    id_2, person_id = self.second_acr.id, self.person.id

    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)
    control = response.json['control']
    control['access_control_list'].append(_acl_json(id_2, person_id))
    response = self.api.put(self.control, {"control": control})
    assert response.status_code == 200, \
        "PUTing control failed {}".format(response.status)
    acl = response.json['control']['access_control_list']
    assert len(acl) == 2, \
        "Access control list not correctly updated {}".format(acl)

  def test_put_removing_roles(self):
    """Test if PUTing an empty list removes object roles correct"""
    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)
    control = response.json['control']
    control['access_control_list'] = []
    response = self.api.put(self.control, {"control": control})
    assert response.status_code == 200, \
        "PUTing control failed {}".format(response.status)
    acl = response.json['control']['access_control_list']
    assert len(acl) == 0, \
        "Access control list not empty {}".format(acl)

  def test_acl_indexing_on_post(self):
    """Test if roles are stored correctly when POSTed with the object"""
    id_, person_id = self.acr.id, self.person.id
    response = self._post_control(id_, person_id, True)
    control = response["control"]
    res = mysql.MysqlRecordProperty.query.filter(
        mysql.MysqlRecordProperty.type == "Control",
        mysql.MysqlRecordProperty.key == control["id"],
        mysql.MysqlRecordProperty.property == self.acr.name
    ).all()
    assert len(res) > 0, \
        "Full text record index not created for {}".format(self.acr.name)
    # email is presented in __sort__ subproperty as well
    assert len([r for r in res if r.content == self.person.email]) == 2, \
        "Person email not indexed {}".format(self.person.email)
    assert len([r for r in res if r.content == self.person.name]) == 1, \
        "Person name not indexed {}".format(self.person.name)

  def test_acl_revision_count(self):
    """Test if acl revision is created when object POSTed and PUTed"""
    id_, person_id = self.acr.id, self.person.id

    response = self._post_control(id_, person_id)
    # One ACL and Control created in setUp and on by POST
    self.assertEqual(
        all_models.Revision.query.filter_by(
            resource_type="AccessControlList"
        ).count(),
        2
    )
    self.assertEqual(
        all_models.Revision.query.filter_by(
            resource_type="Control"
        ).count(),
        2
    )

    # If content of "access_control_list" is changed,
    # new revision should be created for ACL
    control = response["control"]
    control["access_control_list"] = []
    self.api.put(
        all_models.Control.query.get(control["id"]),
        {"control": control}
    )
    self.assertEqual(
        all_models.Revision.query.filter_by(
            resource_type="AccessControlList"
        ).count(),
        3
    )
    self.assertEqual(
        all_models.Revision.query.filter_by(
            resource_type="Control"
        ).count(),
        3
    )
Ejemplo n.º 37
0
class TestAccessControlList(TestCase):
    """TestAccessControlList"""
    @classmethod
    def setUpClass(cls):
        """Sets objects common for all tests in TestCase."""
        super(TestAccessControlList, cls).setUpClass()
        cls.api = Api()

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

        self.person = factories.PersonFactory(name="My Person")
        self.acr = factories.AccessControlRoleFactory(object_type="Control",
                                                      read=True)
        self.second_acr = factories.AccessControlRoleFactory(
            object_type="Control", read=True)
        self.control = factories.ControlFactory()
        factories.AccessControlPersonFactory(
            ac_list=self.control.acr_acl_map[self.acr],
            person=self.person,
        )

    def _acl_asserts(self, acl, acr_id, person_id):
        """Run asserts on a given acl list"""
        self.assertEqual(
            len(acl), 1,
            "Access control list did not get saved {}".format(acl))
        self.assertTrue(acl[0]["id"] > 0,
                        "Acces control list did not set an id")
        self.assertEqual(
            acl[0]["ac_role_id"], acr_id,
            "Access control list does not include the saved role id")
        self.assertEqual(
            acl[0]["person_id"], person_id,
            "Access control list does not include person id {}".format(acl[0]))

    def _post_control(self, acr_id, person_id, assertion, collection=False):
        """Helper function for posting a control"""
        title = factories.random_str(prefix="Control - ")
        control = {
            "control": {
                "title": title,
                "type": "Control",
                "context": None,
                "access_control_list":
                [acl_helper.get_acl_json(acr_id, person_id)],
                "assertions": '["{}"]'.format(assertion),
                "external_id": factories.SynchronizableExternalId.next(),
                "external_slug": factories.random_str(),
                "review_status": all_models.Review.STATES.UNREVIEWED,
                "review_status_display_name": "some status",
            },
        }
        with self.api.as_external():
            response = self.api.post(all_models.Control,
                                     [control] if collection else control)

        self.assertTrue(
            response.status_code == 200 or response.status_code == 201,
            "Control not created successfully {}".format(response.status))

        if collection:
            return response.json[0][1]
        return response.json

    def test_object_roles(self):
        """Test if roles are fetched with the object"""
        acr_id, person_id = self.acr.id, self.person.id
        response = self.api.get(all_models.Control, self.control.id)
        self.assert200(
            response,
            "Failed to fetch created control {}".format(response.status))
        self.assertIn(
            "access_control_list", response.json["control"],
            "Access Control List not present in {}".format(
                response.json["control"].keys()))

        acl = response.json["control"]["access_control_list"]
        self._acl_asserts(acl, acr_id, person_id)

    def test_post_object_roles(self):
        """Test if roles are stored correctly when POSTed with the object"""
        acr_id, person_id = self.acr.id, self.person.id
        response = self._post_control(acr_id, person_id, "test assertion")
        acl = response["control"]["access_control_list"]
        self._acl_asserts(acl, acr_id, person_id)

    def test_acl_revision_content(self):
        """Test if the access control list is added to revisions"""
        acr_id, person_id = self.acr.id, self.person.id
        response = self._post_control(acr_id, person_id, "test assertion")
        control_id = response["control"]["id"]
        rev = all_models.Revision.query.filter(
            all_models.Revision.resource_id == control_id,
            all_models.Revision.resource_type == "Control").first()

        acl = rev.content["access_control_list"]
        self._acl_asserts(acl, acr_id, person_id)

    def test_put_object_roles(self):
        """Test if PUTing object roles saves them correctly"""
        second_acr_id, person_id = self.second_acr.id, self.person.id
        response = self.api.get(all_models.Control, self.control.id)
        self.assert200(
            response,
            "Failed to fetch created control {}".format(response.status))

        control = response.json['control']
        control['access_control_list'].append(
            acl_helper.get_acl_json(second_acr_id, person_id))
        with self.api.as_external():
            response = self.api.put(self.control, {"control": control})
        self.assert200(response,
                       "PUTing control failed {}".format(response.status))

        acl = response.json['control']['access_control_list']
        self.assertEqual(len(acl), 2,
                         "Access control list not updated {}".format(acl))

    def test_put_removing_roles(self):
        """Test if PUTing an empty list removes object roles correct"""
        response = self.api.get(all_models.Control, self.control.id)
        self.assert200(
            response,
            "Failed to fetch created control {}".format(response.status))

        control = response.json['control']
        control['access_control_list'] = []
        with self.api.as_external():
            response = self.api.put(self.control, {"control": control})
        self.assert200(response,
                       "PUTing control failed {}".format(response.status))

        acl = response.json['control']['access_control_list']
        self.assertEqual(len(acl), 0,
                         "Access control list not empty {}".format(acl))

    def test_acl_indexing_on_post(self):
        """Test if roles are stored correctly when POSTed with the object"""
        acr_id, person_id = self.acr.id, self.person.id
        response = self._post_control(acr_id, person_id, "test assertion")
        control = response["control"]
        res = mysql.MysqlRecordProperty.query.filter(
            mysql.MysqlRecordProperty.type == "Control",
            mysql.MysqlRecordProperty.key == control["id"],
            mysql.MysqlRecordProperty.property == self.acr.name).all()

        self.assertTrue(
            len(res) > 0,
            "Full text record index not created for {}".format(self.acr.name))

        # email is presented in __sort__ subproperty as well
        self.assertEqual(
            len([r for r in res if r.content == self.person.email]), 2,
            "Person email not indexed {}".format(self.person.email))

        self.assertEqual(
            len([r for r in res if r.content == self.person.name]), 1,
            "Person name not indexed {}".format(self.person.name))

    def test_acl_revision_count(self):
        """Test if acl revision is created when object POSTed and PUTed"""
        acr_id, person_id = self.acr.id, self.person.id

        response = self._post_control(acr_id, person_id, "test assertion")
        # One ACL and Control created in setUp and on by POST
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="AccessControlPerson").count(), 3)
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="Control").count(), 2)

        # If content of "access_control_list" is changed,
        # new revision should be created for ACL
        control = response["control"]
        control["access_control_list"] = []
        with self.api.as_external():
            self.api.put(all_models.Control.query.get(control["id"]),
                         {"control": control})
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="AccessControlPerson").count(), 4)
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="Control").count(), 3)
Ejemplo n.º 38
0
class TestCreator(TestCase):
    """ TestCreator """
    def setUp(self):
        super(TestCreator, 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 = [("creator", "Creator"), ("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 test_admin_page_access(self):
        for role, code in (("creator", 403), ("admin", 200)):
            self.api.set_user(self.users[role])
            self.assertEqual(self.api.tc.get("/admin").status_code, code)

    def test_creator_can_crud(self):
        """ Test Basic create/read,update/delete operations """
        self.api.set_user(self.users["creator"])
        all_errors = []
        base_models = set([
            "Control", "DataAsset", "Contract", "Policy", "Regulation",
            "Standard", "Document", "Facility", "Market", "Objective",
            "OrgGroup", "Vendor", "Product", "Clause", "System", "Process",
            "Issue", "Project", "AccessGroup"
        ])
        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,
                            "reference_url": "ref",
                            "contact": {
                                "type": "Person",
                                "id": self.users["creator"].id,
                            },
                        },
                    })
                if response.status_code != 201:
                    all_errors.append("{} post creation failed {} {}".format(
                        model_singular, response.status, response.data))
                    continue

                # Test GET when not owner
                obj_id = response.json.get(table_singular).get("id")
                response = self.api.get(model, obj_id)
                if response.status_code != 403:  # we are not onwers yet
                    all_errors.append(
                        "{} can retrieve object if not owner".format(
                            model_singular))
                    continue
                response = self.api.get_collection(model, obj_id)
                collection = response.json.get(
                    "{}_collection".format(table_plural)).get(table_plural)
                if len(collection) != 0:
                    all_errors.append(
                        "{} can retrieve object if not owner (collection)".
                        format(model_singular))
                    continue
                # Become an owner
                response = self.api.post(
                    all_models.ObjectOwner, {
                        "object_owner": {
                            "person": {
                                "id": self.users['creator'].id,
                                "type": "Person",
                            },
                            "ownable": {
                                "type": model_singular,
                                "id": obj_id
                            },
                            "context": None
                        }
                    })
                if response.status_code != 201:
                    all_errors.append("{} can't create owner {}.".format(
                        model_singular, response.status))
                    continue

                # 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 len(collection) == 0:
                    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_creator_search(self):
        """Test if creator can see the correct object while using the 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['creator'])
        response = self.api.post(all_models.Policy, {
            "policy": {
                "title": "Creator Policy",
                "context": None
            },
        })
        obj_id = response.json.get("policy").get("id")
        self.api.post(
            all_models.ObjectOwner, {
                "object_owner": {
                    "person": {
                        "id": self.users['creator'].id,
                        "type": "Person",
                    },
                    "ownable": {
                        "type": "Policy",
                        "id": obj_id,
                    },
                    "context": None
                }
            })
        response, _ = self.api.search("Regulation,Policy")
        entries = response.json["results"]["entries"]
        self.assertEqual(len(entries), 1)
        self.assertEqual(entries[0]["type"], "Policy")
        response, _ = self.api.search("Regulation,Policy", counts=True)
        self.assertEqual(response.json["results"]["counts"]["Policy"], 1)
        self.assertEqual(response.json["results"]["counts"].get("Regulation"),
                         None)

    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_creator_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['creator'])
        creator_count = self._get_count("Person")
        self.assertEqual(admin_count, creator_count)

    def test_creator_cannot_be_owner(self):
        """Test if creator cannot become owner of the object he has not created"""
        self.api.set_user(self.users['admin'])
        _, obj = self.generator.generate(all_models.Regulation, "regulation", {
            "regulation": {
                "title": "Test regulation",
                "context": None
            },
        })
        self.api.set_user(self.users['creator'])
        response = self.api.post(
            all_models.ObjectOwner, {
                "object_owner": {
                    "person": {
                        "id": self.users['creator'].id,
                        "type": "Person",
                    },
                    "ownable": {
                        "type": "Regulation",
                        "id": obj.id,
                    },
                    "context": None
                }
            })
        self.assertEqual(response.status_code, 403)

    def test_relationships_access(self):
        """Check if creator cannot 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['creator'])
        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, 0)

    def test_revision_access(self):
        """Check if creator can access the right revision objects."""
        def gen(title):
            return self.generator.generate(all_models.Section, "section", {
                "section": {
                    "title": title,
                    "context": None
                },
            })[1]

        def check(obj, expected):
            """Check that how many revisions of an object current user can see."""
            response = self.api.get_query(
                all_models.Revision,
                "resource_type={}&resource_id={}".format(obj.type, obj.id))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(
                len(response.json['revisions_collection']['revisions']),
                expected)

        self.api.set_user(self.users["admin"])
        obj_1 = gen("Test Section 1")
        obj_2 = gen("Test Section 2")

        self.api.post(
            all_models.ObjectOwner, {
                "object_owner": {
                    "person": {
                        "id": self.users['creator'].id,
                        "type": "Person",
                    },
                    "ownable": {
                        "type": "Section",
                        "id": obj_2.id,
                    },
                    "context": None
                }
            })

        self.api.set_user(self.users["creator"])
        check(obj_1, 0)
        check(obj_2, 2)
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())
Ejemplo n.º 40
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()
Ejemplo n.º 41
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)
Ejemplo n.º 42
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())
Ejemplo n.º 43
0
class TestWfNotifsGenerator(TestCase):
    """Test wf cycle tasks notifications generation."""
    def setUp(self):
        """Set up."""
        super(TestWfNotifsGenerator, self).setUp()
        self.api = Api()
        self.wf_generator = WorkflowsGenerator()
        self.object_generator = ObjectGenerator()
        Notification.query.delete()

        with freeze_time("2015-05-01 14:29:00"):
            wf_slug = "wf1"
            with factories.single_commit():
                wf = wf_factories.WorkflowFactory(slug=wf_slug,
                                                  is_verification_needed=True)
                task_group = wf_factories.TaskGroupFactory(workflow=wf)
                wf_factories.TaskGroupTaskFactory(task_group=task_group,
                                                  title='task1',
                                                  start_date=datetime.now(),
                                                  end_date=datetime.now() +
                                                  timedelta(7))
            data = workflow_api.get_cycle_post_dict(wf)
            self.api.post(all_models.Cycle, data)
            wf = all_models.Workflow.query.filter_by(slug=wf_slug).one()
            self.cycle = all_models.Cycle.query.filter_by(
                workflow_id=wf.id).one()
            self.ctask = all_models.CycleTaskGroupObjectTask.query.filter_by(
                cycle_id=self.cycle.id).first()

    def test_ctasks_notifs_generator_daily_digest(self):
        """Test cycle tasks notifications generation job."""
        with freeze_time("2015-05-01 14:29:00"):
            self.assert_notifications_for_object(self.cycle,
                                                 "manual_cycle_created")
            self.assert_notifications_for_object(self.ctask,
                                                 "manual_cycle_created",
                                                 "cycle_task_due_in",
                                                 "cycle_task_due_today",
                                                 "cycle_task_overdue")

            # Move task to Finished
            self.wf_generator.modify_object(self.ctask,
                                            data={"status": "Verified"})
            generate_cycle_tasks_notifs()
            self.assert_notifications_for_object(self.cycle,
                                                 "all_cycle_tasks_completed",
                                                 "manual_cycle_created")

            # Undo finish
            self.wf_generator.modify_object(self.ctask,
                                            data={"status": "In Progress"})
            generate_cycle_tasks_notifs()
            self.assert_notifications_for_object(self.cycle,
                                                 "manual_cycle_created")
            self.assert_notifications_for_object(self.ctask,
                                                 "cycle_task_due_in",
                                                 "cycle_task_due_today",
                                                 "cycle_task_overdue")

            self.wf_generator.modify_object(self.ctask,
                                            data={"status": "Declined"})
            self.assert_notifications_for_object(self.ctask,
                                                 "cycle_task_due_in",
                                                 "cycle_task_due_today",
                                                 "cycle_task_overdue",
                                                 "cycle_task_declined")

    @ddt.data(("2015-05-01 14:29:00",
               ("all_cycle_tasks_completed", "manual_cycle_created")),
              ("2015-05-02 07:29:00",
               ("all_cycle_tasks_completed", "manual_cycle_created")),
              ("2015-05-02 14:29:00",
               ("all_cycle_tasks_completed", "manual_cycle_created")),
              ("2015-05-03 07:29:00", ("manual_cycle_created", )))
    @ddt.unpack
    def test_cycle_task_update_timelines(self, _datetime, notifications):
        """Test cycle task has been updated:
    1) the day before job is called;
    2) the same day job is called before 08:00 AM UTC;
    3) the same day job is called after 08:00 AM UTC;
    4) two days before job is called.
    """
        with freeze_time("2015-05-01 14:29:00"):
            # Move task to Finished
            self.wf_generator.modify_object(self.ctask,
                                            data={"status": "Verified"})
        with freeze_time(_datetime):
            generate_cycle_tasks_notifs()
            self.assert_notifications_for_object(self.cycle, *notifications)

    def test_ctasks_notifs_generator_daily_digest_called_twice(self):
        """No duplicated notifications should be generated"""
        with freeze_time("2015-05-01 14:29:00"):
            generate_cycle_tasks_notifs()
            self.assert_notifications_for_object(self.cycle,
                                                 "manual_cycle_created")
            self.assert_notifications_for_object(self.ctask,
                                                 "manual_cycle_created",
                                                 "cycle_task_due_in",
                                                 "cycle_task_due_today",
                                                 "cycle_task_overdue")

            # Move task to Finished
            self.wf_generator.modify_object(self.ctask,
                                            data={"status": "Verified"})
            generate_cycle_tasks_notifs()
            generate_cycle_tasks_notifs()
            self.assert_notifications_for_object(self.cycle,
                                                 "all_cycle_tasks_completed",
                                                 "manual_cycle_created")

    def test_ctasks_notifs_generator_cron_job(self):
        """Test cycle tasks notifications generation cron job."""
        with freeze_time("2015-05-2 08:00:00"):
            generate_cycle_tasks_notifs()
            self.assert_notifications_for_object(self.cycle,
                                                 "manual_cycle_created")
            self.assert_notifications_for_object(self.ctask,
                                                 "manual_cycle_created",
                                                 "cycle_task_due_in",
                                                 "cycle_task_due_today",
                                                 "cycle_task_overdue")
Ejemplo n.º 44
0
class TestCreator(TestCase):
    """ TestCreator """
    def setUp(self):
        super(TestCreator, 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 = [("creator", "Creator"), ("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 test_admin_page_access(self):
        """Permissions to admin page."""
        for role, code in (("creator", 403), ("admin", 200)):
            self.api.set_user(self.users[role])
            self.assertEqual(self.api.client.get("/admin").status_code, code)

    def test_creator_can_crud(self):
        """ Test Basic create/read,update/delete operations """
        self.api.set_user(self.users["creator"])
        creator_id = self.users["creator"].id
        audit_id = factories.AuditFactory().id
        all_errors = []
        base_models = {
            "Control", "DataAsset", "Contract", "Policy", "Regulation",
            "Standard", "Document", "Facility", "Market", "Objective",
            "OrgGroup", "Vendor", "Product", "Clause", "System", "Process",
            "Project", "AccessGroup", "Metric", "ProductGroup",
            "TechnologyEnvironment"
        }
        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": creator_id,
                        },
                        "audit": {  # this is ignored on everything but Issues
                            "id": audit_id,
                            "type": "Audit",
                        }
                    },
                })
                if response.status_code != 201:
                    all_errors.append("{} post creation failed {} {}".format(
                        model_singular, response.status, response.data))
                    continue

                # Test GET when not owner
                obj_id = response.json.get(table_singular).get("id")
                response = self.api.get(model, obj_id)
                if response.status_code != 403:  # we are not onwers yet
                    all_errors.append(
                        "{} can retrieve object if not owner".format(
                            model_singular))
                    continue
                response = self.api.get_collection(model, obj_id)
                collection = response.json.get(
                    "{}_collection".format(table_plural)).get(table_plural)
                if collection:
                    all_errors.append(
                        "{} can retrieve object if not owner (collection)".
                        format(model_singular))
                    continue

                # Test GET when owner
                acr = all_models.AccessControlRole.query.filter_by(
                    object_type=model_singular, name="Admin").first()
                factories.AccessControlListFactory(object_id=obj_id,
                                                   object_type=model_singular,
                                                   ac_role=acr,
                                                   person_id=creator_id)
                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_creator_search(self):
        """Test if creator can see the correct object while using the 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['creator'])
        acr_id = all_models.AccessControlRole.query.filter_by(
            object_type="Policy", name="Admin").first().id
        response = self.api.post(
            all_models.Policy, {
                "policy": {
                    "title":
                    "Creator Policy",
                    "context":
                    None,
                    "access_control_list": [
                        acl_helper.get_acl_json(acr_id,
                                                self.users["creator"].id)
                    ],
                },
            })
        response.json.get("policy").get("id")
        response, _ = self.api.search("Regulation,Policy")
        entries = response.json["results"]["entries"]
        self.assertEqual(len(entries), 1)
        self.assertEqual(entries[0]["type"], "Policy")
        response, _ = self.api.search("Regulation,Policy", counts=True)
        self.assertEqual(response.json["results"]["counts"]["Policy"], 1)
        self.assertEqual(response.json["results"]["counts"].get("Regulation"),
                         None)

    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_creator_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['creator'])
        creator_count = self._get_count("Person")
        self.assertEqual(admin_count, creator_count)

    def test_relationships_access(self):
        """Check if creator cannot 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['creator'])
        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, 0)

    def test_revision_access(self):
        """Check if creator can access the right revision objects."""
        def gen(title, extra_data=None):
            """Generates requirement."""
            requirement_content = {"title": title, "context": None}
            if extra_data:
                requirement_content.update(**extra_data)
            return self.generator.generate(
                all_models.Requirement, "requirement",
                {"requirement": requirement_content})[1]

        def check(obj, expected):
            """Check that how many revisions of an object current user can see."""
            response = self.api.get_query(
                all_models.Revision,
                "resource_type={}&resource_id={}".format(obj.type, obj.id))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(
                len(response.json['revisions_collection']['revisions']),
                expected)

        self.api.set_user(self.users["admin"])
        obj_1 = gen("Test Requirement 1")

        self.api.set_user(self.users["creator"])
        acr_id = all_models.AccessControlRole.query.filter_by(
            object_type="Requirement", name="Admin").first().id
        linked_acl = {
            "access_control_list":
            [acl_helper.get_acl_json(acr_id, self.users["creator"].id)],
        }
        check(obj_1, 0)
        obj_2 = gen("Test Requirement 2", linked_acl)
        obj2_acl = obj_2.access_control_list[0]
        check(obj_2, 1)
        check(obj2_acl, 1)

    @ddt.data("creator", "admin")
    def test_count_type_in_accordion(self, glob_role):
        """Return count of Persons in DB for side accordion."""
        self.api.set_user(self.users[glob_role])
        ocordion_api_person_count_link = (
            "/search?"
            "q=&types=Program%2CWorkflow_All%2C"
            "Audit%2CAssessment%2CIssue%2CRegulation%2C"
            "Policy%2CStandard%2CContract%2CClause%2CRequirement%2CControl%2C"
            "Objective%2CPerson%2COrgGroup%2CVendor%2CAccessGroup%2CSystem%2C"
            "Process%2CDataAsset%2CProduct%2CProject%2CFacility%2C"
            "Market%2CRisk%2CThreat&counts_only=true&"
            "extra_columns=Workflow_All%3DWorkflow%2C"
            "Workflow_Active%3DWorkflow%2CWorkflow_Draft%3D"
            "Workflow%2CWorkflow_Inactive%3DWorkflow&contact_id=1&"
            "extra_params=Workflow%3Astatus%3DActive%3BWorkflow_Active"
            "%3Astatus%3DActive%3BWorkflow_Inactive%3Astatus%3D"
            "Inactive%3BWorkflow_Draft%3Astatus%3DDraft")
        resp = self.api.client.get(ocordion_api_person_count_link)
        self.assertIn("Person", resp.json["results"]["counts"])
        self.assertEqual(all_models.Person.query.count(),
                         resp.json["results"]["counts"]["Person"])

    @ddt.data(
        ("/api/revisions?resource_type={}&resource_id={}", 1),
        ("/api/revisions?source_type={}&source_id={}", 0),
        ("/api/revisions?destination_type={}&destination_id={}", 1),
    )
    @ddt.unpack
    def test_changelog_access(self, link, revision_count):
        """Test accessing changelog under GC user who is assigned to object"""
        with factories.single_commit():
            audit = factories.AuditFactory()
            asmnt = factories.AssessmentFactory(audit=audit)
            asmnt_id = asmnt.id
            factories.RelationshipFactory(source=audit, destination=asmnt)
            verifier_role = all_models.AccessControlRole.query.filter_by(
                object_type="Assessment",
                name="Verifiers",
            ).first()
            factories.AccessControlListFactory(
                person=self.users["creator"],
                ac_role=verifier_role,
                object=asmnt,
            )

        self.api.set_user(self.users["creator"])
        response = self.api.client.get(link.format("Assessment", asmnt_id))
        self.assert200(response)
        self.assertEqual(
            len(
                response.json.get("revisions_collection",
                                  {}).get("revisions")), revision_count)

    @ddt.data(all_models.ControlCategory, all_models.ControlAssertion)
    def test_permissions_for_categories(self, category_model):
        """Test get collection for {0}."""
        self.api.set_user(self.users["creator"])
        resp = self.api.get_collection(category_model, None)
        plural_name = category_model._inflector.table_plural
        key_name = "{}_collection".format(plural_name)
        self.assertIn(key_name, resp.json)
        self.assertIn(plural_name, resp.json[key_name])
        collection = resp.json[key_name][plural_name]
        self.assertTrue(collection, "Collection shouldn't be empty")
Ejemplo n.º 45
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"])
Ejemplo n.º 46
0
class TestWorkflowsApiPost(TestCase):

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

  def tearDown(self):
    pass

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  @ddt.data(True, False, None)
  def test_create_vf_flag(self, flag):
    """Check is_verification_needed flag setup on create."""
    data = self.get_workflow_dict()
    if flag is None:
      data['workflow'].pop('is_verification_needed', None)
    else:
      data['workflow']['is_verification_needed'] = flag
    resp = self.api.post(all_models.Workflow, data)
    self.assertEqual(201, resp.status_code)
    workflow_id = resp.json['workflow']['id']
    self.assertEqual(
        flag if flag is not None else True,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)
Ejemplo n.º 47
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, [])
Ejemplo n.º 48
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)
Ejemplo n.º 49
0
class TestWorkflowsApiPost(TestCase):

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

  def tearDown(self):
    pass

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  @ddt.data(True, False, None)
  def test_create_vf_flag(self, flag):
    """Check is_verification_needed flag setup on create."""
    data = self.get_workflow_dict()
    if flag is None:
      data['workflow'].pop('is_verification_needed', None)
    else:
      data['workflow']['is_verification_needed'] = flag
    resp = self.api.post(all_models.Workflow, data)
    self.assertEqual(201, resp.status_code)
    workflow_id = resp.json['workflow']['id']
    self.assertEqual(
        flag if flag is not None else True,
        all_models.Workflow.query.get(workflow_id).is_verification_needed)
Ejemplo n.º 50
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)
Ejemplo n.º 51
0
class TestPermissions(TestCase):
    """Test checks permissions for proposals."""
    def setUp(self):
        super(TestPermissions, self).setUp()
        self.api = Api()
        roles = {r.name: r for r in all_models.Role.query.all()}
        ac_roles = {
            r.name: r
            for r in all_models.AccessControlRole.query.all()
        }
        with factories.single_commit():
            self.control = factories.ControlFactory()
            acrs = {
                "ACL_Reader":
                factories.AccessControlRoleFactory(name="ACL_Reader",
                                                   object_type="Control",
                                                   update=0),
                "ACL_Editor":
                factories.AccessControlRoleFactory(name="ACL_Editor",
                                                   object_type="Control"),
                "ACL_Nobody":
                factories.AccessControlRoleFactory(
                    name="ACL_Nobody",
                    object_type="Control",
                    read=0,
                    update=0,
                    delete=0,
                ),
            }
            self.program = factories.ProgramFactory()
            self.program.context.related_object = self.program
            self.relationship = factories.RelationshipFactory(
                source=self.program,
                destination=self.control,
                context=self.program.context,
            )
            self.people = {
                "Creator": factories.PersonFactory(),
                "Reader": factories.PersonFactory(),
                "Editor": factories.PersonFactory(),
                "Administrator": factories.PersonFactory(),
                "ACL_Reader": factories.PersonFactory(),
                "ACL_Editor": factories.PersonFactory(),
                "ACL_Nobody": factories.PersonFactory(),
                "Program Editors": factories.PersonFactory(),
                "Program Managers": factories.PersonFactory(),
                "Program Readers": factories.PersonFactory(),
            }
            for role_name in ["Creator", "Reader", "Editor", "Administrator"]:
                rbac_factories.UserRoleFactory(role=roles[role_name],
                                               person=self.people[role_name])
            for role_name in [
                    "Program Editors", "Program Managers", "Program Readers"
            ]:
                person = self.people[role_name]
                rbac_factories.UserRoleFactory(role=roles["Creator"],
                                               person=person)
                factories.AccessControlListFactory(ac_role=ac_roles[role_name],
                                                   object=self.program,
                                                   person=person)
            self.proposal = factories.ProposalFactory(
                instance=self.control,
                content={
                    "access_control_list": {},
                    "custom_attribute_values": {},
                    "fields": {},
                    "mapping_fields": {},
                    "mapping_list_fields": {},
                })
            for role_name in ["ACL_Reader", "ACL_Editor", "ACL_Nobody"]:
                person = self.people[role_name]
                rbac_factories.UserRoleFactory(role=roles["Creator"],
                                               person=person)
                factories.AccessControlListFactory(ac_role=acrs[role_name],
                                                   object=self.control,
                                                   person=person)
        with factories.single_commit():
            proposal_model.set_acl_to_all_proposals_for(self.control)

    @ddt.data(
        ("Creator", 403),
        ("Reader", 200),
        ("Editor", 200),
        ("ACL_Reader", 200),
        ("ACL_Editor", 200),
        ("ACL_Nobody", 403),
        ("Administrator", 200),
        ("Program Editors", 200),
        ("Program Managers", 200),
        ("Program Readers", 200),
    )
    @ddt.unpack
    def test_permissions_on_get(self, role_name, status):
        """Test get proposals for {0}."""
        proposal_id = self.proposal.id
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api.get(all_models.Proposal, proposal_id)
        self.assertEqual(status, resp.status_code)

    def api_proposal_status_change(self, proposal_id, status):
        return self.api.put(all_models.Proposal.query.get(proposal_id),
                            {"proposal": {
                                "status": status
                            }})

    @ddt.data(("Creator", 403), ("Reader", 403), ("Editor", 200),
              ("Administrator", 200), ("ACL_Reader", 403), ("ACL_Editor", 200),
              ("ACL_Nobody", 403), ("Program Editors", 200),
              ("Program Managers", 200), ("Program Readers", 403))
    @ddt.unpack
    def test_permissions_on_apply(self, role_name, status):
        """Test apply proposals for {0}."""
        proposal_id = self.proposal.id
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api_proposal_status_change(
            proposal_id, all_models.Proposal.STATES.APPLIED)
        self.assertEqual(status, resp.status_code)

    @ddt.data(
        ("Creator", 403),
        ("Reader", 403),
        ("Editor", 200),
        ("ACL_Reader", 403),
        ("ACL_Editor", 200),
        ("ACL_Nobody", 403),
        ("Administrator", 200),
        ("Program Editors", 200),
        ("Program Managers", 200),
        ("Program Readers", 403),
    )
    @ddt.unpack
    def test_permissions_on_decline(self, role_name, status):
        """Test decline proposals for {0}."""
        proposal_id = self.proposal.id
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api_proposal_status_change(
            proposal_id, all_models.Proposal.STATES.DECLINED)
        self.assertEqual(status, resp.status_code)

    @ddt.data(
        ("Creator", 403),
        ("Reader", 201),
        ("Editor", 201),
        ("ACL_Reader", 201),
        ("ACL_Editor", 201),
        ("ACL_Nobody", 403),
        ("Administrator", 201),
        ("Program Editors", 201),
        ("Program Managers", 201),
        ("Program Readers", 201),
    )
    @ddt.unpack
    def test_permissions_on_create(self, role_name, status):
        """Test create proposal for {0}."""
        data = {
            "proposal": {
                "instance": {
                    "id": self.control.id,
                    "type": self.control.type,
                },
                "full_instance_content": {
                    "title": "new_title"
                },
                "agenda": "update cav",
                "context": None,
            }
        }
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        resp = self.api.post(all_models.Proposal, data)
        self.assertEqual(status, resp.status_code)

    @ddt.data(
        ("Creator", 0),
        ("Reader", 1),
        ("Editor", 1),
        ("ACL_Reader", 1),
        ("ACL_Editor", 1),
        ("ACL_Nobody", 0),
        ("Administrator", 1),
        ("Program Editors", 1),
        ("Program Managers", 1),
        ("Program Readers", 1),
    )
    @ddt.unpack
    def test_query_filter(self, role_name, expected_count):
        """Test query proposals for {0}.

    Args:
        role_name: string, unique key,
                   shows the position of user in generated infrustructure
        expected_count: int, number of proposals,
                        that should be filtered by query
    """
        control_id = self.control.id
        data = [{
            "limit": [0, 5],
            "object_name":
            all_models.Proposal.__name__,
            "order_by": [
                {
                    "name": "status",
                    "desc": True
                },
                {
                    "name": "created_at",
                    "desc": True
                },
            ],
            "filters": {
                "expression": {
                    "left": {
                        "left": "instance_type",
                        "op": {
                            "name": "="
                        },
                        "right": self.control.type,
                    },
                    "op": {
                        "name": "AND"
                    },
                    "right": {
                        "left": "instance_id",
                        "op": {
                            "name": "="
                        },
                        "right": control_id,
                    },
                },
            },
        }]
        self.api.set_user(self.people[role_name])
        self.client.get("/login")
        headers = {
            "Content-Type": "application/json",
        }
        resp = self.api.client.post("/query",
                                    data=json.dumps(data),
                                    headers=headers).json
        self.assertEqual(1, len(resp))
        self.assertEqual(expected_count, resp[0]["Proposal"]["count"])
Ejemplo n.º 52
0
class TestCreator(TestCase):
  """ TestCreator """

  def setUp(self):
    super(TestCreator, 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 = [("creator", "Creator"), ("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 test_admin_page_access(self):
    for role, code in (("creator", 403), ("admin", 200)):
      self.api.set_user(self.users[role])
      self.assertEqual(self.api.client.get("/admin").status_code, code)

  def test_creator_can_crud(self):
    """ Test Basic create/read,update/delete operations """
    self.api.set_user(self.users["creator"])
    audit_id = factories.AuditFactory().id
    all_errors = []
    base_models = set([
        "Control", "DataAsset", "Contract",
        "Policy", "Regulation", "Standard", "Document", "Facility",
        "Market", "Objective", "OrgGroup", "Vendor", "Product",
        "Clause", "System", "Process", "Project", "AccessGroup"
    ])
    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,
                "reference_url": "ref",
                "contact": {
                    "type": "Person",
                    "id": self.users["creator"].id,
                },
                "audit": {  # this is ignored on everything but Issues
                    "id": audit_id,
                    "type": "Audit",
                }
            },
        })
        if response.status_code != 201:
          all_errors.append("{} post creation failed {} {}".format(
              model_singular, response.status, response.data))
          continue

        # Test GET when not owner
        obj_id = response.json.get(table_singular).get("id")
        response = self.api.get(model, obj_id)
        if response.status_code != 403:  # we are not onwers yet
          all_errors.append(
              "{} can retrieve object if not owner".format(model_singular))
          continue
        response = self.api.get_collection(model, obj_id)
        collection = response.json.get(
            "{}_collection".format(table_plural)).get(table_plural)
        if len(collection) != 0:
          all_errors.append(
              "{} can retrieve object if not owner (collection)"
              .format(model_singular))
          continue
        # Become an owner
        response = self.api.post(all_models.ObjectOwner, {"object_owner": {
            "person": {
                "id": self.users['creator'].id,
                "type": "Person",
            }, "ownable": {
                "type": model_singular,
                "id": obj_id
            }, "context": None}})
        if response.status_code != 201:
          all_errors.append("{} can't create owner {}.".format(
              model_singular, response.status))
          continue

        # 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 len(collection) == 0:
          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_creator_search(self):
    """Test if creator can see the correct object while using the 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['creator'])
    response = self.api.post(all_models.Policy, {
        "policy": {"title": "Creator Policy", "context": None},
    })
    obj_id = response.json.get("policy").get("id")
    self.api.post(all_models.ObjectOwner, {"object_owner": {
        "person": {
            "id": self.users['creator'].id,
            "type": "Person",
        }, "ownable": {
            "type": "Policy",
            "id": obj_id,
        }, "context": None}})
    response, _ = self.api.search("Regulation,Policy")
    entries = response.json["results"]["entries"]
    self.assertEqual(len(entries), 1)
    self.assertEqual(entries[0]["type"], "Policy")
    response, _ = self.api.search("Regulation,Policy", counts=True)
    self.assertEqual(response.json["results"]["counts"]["Policy"], 1)
    self.assertEqual(
        response.json["results"]["counts"].get("Regulation"), None)

  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_creator_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['creator'])
    creator_count = self._get_count("Person")
    self.assertEqual(admin_count, creator_count)

  def test_creator_cannot_be_owner(self):
    """Test if creator cannot become owner of the object he has not created"""
    self.api.set_user(self.users['admin'])
    _, obj = self.generator.generate(all_models.Regulation, "regulation", {
        "regulation": {"title": "Test regulation", "context": None},
    })
    self.api.set_user(self.users['creator'])
    response = self.api.post(all_models.ObjectOwner, {"object_owner": {
        "person": {
            "id": self.users['creator'].id,
            "type": "Person",
        }, "ownable": {
            "type": "Regulation",
            "id": obj.id,
        }, "context": None}})
    self.assertEqual(response.status_code, 403)

  def test_relationships_access(self):
    """Check if creator cannot 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['creator'])
    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, 0)

  def test_revision_access(self):
    """Check if creator can access the right revision objects."""

    def gen(title):
      return self.generator.generate(all_models.Section, "section", {
          "section": {"title": title, "context": None},
      })[1]

    def check(obj, expected):
      """Check that how many revisions of an object current user can see."""
      response = self.api.get_query(
          all_models.Revision,
          "resource_type={}&resource_id={}".format(obj.type, obj.id)
      )
      self.assertEqual(response.status_code, 200)
      self.assertEqual(
          len(response.json['revisions_collection']['revisions']),
          expected
      )

    self.api.set_user(self.users["admin"])
    obj_1 = gen("Test Section 1")
    obj_2 = gen("Test Section 2")

    self.api.post(all_models.ObjectOwner, {"object_owner": {
        "person": {
            "id": self.users['creator'].id,
            "type": "Person",
        }, "ownable": {
            "type": "Section",
            "id": obj_2.id,
        }, "context": None}})

    self.api.set_user(self.users["creator"])
    check(obj_1, 0)
    check(obj_2, 2)
Ejemplo n.º 53
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)
Ejemplo n.º 54
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, [])
Ejemplo n.º 55
0
class TestWorkflowsApiPost(TestCase):
    def setUp(self):
        TestCase.setUp(self)
        self.api = Api()

    def tearDown(self):
        pass

    def test_send_invalid_data(self):
        data = self.get_workflow_dict()
        del data["workflow"]["title"]
        del data["workflow"]["context"]
        response = self.api.post(Workflow, data)
        self.assert400(response)

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

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

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

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

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

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

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

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

    # TODO: Api should be able to handle invalid data
    @SkipTest
    def test_create_task_group_invalid_workflow_data(self):
        wf = {"id": -1, "context": {"id": -1}}
        data = self.get_task_group_dict(wf)

        response = self.api.post(TaskGroup, data)
        self.assert400(response)

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

    def get_task_group_dict(self, wf):
        data = {
            "task_group": {
                "custom_attribute_definitions": [],
                "custom_attributes": {},
                "_transient": {},
                "contact": {
                    "id": 1,
                    "href": "/api/people/1",
                    "type": "Person"
                },
                "workflow": {
                    "id": wf["id"],
                    "href": "/api/workflows/%d" % wf["id"],
                    "type": "Workflow"
                },
                "context": {
                    "id": wf["context"]["id"],
                    "href": "/api/contexts/%d" % wf["context"]["id"],
                    "type": "Context"
                },
                "modal_title": "Create Task Group",
                "title": "Create_task_group",
                "description": "",
            }
        }
        return data
Ejemplo n.º 56
0
class TestWorkflowsApiPost(TestCase):
    """Test class for ggrc workflow api post action."""
    def setUp(self):
        super(TestWorkflowsApiPost, self).setUp()
        self.api = Api()
        self.generator = wf_generator.WorkflowsGenerator()

    def tearDown(self):
        pass

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    @ddt.data(True, False, None)
    def test_create_vf_flag(self, flag):
        """Check is_verification_needed flag setup on create."""
        data = self.get_workflow_dict()
        if flag is None:
            data['workflow'].pop('is_verification_needed', None)
        else:
            data['workflow']['is_verification_needed'] = flag
        resp = self.api.post(all_models.Workflow, data)
        self.assertEqual(201, resp.status_code)
        workflow_id = resp.json['workflow']['id']
        self.assertEqual(
            flag if flag is not None else True,
            all_models.Workflow.query.get(workflow_id).is_verification_needed)
class TestAccessControlList(TestCase):
    """TestAccessControlList"""
    def setUp(self):
        super(TestAccessControlList, self).setUp()
        self.api = Api()
        self.person = factories.PersonFactory(name="My Person")
        self.control = factories.ControlFactory()
        self.acr = factories.AccessControlRoleFactory(object_type="Control",
                                                      read=True)
        self.second_acr = factories.AccessControlRoleFactory(
            object_type="Control", read=True)
        self.acl = factories.AccessControlListFactory(object=self.control,
                                                      ac_role_id=self.acr.id,
                                                      person=self.person)

    def _post_control(self, id_, person_id, collection=False):
        """Helper function for posting a control"""
        title = random_str(prefix="Control - ")
        control = {
            "control": {
                "title": title,
                "type": "Control",
                "context": None,
                "access_control_list": [_acl_json(id_, person_id)]
            },
        }
        response = self.api.post(all_models.Control,
                                 [control] if collection else control)
        assert response.status_code == 200 or response.status_code == 201, \
            "Control with acl not created successfully {}".format(response.status)

        if collection:
            return response.json[0][1]
        return response.json

    def test_object_roles(self):
        """Test if roles are fetched with the object"""
        id_, person_id = self.acr.id, self.person.id
        response = self.api.get(all_models.Control, self.control.id)
        assert response.status_code == 200, \
            "Failed to fetch created control {}".format(response.status)

        assert "access_control_list" in response.json["control"], \
            "Access Control List not a property in {}".format(
                response.json["control"].keys())

        ac_list = response.json["control"]["access_control_list"]
        assert len(ac_list) == 1, "{}".format(len(ac_list))

        assert ac_list[0]["ac_role_id"] == id_, \
            "ac_role_id not properly set {}".format(ac_list[0].get("ac_role_id"))
        assert ac_list[0]["person"]["id"] == person_id, \
            "Person stub not properly set {}".format(ac_list[0]["person"])

    def test_post_object_roles(self):
        """Test if roles are stored correctly when POSTed with the object"""
        id_, person_id = self.acr.id, self.person.id
        response = self._post_control(id_, person_id)

        acl = response["control"]["access_control_list"]
        _acl_asserts(acl, id_, person_id)

    def test_acl_revision_content(self):
        """Test if the access control list is added to revisions"""
        id_, person_id = self.acr.id, self.person.id
        response = self._post_control(id_, person_id)
        control_id = response["control"]["id"]
        rev = all_models.Revision.query.filter(
            all_models.Revision.resource_id == control_id,
            all_models.Revision.resource_type == "Control").first()

        acl = rev.content["access_control_list"]
        _acl_asserts(acl, id_, person_id)

    def test_put_object_roles(self):
        """Test if PUTing object roles saves them correctly"""
        id_2, person_id = self.second_acr.id, self.person.id

        response = self.api.get(all_models.Control, self.control.id)
        assert response.status_code == 200, \
            "Failed to fetch created control {}".format(response.status)
        control = response.json['control']
        control['access_control_list'].append(_acl_json(id_2, person_id))
        response = self.api.put(self.control, {"control": control})
        assert response.status_code == 200, \
            "PUTing control failed {}".format(response.status)
        acl = response.json['control']['access_control_list']
        assert len(acl) == 2, \
            "Access control list not correctly updated {}".format(acl)

    def test_put_removing_roles(self):
        """Test if PUTing an empty list removes object roles correct"""
        response = self.api.get(all_models.Control, self.control.id)
        assert response.status_code == 200, \
            "Failed to fetch created control {}".format(response.status)
        control = response.json['control']
        control['access_control_list'] = []
        response = self.api.put(self.control, {"control": control})
        assert response.status_code == 200, \
            "PUTing control failed {}".format(response.status)
        acl = response.json['control']['access_control_list']
        assert len(acl) == 0, \
            "Access control list not empty {}".format(acl)

    def test_acl_indexing_on_post(self):
        """Test if roles are stored correctly when POSTed with the object"""
        id_, person_id = self.acr.id, self.person.id
        response = self._post_control(id_, person_id, True)
        control = response["control"]
        res = mysql.MysqlRecordProperty.query.filter(
            mysql.MysqlRecordProperty.type == "Control",
            mysql.MysqlRecordProperty.key == control["id"],
            mysql.MysqlRecordProperty.property == self.acr.name).all()
        assert len(res) > 0, \
            "Full text record index not created for {}".format(self.acr.name)
        # email is presented in __sort__ subproperty as well
        assert len([r for r in res if r.content == self.person.email]) == 2, \
            "Person email not indexed {}".format(self.person.email)
        assert len([r for r in res if r.content == self.person.name]) == 1, \
            "Person name not indexed {}".format(self.person.name)

    def test_acl_revision_count(self):
        """Test if acl revision is created when object POSTed and PUTed"""
        id_, person_id = self.acr.id, self.person.id

        response = self._post_control(id_, person_id)
        # One ACL and Control created in setUp and on by POST
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="AccessControlList").count(), 2)
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="Control").count(), 2)

        # If content of "access_control_list" is changed,
        # new revision should be created for ACL
        control = response["control"]
        control["access_control_list"] = []
        self.api.put(all_models.Control.query.get(control["id"]),
                     {"control": control})
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="AccessControlList").count(), 3)
        self.assertEqual(
            all_models.Revision.query.filter_by(
                resource_type="Control").count(), 3)
Ejemplo n.º 58
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)
Ejemplo n.º 59
0
class TestCommentsForProposals(TestCase):
  """Test generate comments for proposals."""

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

  TMPLS = all_models.Proposal.CommentTemplatesTextBuilder

  @ddt.data({"agenda": "",
             "comment": TMPLS.PROPOSED_WITHOUT_AGENDA},
            {"agenda": "tmp",
             "comment": TMPLS.PROPOSED_WITH_AGENDA.format(text="tmp")},
            {"agenda": "bla",
             "comment": TMPLS.PROPOSED_WITH_AGENDA.format(text="bla")},
            {"agenda": "<p>bla</p>",
             "comment": TMPLS.PROPOSED_WITH_AGENDA.format(text="bla")})
  @ddt.unpack
  def test_create(self, agenda, comment):
    """Test case create proposal with agenda {agenda}."""
    risk = factories.RiskFactory()
    risk_id = risk.id
    self.assertEqual(0, len(risk.comments))
    resp = self.api.post(
        all_models.Proposal,
        {"proposal": {
            "instance": {
                "id": risk.id,
                "type": risk.type,
            },
            # "content": {"123": 123},
            "full_instance_content": risk.log_json(),
            "agenda": agenda,
            "context": None,
        }})
    self.assertEqual(201, resp.status_code)
    risk = all_models.Risk.query.get(risk_id)
    self.assertEqual(1, len(risk.comments))
    self.assertEqual(comment, risk.comments[0].description)

  @ddt.data({"agenda": "",
             "comment_agenda": "",
             "status": all_models.Proposal.STATES.APPLIED,
             "tmpl": TMPLS.APPLIED_WITHOUT_COMMENT},
            {"agenda": "tmp",
             "comment_agenda": "tmp",
             "status": all_models.Proposal.STATES.APPLIED,
             "tmpl": TMPLS.APPLIED_WITH_COMMENT},
            {"agenda": "<p>tmp</p>",
             "comment_agenda": "tmp",
             "status": all_models.Proposal.STATES.APPLIED,
             "tmpl": TMPLS.APPLIED_WITH_COMMENT},
            {"agenda": "<p>     </p>",
             "comment_agenda": "",
             "status": all_models.Proposal.STATES.APPLIED,
             "tmpl": TMPLS.APPLIED_WITHOUT_COMMENT},
            {"agenda": "bla",
             "comment_agenda": "bla",
             "status": all_models.Proposal.STATES.APPLIED,
             "tmpl": TMPLS.APPLIED_WITH_COMMENT},
            {"agenda": "tmp",
             "comment_agenda": "tmp",
             "status": all_models.Proposal.STATES.DECLINED,
             "tmpl": TMPLS.DECLINED_WITH_COMMENT},
            {"agenda": " <p>tmp</p>      ",
             "comment_agenda": "tmp",
             "status": all_models.Proposal.STATES.DECLINED,
             "tmpl": TMPLS.DECLINED_WITH_COMMENT},
            {"agenda": "BLa",
             "comment_agenda": "BLa",
             "status": all_models.Proposal.STATES.DECLINED,
             "tmpl": TMPLS.DECLINED_WITH_COMMENT},
            {"agenda": "",
             "comment_agenda": "",
             "status": all_models.Proposal.STATES.DECLINED,
             "tmpl": TMPLS.DECLINED_WITHOUT_COMMENT})
  @ddt.unpack
  def test_change_status(self, agenda, comment_agenda, status, tmpl):
    """Test comment proposal status move to {status} with agenda {agenda}."""
    test_email = "*****@*****.**"
    with factories.single_commit():
      risk = factories.RiskFactory()
      proposer = factories.PersonFactory(email=test_email)
    with factories.single_commit():
      proposal = factories.ProposalFactory(
          instance=risk,
          content={"field": "a"},
          agenda="agenda content",
          proposed_by=proposer)
    risk_id = risk.id
    if status == all_models.Proposal.STATES.APPLIED:
      resp = self.api.put(
          proposal, {"proposal": {"status": status, "apply_reason": agenda}})
    else:
      resp = self.api.put(
          proposal, {"proposal": {"status": status, "decline_reason": agenda}})
    self.assertEqual(200, resp.status_code)
    risk = all_models.Risk.query.get(risk_id)
    self.assertEqual(1, len(risk.comments))
    comment = tmpl.format(user=test_email, text=comment_agenda)
    self.assertEqual(comment, risk.comments[0].description)
Ejemplo n.º 60
0
class TestPermissions(TestCase):
  """Test checks permissions for proposals."""

  def setUp(self):
    super(TestPermissions, self).setUp()
    self.api = Api()
    roles = {r.name: r for r in all_models.Role.query.all()}
    factories.AccessControlRoleFactory(
        name="ACL_Reader",
        object_type="Risk",
        update=0
    )
    factories.AccessControlRoleFactory(
        name="ACL_Editor",
        object_type="Risk"
    )
    factories.AccessControlRoleFactory(
        name="ACL_Nobody",
        object_type="Risk",
        read=0,
        update=0,
        delete=0,
    )
    with factories.single_commit():
      self.risk = factories.RiskFactory()
      self.program = factories.ProgramFactory()
      self.program.context.related_object = self.program
      self.relationship = factories.RelationshipFactory(
          source=self.program,
          destination=self.risk,
          context=self.program.context,
      )
      self.people = {
          "Creator": factories.PersonFactory(),
          "Reader": factories.PersonFactory(),
          "Editor": factories.PersonFactory(),
          "Administrator": factories.PersonFactory(),
          "ACL_Reader": factories.PersonFactory(),
          "ACL_Editor": factories.PersonFactory(),
          "ACL_Nobody": factories.PersonFactory(),
          "Program Editors": factories.PersonFactory(),
          "Program Managers": factories.PersonFactory(),
          "Program Readers": factories.PersonFactory(),
      }
      for role_name in ["Creator", "Reader", "Editor", "Administrator"]:
        rbac_factories.UserRoleFactory(role=roles[role_name],
                                       person=self.people[role_name])
      for role_name in ["Program Editors",
                        "Program Managers",
                        "Program Readers"]:
        person = self.people[role_name]
        rbac_factories.UserRoleFactory(role=roles["Creator"], person=person)
        factories.AccessControlPersonFactory(
            ac_list=self.program.acr_name_acl_map[role_name],
            person=person,
        )
      self.proposal = factories.ProposalFactory(
          instance=self.risk,
          content={
              "access_control_list": {},
              "custom_attribute_values": {},
              "fields": {},
              "mapping_fields": {},
              "mapping_list_fields": {},
          }
      )
      factories.RelationshipFactory(
          source=self.risk,
          destination=self.proposal,
      )

      for role_name in ["ACL_Reader", "ACL_Editor", "ACL_Nobody"]:
        person = self.people[role_name]
        rbac_factories.UserRoleFactory(role=roles["Creator"], person=person)
        factories.AccessControlPersonFactory(
            ac_list=self.risk.acr_name_acl_map[role_name],
            person=person,
        )

  @ddt.data(
      ("Creator", 403),
      ("Reader", 200),
      ("Editor", 200),
      ("ACL_Reader", 200),
      ("ACL_Editor", 200),
      ("ACL_Nobody", 403),
      ("Administrator", 200),
      ("Program Editors", 200),
      ("Program Managers", 200),
      ("Program Readers", 200),
  )
  @ddt.unpack
  def test_permissions_on_get(self, role_name, status):
    """Test get proposals for {0}."""
    proposal_id = self.proposal.id
    self.api.set_user(self.people[role_name])
    self.client.get("/login")
    resp = self.api.get(all_models.Proposal, proposal_id)
    self.assertEqual(status, resp.status_code)

  def api_proposal_status_change(self, proposal_id, status):
    return self.api.put(all_models.Proposal.query.get(proposal_id),
                        {"status": status})

  @ddt.data(
      ("Creator", 403),
      ("Reader", 403),
      ("Editor", 200),
      ("Administrator", 200),
      ("ACL_Reader", 403),
      ("ACL_Editor", 200),
      ("ACL_Nobody", 403),
      ("Program Editors", 200),
      ("Program Managers", 200),
      ("Program Readers", 403)
  )
  @ddt.unpack
  def test_permissions_on_apply(self, role_name, status):
    """Test apply proposals for {0}."""
    proposal_id = self.proposal.id
    self.api.set_user(self.people[role_name])
    self.client.get("/login")
    resp = self.api_proposal_status_change(proposal_id,
                                           all_models.Proposal.STATES.APPLIED)
    self.assertEqual(status, resp.status_code)

  @ddt.data(
      ("Creator", 403),
      ("Reader", 403),
      ("Editor", 200),
      ("ACL_Reader", 403),
      ("ACL_Editor", 200),
      ("ACL_Nobody", 403),
      ("Administrator", 200),
      ("Program Editors", 200),
      ("Program Managers", 200),
      ("Program Readers", 403),
  )
  @ddt.unpack
  def test_permissions_on_decline(self, role_name, status):
    """Test decline proposals for {0}."""
    proposal_id = self.proposal.id
    self.api.set_user(self.people[role_name])
    self.client.get("/login")
    resp = self.api_proposal_status_change(proposal_id,
                                           all_models.Proposal.STATES.DECLINED)
    self.assertEqual(status, resp.status_code)

  @ddt.data(
      ("Creator", 403),
      ("Reader", 201),
      ("Editor", 201),
      ("ACL_Reader", 201),
      ("ACL_Editor", 201),
      ("ACL_Nobody", 403),
      ("Administrator", 201),
      ("Program Editors", 201),
      ("Program Managers", 201),
      ("Program Readers", 201),
  )
  @ddt.unpack
  def test_permissions_on_create(self, role_name, status):
    """Test create proposal for {0}."""
    data = {
        "proposal": {
            "instance": {
                "id": self.risk.id,
                "type": self.risk.type,
            },
            "full_instance_content": {"title": "new_title"},
            "agenda": "update cav",
            "context": None,
        }
    }
    self.api.set_user(self.people[role_name])
    self.client.get("/login")
    resp = self.api.post(all_models.Proposal, data)
    self.assertEqual(status, resp.status_code)

  @ddt.data(
      ("Creator", 0),
      ("Reader", 1),
      ("Editor", 1),
      # Following two tests have been commented out as the functionality for
      # custom role propagation has been temporarily removed This test should
      # be enabled back in scope of ticket GGRC-4991
      # ("ACL_Reader", 1),
      # ("ACL_Editor", 1),
      ("ACL_Nobody", 0),
      ("Administrator", 1),
      ("Program Editors", 1),
      ("Program Managers", 1),
      ("Program Readers", 1),
  )
  @ddt.unpack
  def test_query_filter(self, role_name, expected_count):
    """Test query proposals for {0}.

    Args:
        role_name: string, unique key,
                   shows the position of user in generated infrustructure
        expected_count: int, number of proposals,
                        that should be filtered by query
    """
    risk_id = self.risk.id
    data = [{
        "limit": [0, 5],
        "object_name": all_models.Proposal.__name__,
        "order_by":[
            {"name": "status", "desc": True},
            {"name": "created_at", "desc": True},
        ],
        "filters": {
            "expression": {
                "left": {
                    "left": "instance_type",
                    "op": {"name": "="},
                    "right": self.risk.type,
                },
                "op": {"name": "AND"},
                "right": {
                    "left": "instance_id",
                    "op": {"name": "="},
                    "right": risk_id,
                },
            },
        },
    }]
    self.api.set_user(self.people[role_name])
    self.client.get("/login")
    headers = {"Content-Type": "application/json", }
    resp = self.api.client.post("/query",
                                data=json.dumps(data),
                                headers=headers).json
    self.assertEqual(1, len(resp))
    self.assertEqual(expected_count, resp[0]["Proposal"]["count"])