Merge container-handling into cluster-testing
This commit is contained in:
commit
96a00317b8
41 changed files with 1175 additions and 851 deletions
|
@ -1,61 +1,166 @@
|
|||
# Keycloak Integration Testsuite with Arquillian
|
||||
# Keycloak Arquillian Integration Testsuite
|
||||
|
||||
## Structure
|
||||
## Container Lifecycles
|
||||
|
||||
### Keycloak Auth Server
|
||||
|
||||
There is only one instance of Keycloak server running during a single test run.
|
||||
It is automatically started by Arquillian on the `BeforeSuite` event and stopped `AfterSuite`.
|
||||
|
||||
The type of container can be determined by property `-Dauth.server.container`. Default value is `auth-server-undertow`,
|
||||
other options are: `auth-server-wildfly` and `auth-server-eap7`. The values correspond to Arquillian *container qualifiers* in `arquillian.xml` config file.
|
||||
|
||||
**Note 1:** For the non-default options it's necessary to build a corresponding server module prior to running any of the test modules.
|
||||
This can be done by building the server module directly (from `servers/wildfly`/`servers/eap7`),
|
||||
or by activating `auth-server-wildfly`/`auth-server-eap7` profile when building from the top level module.
|
||||
(The profiles will also set the proper value of the `auth.server.container` property.)
|
||||
|
||||
**Note 2:** Most server-side configurations are done during the build of the server module
|
||||
and included in the output artifact - which is then consumed by the test modules( if a corresponding profile is activated).
|
||||
To reflect a change in server config in the test (e.g. a datasource) it's necessary to rebuild the server module after each change.
|
||||
|
||||
### Migration
|
||||
|
||||
Migration tests can be enabled by setting `-Dmigrated.auth.server.container` property or activating a corresponding profile.
|
||||
When enabled, the `AuthServerTestEnricher` class will start/stop the selected *migrated* instance
|
||||
even **before** the *current* auth server instance is started.
|
||||
|
||||
### App Servers
|
||||
|
||||
Lifecycle of application server is always tied to a particular TestClass.
|
||||
|
||||
Each *adapter* test class is annotated by `@AppServerContainer("app-server-*")` annotation
|
||||
that links it to a particular Arquillian container in `arquillian.xml`.
|
||||
The `AppServerTestEnricher` then ensures the server is started before and stopped after all tests methods in the class.
|
||||
In case the `@AppServerContainer` annotation has no value it's assumed that the application container
|
||||
is the same as the auth server container (a relative adapter test scenario).
|
||||
|
||||
Adapter tests are separated into submodules because different app containers require different configurations
|
||||
(installation of adapter libs, etc.).
|
||||
Container entries of app servers are not present in the main `arquillian.xml` in the `base` module.
|
||||
Each adapter submodule adds it's own entry before it runs the tests.
|
||||
|
||||
## SuiteContext and TestContext
|
||||
|
||||
These objects are injected into `AbstractKeycloakTest` class so they can be used everywhere.
|
||||
They can be used to get information about the tested containers, and to store information that won't survive across test classes or test methods.
|
||||
(Arquillian creates a new instance of test class for each test method run, so all data in the fields is always lost.)
|
||||
|
||||
## REST Testing
|
||||
|
||||
The `AbstractKeycloakTest` has an initialized instance of AdminClient. Subclasses can use it to access any REST subresources.
|
||||
|
||||
## UI Testing
|
||||
|
||||
### Page Objects
|
||||
|
||||
Page Objects are used by tests to access and operate on UI.
|
||||
They can be injected using annotation `@Page` provided by the *Arquillian Graphene* extension.
|
||||
|
||||
The base class for all page objects used throughout this Arquillian testsuite is `AbstractPage`, and it's subclass `AbstractPageWithInjectedUrl`.
|
||||
|
||||
For the page objects for the *adapter test apps* the URLs are injected automatically by Arquillian depending on actual URL of the deployed app/example.
|
||||
|
||||
For the pages under the `/auth` context the URL is only injected to the `AuthServerContextRoot` page object,
|
||||
and the URL hierarchy is modeled by the class inheritance hierarchy (subclasses/extending of `AuthServerContextRoot`).
|
||||
|
||||
|
||||
### Browsers
|
||||
|
||||
The default browser for UI testing is `phantomjs` which is used for fast "headless" testing.
|
||||
Other browsers can be selected with the `-Dbrowser` property, for example `firefox`.
|
||||
See Arquillian Graphene documentation for more details.
|
||||
|
||||
|
||||
## Test Modules
|
||||
|
||||
### Base Testsuite
|
||||
|
||||
The base testsuite contains custom Arquillian extensions and most functional tests.
|
||||
The other test modules depend on this module.
|
||||
|
||||
### Admin Console UI Tests
|
||||
|
||||
Tests for Keycloak Admin Console are located in a separate module `tests/other/console`
|
||||
and are **disabled** by default. Can be enabled by `-Pconsole-ui-tests`.
|
||||
|
||||
### Adapter Tests
|
||||
|
||||
Adapter tests are located in submodules of the `tests/other/adapters` module.
|
||||
|
||||
They are **disabled** by default; they can be enabled by corresponding profiles.
|
||||
Multiple profiles can be enabled for a single test execution.
|
||||
|
||||
#### Types of adapter tests
|
||||
|
||||
1. Using *custom test servlets*
|
||||
2. Using *example demo apps* from `keycloak/examples` modules.
|
||||
|
||||
#### Relative vs Non-relative scenario
|
||||
|
||||
The test suite can handle both types.
|
||||
It automatically modifies imported test realms and deployments' adapter configs based on scenario type.
|
||||
|
||||
| Scenario | Description | Realm config (server side) | Adapter config (client side) |
|
||||
| --- | --- | --- | --- |
|
||||
| **Relative** | auth server == app server | client `baseUrl`, `adminUrl` and `redirect-uris` can be relative | `auth-server-url` can be relative |
|
||||
| **Non-relative** | auth server != app server | client `baseUrl`, `adminUrl` and `redirect-uris` need to include FQDN of the app server | `auth-server-url` needs to include FQDN of the auth server|
|
||||
|
||||
|
||||
|
||||
#### Adapter Libs Mode
|
||||
|
||||
1. **Provided** - By container, e.g. as a subsystem. **Default.**
|
||||
2. **Bundled** - In the deployed war in `/WEB-INF/libs`. Enable with `-Dadapter.libs.bundled`. *Wildfly only*.
|
||||
|
||||
#### Adapter Config Mode
|
||||
|
||||
1. ~~**Provided** - In `standalone.xml` using `secure-deployment`. *Wildfly only.*~~ WIP
|
||||
2. **Bundled** - In the deployed war in `/WEB-INF/keycloak.json`. **Default.**
|
||||
|
||||
|
||||
## Maven Modules Structure
|
||||
|
||||
```
|
||||
integration-arquillian
|
||||
│
|
||||
├──servers (submodules enabled via profiles)
|
||||
│ ├──wildfly
|
||||
│ └──eap6
|
||||
├──servers
|
||||
│ ├──wildfly (activated by -Pauth-server-wildfly)
|
||||
│ └──eap7 (activated by -Pauth-server-eap7)
|
||||
│
|
||||
└──tests
|
||||
├──base
|
||||
└──adapters (submodules enabled via profiles, all depend on base)
|
||||
├──wildfly
|
||||
├──wildfly-relative (needs servers/wildfly)
|
||||
├──wildfly8
|
||||
├──as7
|
||||
├──tomcat
|
||||
└──karaf
|
||||
|
||||
└──tests (common settings for all test modules)
|
||||
├──base (custom ARQ extensions + base functional tests)
|
||||
└──other (common settings for all modules dependent on base)
|
||||
│
|
||||
├──adapters (common settings for all adapter submodules)
|
||||
│ ├──wildfly (activated by -Papp-server-wildfly)
|
||||
│ ├──wildfly-relative (activated by -Papp-server-wildfly-relative,auth-server-wildfly)
|
||||
│ ├──...
|
||||
│ ├──tomcat (activated by -Papp-server-tomcat)
|
||||
│ └──karaf (activated by -Papp-server-karaf)
|
||||
│
|
||||
├──console (activated by -Pconsole-ui-tests)
|
||||
├──mod_auth_mellon (activated by -Pmod_auth_mellon)
|
||||
└──...
|
||||
```
|
||||
|
||||
## General Concepts
|
||||
## Custom Arquillian Extensions
|
||||
|
||||
The testsuite supports **multiple server runtimes** for the Keycloak server.
|
||||
The **default is Undertow** which is the fastest and easiest option, and runs in the same JVM as the tests.
|
||||
Custom extensions are registered in `META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension`.
|
||||
|
||||
Other options are **Wildfly 9** and **EAP 6**. These have some additional requirements and limitations:
|
||||
1. The selected server module must be built before any tests can be run.
|
||||
All server-side configuration is done during this build (e.g. datasource configuration).
|
||||
Once server artifact is built the tests modules can unpack it via `maven-dependency-plugin` into their working directory before running.
|
||||
2. Before the selected server module can be built the `keycloak/distribution` module also needs to be built.
|
||||
### MultipleContainersExtension
|
||||
* Replaces Arquillian's default container handling.
|
||||
* Allows to manage multiple container instances of different types within a single test run.
|
||||
* Allows to skip loading disabled containers based on `enabled` config property in `arquillian.xml`.
|
||||
|
||||
### Server Runtimes
|
||||
### KeycloakArquillianExtension
|
||||
* `AuthServerTestEnricher` - Handles lifecycle of auth server and migrated auth server.
|
||||
* `AppServerTestEnricher` - Handles lifecycles of app servers.
|
||||
* `CustomUndertowContainer` - Custom container controller for JAX-RS-enabled Undertow with Keycloak Server.
|
||||
* `DeploymentArchiveProcessor` - Modifies adapter configs before test apps are deployed.
|
||||
* `DeploymentTargetModifier` - Ensures all test app deployments are targeted at app server containers.
|
||||
* `URLProvider` - Fixes URLs injected by Arquillian Graphene which contain value `127.0.0.1` instead of required `localhost`.
|
||||
|
||||
TODO: explain why separate module, list config options, note on migration modules
|
||||
### CustomKarafContainerExtension
|
||||
|
||||
### Base Testsuite
|
||||
|
||||
login flows + account management
|
||||
|
||||
admin ui
|
||||
|
||||
abstract adapter tests
|
||||
|
||||
### Adapter Tests
|
||||
|
||||
test servlets: demo, session
|
||||
|
||||
examples
|
||||
|
||||
## Running the Tests
|
||||
|
||||
### Undertow
|
||||
|
||||
### Wildfly or EAP 6
|
||||
|
||||
### Adapters
|
||||
|
||||
### Supported Browsers
|
||||
Extension for executing karaf commands after container is started. Used for installation of bundles (test apps and adapter libs).
|
|
@ -1,189 +0,0 @@
|
|||
# Keycloak Integration Testsuite with Arquillian
|
||||
|
||||
*OUT OF DATE - NEEDS REWRITE*
|
||||
|
||||
## Usage
|
||||
|
||||
Running the tests: `mvn test` or `mvn clean test`
|
||||
|
||||
## Test suite
|
||||
|
||||
### Selecting container for Keycloak Server
|
||||
|
||||
The testsuite requires a container for Keycloak Server to be selected.
|
||||
This container is used by all tests in the suite during a single test execution.
|
||||
|
||||
*By default* the tests run with server on embedded *Undertow*.
|
||||
A different container can be selected with profile, e.g. `-Pauth-server-wildfly`.
|
||||
|
||||
### Containers Supported for Keycloak Server
|
||||
|
||||
| Container | Arquillian Qualifier | Maven | Dependencies |
|
||||
| --- | --- | --- | --- |
|
||||
| **Undertow** | `auth-server-undertow` | **default** | `undertow-core`, `resteasy-undertow` |
|
||||
| **Wildfly 9** | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay` |
|
||||
| **EAP 6.4** | `auth-server-eap6` | `-Pauth-server-eap6` | `keycloak-server-dist` or `eap6-dist`+`keycloak-server-overlay` |
|
||||
|
||||
See the relevant container definitions in `arquillian.xml` located in the **test resources** folder.
|
||||
|
||||
### Test Class Hierarchy
|
||||
```
|
||||
AbstractKeycloakTest
|
||||
├── AbstractAdminConsoleTest
|
||||
└── AbstractAdapterTest
|
||||
```
|
||||
|
||||
### AbstractKeycloakTest
|
||||
|
||||
Handles test realms. Provides Admin Client for REST operations.
|
||||
|
||||
* **@BeforeClass**
|
||||
1. Updates the admin password to enable the admin user.
|
||||
* **@Before**
|
||||
1. Initiates admin client
|
||||
2. Imports test realms. (Loading test realms is overriden in subclasses.)
|
||||
* **@After**
|
||||
1. Removes test realms.
|
||||
2. Closes admin client.
|
||||
|
||||
### ContainersTestEnricher
|
||||
|
||||
Manages *container lifecycles*.
|
||||
|
||||
`ContainersTestEnricher` is a custom Arquillian observer that handles lifecycles of auth server and app server containers for each test class.
|
||||
Containers are started during `@BeforeClass` and shut down during `@AfterClass` event.
|
||||
|
||||
*Optionally* each test class can be annotated with `@AuthServerContainer("qualifier")` and `@AppServerConatiner("qualifier")` annotations
|
||||
to indicate containers required for the test.
|
||||
|
||||
* In case `@AuthServerContainer` is not present the *auth server qualifier* is loaded from `auth.server.container` property.
|
||||
* In case `@AppServerContainer` is not present or it's value is the same as *auth server qualifier*, the app server isn't started for the test class.
|
||||
|
||||
## Admin Console Tests
|
||||
|
||||
Tests for admin console are located in `org/keycloak/testsuite/console`.
|
||||
Related non-test classes are located on the same path in the **main sources**.
|
||||
|
||||
Admin console tests are **ENABLED by default**. They can be disabled by `-P no-console`.
|
||||
|
||||
|
||||
## Adapter Tests
|
||||
|
||||
Adapter tests are located in `org/keycloak/testsuite/adapter`.
|
||||
Related non-test classes can be found on the same path in the **main sources**.
|
||||
|
||||
Adapter tests are **DISABLED by default**. They can be enabled by profiles.
|
||||
Multiple profiles can be enabled for a single test execution.
|
||||
|
||||
*Note:* When testing adapter with multiple containers in a single run it is better
|
||||
to use the `--fail-at-end` (`-fae`) strategy instead of the default `--fail-fast` one.
|
||||
This will allow Maven to continue building other modules even if some of them have test failures.
|
||||
|
||||
### Containers Supported for Adapter Tests
|
||||
|
||||
| Container | Arquillian Qualifier | Maven | Dependencies |
|
||||
| --- | --- | --- | --- |
|
||||
| **Wildfly 9** Relative | `auth-server-wildfly` | `-Pauth-server-wildfly` | `keycloak-server-dist` or `wildfly-dist`+`keycloak-server-overlay`, `keycloak-adapter-dist-wf9` |
|
||||
| **Wildfly 9** | `app-server-wildfly` | `-Papp-server-wildfly` | `wildfly-dist`, `keycloak-adapter-dist-wf9` |
|
||||
| **Wildfly 8** | `app-server-wildfly` | `-Papp-server-wildfly8` | `wildfly-dist:8.2.1.Final`, `keycloak-adapter-dist-wf8` |
|
||||
| **JBoss AS 7** | `app-server-as7` | `-Papp-server-as7` | `jboss-as-dist`, `keycloak-adapter-dist-as7` |
|
||||
| **Tomcat 8** | `app-server-tomcat` | `-Papp-server-tomcat` | `tomcat`, `keycloak-tomcat8-adapter-dist` |
|
||||
| **Karaf 3** | `app-server-karaf` | `-Papp-server-karaf` | `apache-camel`, `apache-cxf`, `keycloak-osgi-features`, `keycloak-fuse-example-features` |
|
||||
|
||||
See the relevant container definitions in `tests/adapter/<container>/src/main/xslt/arquillian.xsl`.
|
||||
|
||||
***Important:*** Arquillian cannot load multiple controllers for JBossAS/Wildfly containers in a single run (because same class name)
|
||||
but a different controller is required for JBossAS7/EAP6 than for WF8/9. Because of this:
|
||||
|
||||
- Adapter tests for *Wildfly 8/9* cannot be run against server on *EAP 6*. `-Papp-server-wildfly*` ⇒ `!auth-server-eap6`
|
||||
- Adapter tests for *JBossAS 7* can only be run against server on *EAP 6*. `-Papp-server-as7,auth-server-eap6`
|
||||
|
||||
### Adapter Test Types
|
||||
|
||||
1. Using **test servlets**.
|
||||
2. Using **example/demo wars**.
|
||||
|
||||
```
|
||||
AbstractKeycloakTest
|
||||
└── AbstractAdapterTest
|
||||
├── AbstractServletsAdapterTest
|
||||
| ├── Relative…
|
||||
| ├── Wildfly…
|
||||
| ├── Tomcat…
|
||||
| …
|
||||
└── AbstractExampleAdapterTest
|
||||
├── AbstractDemoExampleAdapterTest
|
||||
| ├── Relative…
|
||||
| ├── Wildfly…
|
||||
| ├── Tomcat…
|
||||
| …
|
||||
├── AbstractBasicAuthExampleAdapterTest
|
||||
| ├── Relative…
|
||||
| ├── Wildfly…
|
||||
| ├── Tomcat…
|
||||
| …
|
||||
…
|
||||
```
|
||||
|
||||
### Relative vs Non-relative scenario
|
||||
|
||||
The test suite can handle both types.
|
||||
It automatically modifies imported test realms and deployments' adapter configs based on scenario type.
|
||||
|
||||
| Scenario | Description | Realm config (server side) | Adapter config (client side) |
|
||||
| --- | --- | --- | --- |
|
||||
| **Relative** | Both Keycloak Server and test apps running in the same container. | client `baseUrl`, `adminUrl` and `redirect-uris` can be relative | `auth-server-url` can be relative |
|
||||
| **Non-relative** | Test apps run in a different container than Keycloak Server. | client `baseUrl`, `adminUrl` and `redirect-uris` need to include FQDN of the app server | `auth-server-url` needs to include FQDN of the auth server|
|
||||
|
||||
### Adapter Libraries Mode
|
||||
|
||||
1. **Provided.** By container, e.g. as a subsystem. *Default.*
|
||||
2. **Bundled.** In the deployed war in `/WEB-INF/libs`. Enable with `-Dadapter.libs.bundled`. *Wildfly only*.
|
||||
|
||||
### Adapter Config Mode
|
||||
|
||||
1. ~~**Provided.** In `standalone.xml` using `secure-deployment`. *Wildfly only.*~~ WIP
|
||||
2. **Bundled.** In the deployed war in `/WEB-INF/keycloak.json`. *Default.*
|
||||
|
||||
### Adapters Test Coverage
|
||||
|
||||
| Module | Coverage | Supported Containers |
|
||||
| --- | --- | --- |
|
||||
| ***Test Servlets*** | Good | All |
|
||||
| **Demo** | Minimal, WIP | `auth-server-wildfly` (relative) |
|
||||
| **Admin Client** | |
|
||||
| **Cordova** | |
|
||||
| **CORS** | |
|
||||
| **JS Console** | Good | `auth-server-wildfly` (relative) |
|
||||
| **Providers** | |
|
||||
| Themes | |
|
||||
| Multitenancy | WIP | |
|
||||
| **Basic Auth** | Good | All |
|
||||
| **Fuse** | Good | `app-server-karaf` |
|
||||
| SAML | |
|
||||
| LDAP | |
|
||||
| Kerberos | |
|
||||
|
||||
## Supported Browsers
|
||||
|
||||
| Browser | Maven |
|
||||
| --- | --- |
|
||||
| **PhantomJS** | `-Dbrowser=phantomjs` **default** |
|
||||
| **Firefox** | `-Dbrowser=firefox` |
|
||||
|
||||
|
||||
## Custom Arquillian Extensions
|
||||
|
||||
Custom extensions are registered in `META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension`.
|
||||
|
||||
* Multiple containers extension
|
||||
* Replaces Arquillian's default container handling.
|
||||
* Allows to manage multiple container instances of different types within a single test run.
|
||||
* Allows to skip loading disabled containers based on `enabled` config property in `arquillian.xml`.
|
||||
* Custom extension
|
||||
* `ContainersTestEnricher` - Handles lifecycles of auth-server and app-server.
|
||||
* `CustomUndertowContainer` - A custom container controller for JAX-RS-enabled Undertow with Keycloak Server.
|
||||
* `DeploymentArchiveProcessor` - Modifies adapter config before deployment on app server based on relative/non-relative scenario.
|
||||
* `URLProvider` - Fixes URLs injected by Arquillian which contain 127.0.0.1 instead of localhost.
|
||||
* `JiraTestExecutionDecider` - Skipping tests for unresolved JIRAs.
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
package org.keycloak.testsuite.arquillian;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import org.jboss.arquillian.container.spi.event.container.BeforeDeploy;
|
||||
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||
import org.jboss.arquillian.core.api.Instance;
|
||||
import org.jboss.arquillian.core.api.InstanceProducer;
|
||||
import org.jboss.arquillian.core.api.annotation.Inject;
|
||||
import org.jboss.arquillian.core.api.annotation.Observes;
|
||||
import org.jboss.arquillian.test.spi.annotation.ClassScoped;
|
||||
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
|
||||
import org.jboss.logging.Logger;
|
||||
import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerContextRoot;
|
||||
import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerQualifier;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
import static org.keycloak.testsuite.util.IOUtil.execCommand;
|
||||
import org.keycloak.testsuite.util.LogChecker;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class AppServerTestEnricher {
|
||||
|
||||
protected final Logger log = Logger.getLogger(this.getClass());
|
||||
|
||||
@Inject
|
||||
@ClassScoped
|
||||
private InstanceProducer<TestContext> testContextProducer;
|
||||
private TestContext testContext;
|
||||
|
||||
public static String getAppServerQualifier(Class testClass) {
|
||||
Class<? extends AuthServerTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class);
|
||||
|
||||
String appServerQ = (annotatedClass == null ? null
|
||||
: annotatedClass.getAnnotation(AppServerContainer.class).value());
|
||||
|
||||
return appServerQ == null || appServerQ.isEmpty()
|
||||
? getAuthServerQualifier() // app server == auth server
|
||||
: appServerQ;
|
||||
}
|
||||
|
||||
public static String getAppServerContextRoot() {
|
||||
return getAppServerContextRoot(0);
|
||||
}
|
||||
|
||||
public static String getAppServerContextRoot(int clusterPortOffset) {
|
||||
int httpPort = Integer.parseInt(System.getProperty("app.server.http.port")); // property must be set
|
||||
int httpsPort = Integer.parseInt(System.getProperty("app.server.https.port")); // property must be set
|
||||
boolean sslRequired = Boolean.parseBoolean(System.getProperty("app.server.ssl.required"));
|
||||
|
||||
return sslRequired
|
||||
? "https://localhost:" + (httpsPort + clusterPortOffset)
|
||||
: "http://localhost:" + (httpPort + clusterPortOffset);
|
||||
}
|
||||
|
||||
public void updateTestContextWithAppServerInfo(@Observes(precedence = 1) BeforeClass event) {
|
||||
testContext = testContextProducer.get();
|
||||
String appServerQualifier = getAppServerQualifier(testContext.getTestClass());
|
||||
for (ContainerInfo container : testContext.getSuiteContext().getContainers()) {
|
||||
if (container.getQualifier().equals(appServerQualifier)) {
|
||||
testContext.setAppServerInfo(updateWithAppServerInfo(container));
|
||||
}
|
||||
}
|
||||
// validate app server
|
||||
if (appServerQualifier != null && testContext.getAppServerInfo() == null) {
|
||||
throw new RuntimeException(String.format("No app server container matching '%s' was activated. Check if defined and enabled in arquillian.xml.", appServerQualifier));
|
||||
}
|
||||
log.info("\n\n" + testContext);
|
||||
}
|
||||
|
||||
private ContainerInfo updateWithAppServerInfo(ContainerInfo appServerInfo) {
|
||||
return updateWithAppServerInfo(appServerInfo, 0);
|
||||
}
|
||||
|
||||
private ContainerInfo updateWithAppServerInfo(ContainerInfo appServerInfo, int clusterPortOffset) {
|
||||
try {
|
||||
|
||||
String appServerContextRootStr = isRelative(testContext.getTestClass())
|
||||
? getAuthServerContextRoot(clusterPortOffset)
|
||||
: getAppServerContextRoot(clusterPortOffset);
|
||||
|
||||
appServerInfo.setContextRoot(new URL(appServerContextRootStr));
|
||||
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
return appServerInfo;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private Instance<ContainerController> containerConrollerInstance;
|
||||
|
||||
public void startAppServer(@Observes(precedence = -1) BeforeClass event) throws MalformedURLException, InterruptedException, IOException {
|
||||
if (testContext.isAdapterTest()) {
|
||||
ContainerController controller = containerConrollerInstance.get();
|
||||
if (!controller.isStarted(testContext.getAppServerInfo().getQualifier())) {
|
||||
controller.start(testContext.getAppServerInfo().getQualifier());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void installAdapterLibs(@Observes BeforeDeploy event) {
|
||||
log.debug("BEFORE DEPLOY - INSTALL ADAPTER LIBS");
|
||||
if (testContext.isAdapterTest()) {
|
||||
// install adapter libs on JBoss-based container via CLI
|
||||
if (testContext.getAppServerInfo().isJBossBased()) {
|
||||
try {
|
||||
installAdapterLibsUsingJBossCLIClient(testContext.getAppServerInfo());
|
||||
} catch (InterruptedException | IOException ex) {
|
||||
throw new RuntimeException("Failed to install adapter libs.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void installAdapterLibsUsingJBossCLIClient(ContainerInfo appServerInfo) throws InterruptedException, IOException {
|
||||
if (!appServerInfo.isAdapterLibsInstalled()) {
|
||||
|
||||
if (!appServerInfo.isJBossBased()) {
|
||||
throw new IllegalArgumentException("App server must be JBoss-based to run jboss-cli-client.");
|
||||
}
|
||||
|
||||
String jbossHomePath = appServerInfo.getProperties().get("jbossHome");
|
||||
|
||||
File bin = new File(jbossHomePath + "/bin");
|
||||
|
||||
File clientJar = new File(jbossHomePath + "/bin/client/jboss-cli-client.jar");
|
||||
if (!clientJar.exists()) {
|
||||
clientJar = new File(jbossHomePath + "/bin/client/jboss-client.jar"); // AS7
|
||||
}
|
||||
if (!clientJar.exists()) {
|
||||
throw new IOException("JBoss CLI client JAR not found.");
|
||||
}
|
||||
|
||||
String command = "java -jar " + clientJar.getAbsolutePath();
|
||||
String adapterScript = "adapter-install.cli";
|
||||
String samlAdapterScript = "adapter-install-saml.cli";
|
||||
String managementPort = appServerInfo.getProperties().get("managementPort");
|
||||
|
||||
String controllerArg = " --controller=localhost:" + managementPort;
|
||||
if (new File(bin, adapterScript).exists()) {
|
||||
log.info("Installing adapter to app server via cli script");
|
||||
execCommand(command + " --connect --file=" + adapterScript + controllerArg, bin);
|
||||
}
|
||||
if (new File(bin, samlAdapterScript).exists()) {
|
||||
log.info("Installing saml adapter to app server via cli script");
|
||||
execCommand(command + " --connect --file=" + samlAdapterScript + controllerArg, bin);
|
||||
}
|
||||
if (new File(bin, adapterScript).exists() || new File(bin, samlAdapterScript).exists()) {
|
||||
log.info("Restarting container");
|
||||
execCommand(command + " --connect --command=reload" + controllerArg, bin);
|
||||
log.info("Container restarted");
|
||||
pause(5000);
|
||||
LogChecker.checkJBossServerLog(jbossHomePath);
|
||||
}
|
||||
|
||||
appServerInfo.setAdapterLibsInstalled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param testClass
|
||||
* @param annotationClass
|
||||
* @return testClass or the nearest superclass of testClass annotated with
|
||||
* annotationClass
|
||||
*/
|
||||
public static Class getNearestSuperclassWithAnnotation(Class testClass, Class annotationClass) {
|
||||
return testClass.isAnnotationPresent(annotationClass) ? testClass
|
||||
: (testClass.getSuperclass().equals(Object.class) ? null // stop recursion
|
||||
: getNearestSuperclassWithAnnotation(testClass.getSuperclass(), annotationClass)); // continue recursion
|
||||
}
|
||||
|
||||
public static boolean hasAppServerContainerAnnotation(Class testClass) {
|
||||
return getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class) != null;
|
||||
}
|
||||
|
||||
public static boolean isRelative(Class testClass) {
|
||||
return getAppServerQualifier(testClass).equals(getAuthServerQualifier());
|
||||
}
|
||||
|
||||
public static String getAdapterLibsLocationProperty(Class testClass) {
|
||||
Class<? extends AuthServerTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AdapterLibsLocationProperty.class);
|
||||
return (annotatedClass == null ? null
|
||||
: annotatedClass.getAnnotation(AdapterLibsLocationProperty.class).value());
|
||||
}
|
||||
|
||||
public static boolean isWildflyAppServer(Class testClass) {
|
||||
return getAppServerQualifier(testClass).contains("wildfly");
|
||||
}
|
||||
|
||||
public static boolean isTomcatAppServer(Class testClass) {
|
||||
return getAppServerQualifier(testClass).contains("tomcat");
|
||||
}
|
||||
|
||||
public static boolean isOSGiAppServer(Class testClass) {
|
||||
String q = getAppServerQualifier(testClass);
|
||||
return q.contains("karaf") || q.contains("fuse");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.arquillian;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.arquillian.container.spi.Container;
|
||||
import org.jboss.arquillian.container.spi.ContainerRegistry;
|
||||
import org.jboss.arquillian.container.spi.event.StartContainer;
|
||||
import org.jboss.arquillian.container.spi.event.StartSuiteContainers;
|
||||
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||
import org.jboss.arquillian.core.api.Event;
|
||||
import org.jboss.arquillian.core.api.Instance;
|
||||
import org.jboss.arquillian.core.api.InstanceProducer;
|
||||
import org.jboss.arquillian.core.api.annotation.Inject;
|
||||
import org.jboss.arquillian.core.api.annotation.Observes;
|
||||
import org.jboss.arquillian.test.spi.annotation.ClassScoped;
|
||||
import org.jboss.arquillian.test.spi.annotation.SuiteScoped;
|
||||
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
|
||||
import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.testsuite.util.LogChecker;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
* @author vramik
|
||||
*/
|
||||
public class AuthServerTestEnricher {
|
||||
|
||||
protected final Logger log = Logger.getLogger(this.getClass());
|
||||
|
||||
@Inject
|
||||
private Instance<ContainerRegistry> containerRegistry;
|
||||
|
||||
@Inject
|
||||
private Instance<ContainerController> containerController;
|
||||
|
||||
@Inject
|
||||
private Event<StartContainer> startContainerEvent;
|
||||
|
||||
private static final String AUTH_SERVER_CONTAINER_PROPERTY = "auth.server.container";
|
||||
private static final String AUTH_SERVER_CONTAINER_DEFAULT = "auth-server-undertow";
|
||||
|
||||
private static final String MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY = "migrated.auth.server.container";
|
||||
|
||||
@Inject
|
||||
@SuiteScoped
|
||||
private InstanceProducer<SuiteContext> suiteContextProducer;
|
||||
private SuiteContext suiteContext;
|
||||
|
||||
@Inject
|
||||
@ClassScoped
|
||||
private InstanceProducer<TestContext> testContextProducer;
|
||||
|
||||
public static String getAuthServerQualifier() {
|
||||
return System.getProperty(AUTH_SERVER_CONTAINER_PROPERTY, AUTH_SERVER_CONTAINER_DEFAULT);
|
||||
}
|
||||
|
||||
public static String getMigratedAuthServerQualifier() {
|
||||
return System.getProperty(MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY); // == null if migration not enabled
|
||||
}
|
||||
|
||||
public static String getAuthServerContextRoot() {
|
||||
return getAuthServerContextRoot(0);
|
||||
}
|
||||
|
||||
public static String getAuthServerContextRoot(int clusterPortOffset) {
|
||||
int httpPort = Integer.parseInt(System.getProperty("auth.server.http.port")); // property must be set
|
||||
int httpsPort = Integer.parseInt(System.getProperty("auth.server.https.port")); // property must be set
|
||||
boolean sslRequired = Boolean.parseBoolean(System.getProperty("auth.server.ssl.required"));
|
||||
|
||||
return sslRequired
|
||||
? "https://localhost:" + (httpsPort + clusterPortOffset)
|
||||
: "http://localhost:" + (httpPort + clusterPortOffset);
|
||||
}
|
||||
|
||||
public void initializeSuiteContext(@Observes(precedence = 2) BeforeSuite event) {
|
||||
|
||||
Set<ContainerInfo> containers = new LinkedHashSet<>();
|
||||
for (Container c : containerRegistry.get().getContainers()) {
|
||||
containers.add(new ContainerInfo(c));
|
||||
}
|
||||
|
||||
suiteContext = new SuiteContext(containers);
|
||||
|
||||
String authServerQualifier = getAuthServerQualifier();
|
||||
String migratedAuthServerQualifier = getMigratedAuthServerQualifier();
|
||||
|
||||
// init authServerInfo and authServerBackendsInfo
|
||||
if (authServerQualifier.startsWith("auth-server-")) {
|
||||
|
||||
boolean authServerCluster = authServerQualifier.endsWith("-cluster");
|
||||
|
||||
String authServerType = authServerQualifier.replaceAll("^auth-server-", "").replaceAll("-cluster$", "");
|
||||
String authServerFrontend = authServerCluster
|
||||
? "auth-server-" + authServerType + "-balancer" // in cluster mode the load-balancer container serves as auth server frontend
|
||||
: authServerQualifier; // single-node mode
|
||||
String authServerBackend = "auth-server-" + authServerType + "-backend";
|
||||
int backends = 0;
|
||||
for (ContainerInfo container : suiteContext.getContainers()) {
|
||||
// frontend
|
||||
if (container.getQualifier().equals(authServerFrontend)) {
|
||||
updateWithAuthServerInfo(container);
|
||||
suiteContext.setAuthServerInfo(container);
|
||||
}
|
||||
// backends
|
||||
if (container.getQualifier().startsWith(authServerBackend)) {
|
||||
updateWithAuthServerInfo(container, ++backends);
|
||||
suiteContext.getAuthServerBackendsInfo().add(container);
|
||||
}
|
||||
}
|
||||
|
||||
// validate auth server setup
|
||||
if (suiteContext.getAuthServerInfo() == null) {
|
||||
throw new RuntimeException(String.format("No auth server activated. A container matching '%s' needs to be enabled in arquillian.xml.", authServerFrontend));
|
||||
}
|
||||
if (authServerCluster && !suiteContext.getAuthServerBackendsInfo().isEmpty()) {
|
||||
throw new RuntimeException(String.format("No cluster backend nodes activated. Containers matching '%sN' need to be enabled in arquillian.xml.", authServerBackend));
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Value of %s should start with 'auth-server-' prefix.", AUTH_SERVER_CONTAINER_PROPERTY));
|
||||
}
|
||||
|
||||
if (migratedAuthServerQualifier != null) {
|
||||
// init migratedAuthServerInfo
|
||||
if (migratedAuthServerQualifier.startsWith("migrated-auth-server-")) {
|
||||
for (ContainerInfo container : suiteContext.getContainers()) {
|
||||
// migrated auth server
|
||||
if (container.getQualifier().equals(migratedAuthServerQualifier)) {
|
||||
updateWithAuthServerInfo(container);
|
||||
suiteContext.setMigratedAuthServerInfo(container);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Value of %s should start with 'migrated-auth-server-' prefix.", MIGRATED_AUTH_SERVER_CONTAINER_PROPERTY));
|
||||
}
|
||||
// validate setup
|
||||
if (suiteContext.getMigratedAuthServerInfo() == null) {
|
||||
throw new RuntimeException(String.format("Migration test was enabled but no auth server from which to migrate was activated. "
|
||||
+ "A container matching '%s' needs to be enabled in arquillian.xml.", migratedAuthServerQualifier));
|
||||
}
|
||||
}
|
||||
|
||||
suiteContextProducer.set(suiteContext);
|
||||
log.info("\n\n" + suiteContext);
|
||||
}
|
||||
|
||||
private ContainerInfo updateWithAuthServerInfo(ContainerInfo authServerInfo) {
|
||||
return updateWithAuthServerInfo(authServerInfo, 0);
|
||||
}
|
||||
|
||||
private ContainerInfo updateWithAuthServerInfo(ContainerInfo authServerInfo, int clusterPortOffset) {
|
||||
try {
|
||||
authServerInfo.setContextRoot(new URL(getAuthServerContextRoot(clusterPortOffset)));
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
return authServerInfo;
|
||||
}
|
||||
|
||||
public void startMigratedContainer(@Observes(precedence = 2) StartSuiteContainers event) {
|
||||
if (suiteContext.isAuthServerMigrationEnabled()) {
|
||||
log.info("\n\n### Starting keycloak " + System.getProperty("version", "- previous") + " ###\n");
|
||||
startContainerEvent.fire(new StartContainer(suiteContext.getMigratedAuthServerInfo().getArquillianContainer()));
|
||||
}
|
||||
}
|
||||
|
||||
public void stopMigratedContainer(@Observes(precedence = 1) StartSuiteContainers event) {
|
||||
if (suiteContext.isAuthServerMigrationEnabled()) {
|
||||
containerController.get().stop(suiteContext.getAuthServerInfo().getQualifier());
|
||||
}
|
||||
}
|
||||
|
||||
public void checkServerLogs(@Observes(precedence = -1) BeforeSuite event) throws IOException, InterruptedException {
|
||||
boolean checkLog = System.getProperty("auth.server.log.check", "true").equals("true");
|
||||
if (checkLog && suiteContext.getAuthServerInfo().isJBossBased()) {
|
||||
String jbossHomePath = suiteContext.getAuthServerInfo().getProperties().get("jbossHome");
|
||||
LogChecker.checkJBossServerLog(jbossHomePath);
|
||||
}
|
||||
}
|
||||
|
||||
public void initializeTestContext(@Observes(precedence = 2) BeforeClass event) {
|
||||
TestContext testContext = new TestContext(suiteContext, event.getTestClass().getJavaClass());
|
||||
testContextProducer.set(testContext);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package org.keycloak.testsuite.arquillian;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.jboss.arquillian.container.spi.Container;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class ContainerInfo {
|
||||
|
||||
private URL contextRoot;
|
||||
private Container arquillianContainer;
|
||||
private boolean adapterLibsInstalled;
|
||||
|
||||
public ContainerInfo(Container arquillianContainer) {
|
||||
if (arquillianContainer == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.arquillianContainer = arquillianContainer;
|
||||
}
|
||||
|
||||
public Container getArquillianContainer() {
|
||||
return arquillianContainer;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return getArquillianContainer().getContainerConfiguration().getContainerProperties();
|
||||
}
|
||||
|
||||
public String getQualifier() {
|
||||
return getArquillianContainer().getName();
|
||||
}
|
||||
|
||||
public URL getContextRoot() {
|
||||
return contextRoot;
|
||||
}
|
||||
|
||||
public void setContextRoot(URL contextRoot) {
|
||||
this.contextRoot = contextRoot;
|
||||
}
|
||||
|
||||
public boolean isAS7() {
|
||||
return getQualifier().toLowerCase().contains("as7");
|
||||
}
|
||||
|
||||
public boolean isWildfly() {
|
||||
return getQualifier().toLowerCase().contains("wildfly");
|
||||
}
|
||||
|
||||
public boolean isEAP() {
|
||||
return getQualifier().toLowerCase().contains("eap");
|
||||
}
|
||||
|
||||
public boolean isJBossBased() {
|
||||
return isAS7() || isWildfly() || isEAP();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getQualifier();
|
||||
}
|
||||
|
||||
public boolean isAdapterLibsInstalled() {
|
||||
return adapterLibsInstalled;
|
||||
}
|
||||
|
||||
public void setAdapterLibsInstalled(boolean adapterLibsInstalled) {
|
||||
this.adapterLibsInstalled = adapterLibsInstalled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 97 * hash + Objects.hashCode(this.arquillianContainer);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ContainerInfo other = (ContainerInfo) obj;
|
||||
return Objects.equals(
|
||||
this.arquillianContainer.getContainerConfiguration().getContainerName(),
|
||||
other.arquillianContainer.getContainerConfiguration().getContainerName());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,362 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.arquillian;
|
||||
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.jboss.arquillian.container.spi.Container;
|
||||
import org.jboss.arquillian.container.spi.ContainerRegistry;
|
||||
import org.jboss.arquillian.container.spi.event.StartSuiteContainers;
|
||||
import org.jboss.arquillian.container.spi.event.StopSuiteContainers;
|
||||
import org.jboss.arquillian.container.spi.event.container.AfterStart;
|
||||
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||
import org.jboss.arquillian.core.api.Event;
|
||||
import org.jboss.arquillian.core.api.Instance;
|
||||
import org.jboss.arquillian.core.api.InstanceProducer;
|
||||
import org.jboss.arquillian.core.api.annotation.Inject;
|
||||
import org.jboss.arquillian.core.api.annotation.Observes;
|
||||
import org.jboss.arquillian.test.spi.annotation.ClassScoped;
|
||||
import org.jboss.arquillian.test.spi.annotation.SuiteScoped;
|
||||
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
|
||||
import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
* @author vramik
|
||||
*/
|
||||
public class ContainersTestEnricher {
|
||||
|
||||
protected final Logger log = Logger.getLogger(this.getClass());
|
||||
|
||||
@Inject
|
||||
private Instance<ContainerController> containerController;
|
||||
|
||||
@Inject
|
||||
private Instance<ContainerRegistry> containerRegistry;
|
||||
|
||||
@Inject
|
||||
private Event<StopSuiteContainers> stopSuiteContainers;
|
||||
|
||||
private String appServerQualifier;
|
||||
|
||||
private static final String AUTH_SERVER_CONTAINER_PROPERTY = "auth.server.container";
|
||||
private static final String AUTH_SERVER_CONTAINER_DEFAULT = "auth-server-undertow";
|
||||
|
||||
@Inject
|
||||
@SuiteScoped
|
||||
private InstanceProducer<SuiteContext> suiteContext;
|
||||
|
||||
@Inject
|
||||
@ClassScoped
|
||||
private InstanceProducer<TestContext> testContext;
|
||||
|
||||
@Inject
|
||||
@ClassScoped
|
||||
private InstanceProducer<Keycloak> adminClient;
|
||||
|
||||
@Inject
|
||||
@ClassScoped
|
||||
private InstanceProducer<OAuthClient> oauthClient;
|
||||
|
||||
private ContainerController controller;
|
||||
private LinkedList<Container> containers;
|
||||
|
||||
private String jbossHomePath;
|
||||
private final boolean migrationTests = System.getProperty("migration", "false").equals("true");
|
||||
private final boolean skipInstallAdapters = System.getProperty("skip.install.adapters", "false").equals("true");
|
||||
private boolean alreadyInstalled = false;
|
||||
private boolean alreadyStopped = false;
|
||||
private boolean init = false;
|
||||
|
||||
private void init() {
|
||||
if (!init) {
|
||||
containers = new LinkedList<>(containerRegistry.get().getContainers());
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* non-javadoc
|
||||
*
|
||||
* Before starting suite containers. Initialization of containers is done
|
||||
* (only once during class life cycle)
|
||||
*/
|
||||
public void startSuiteContainers(@Observes(precedence = 1) StartSuiteContainers event) {
|
||||
init();
|
||||
if (migrationTests) {
|
||||
log.info("\n\n### Starting keycloak " + System.getProperty("version", "- previous") + " ###\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* non-javadoc
|
||||
*
|
||||
* After start container. Server logs are checked (in case jboss based container).
|
||||
* In case of migration scenario: previous container is stopped.
|
||||
*/
|
||||
public void afterStart(@Observes AfterStart event) throws IOException, InterruptedException {
|
||||
Container container = containers.pollFirst();
|
||||
|
||||
if (isJBossBased(container)) {
|
||||
jbossHomePath = container.getContainerConfiguration().getContainerProperties().get("jbossHome");
|
||||
log.debug("jbossHome: " + jbossHomePath + "\n");
|
||||
}
|
||||
checkServerLog(jbossHomePath);
|
||||
|
||||
if (migrationTests && !alreadyStopped) {
|
||||
log.info("\n\n### Stopping keycloak " + System.getProperty("version", "- previous") + " ###\n");
|
||||
stopSuiteContainers.fire(new StopSuiteContainers());
|
||||
log.info("\n\n### Starting keycloak current version ###\n");
|
||||
alreadyStopped = true;
|
||||
}
|
||||
installAdapters(container);
|
||||
}
|
||||
|
||||
/*
|
||||
* non-javadoc
|
||||
*
|
||||
* check server logs whether there are no ERRORs or SEVEREs
|
||||
*/
|
||||
private void checkServerLog(String jbossHomePath) throws IOException {
|
||||
if (jbossHomePath != null && System.getProperty("check.server.log", "true").equals("true")) {
|
||||
File serverLog = new File(jbossHomePath + "/standalone/log/server.log");
|
||||
String serverLogContent = FileUtils.readFileToString(serverLog);
|
||||
|
||||
boolean containsError
|
||||
= serverLogContent.contains("ERROR")
|
||||
|| serverLogContent.contains("SEVERE")
|
||||
|| serverLogContent.contains("Exception ");
|
||||
//There is expected string "Exception" in server log: Adding provider
|
||||
//singleton org.keycloak.services.resources.ModelExceptionMapper
|
||||
|
||||
if (containsError) {
|
||||
throw new RuntimeException(serverLog.getPath() + " contains ERROR.");
|
||||
}
|
||||
log.info(serverLog.getPath() + " doesn't contain Error");
|
||||
}
|
||||
}
|
||||
|
||||
public void beforeSuite(@Observes BeforeSuite event) {
|
||||
suiteContext.set(new SuiteContext());
|
||||
}
|
||||
|
||||
public void startContainers(@Observes(precedence = -1) BeforeClass event) {
|
||||
controller = containerController.get();
|
||||
|
||||
Class testClass = event.getTestClass().getJavaClass();
|
||||
appServerQualifier = getAppServerQualifier(testClass);
|
||||
|
||||
if (!controller.isStarted(appServerQualifier)) {
|
||||
controller.start(appServerQualifier);
|
||||
}
|
||||
|
||||
initializeTestContext(testClass);
|
||||
initializeAdminClient();
|
||||
initializeOAuthClient();
|
||||
}
|
||||
|
||||
private void initializeTestContext(Class testClass) {
|
||||
String authServerContextRootStr = getAuthServerContextRootFromSystemProperty();
|
||||
String appServerContextRootStr = isRelative(testClass)
|
||||
? authServerContextRootStr
|
||||
: getAppServerContextRootFromSystemProperty();
|
||||
try {
|
||||
URL authServerContextRoot = new URL(authServerContextRootStr);
|
||||
URL appServerContextRoot = new URL(appServerContextRootStr);
|
||||
|
||||
testContext.set(new TestContext(authServerContextRoot, appServerContextRoot));
|
||||
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new IllegalStateException("Malformed url.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeAdminClient() {
|
||||
adminClient.set(Keycloak.getInstance(
|
||||
getAuthServerContextRootFromSystemProperty() + "/auth",
|
||||
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID));
|
||||
}
|
||||
|
||||
private void initializeOAuthClient() {
|
||||
oauthClient.set(new OAuthClient(getAuthServerContextRootFromSystemProperty() + "/auth"));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param testClass
|
||||
* @param annotationClass
|
||||
* @return testClass or the nearest superclass of testClass annotated with
|
||||
* annotationClass
|
||||
*/
|
||||
public static Class getNearestSuperclassWithAnnotation(Class testClass, Class annotationClass) {
|
||||
return testClass.isAnnotationPresent(annotationClass) ? testClass
|
||||
: (testClass.getSuperclass().equals(Object.class) ? null // stop recursion
|
||||
: getNearestSuperclassWithAnnotation(testClass.getSuperclass(), annotationClass)); // continue recursion
|
||||
}
|
||||
|
||||
public static String getAuthServerQualifier() {
|
||||
return System.getProperty(
|
||||
AUTH_SERVER_CONTAINER_PROPERTY,
|
||||
AUTH_SERVER_CONTAINER_DEFAULT);
|
||||
}
|
||||
|
||||
public static String getAppServerQualifier(Class testClass) {
|
||||
Class<? extends ContainersTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class);
|
||||
|
||||
String appServerQ = (annotatedClass == null ? null
|
||||
: annotatedClass.getAnnotation(AppServerContainer.class).value());
|
||||
|
||||
return appServerQ == null || appServerQ.isEmpty()
|
||||
? getAuthServerQualifier() // app server == auth server
|
||||
: appServerQ;
|
||||
}
|
||||
|
||||
public static boolean hasAppServerContainerAnnotation(Class testClass) {
|
||||
return getNearestSuperclassWithAnnotation(testClass, AppServerContainer.class) != null;
|
||||
}
|
||||
|
||||
public static boolean isRelative(Class testClass) {
|
||||
return getAppServerQualifier(testClass).equals(getAuthServerQualifier());
|
||||
}
|
||||
|
||||
public static String getAdapterLibsLocationProperty(Class testClass) {
|
||||
Class<? extends ContainersTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AdapterLibsLocationProperty.class);
|
||||
return (annotatedClass == null ? null
|
||||
: annotatedClass.getAnnotation(AdapterLibsLocationProperty.class).value());
|
||||
}
|
||||
|
||||
public static boolean isWildflyAppServer(Class testClass) {
|
||||
return getAppServerQualifier(testClass).contains("wildfly");
|
||||
}
|
||||
|
||||
public static boolean isTomcatAppServer(Class testClass) {
|
||||
return getAppServerQualifier(testClass).contains("tomcat");
|
||||
}
|
||||
|
||||
public static boolean isOSGiAppServer(Class testClass) {
|
||||
String q = getAppServerQualifier(testClass);
|
||||
return q.contains("karaf") || q.contains("fuse");
|
||||
}
|
||||
|
||||
public static String getAuthServerContextRootFromSystemProperty() {
|
||||
// TODO find if this can be extracted from ARQ metadata instead of System properties
|
||||
boolean sslRequired = Boolean.parseBoolean(System.getProperty("auth.server.ssl.required"));
|
||||
if (sslRequired) {
|
||||
return "https://localhost:" + Integer.parseInt(System.getProperty("auth.server.https.port", "8543"));
|
||||
}
|
||||
return "http://localhost:" + Integer.parseInt(System.getProperty("auth.server.http.port", "8180"));
|
||||
}
|
||||
|
||||
public static String getAppServerContextRootFromSystemProperty() {
|
||||
boolean sslRequired = Boolean.parseBoolean(System.getProperty("app.server.ssl.required"));
|
||||
if (sslRequired) {
|
||||
return "https://localhost:" + Integer.parseInt(System.getProperty("app.server.https.port", "8643"));
|
||||
}
|
||||
return "http://localhost:" + Integer.parseInt(System.getProperty("app.server.http.port", "8280"));
|
||||
}
|
||||
|
||||
private void installAdapters(Container container) throws InterruptedException, IOException {
|
||||
if (!alreadyInstalled && !skipInstallAdapters && isJBossBased(container)) {
|
||||
File bin = new File(jbossHomePath + "/bin");
|
||||
String command = "java -jar " + jbossHomePath + "/bin/client/jboss-cli-client.jar";
|
||||
String adapterScript = "adapter-install.cli";
|
||||
String samlAdapterScript = "adapter-install-saml.cli";
|
||||
String managementPort = container.getContainerConfiguration().getContainerProperties().get("managementPort");
|
||||
|
||||
String controllerArg = " --controller=localhost:" + managementPort;
|
||||
if (new File(bin, adapterScript).exists()) {
|
||||
log.info("Installing adapter to app server via cli script");
|
||||
execCommand(command + " --connect --file=" + adapterScript + controllerArg, bin);
|
||||
}
|
||||
if (new File(bin, samlAdapterScript).exists()) {
|
||||
log.info("Installing saml adapter to app server via cli script");
|
||||
execCommand(command + " --connect --file=" + samlAdapterScript + controllerArg, bin);
|
||||
}
|
||||
if (new File(bin, adapterScript).exists() || new File(bin, samlAdapterScript).exists()) {
|
||||
log.info("Restarting container");
|
||||
execCommand(command + " --connect --command=reload" + controllerArg, bin);
|
||||
log.info("Container restarted");
|
||||
pause(5000);
|
||||
checkServerLog(jbossHomePath);
|
||||
}
|
||||
if (container.getName().startsWith("app-server")) {
|
||||
alreadyInstalled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void execCommand(String command, File dir) throws IOException, InterruptedException {
|
||||
Process process = Runtime.getRuntime().exec(command, null, dir);
|
||||
if (process.waitFor(10, TimeUnit.SECONDS)) {
|
||||
if (process.exitValue() != 0) {
|
||||
getOutput("ERROR", process.getErrorStream());
|
||||
throw new RuntimeException("Adapter installation failed. Process exitValue: "
|
||||
+ process.exitValue());
|
||||
}
|
||||
getOutput("OUTPUT", process.getInputStream());
|
||||
log.debug("process.isAlive(): " + process.isAlive());
|
||||
} else {
|
||||
if (process.isAlive()) {
|
||||
process.destroyForcibly();
|
||||
}
|
||||
throw new RuntimeException("Timeout after 10 seconds.");
|
||||
}
|
||||
}
|
||||
|
||||
private void getOutput(String type, InputStream is) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<").append(type).append(">");
|
||||
System.out.println(builder);
|
||||
builder = new StringBuilder();
|
||||
while (reader.ready()) {
|
||||
System.out.println(reader.readLine());
|
||||
}
|
||||
builder.append("</").append(type).append(">");
|
||||
System.out.println(builder);
|
||||
}
|
||||
|
||||
private boolean isJBossBased(Container container) {
|
||||
if (container == null) {
|
||||
return false;
|
||||
}
|
||||
return container.getName().matches("a.*-server-wildfly")
|
||||
|| container.getName().matches("a.*-server-eap.")
|
||||
|| container.getName().equals("app-server-as7");
|
||||
}
|
||||
}
|
|
@ -37,8 +37,12 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getAdapterLibsLocationProperty;
|
||||
import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.hasAppServerContainerAnnotation;
|
||||
import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isRelative;
|
||||
import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isTomcatAppServer;
|
||||
|
||||
import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*;
|
||||
import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.*;
|
||||
import static org.keycloak.testsuite.util.IOUtil.*;
|
||||
|
||||
;
|
||||
|
@ -66,7 +70,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
|
|||
log.info("Processing archive " + archive.getName());
|
||||
// if (isAdapterTest(testClass)) {
|
||||
modifyAdapterConfigs(archive, testClass);
|
||||
attachKeycloakLibs(archive, testClass);
|
||||
attachAdapterLibs(archive, testClass);
|
||||
modifyWebXml(archive, testClass);
|
||||
// } else {
|
||||
// log.info(testClass.getJavaClass().getSimpleName() + " is not an AdapterTest");
|
||||
|
@ -89,21 +93,21 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
|
|||
protected void modifyAdapterConfig(Archive<?> archive, String adapterConfigPath, boolean relative) {
|
||||
if (archive.contains(adapterConfigPath)) {
|
||||
log.info("Modifying adapter config " + adapterConfigPath + " in " + archive.getName());
|
||||
if (adapterConfigPath.equals(SAML_ADAPTER_CONFIG_PATH)) {
|
||||
if (adapterConfigPath.equals(SAML_ADAPTER_CONFIG_PATH)) { // SAML adapter config
|
||||
log.info("Modyfying saml adapter config in " + archive.getName());
|
||||
|
||||
Document doc = loadXML(archive.get("WEB-INF/keycloak-saml.xml").getAsset().openStream());
|
||||
if (authServerSslRequired) {
|
||||
modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.https.port", null));
|
||||
modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.https.port"));
|
||||
modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "http", "https");
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.https.port", null));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.https.port"));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "http", "https");
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.https.port", null));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.https.port"));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "http", "https");
|
||||
} else {
|
||||
modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.http.port", null));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.http.port", null));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.http.port", null));
|
||||
modifyDocElementAttribute(doc, "SingleSignOnService", "bindingUrl", "8080", System.getProperty("auth.server.http.port"));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "postBindingUrl", "8080", System.getProperty("auth.server.http.port"));
|
||||
modifyDocElementAttribute(doc, "SingleLogoutService", "redirectBindingUrl", "8080", System.getProperty("auth.server.http.port"));
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -112,7 +116,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
|
|||
log.error("Can't transform document to String");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
} else { // OIDC adapter config
|
||||
try {
|
||||
BaseAdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
|
||||
.getAsset().openStream(), BaseAdapterConfig.class);
|
||||
|
@ -122,7 +126,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
|
|||
adapterConfig.setAuthServerUrl("/auth");
|
||||
// ac.setRealmKey(null); // TODO verify if realm key is required for relative scneario
|
||||
} else {
|
||||
adapterConfig.setAuthServerUrl(getAuthServerContextRootFromSystemProperty() + "/auth");
|
||||
adapterConfig.setAuthServerUrl(getAuthServerContextRoot() + "/auth");
|
||||
adapterConfig.setRealmKey(REALM_KEY);
|
||||
}
|
||||
|
||||
|
@ -140,7 +144,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
protected void attachKeycloakLibs(Archive<?> archive, TestClass testClass) {
|
||||
protected void attachAdapterLibs(Archive<?> archive, TestClass testClass) {
|
||||
AdapterLibsMode adapterType = AdapterLibsMode.getByType(System.getProperty("adapter.libs.mode",
|
||||
AdapterLibsMode.PROVIDED.getType()));
|
||||
log.info("Adapter type: " + adapterType);
|
||||
|
|
|
@ -23,7 +23,7 @@ import org.jboss.arquillian.container.spi.client.deployment.TargetDescription;
|
|||
import org.jboss.arquillian.container.test.impl.client.deployment.AnnotationDeploymentScenarioGenerator;
|
||||
import org.jboss.arquillian.test.spi.TestClass;
|
||||
import org.jboss.logging.Logger;
|
||||
import static org.keycloak.testsuite.arquillian.ContainersTestEnricher.*;
|
||||
import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getAppServerQualifier;
|
||||
|
||||
/**
|
||||
* Changes target container for all Arquillian deployments based on value of
|
||||
|
|
|
@ -47,7 +47,8 @@ public class KeycloakArquillianExtension implements LoadableExtension {
|
|||
builder
|
||||
.service(DeploymentScenarioGenerator.class, DeploymentTargetModifier.class)
|
||||
.service(ApplicationArchiveProcessor.class, DeploymentArchiveProcessor.class)
|
||||
.observer(ContainersTestEnricher.class);
|
||||
.observer(AuthServerTestEnricher.class)
|
||||
.observer(AppServerTestEnricher.class);
|
||||
|
||||
builder
|
||||
.service(DeployableContainer.class, CustomUndertowContainer.class);
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.arquillian;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import static org.keycloak.testsuite.util.MailServerConfiguration.*;
|
||||
|
||||
/**
|
||||
|
@ -27,10 +29,18 @@ import static org.keycloak.testsuite.util.MailServerConfiguration.*;
|
|||
*/
|
||||
public final class SuiteContext {
|
||||
|
||||
private final Set<ContainerInfo> container;
|
||||
|
||||
private ContainerInfo authServerInfo;
|
||||
private final List<ContainerInfo> authServerBackendsInfo = new ArrayList<>();
|
||||
|
||||
private ContainerInfo migratedAuthServerInfo;
|
||||
|
||||
private boolean adminPasswordUpdated;
|
||||
private final Map<String, String> smtpServer = new HashMap<>();
|
||||
|
||||
public SuiteContext() {
|
||||
public SuiteContext(Set<ContainerInfo> arquillianContainers) {
|
||||
this.container = arquillianContainers;
|
||||
this.adminPasswordUpdated = false;
|
||||
smtpServer.put("from", FROM);
|
||||
smtpServer.put("host", HOST);
|
||||
|
@ -48,4 +58,44 @@ public final class SuiteContext {
|
|||
public Map<String, String> getSmtpServer() {
|
||||
return smtpServer;
|
||||
}
|
||||
|
||||
public ContainerInfo getAuthServerInfo() {
|
||||
return authServerInfo;
|
||||
}
|
||||
|
||||
public void setAuthServerInfo(ContainerInfo authServerInfo) {
|
||||
this.authServerInfo = authServerInfo;
|
||||
}
|
||||
|
||||
public List<ContainerInfo> getAuthServerBackendsInfo() {
|
||||
return authServerBackendsInfo;
|
||||
}
|
||||
|
||||
public ContainerInfo getMigratedAuthServerInfo() {
|
||||
return migratedAuthServerInfo;
|
||||
}
|
||||
|
||||
public void setMigratedAuthServerInfo(ContainerInfo migratedAuthServerInfo) {
|
||||
this.migratedAuthServerInfo = migratedAuthServerInfo;
|
||||
}
|
||||
|
||||
public boolean isAuthServerCluster() {
|
||||
return !authServerBackendsInfo.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isAuthServerMigrationEnabled() {
|
||||
return migratedAuthServerInfo != null;
|
||||
}
|
||||
|
||||
public Set<ContainerInfo> getContainers() {
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SUITE CONTEXT:\n"
|
||||
+ "Auth server: " + authServerInfo.getQualifier() + "\n"
|
||||
+(isAuthServerCluster() ? "Auth server cluster: " + getAuthServerBackendsInfo().size() + " nodes+\n" : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.arquillian;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -25,29 +25,21 @@ import java.net.URL;
|
|||
*/
|
||||
public final class TestContext {
|
||||
|
||||
private URL authServerContextRoot;
|
||||
private URL appServerContextRoot;
|
||||
private final SuiteContext suiteContext;
|
||||
|
||||
private final Class testClass;
|
||||
|
||||
private ContainerInfo appServerInfo;
|
||||
private final List<ContainerInfo> appServerBackendsInfo = new ArrayList<>();
|
||||
|
||||
private boolean adminLoggedIn;
|
||||
|
||||
public TestContext() {
|
||||
public TestContext(SuiteContext suiteContext, Class testClass) {
|
||||
this.suiteContext = suiteContext;
|
||||
this.testClass = testClass;
|
||||
this.adminLoggedIn = false;
|
||||
}
|
||||
|
||||
public TestContext(URL authServerContextRoot, URL appServerContextRoot) {
|
||||
this();
|
||||
this.authServerContextRoot = authServerContextRoot;
|
||||
this.appServerContextRoot = appServerContextRoot;
|
||||
}
|
||||
|
||||
public URL getAuthServerContextRoot() {
|
||||
return authServerContextRoot;
|
||||
}
|
||||
|
||||
public URL getAppServerContextRoot() {
|
||||
return appServerContextRoot;
|
||||
}
|
||||
|
||||
public boolean isAdminLoggedIn() {
|
||||
return adminLoggedIn;
|
||||
}
|
||||
|
@ -56,12 +48,44 @@ public final class TestContext {
|
|||
this.adminLoggedIn = adminLoggedIn;
|
||||
}
|
||||
|
||||
public void setAuthServerContextRoot(URL authServerContextRoot) {
|
||||
this.authServerContextRoot = authServerContextRoot;
|
||||
public ContainerInfo getAppServerInfo() {
|
||||
return appServerInfo;
|
||||
}
|
||||
|
||||
public void setAppServerContextRoot(URL appServerContextRoot) {
|
||||
this.appServerContextRoot = appServerContextRoot;
|
||||
public void setAppServerInfo(ContainerInfo appServerInfo) {
|
||||
this.appServerInfo = appServerInfo;
|
||||
}
|
||||
|
||||
public List<ContainerInfo> getAppServerBackendsInfo() {
|
||||
return appServerBackendsInfo;
|
||||
}
|
||||
|
||||
public Class getTestClass() {
|
||||
return testClass;
|
||||
}
|
||||
|
||||
public boolean isAdapterTest() {
|
||||
return appServerInfo != null;
|
||||
}
|
||||
|
||||
public boolean isRelativeAdapterTest() {
|
||||
return isAdapterTest()
|
||||
&& appServerInfo.getQualifier().equals(
|
||||
suiteContext.getAuthServerInfo().getQualifier()); // app server == auth server
|
||||
}
|
||||
|
||||
public boolean isClusteredAdapterTest() {
|
||||
return isAdapterTest() && !appServerBackendsInfo.isEmpty();
|
||||
}
|
||||
|
||||
public SuiteContext getSuiteContext() {
|
||||
return suiteContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TEST CONTEXT: " + getTestClass().getCanonicalName() + "\n"
|
||||
+ (isAdapterTest() ? "App server container: " + getAppServerInfo() + "\n" : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.net.MalformedURLException;
|
|||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.keycloak.testsuite.arquillian.SuiteContext;
|
||||
|
||||
public class URLProvider extends URLResourceProvider {
|
||||
|
||||
|
@ -43,6 +44,8 @@ public class URLProvider extends URLResourceProvider {
|
|||
|
||||
private final boolean appServerSslRequired = Boolean.parseBoolean(System.getProperty("app.server.ssl.required"));
|
||||
|
||||
@Inject
|
||||
Instance<SuiteContext> suiteContext;
|
||||
@Inject
|
||||
Instance<TestContext> testContext;
|
||||
|
||||
|
@ -97,10 +100,10 @@ public class URLProvider extends URLResourceProvider {
|
|||
// inject context roots if annotation present
|
||||
for (Annotation a : qualifiers) {
|
||||
if (AuthServerContext.class.isAssignableFrom(a.annotationType())) {
|
||||
return testContext.get().getAuthServerContextRoot();
|
||||
return suiteContext.get().getAuthServerInfo().getContextRoot();
|
||||
}
|
||||
if (AppServerContext.class.isAssignableFrom(a.annotationType())) {
|
||||
return testContext.get().getAppServerContextRoot();
|
||||
return testContext.get().getAppServerInfo().getContextRoot();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,11 +41,11 @@ public class AuthServer extends AuthServerContextRoot {
|
|||
return uri.getScheme() + "://" + uri.getAuthority() + "/auth";
|
||||
}
|
||||
|
||||
@ArquillianResource
|
||||
protected Keycloak keycloak;
|
||||
|
||||
public Keycloak keycloak() {
|
||||
return keycloak;
|
||||
}
|
||||
// @ArquillianResource
|
||||
// protected Keycloak keycloak;
|
||||
//
|
||||
// public Keycloak keycloak() {
|
||||
// return keycloak;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -101,9 +101,9 @@ public class AccountManagement extends AuthRealm {
|
|||
save.click();
|
||||
}
|
||||
|
||||
public RealmResource realmResource() {
|
||||
return keycloak().realm(getAuthRealm());
|
||||
}
|
||||
// public RealmResource realmResource() {
|
||||
// return keycloak().realm(getAuthRealm());
|
||||
// }
|
||||
|
||||
public void waitForAccountLinkPresent() {
|
||||
waitUntilElement(accountLink, "account link should be present").is().present();
|
||||
|
|
|
@ -59,9 +59,9 @@ public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
|
|||
return configureMenu;
|
||||
}
|
||||
|
||||
public RealmResource realmResource() {
|
||||
return realmsResource().realm(getConsoleRealm());
|
||||
}
|
||||
// public RealmResource realmResource() {
|
||||
// return realmsResource().realm(getConsoleRealm());
|
||||
// }
|
||||
|
||||
public class ConfigureMenu {
|
||||
|
||||
|
|
|
@ -59,8 +59,8 @@ public class AdminConsoleRealmsRoot extends AdminConsole {
|
|||
@FindBy(css = "realm-selector")
|
||||
protected RealmSelector realmSelector;
|
||||
|
||||
public RealmsResource realmsResource() {
|
||||
return keycloak.realms();
|
||||
}
|
||||
// public RealmsResource realmsResource() {
|
||||
// return keycloak.realms();
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.util;
|
||||
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -33,6 +32,8 @@ import javax.xml.transform.TransformerFactory;
|
|||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -40,6 +41,8 @@ import java.io.*;
|
|||
*/
|
||||
public class IOUtil {
|
||||
|
||||
private static final Logger log = Logger.getLogger(IOUtil.class);
|
||||
|
||||
public static <T> T loadJson(InputStream is, Class<T> type) {
|
||||
try {
|
||||
return JsonSerialization.readValue(is, type);
|
||||
|
@ -71,7 +74,7 @@ public class IOUtil {
|
|||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
return dBuilder.parse(is);
|
||||
} catch (ParserConfigurationException|SAXException|IOException e) {
|
||||
} catch (ParserConfigurationException | SAXException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
@ -99,4 +102,36 @@ public class IOUtil {
|
|||
}
|
||||
node.setTextContent(node.getTextContent().replace(regex, replacement));
|
||||
}
|
||||
|
||||
public static void execCommand(String command, File dir) throws IOException, InterruptedException {
|
||||
Process process = Runtime.getRuntime().exec(command, null, dir);
|
||||
if (process.waitFor(10, TimeUnit.SECONDS)) {
|
||||
if (process.exitValue() != 0) {
|
||||
getOutput("ERROR", process.getErrorStream());
|
||||
throw new RuntimeException("Adapter installation failed. Process exitValue: "
|
||||
+ process.exitValue());
|
||||
}
|
||||
getOutput("OUTPUT", process.getInputStream());
|
||||
log.debug("process.isAlive(): " + process.isAlive());
|
||||
} else {
|
||||
if (process.isAlive()) {
|
||||
process.destroyForcibly();
|
||||
}
|
||||
throw new RuntimeException("Timeout after 10 seconds.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void getOutput(String type, InputStream is) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<").append(type).append(">");
|
||||
System.out.println(builder);
|
||||
builder = new StringBuilder();
|
||||
while (reader.ready()) {
|
||||
System.out.println(reader.readLine());
|
||||
}
|
||||
builder.append("</").append(type).append(">");
|
||||
System.out.println(builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package org.keycloak.testsuite.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author vramik
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class LogChecker {
|
||||
|
||||
private static final Logger log = Logger.getLogger(LogChecker.class);
|
||||
|
||||
public static void checkServerLog(File logFile) throws IOException {
|
||||
log.info(String.format("Checking server log: '%s'", logFile.getAbsolutePath()));
|
||||
String logContent = FileUtils.readFileToString(logFile);
|
||||
|
||||
boolean containsError
|
||||
= logContent.contains("ERROR")
|
||||
|| logContent.contains("SEVERE")
|
||||
|| logContent.contains("Exception ");
|
||||
|
||||
//There is expected string "Exception" in server log: Adding provider
|
||||
//singleton org.keycloak.services.resources.ModelExceptionMapper
|
||||
if (containsError) {
|
||||
throw new RuntimeException(String.format("Server log file contains ERROR: '%s'", logFile.getPath()));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkJBossServerLog(String jbossHome) throws IOException {
|
||||
checkServerLog(new File(jbossHome + "/standalone/log/server.log"));
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,6 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite;
|
||||
|
||||
import org.keycloak.testsuite.arquillian.TestContext;
|
||||
|
@ -33,9 +32,12 @@ import org.junit.Before;
|
|||
import org.junit.runner.RunWith;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.RealmsResource;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
||||
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
|
||||
import org.keycloak.testsuite.arquillian.SuiteContext;
|
||||
import org.keycloak.testsuite.auth.page.WelcomePage;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
@ -67,10 +69,8 @@ public abstract class AbstractKeycloakTest {
|
|||
@ArquillianResource
|
||||
protected TestContext testContext;
|
||||
|
||||
@ArquillianResource
|
||||
protected Keycloak adminClient;
|
||||
|
||||
@ArquillianResource
|
||||
protected OAuthClient oauthClient;
|
||||
|
||||
protected List<RealmRepresentation> testRealmReps;
|
||||
|
@ -100,6 +100,11 @@ public abstract class AbstractKeycloakTest {
|
|||
|
||||
@Before
|
||||
public void beforeAbstractKeycloakTest() {
|
||||
adminClient = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
|
||||
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
|
||||
oauthClient = new OAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth");
|
||||
|
||||
|
||||
adminUser = createAdminUserRepresentation();
|
||||
|
||||
setDefaultPageUriParameters();
|
||||
|
@ -196,4 +201,8 @@ public abstract class AbstractKeycloakTest {
|
|||
adminClient.realms().realm(realm.getRealm()).remove();
|
||||
}
|
||||
|
||||
public RealmsResource realmsResouce() {
|
||||
return adminClient.realms();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package org.keycloak.testsuite;
|
||||
|
||||
import java.util.List;
|
||||
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class ContainersTest extends AbstractKeycloakTest {
|
||||
|
||||
@ArquillianResource
|
||||
ContainerController controller;
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAuthServer() {
|
||||
|
||||
log.info("AUTH SERVER should be started.");
|
||||
assertTrue(controller.isStarted(AuthServerTestEnricher.getAuthServerQualifier()));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,6 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
|||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.AbstractAuthTest;
|
||||
import org.keycloak.testsuite.adapter.page.AppServerContextRoot;
|
||||
import org.keycloak.testsuite.arquillian.ContainersTestEnricher;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -78,7 +77,7 @@ public abstract class AbstractAdapterTest extends AbstractAuthTest {
|
|||
public abstract void addAdapterTestRealms(List<RealmRepresentation> testRealms);
|
||||
|
||||
public boolean isRelative() {
|
||||
return ContainersTestEnricher.isRelative(this.getClass());
|
||||
return testContext.isRelativeAdapterTest();
|
||||
}
|
||||
|
||||
protected void modifyClientRedirectUris(RealmRepresentation realm, String regex, String replacement) {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.client;
|
||||
|
||||
import org.junit.After;
|
||||
|
@ -46,7 +45,7 @@ public abstract class AbstractClientRegistrationTest extends AbstractKeycloakTes
|
|||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
reg = ClientRegistration.create().url(testContext.getAuthServerContextRoot() + "/auth", "test").build();
|
||||
reg = ClientRegistration.create().url(suiteContext.getAuthServerInfo().getContextRoot() + "/auth", "test").build();
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.client;
|
||||
|
||||
import org.junit.Before;
|
||||
|
@ -87,7 +86,7 @@ public class AdapterInstallationConfigTest extends AbstractClientRegistrationTes
|
|||
AdapterConfig config = reg.getAdapterConfig(client.getClientId());
|
||||
assertNotNull(config);
|
||||
|
||||
assertEquals(testContext.getAuthServerContextRoot() + "/auth", config.getAuthServerUrl());
|
||||
assertEquals(suiteContext.getAuthServerInfo().getContextRoot() + "/auth", config.getAuthServerUrl());
|
||||
assertEquals("test", config.getRealm());
|
||||
|
||||
assertEquals(1, config.getCredentials().size());
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<!--
|
||||
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
~ and other contributors as indicated by the @author tags.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
~ and other contributors as indicated by the @author tags.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<arquillian xmlns="http://jboss.org/schema/arquillian"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
|
@ -44,80 +44,6 @@
|
|||
<property name="deploymentExportPath">target/deployments</property>
|
||||
</engine>
|
||||
|
||||
<!-- PREVIOUS VERSIONS KEYCLOAK FOR MIGRATION TESTS -->
|
||||
<!-- IT HAS TO BE LISTED ABOWE KEYCLOAK AUTH SERVERS -->
|
||||
|
||||
<container qualifier="keycloak-1.6.1.Final" mode="suite" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc16}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">
|
||||
-Dkeycloak.migration.action=import
|
||||
-Dkeycloak.migration.provider=singleFile
|
||||
-Dkeycloak.migration.file=${keycloak.migration.file}
|
||||
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
|
||||
-Dkeycloak.migration.realmName=Migration
|
||||
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
|
||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
||||
</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="keycloak-1.5.1.Final" mode="suite" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc15}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">
|
||||
-Dkeycloak.migration.action=import
|
||||
-Dkeycloak.migration.provider=singleFile
|
||||
-Dkeycloak.migration.file=${keycloak.migration.file}
|
||||
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
|
||||
-Dkeycloak.migration.realmName=Migration
|
||||
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
|
||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
||||
</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="keycloak-1.4.0.Final" mode="suite" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc14}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="keycloak-1.3.1.Final" mode="suite" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc13}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="keycloak-1.2.0.Final" mode="suite" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc12}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<!-- KEYCLOAK AUTH SERVERS -->
|
||||
|
||||
<container qualifier="auth-server-undertow" mode="suite" >
|
||||
|
@ -140,6 +66,37 @@
|
|||
</configuration>
|
||||
</container>
|
||||
|
||||
<group qualifier="auth-server-wildfly-cluster">
|
||||
<container qualifier="auth-server-wildfly-balancer" mode="suite" >
|
||||
<configuration>
|
||||
<property name="enabled">${auth.server.wildfly.cluster}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${wildfly.home}</property>
|
||||
<property name="javaVmArguments">
|
||||
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
|
||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
||||
${adapter.test.props}
|
||||
</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
<container qualifier="auth-server-wildfly-backend1" mode="manual" >
|
||||
<configuration>
|
||||
<property name="enabled">${auth.server.wildfly.cluster}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.backend1.home}</property>
|
||||
<property name="javaVmArguments">
|
||||
-Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset}
|
||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
||||
${adapter.test.props}
|
||||
</property>
|
||||
<property name="managementPort">${auth.server.backend1.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
</group>
|
||||
|
||||
<container qualifier="auth-server-eap7" mode="suite" >
|
||||
<configuration>
|
||||
<property name="enabled">${auth.server.eap7}</property>
|
||||
|
@ -151,4 +108,85 @@
|
|||
</configuration>
|
||||
</container>
|
||||
|
||||
<!-- PREVIOUS VERSIONS OF KEYCLOAK FOR MIGRATION TESTS -->
|
||||
|
||||
<container qualifier="migrated-auth-server-wildfly_kc16" mode="manual" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc16}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">
|
||||
-Dkeycloak.migration.action=import
|
||||
-Dkeycloak.migration.provider=singleFile
|
||||
-Dkeycloak.migration.file=${keycloak.migration.file}
|
||||
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
|
||||
-Dkeycloak.migration.realmName=Migration
|
||||
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
|
||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
||||
</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="migrated-auth-server-wildfly_kc15" mode="manual" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc15}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">
|
||||
-Dkeycloak.migration.action=import
|
||||
-Dkeycloak.migration.provider=singleFile
|
||||
-Dkeycloak.migration.file=${keycloak.migration.file}
|
||||
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
|
||||
-Dkeycloak.migration.realmName=Migration
|
||||
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
|
||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
||||
</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="migrated-auth-server-wildfly_kc14" mode="manual" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc14}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="migrated-auth-server-wildfly_kc13" mode="manual" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc13}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<container qualifier="migrated-auth-server-wildfly_kc12" mode="manual" >
|
||||
<configuration>
|
||||
<property name="enabled">${migration.kc12}</property>
|
||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||
<property name="jbossHome">${keycloak.migration.home}</property>
|
||||
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=${auth.server.port.offset} -Xms64m -Xmx512m -XX:MaxPermSize=256m</property>
|
||||
<property name="managementPort">${auth.server.management.port}</property>
|
||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||
</configuration>
|
||||
</container>
|
||||
|
||||
<!--
|
||||
|
||||
APP SERVER CONTAINERS ARE ADDED BY XSL TRANSFORMATIONS IN ADAPTER TEST SUBMODULES
|
||||
The configuration of various application containers had to be split into multiple
|
||||
maven submodules: tests/other/adapters, which are activated on demand by profiles.
|
||||
|
||||
-->
|
||||
|
||||
</arquillian>
|
||||
|
|
|
@ -286,13 +286,6 @@
|
|||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>auth-server-wildfly</id>
|
||||
<modules>
|
||||
<module>wildfly-relative</module>
|
||||
</modules>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>app-server-eap6</id>
|
||||
<modules>
|
||||
|
@ -311,6 +304,12 @@
|
|||
<module>wildfly</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>app-server-wildfly-relative</id>
|
||||
<modules>
|
||||
<module>wildfly-relative</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>app-server-wildfly8</id>
|
||||
<modules>
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
~ and other contributors as indicated by the @author tags.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
~ and other contributors as indicated by the @author tags.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
@ -54,7 +54,39 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-auth-server-wildfly-profile</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireActiveProfile>
|
||||
<profiles>auth-server-wildfly</profiles>
|
||||
</requireActiveProfile>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
|
||||
<profile>
|
||||
<id>auth-server-wildfly</id>
|
||||
<!--dummy profile for the enforcer plugin to work-->
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>adapter-libs-bundled</id>
|
||||
<activation>
|
||||
|
|
|
@ -108,8 +108,6 @@ public class Client extends Clients {
|
|||
|
||||
}
|
||||
|
||||
public ClientResource clientResource() {
|
||||
return clientsResource().get(getId());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -126,8 +126,4 @@ public class Clients extends AdminConsoleRealm {
|
|||
}
|
||||
}
|
||||
|
||||
public ClientsResource clientsResource() {
|
||||
return realmResource().clients();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,8 +23,4 @@ public class ClientRoles extends Client {
|
|||
return table;
|
||||
}
|
||||
|
||||
public RolesResource rolesResource() {
|
||||
return clientResource().roles();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -92,8 +92,4 @@ public class IdentityProviderSettings extends AdminConsoleRealm {
|
|||
return rows;
|
||||
}
|
||||
|
||||
public IdentityProvidersResource identityProviders() {
|
||||
return realmResource().identityProviders();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,8 +35,4 @@ public class Roles extends AdminConsoleRealm {
|
|||
|
||||
}
|
||||
|
||||
public RolesResource rolesResource() {
|
||||
return realmResource().roles();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.keycloak.testsuite.console.page.users;
|
||||
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.testsuite.console.page.fragment.Breadcrumb;
|
||||
import static org.keycloak.testsuite.console.page.fragment.Breadcrumb.BREADCRUMB_XPATH;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
@ -76,8 +75,4 @@ public class User extends Users {
|
|||
|
||||
}
|
||||
|
||||
public UserResource userResource() {
|
||||
return usersResource().get(getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,4 @@ public class UserRoleMappings extends User {
|
|||
return form;
|
||||
}
|
||||
|
||||
public RoleMappingResource roleMappingResource() {
|
||||
return userResource().roles();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.openqa.selenium.support.FindBy;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
|
||||
|
@ -135,8 +134,4 @@ public class Users extends AdminConsoleRealm {
|
|||
|
||||
}
|
||||
|
||||
public UsersResource usersResource() {
|
||||
return realmResource().users();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.console;
|
||||
|
||||
import org.jboss.arquillian.graphene.findby.FindByJQuery;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
|
|
|
@ -8,6 +8,8 @@ import java.util.Map;
|
|||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Before;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.ClientsResource;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import static org.keycloak.testsuite.auth.page.login.OIDCLogin.OIDC;
|
||||
|
@ -174,8 +176,7 @@ public abstract class AbstractClientTest extends AbstractConsoleTest {
|
|||
}
|
||||
assertEqualsBooleanAttributes(c1.isSurrogateAuthRequired(), c2.isSurrogateAuthRequired());
|
||||
assertEqualsBooleanAttributes(c1.isServiceAccountsEnabled(), c2.isServiceAccountsEnabled());
|
||||
}
|
||||
else if (c1.getProtocol().equals(SAML)) {
|
||||
} else if (c1.getProtocol().equals(SAML)) {
|
||||
assertEqualsBooleanAttributes(c1.isFrontchannelLogout(), c2.isFrontchannelLogout());
|
||||
}
|
||||
}
|
||||
|
@ -215,4 +216,13 @@ public abstract class AbstractClientTest extends AbstractConsoleTest {
|
|||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public ClientsResource clientsResource() {
|
||||
return testRealmResource().clients();
|
||||
}
|
||||
|
||||
public ClientResource clientResource(String id) {
|
||||
return clientsResource().get(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -153,11 +153,11 @@ public class ClientSettingsTest extends AbstractClientTest {
|
|||
c.setPublicClient(true);
|
||||
c.setBearerOnly(true);
|
||||
|
||||
Response r = clientsPage.clientsResource().create(c);
|
||||
Response r = clientsResource().create(c);
|
||||
r.close();
|
||||
clientSettingsPage.setId(getCreatedId(r));
|
||||
|
||||
c = clientSettingsPage.clientResource().toRepresentation();
|
||||
c = clientResource(clientSettingsPage.getId()).toRepresentation();
|
||||
assertTrue(c.isBearerOnly());
|
||||
assertTrue(c.isPublicClient());
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import javax.ws.rs.core.Response;
|
|||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.keycloak.admin.client.resource.ClientsResource;
|
||||
import static org.keycloak.testsuite.console.page.clients.CreateClientForm.OidcAccessType.CONFIDENTIAL;
|
||||
|
||||
|
||||
|
@ -50,12 +51,12 @@ public class AdminEventsTest extends AbstractConsoleTest {
|
|||
@Test
|
||||
public void clientsAdminEventsTest() {
|
||||
newClient = AbstractClientTest.createOidcClientRep(CONFIDENTIAL, "test_client", "http://example.test/test_client/*");
|
||||
Response response = clientsPage.clientsResource().create(newClient);
|
||||
Response response = clientsResource().create(newClient);
|
||||
String id = ApiUtil.getCreatedId(response);
|
||||
response.close();
|
||||
newClient.setClientId("test_client2");
|
||||
clientsPage.clientsResource().get(id).update(newClient);
|
||||
clientsPage.clientsResource().get(id).remove();
|
||||
clientsResource().get(id).update(newClient);
|
||||
clientsResource().get(id).remove();
|
||||
|
||||
adminEventsPage.navigateTo();
|
||||
adminEventsPage.table().filter();
|
||||
|
@ -85,4 +86,8 @@ public class AdminEventsTest extends AbstractConsoleTest {
|
|||
resultList.get(0).findElement(By.xpath("//td[text()='DELETE']"));
|
||||
resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
|
||||
}
|
||||
|
||||
public ClientsResource clientsResource() {
|
||||
return testRealmResource().clients();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.testsuite.console.roles;
|
|||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.keycloak.admin.client.resource.RoleMappingResource;
|
||||
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
||||
import org.keycloak.testsuite.console.page.roles.Roles;
|
||||
import org.keycloak.testsuite.console.page.users.User;
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.jboss.arquillian.graphene.page.Page;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RolesResource;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
|
||||
|
@ -31,7 +32,7 @@ public class DefaultRolesTest extends AbstractRolesTest {
|
|||
public void beforeDefaultRolesTest() {
|
||||
// create a role via admin client
|
||||
defaultRoleRep = new RoleRepresentation("default-role", "", false);
|
||||
rolesPage.rolesResource().create(defaultRoleRep);
|
||||
rolesResource().create(defaultRoleRep);
|
||||
|
||||
defaultRolesPage.navigateTo();
|
||||
// navigate to default roles page
|
||||
|
@ -58,4 +59,8 @@ public class DefaultRolesTest extends AbstractRolesTest {
|
|||
assertTrue(userRolesPage.form().isAssignedRole(defaultRoleName));
|
||||
}
|
||||
|
||||
public RolesResource rolesResource() {
|
||||
return testRealmResource().roles();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package org.keycloak.testsuite.console.users;
|
|||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
||||
import org.keycloak.testsuite.console.page.users.CreateUser;
|
||||
|
@ -36,4 +38,12 @@ public abstract class AbstractUserTest extends AbstractConsoleTest {
|
|||
createUserPage.form().save();
|
||||
}
|
||||
|
||||
public UsersResource usersResource() {
|
||||
return testRealmResource().users();
|
||||
}
|
||||
|
||||
public UserResource userResource(String id) {
|
||||
return usersResource().get(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue