Introduction

Permission tests are an inseparable part of the development of many web applications. This is especially true for AEM-based applications where the existence of multiple roles such as authors, reviewers, publishers, or super authors, is standard. Nevertheless, these tests are often performed manually and any attempt to automate them is abandoned. And here is where APMT comes to the rescue. APMT provides a suite of tests that checks permissions to perform read and write operations on resources. The only thing to configure is to provide the paths and users for which they will be run. Little effort, huge benefits.

Let's start

At the beginning, we need to create a file with general settings. It's called apmt.yaml, and contains credentials of apmt user and the addresses of author and publish instances. The APMT user is a special user, which should be able to perform all actions on tested paths: creating, updating, reading and deleting resources. It's required because it prepares environment for tests, and cleans it up when tests are done. AEM instances have to be accessible from the machine where test are being executed. APMT connects to them, and performs CRUD operations on given paths, using HTTP requests.

apmt-user:
  username: apmt-user
  password: p@SSWoRd
instances:
  author:
    name: author@local
    url: http://localhost:4502
  publish:
    name: publish@local
    url: http://localhost:4503

Currently there is no different way to provide password for the APMT user. But you may get around the problem using resource filtering mechanism available in many build tools like gradle or maven. Resource filtering would be a great choice also for handling different sets of environments. You may find simple configuration in example project.

In the second step we need to define test users. Let's put them into an enum class. As you can see below, it's written in Kotlin. We strongly recommend using Kotlin, because the whole code of APMT is written in this language, and we use cool features of that language like lambdas with receivers, and extension functions. That simplifies tests, and increases readability. Of course there is still possibility to use plain Java.

import com.cognifide.apmt.User

const val PASSWORD = "p@SSWoRd"

enum class Users (
    override val username: String,
    override val password: String
) : User {
    GLOBAL_AUTHOR("global-test-author", PASSWORD),
    LOCAL_AUTHOR("en_us-test-author", PASSWORD),
    GLOBAL_SUPER_AUTHOR("global-test-super-author", PASSWORD),
    LOCAL_SUPER_AUTHOR("en_us-test-super-author", PASSWORD)
}

Because users are defined in enum class, you may use different ways to store passwords than directly in code. For example you may fetch passwords from environment variable. Here is an example how it may look like:

import com.cognifide.apmt.User
import java.lang.RuntimeException

val PASSWORD = loadPassword()

fun loadPassword() : String = System.getenv("TEST_USER_PASSWORD") ?: throw RuntimeException("Cannot find environment variable with password")

Configuring permission test

And now we can go to tests. Let's start with a test checking the permissions to create a page. We need to create a class that extends CreatePageTest, and provide configuration using super class constructor. The first argument of all tests is the same, it is a vararg of type TestCase. TestCase is just an interface, so in the example below, we are using its implementation BasicTestCase. The second argument is specific to this test, it defines structure of the created page, like title or template, or any other property (or even child node).

import com.cognifide.apmt.BasicTestCase
import com.cognifide.apmt.tests.page.CreatePageTest

class CustomCreatePageTest : CreatePageTest(
    BasicTestCase {
         paths(
            "/content/we-retail/us/es/apt-test-page"
        )
        allowedUsers(
            Users.GLOBAL_AUTHOR,
            Users.GLOBAL_SUPER_AUTHOR
        )
        allUsers(Users.values())
    },
    pageContent = {
        jcrTitle = "APMT"
        cqTemplate = "/conf/we-retail/settings/wcm/templates/content-page"
    }
)

As you probably noticed, the BasicTestCase doesn't simply define users, but there are allowedUsers and allUsers methods instead. Actually, there is also deniedUsers method. It makes no sense to use all of them at once. Methods allowedUsers and deniedUsers directly indicate which users can create pages and which cannot. Using one of these methods together with allUsers causes the second group of users to be computed, as shown in the table:

allowedUsers deniedUsers allUsers Allowed users Denied users
defined - - allowedUser -
defined - defined allowedUser allUsers - allowedUsers
defined defined - allowedUser deniedUsers
- defined - - deniedUsers
- defined defined allUsers - deniedUsers deniedUsers

It's very useful when list of users is long, or you are adding new users to it (they will be automatically used during next test's execution).

Execution

And that's it. You can now execute your test.

$ sh gradlew test
> Task :test

Check user permissions to create pages > User LOCAL_AUTHOR cannot create page /content/we-retail/us/es/apt-test-page PASSED

Check user permissions to create pages > User LOCAL_SUPER_AUTHOR cannot create page /content/we-retail/us/es/apt-test-page PASSED

Check user permissions to create pages > User GLOBAL_AUTHOR can create page /content/we-retail/us/es/apt-test-page PASSED

Check user permissions to create pages > User GLOBAL_SUPER_AUTHOR can create page /content/we-retail/us/es/apt-test-page PASSED

BUILD SUCCESSFUL in 4s
3 actionable tasks: 1 executed, 2 up-to-date

Next steps

At this point, you are familiar with main concepts of APMT library, so you may proceed to cover next test cases. Below is a list of tests currently provided by APMT. They check CRUD operations on assets, pages, and resources.

Summary

APMT comes with several tests for CRUD operations on pages, resources, and assets. They should be enough to cover big part of permission tests scope. If you've any questions, or are interested in details, please visit project's repo: https://github.com/wttech/apmt. You may also check out example project.