Knowledge Hub
Comprehensive guides and references for the OpenFrame platform
OpenFrame Gen1 is Here · Our AI platform for autonomous IT is out of beta.
Comprehensive guides and references for the OpenFrame platform
This guide covers the test structure, how to run tests, and guidelines for writing new tests in OpenFrame OSS Tenant.
OpenFrame OSS Tenant uses several testing approaches across its different technology stacks.
Tests are co-located with each service in the standard Maven structure:
openframe/services/openframe-api/
└── src/
├── main/java/com/openframe/api/ # Production code
└── test/java/com/openframe/api/ # Test code
├── *Test.java # Unit tests (Mockito)
└── integration/ # Integration tests (IT suffix)
Testing Frameworks Used:
spring-boot-starter-test (includes JUnit 5, AssertJ, Hamcrest)spring-security-test — For testing security-related functionalitymockito-core + mockito-junit-jupiter — For mocking dependenciesTest Class Conventions:
*Test.java (e.g., ScriptServiceTest.java)*IT.java (e.g., CommandResultListenerIT.java)BaseMongoIntegrationTest, GraphQlIntegrationTestApplicationRust tests are written using the built-in test framework (#[test] / #[tokio::test]):
clients/openframe-client/src/
├── services/
│ └── mod.rs # Unit tests inline with source using #[cfg(test)]
└── ...
The openframe-chat project uses Vite's testing ecosystem:
# openframe-frontend-core uses Vitest
# Configuration: vitest.config.ts
# Run all tests from the root
mvn test
# Run tests for a specific service
mvn test -pl openframe/services/openframe-api
# Run tests matching a pattern
mvn test -pl openframe/services/openframe-api -Dtest="ScriptServiceTest"
# Run integration tests only
mvn test -pl openframe/services/openframe-api -Dtest="*IT"
# Skip tests (useful for fast builds)
mvn install -DskipTests
# Run a single test class
mvn test -pl openframe/services/openframe-api \
-Dtest="com.openframe.api.service.rmm.ScriptServiceTest"
# Run a single test method
mvn test -pl openframe/services/openframe-api \
-Dtest="ScriptServiceTest#shouldCreateScript"
cd clients/openframe-client
# Run all tests
cargo test
# Run tests with output (useful for debugging)
cargo test -- --nocapture
# Run a specific test
cargo test test_name
# Run tests matching a pattern
cargo test service
cd clients/openframe-chat
# Type check only
npx tsc --noEmit
Many integration tests rely on an embedded MongoDB or Testcontainers MongoDB. The shared base class BaseMongoIntegrationTest provides the configured test application context:
// Example: Extending the base integration test
@SpringBootTest(classes = IntegrationTestApplication.class)
class MyRepositoryIT extends BaseMongoIntegrationTest {
@Autowired
private MyRepository myRepository;
@Test
void shouldFindByTenantId() {
// Test runs against real MongoDB (via Testcontainers)
}
}
The TestAuthenticationManager provides convenience methods for creating authenticated test contexts:
// Setting up a test with a specific tenant context
@WithMockUser(username = "test-user")
@Test
void shouldReturnTenantScopedResults() {
// JWT principal is mocked; tenant context is available
}
The openframe-test service (openframe/services/openframe-test) provides a full E2E test runner (TestRunner) with test suites for:
These tests run against a deployed OpenFrame instance (not locally), using EnvironmentConfig to point at the target environment.
@ExtendWith(MockitoExtension.class)
class ScriptServiceTest {
@Mock
private ScriptRepository scriptRepository;
@InjectMocks
private ScriptService scriptService;
@Test
void shouldCreateScript_givenValidInput() {
// Arrange
var input = CreateScriptInput.builder()
.name("My Script")
.content("echo hello")
.build();
when(scriptRepository.save(any())).thenAnswer(i -> i.getArgument(0));
// Act
var result = scriptService.createScript(input, mockPrincipal());
// Assert
assertThat(result.getName()).isEqualTo("My Script");
verify(scriptRepository).save(any(Script.class));
}
}
@SpringBootTest(classes = IntegrationTestApplication.class)
class ScriptRepositoryIT extends BaseMongoIntegrationTest {
@Autowired
private ScriptRepository scriptRepository;
@Test
void shouldPersistAndRetrieveScript() {
var script = Script.builder()
.tenantId("test-tenant")
.name("test-script")
.build();
scriptRepository.save(script);
var found = scriptRepository.findByIdAndTenantId(script.getId(), "test-tenant");
assertThat(found).isPresent();
}
}
@SpringBootTest(classes = GraphQlIntegrationTestApplication.class)
class ScriptDataFetcherTest {
@Autowired
private DgsQueryExecutor dgsQueryExecutor;
@Test
void shouldReturnScripts() {
var result = dgsQueryExecutor.executeAndExtractJsonPath(
"{ scripts { edges { node { name } } } }",
"$.data.scripts.edges[*].node.name"
);
assertThat(result).isNotEmpty();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_compare_versions_correctly() {
let result = VersionComparator::is_newer("1.2.0", "1.1.0");
assert!(result);
}
#[tokio::test]
async fn should_parse_script_args() {
let args = ScriptArgsTokenizer::tokenize("arg1 \"arg with spaces\" arg3");
assert_eq!(args.len(), 3);
assert_eq!(args[1], "arg with spaces");
}
}
While no hard coverage thresholds are enforced in CI at this time, the following guidelines apply:
| Component | Target Coverage |
|---|---|
| Service layer (business logic) | High — unit test all service methods |
| Repository layer | Integration tests preferred over mocks |
| GraphQL data fetchers | Integration tests with DGS test framework |
| Controllers/REST endpoints | Integration tests using MockMvc or WebTestClient |
| Rust services | Unit + integration tests for all public functions |
# Generate JaCoCo coverage report
mvn test jacoco:report -pl openframe/services/openframe-api
# View report at:
# openframe/services/openframe-api/target/site/jacoco/index.html
The openframe-test-service-core library provides reusable test data generators:
| Generator | Purpose |
|---|---|
AuthGenerator |
Creates test auth tokens and user contexts |
DeviceGenerator |
Creates test machine/device records |
ScriptGenerator |
Creates test script definitions |
OrganizationGenerator |
Creates test organization records |
TicketGenerator |
Creates test ticket records |
TestAuthenticationManager or mock the AuthPrincipal.NatsMessagePublisher rather than connecting to a real NATS server unless an embedded NATS is available.@EmbeddedKafka from Spring Kafka Test for tests involving Kafka producers/consumers.