ConfigServiceRepository leverages brXM's production ConfigurationConfigService
to create HST configuration in tests, providing production-identical JCR structure without manual node construction.
Key Benefits:
With BRUT 5.1.0+, ConfigServiceRepository integration is a one-liner via the loadProjectContent attribute:
@BrxmJaxrsTest(
beanPackages = {"org.example.model"},
resources = {MyResource.class},
loadProjectContent = true // Enables ConfigServiceRepository
)
class MyTest {
@Test
void testEndpoint(DynamicJaxrsTest brxm) {
brxm.request()
.get("/site/api/my-endpoint")
.assertStatus(200);
}
}
What loadProjectContent = true does:
pom.xml groupIdtarget/test-classes/META-INF/hcm-module.yamlYou still need the HCM module descriptor and config files (see Manual Setup below), but the annotation handles the repository wiring automatically.
For legacy abstract class tests or advanced customization, use manual Spring XML configuration:
File: src/test/resources/META-INF/hcm-module.yaml
group:
name: myproject-test
project: myproject-test
module:
name: test-config
Important: Do NOT include config: or after: sections.
ModuleReader discovers config by directory convention.
Directory: src/test/resources/hcm-config/hst/
File: demo-hst.yaml
definitions:
config:
/hst:myproject:
jcr:primaryType: hst:hst
/hst:myproject/hst:sites:
jcr:primaryType: hst:sites
/hst:myproject/hst:sites/myproject:
jcr:primaryType: hst:site
hst:content: /content/documents/myproject
/hst:myproject/hst:configurations:
jcr:primaryType: hst:configurations
/hst:myproject/hst:configurations/myproject:
jcr:primaryType: hst:configuration
/hst:myproject/hst:configurations/myproject/hst:sitemap:
jcr:primaryType: hst:sitemap
/hst:myproject/hst:configurations/myproject/hst:sitemap/root:
jcr:primaryType: hst:sitemapitem
hst:componentconfigurationid: hst:pages/homepage
/hst:myproject/hst:configurations/myproject/hst:pages:
jcr:primaryType: hst:pages
/hst:myproject/hst:configurations/myproject/hst:pages/homepage:
jcr:primaryType: hst:component
/hst:myproject/hst:hosts:
jcr:primaryType: hst:virtualhosts
Note: BRUT uses /hst:myproject as HST root (not /hst:hst) for test isolation.
File: src/test/resources/org/example/config-service-jcr.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<bean id="javax.jcr.Repository"
class="org.bloomreach.forge.brut.resources.ConfigServiceRepository"
init-method="init"
destroy-method="close">
<constructor-arg ref="cndResourcesPatterns"/>
<constructor-arg ref="contributedCndResourcesPatterns"/>
<constructor-arg ref="yamlResourcesPatterns"/>
<constructor-arg ref="contributedYamlResourcesPatterns"/>
<constructor-arg value="myproject"/> <!-- project namespace -->
</bean>
</beans>
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyIntegrationTest extends AbstractJaxrsTest {
@Override
protected List<String> contributeSpringConfigurationLocations() {
return Arrays.asList(
"/org/example/config-service-jcr.xml", // ConfigServiceRepository override
"/org/example/custom-jaxrs.xml",
"/org/example/rest-resources.xml"
);
}
@Override
protected String contributeHstConfigurationRootPath() {
return "/hst:myproject"; // BRUT uses project-specific root
}
@Test
void testHstStructureCreated() throws Exception {
Repository repo = getComponentManager().getComponent(Repository.class);
Session session = repo.login(new SimpleCredentials("admin", "admin".toCharArray()));
assertTrue(session.nodeExists("/hst:myproject"));
assertTrue(session.nodeExists("/hst:myproject/hst:configurations/myproject"));
}
}
ConfigServiceRepository uses ModuleReader for explicit module loading:
Test Resources (target/test-classes)
├── META-INF/hcm-module.yaml <- Module descriptor
└── hcm-config/ <- Config discovered by convention
└── hst/*.yaml <- Your HST definitions
|
ModuleReader <- Loads module explicitly (no classpath scan)
|
ConfigurationModelImpl.build() <- Builds configuration model
|
ConfigurationConfigService <- brXM's production bootstrap service
|
JCR Repository <- Production-identical structure
Key Insight: We use ModuleReader.read(path, false) to load test modules
explicitly by path, avoiding ClasspathConfigurationModelReader which scans for ALL modules
(including framework JARs with unmet dependencies).
META-INF/hcm-module.yaml in target/test-classeshcm-config/**/*.yamlConfigurationModelImpl with only test modules
# META-INF/hcm-module.yaml
group:
name: test-group
project: test-project
module:
name: test-config
# NO 'config:' key here! ModuleReader discovers by convention.
ModuleReader automatically discovers:
hcm-config/**/*.yaml - Configurationhcm-content/**/*.yaml - Contentnamespaces/**/*.cnd - Node types
# WRONG - config: key is invalid for ModuleReader
module:
name: test-config
config: # <- ERROR: Not valid!
source: /hcm-config
# WRONG - Missing dependencies cause errors
group:
name: test-group
after:
- hippo-cms # <- ERROR: hippo-cms doesn't exist in test env
HCM config uses flat paths, not nested YAML:
# CORRECT - Flat paths
definitions:
config:
/hst:myproject:
jcr:primaryType: hst:hst
/hst:myproject/hst:sites:
jcr:primaryType: hst:sites
/hst:myproject/hst:sites/myproject:
jcr:primaryType: hst:site
# WRONG - Nested structure (creates wrong paths)
definitions:
config:
/hst:myproject:
jcr:primaryType: hst:hst
/hst:sites: # Wrong: creates /hst:sites not /hst:myproject/hst:sites
jcr:primaryType: hst:sites
| Aspect | SkeletonRepository | ConfigServiceRepository |
|---|---|---|
| HST Bootstrap | Minimal hardcoded structure | Full production ConfigService |
| Maintenance | Manual updates when brXM changes | Automatic (uses production code) |
| Structure | Basic hst:hst node only | Complete HST tree |
| Setup | Zero configuration | Requires HCM module + config |
| Speed | Faster (minimal setup) | Slightly slower (full bootstrap) |
| Use Case | Simple unit tests | Integration tests needing real HST |
| Production Parity | No | Yes (exact same code path) |
Cause: Using ClasspathConfigurationModelReader format in hcm-module.yaml
Fix: Remove config: section. ModuleReader discovers by convention.
Cause: Module declares dependency on framework module not present in test
Fix: Remove after: section from group.
Cause: HCM config files missing or in wrong location
Fix:
hcm-config/ directory exists in test resources/hst:myproject (not /hst:hst)ConfigServiceRepository uses pluggable strategies:
canHandle() - checks for META-INF/hcm-module.yamlcanHandle()/hst:hst node onlyStrategy selection is automatic based on classpath resources.
src/test/
├── java/org/example/
│ └── MyIntegrationTest.java
└── resources/
├── META-INF/
│ └── hcm-module.yaml # Module descriptor
├── hcm-config/
│ └── hst/
│ └── demo-hst.yaml # HST configuration
└── org/example/
└── config-service-jcr.xml # Repository override