From 368d46716447a4142bd5c93f0fe3e74dea51c9e5 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Tue, 25 Nov 2025 12:11:28 -0800 Subject: [PATCH 01/25] feat(ci): implement unit tests --- .gitignore | 1 + pom.xml | 35 ++- test/README.md | 230 +++++++++++++++ test/reactors/BaseReactorTest.java | 273 ++++++++++++++++++ test/reactors/ReactorTestSuite.java | 41 +++ .../example/CallPythonReactorTest.java | 206 +++++++++++++ test/reactors/example/HelloReactorTest.java | 89 ++++++ .../example/OpenMCPAppReactorTest.java | 108 +++++++ 8 files changed, 982 insertions(+), 1 deletion(-) create mode 100644 test/README.md create mode 100644 test/reactors/BaseReactorTest.java create mode 100644 test/reactors/ReactorTestSuite.java create mode 100644 test/reactors/example/CallPythonReactorTest.java create mode 100644 test/reactors/example/HelloReactorTest.java create mode 100644 test/reactors/example/OpenMCPAppReactorTest.java diff --git a/.gitignore b/.gitignore index 7803f84..8206bb0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ client/node_modules/ portals/ classes/ target/ +test-classes/ # Local configuration files *.local diff --git a/pom.xml b/pom.xml index d9d575c..7e7b41e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,9 @@ java/src + test classes + test-classes java @@ -80,6 +82,38 @@ ${ci.version} provided + + + + org.junit.jupiter + junit-jupiter + 6.0.0 + test + + + + org.junit.platform + junit-platform-suite + 6.0.0 + test + + + + org.mockito + mockito-core + 5.18.0 + test + + + net.bytebuddy + byte-buddy + + + org.objenesis + objenesis + + + @@ -89,7 +123,6 @@ 3.6.3 21 - 21 UTF-8 private true diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..cee70d8 --- /dev/null +++ b/test/README.md @@ -0,0 +1,230 @@ +# Reactor Test Suite + +Comprehensive test suite for SEMOSS Template project reactors with organized test structure, helper utilities, and extensive test coverage. + +## Test Structure + +``` +test/ +├── reactors/ +│ ├── BaseReactorTest.java # Base test class with common mocking utilities +│ ├── ReactorTestSuite.java # Test suite to run all tests together +│ └── example/ +│ ├── HelloReactorTest.java # Tests for HelloUserReactor +│ ├── CallPythonReactorTest.java # Tests for CallPythonReactor +│ └── OpenMCPAppReactorTest.java # Tests for OpenMCPAppReactor +``` + +## Running Tests + +### Run All Tests in the Suite + +```bash +mvn test -Dtest=ReactorTestSuite +``` + +### Run Individual Test Classes + +```bash +# Run HelloUserReactor tests +mvn test -Dtest=HelloReactorTest + +# Run CallPythonReactor tests +mvn test -Dtest=CallPythonReactorTest + +# Run OpenMCPAppReactor tests +mvn test -Dtest=OpenMCPAppReactorTest +``` + +### Run All Tests + +```bash +mvn test +``` + +### Run Specific Test Method + +```bash +mvn test -Dtest=HelloReactorTest#testHelloUserReactor_CustomName +``` + +## Test Coverage + +### HelloUserReactor Tests +- ✅ Default user greeting (no parameters) +- ✅ Custom name parameter +- ✅ Empty string name parameter + +### CallPythonReactor Tests +- ✅ Fibonacci calculation for input 0 +- ✅ Fibonacci calculation for input 1 +- ✅ Fibonacci calculation for input 5 +- ✅ Fibonacci calculation for input 10 +- ✅ Fibonacci calculation for input 20 (large number) +- ✅ Argument list verification + +### OpenMCPAppReactor Tests +- ✅ Returns placeholder message +- ✅ Exact message verification +- ✅ No parameters required +- ✅ Reactor description verification +- ✅ Multiple executions consistency + +## BaseReactorTest Utilities + +The `BaseReactorTest` class provides common mocking utilities for all reactor tests: + +### Provided Mocks +- `@Mock Insight insight` - Mock insight for execution context +- `@Mock User user` - Mock user for authentication +- `@Mock NounStore nounStore` - Mock parameter storage +- `@Mock PyTranslator pyTranslator` - Mock Python integration +- `MockedStatic assetUtilsMock` - Mock asset utilities +- `Path tempDir` - Temporary directory for test files + +### Helper Methods + +#### Setting Reactor Parameters +```java +// Set string parameter +setReactorParameter(reactor, ReactorKeysEnum.NAME.getKey(), "Alice"); + +// Set numeric parameter +setReactorParameter(reactor, ReactorKeysEnum.NUMERIC_VALUE.getKey(), 42); +``` + +#### Python Integration Setup +```java +// Mock Python module loading and function execution +setupPyTranslatorMocks("moduleName", "functionName", returnValue); +``` + +#### Creating Test Files +```java +// Create a Python file in the temp directory +createPythonFile("script.py", pythonCode); +``` + +#### Custom Project Properties +```java +@Override +protected void configureProjectProperties(Properties props) { + props.put("custom.property", "value"); +} +``` + +## Writing New Tests + +### Basic Test Structure + +```java +package reactors.example; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import reactors.BaseReactorTest; +import reactors.examples.YourReactor; +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("YourReactor Tests") +public class YourReactorTest extends BaseReactorTest { + + private YourReactor reactor; + + @BeforeEach + void setup() { + reactor = new YourReactor(); + reactor.setInsight(insight); + reactor.setNounStore(nounStore); + } + + @Test + @DisplayName("Description of what this test does") + public void testYourReactor_Scenario() { + // Arrange: Set up parameters + setReactorParameter(reactor, "paramKey", "paramValue"); + + // Act: Execute reactor + NounMetadata result = reactor.execute(); + + // Assert: Verify results + assertNotNull(result); + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + } +} +``` + +### Add to Test Suite + +Update `ReactorTestSuite.java` to include your new test class: + +```java +@SelectClasses({ + HelloReactorTest.class, + CallPythonReactorTest.class, + OpenMCPAppReactorTest.class, + YourNewReactorTest.class // Add here +}) +``` + +## Test Dependencies + +All required dependencies are already configured in `pom.xml`: + +- **JUnit Jupiter 6.0.0** - Testing framework +- **JUnit Platform Suite 6.0.0** - Test suite support +- **Mockito 5.18.0** - Mocking framework + +## Best Practices + +1. **Extend BaseReactorTest** - Always extend `BaseReactorTest` for new reactor tests +2. **Use @DisplayName** - Add descriptive display names to tests and test classes +3. **Arrange-Act-Assert** - Follow AAA pattern in test methods +4. **Test Multiple Scenarios** - Test happy path, edge cases, and error conditions +5. **Use Helper Methods** - Leverage `BaseReactorTest` helper methods for cleaner tests +6. **Mock External Dependencies** - Use provided mocks for PyTranslator, AssetUtility, etc. +7. **Verify Interactions** - Use Mockito's `verify()` to ensure proper method calls + +## Continuous Integration + +These tests are designed to run in CI/CD pipelines. Ensure your CI configuration includes: + +```yaml +# Example for GitHub Actions +- name: Run Tests + run: mvn test +``` + +## Troubleshooting + +### Tests Failing Due to Missing Dependencies +```bash +mvn clean install +``` + +### Cannot Find Test Classes +Ensure the test source directory is correctly configured in `pom.xml`: +```xml +test +``` + +### Mock Setup Issues +Verify that `MockitoAnnotations.openMocks(this)` is called in `BaseReactorTest.baseSetup()` + +### Python Integration Tests Failing +Ensure `setupPyTranslatorMocks()` is called with correct module and function names + +## Additional Resources + +- [JUnit 5 User Guide](https://junit.org/junit5/docs/current/user-guide/) +- [Mockito Documentation](https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html) +- [SEMOSS Documentation](https://semoss.org/docs) + +## Contributing + +When adding new reactors, please: +1. Create corresponding test classes extending `BaseReactorTest` +2. Add comprehensive test coverage (minimum 3-5 test cases) +3. Update `ReactorTestSuite.java` to include new tests +4. Update this README with test coverage details diff --git a/test/reactors/BaseReactorTest.java b/test/reactors/BaseReactorTest.java new file mode 100644 index 0000000..3038ed6 --- /dev/null +++ b/test/reactors/BaseReactorTest.java @@ -0,0 +1,273 @@ +package reactors; + +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Properties; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import prerna.auth.AccessToken; +import prerna.auth.AuthProvider; +import prerna.auth.User; +import prerna.ds.py.PyTranslator; +import prerna.om.Insight; +import prerna.sablecc2.om.NounStore; +import prerna.util.AssetUtility; + +/** + * Base test class providing common mocking utilities and setup for reactor + * tests. + * All reactor test classes should extend this class to leverage shared test + * infrastructure. + * + *

+ * This class handles: + *

    + *
  • Mock setup and teardown for common SEMOSS components
  • + *
  • Temporary directory management for project assets
  • + *
  • User authentication mocking
  • + *
  • Project property file creation
  • + *
  • PyTranslator mocking for Python-based reactors
  • + *
+ */ +public abstract class BaseReactorTest { + + /** Mock insight providing context for reactor execution */ + @Mock + protected Insight insight; + + /** Mock user for authentication context */ + @Mock + protected User user; + + /** Mock noun store for reactor parameter management */ + @Mock + protected NounStore nounStore; + + /** Mock PyTranslator for Python integration testing */ + @Mock + protected PyTranslator pyTranslator; + + /** Static mock for AssetUtility to control project asset paths */ + protected MockedStatic assetUtilsMock; + + /** AutoCloseable for managing Mockito annotations lifecycle */ + private AutoCloseable mocks; + + /** Temporary directory for test execution */ + protected Path tempDir; + + /** Fake project ID for testing */ + protected static final String TEST_PROJECT_ID = "test-project-id"; + + /** Default test user name */ + protected static final String TEST_USER_NAME = "TestUser"; + + /** + * Sets up the test environment before each test execution. + * This method initializes mocks, creates temporary directories, and sets up + * common mock behaviors for insight, user, and asset utilities. + * + * @param p Temporary directory provided by JUnit + * @throws IOException if file operations fail during setup + */ + @BeforeEach + void baseSetup(@TempDir Path p) throws IOException { + tempDir = p; + mocks = MockitoAnnotations.openMocks(this); + + setupInsightMocks(); + setupUserMocks(); + setupAssetUtilityMocks(); + setupProjectProperties(); + } + + /** + * Sets up mock behaviors for the Insight object. + * Configures project ID retrieval and user context. + */ + protected void setupInsightMocks() { + when(insight.getUser()).thenReturn(user); + when(insight.getContextProjectId()).thenReturn(TEST_PROJECT_ID); + when(insight.getProjectId()).thenReturn(TEST_PROJECT_ID); + when(insight.getPyTranslator()).thenReturn(pyTranslator); + } + + /** + * Sets up mock behaviors for the User object. + * Creates a mock access token with test user credentials. + */ + protected void setupUserMocks() { + AccessToken token = new AccessToken(); + token.setName(TEST_USER_NAME); + token.setProvider(AuthProvider.NATIVE); + when(user.getPrimaryLoginToken()).thenReturn(token); + } + + /** + * Sets up static mocking for AssetUtility. + * Configures the asset utility to return the temporary directory as the project + * assets folder. + */ + protected void setupAssetUtilityMocks() { + assetUtilsMock = Mockito.mockStatic(AssetUtility.class); + assetUtilsMock.when(() -> AssetUtility.getProjectAssetsFolder(TEST_PROJECT_ID)) + .thenReturn(tempDir.toAbsolutePath().toString()); + } + + /** + * Creates a project.properties file in the temporary directory. + * Subclasses can override {@link #configureProjectProperties(Properties)} to + * add custom properties. + * + * @throws IOException if file creation or writing fails + */ + protected void setupProjectProperties() throws IOException { + Properties props = new Properties(); + configureProjectProperties(props); + + Path javaDir = tempDir.resolve("java"); + Files.createDirectories(javaDir); + Path projectPropertiesFile = javaDir.resolve("project.properties"); + + try (OutputStream os = Files.newOutputStream(projectPropertiesFile, + StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { + props.store(os, "Test project properties"); + } + } + + /** + * Hook method for subclasses to configure custom project properties. + * Override this method to add specific properties needed for your reactor + * tests. + * + * @param props Properties object to configure + */ + protected void configureProjectProperties(Properties props) { + // Default implementation - subclasses can override to add custom properties + } + + /** + * Sets up mock behaviors for PyTranslator. + * Configures default responses for Python module loading and function + * execution. + * + * @param moduleName The name of the Python module to mock + * @param functionName The name of the Python function to mock + * @param returnValue The value to return when the function is called + */ + protected void setupPyTranslatorMocks(String moduleName, String functionName, Object returnValue) { + when(pyTranslator.loadPythonModuleFromFile( + Mockito.eq(insight), + Mockito.anyString(), + Mockito.eq(TEST_PROJECT_ID))) + .thenReturn(moduleName); + + when(pyTranslator.runFunctionFromLoadedModule( + Mockito.eq(insight), + Mockito.eq(moduleName), + Mockito.eq(functionName), + Mockito.anyList())) + .thenReturn(returnValue); + } + + /** + * Creates a Python source file in the temporary directory for testing. + * Useful for reactors that need to load Python files. + * + * @param fileName The name of the Python file to create + * @param content The content of the Python file + * @throws IOException if file creation fails + */ + protected void createPythonFile(String fileName, String content) throws IOException { + Path pyDir = tempDir.resolve("py"); + Files.createDirectories(pyDir); + Path pythonFile = pyDir.resolve(fileName); + Files.writeString(pythonFile, content); + } + + /** + * Helper method to set a parameter value on a reactor. + * This directly sets the value in the reactor's keyValue map via reflection. + * + * @param reactor The reactor to set the parameter on + * @param key The parameter key + * @param value The parameter value + */ + protected void setReactorParameter(reactors.AbstractProjectReactor reactor, String key, String value) { + try { + // Access the protected keyValue map field via reflection + java.lang.reflect.Field keyValueField = findField(reactor.getClass(), "keyValue"); + keyValueField.setAccessible(true); + + @SuppressWarnings("unchecked") + java.util.Map keyValueMap = (java.util.Map) keyValueField.get(reactor); + + // Initialize the map if it's null + if (keyValueMap == null) { + keyValueMap = new java.util.HashMap<>(); + keyValueField.set(reactor, keyValueMap); + } + + // Add the parameter to the map + keyValueMap.put(key, value); + + } catch (Exception e) { + throw new RuntimeException("Failed to set reactor parameter: " + key, e); + } + } + + /** + * Helper method to find a field in the class hierarchy. + */ + private java.lang.reflect.Field findField(Class clazz, String fieldName) throws NoSuchFieldException { + Class current = clazz; + while (current != null) { + try { + return current.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + current = current.getSuperclass(); + } + } + throw new NoSuchFieldException(fieldName); + } + + /** + * Helper method to set a numeric parameter on a reactor. + * Converts the number to a string automatically. + * + * @param reactor The reactor to set the parameter on + * @param key The parameter key + * @param value The numeric value + */ + protected void setReactorParameter(reactors.AbstractProjectReactor reactor, String key, int value) { + setReactorParameter(reactor, key, String.valueOf(value)); + } + + /** + * Cleans up test resources after each test execution. + * Closes static mocks and Mockito annotations. + * + * @throws Exception if cleanup fails + */ + @AfterEach + void baseTearDown() throws Exception { + if (assetUtilsMock != null) { + assetUtilsMock.close(); + } + if (mocks != null) { + mocks.close(); + } + } +} diff --git a/test/reactors/ReactorTestSuite.java b/test/reactors/ReactorTestSuite.java new file mode 100644 index 0000000..9f12752 --- /dev/null +++ b/test/reactors/ReactorTestSuite.java @@ -0,0 +1,41 @@ +package reactors; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; +import org.junit.platform.suite.api.SuiteDisplayName; + +import reactors.example.CallPythonReactorTest; +import reactors.example.HelloReactorTest; +import reactors.example.OpenMCPAppReactorTest; + +/** + * Test suite that runs all reactor tests in the project. + * This suite aggregates all reactor test classes and can be executed to run + * all tests at once for comprehensive validation. + * + *

+ * To run this suite: + * + *

+ * mvn test -Dtest=ReactorTestSuite
+ * 
+ * + *

+ * Included test classes: + *

    + *
  • {@link HelloReactorTest} - Tests for HelloUserReactor
  • + *
  • {@link CallPythonReactorTest} - Tests for CallPythonReactor
  • + *
  • {@link OpenMCPAppReactorTest} - Tests for OpenMCPAppReactor
  • + *
+ */ +@Suite +@SuiteDisplayName("Reactor Test Suite") +@SelectClasses({ + HelloReactorTest.class, + CallPythonReactorTest.class, + OpenMCPAppReactorTest.class +}) +public class ReactorTestSuite { + // This class remains empty, it is used only as a holder for the above + // annotations +} diff --git a/test/reactors/example/CallPythonReactorTest.java b/test/reactors/example/CallPythonReactorTest.java new file mode 100644 index 0000000..30aa1ed --- /dev/null +++ b/test/reactors/example/CallPythonReactorTest.java @@ -0,0 +1,206 @@ +package reactors.example; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import reactors.BaseReactorTest; +import reactors.examples.CallPythonReactor; +import prerna.sablecc2.om.PixelDataType; +import prerna.sablecc2.om.ReactorKeysEnum; +import prerna.sablecc2.om.nounmeta.NounMetadata; + +/** + * Test class for CallPythonReactor functionality. + * Tests Python integration for Fibonacci number calculation. + */ +@DisplayName("CallPythonReactor Tests") +public class CallPythonReactorTest extends BaseReactorTest { + + private CallPythonReactor reactor; + private static final String FIBONACCI_MODULE = "nthFibonacci"; + private static final String FIBONACCI_FUNCTION = "nthFibonacci"; + + @BeforeEach + void setup() throws IOException { + reactor = new CallPythonReactor(); + reactor.setInsight(insight); + reactor.setNounStore(nounStore); + + // Create the Python file in the temp directory + String pythonCode = """ + # sample python function that finds the nth fibonacci number + def nthFibonacci(n: int) -> int: + if n <= 1: + return n + + dp = [0] * (n + 1) + + dp[0] = 0 + dp[1] = 1 + + for i in range(2, n + 1): + dp[i] = dp[i - 1] + dp[i - 2] + + return dp[n] + """; + createPythonFile("nthFibonacci.py", pythonCode); + } + + @Test + @DisplayName("Should calculate Fibonacci number for input 0") + public void testCallPythonReactor_Fibonacci0() { + // Set up mocks + int input = 0; + int expectedFibonacci = 0; + setupPyTranslatorMocks(FIBONACCI_MODULE, FIBONACCI_FUNCTION, expectedFibonacci); + + // Set up reactor with input parameter + setReactorParameter(reactor, ReactorKeysEnum.NUMERIC_VALUE.getKey(), input); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result type + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + + // Verify the result value + assertNotNull(result.getValue()); + assertEquals(expectedFibonacci, result.getValue()); + + // Verify Python translator was called correctly + verify(pyTranslator).loadPythonModuleFromFile( + eq(insight), + eq("nthFibonacci.py"), + eq(TEST_PROJECT_ID)); + verify(pyTranslator).runFunctionFromLoadedModule( + eq(insight), + eq(FIBONACCI_MODULE), + eq(FIBONACCI_FUNCTION), + anyList()); + } + + @Test + @DisplayName("Should calculate Fibonacci number for input 1") + public void testCallPythonReactor_Fibonacci1() { + // Set up mocks + int input = 1; + int expectedFibonacci = 1; + setupPyTranslatorMocks(FIBONACCI_MODULE, FIBONACCI_FUNCTION, expectedFibonacci); + + // Set up reactor with input parameter + setReactorParameter(reactor, ReactorKeysEnum.NUMERIC_VALUE.getKey(), input); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + assertEquals(expectedFibonacci, result.getValue()); + } + + @Test + @DisplayName("Should calculate Fibonacci number for input 5") + public void testCallPythonReactor_Fibonacci5() { + // Set up mocks + int input = 5; + int expectedFibonacci = 5; // Fibonacci(5) = 5 + setupPyTranslatorMocks(FIBONACCI_MODULE, FIBONACCI_FUNCTION, expectedFibonacci); + + // Set up reactor with input parameter + setReactorParameter(reactor, ReactorKeysEnum.NUMERIC_VALUE.getKey(), input); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + assertEquals(expectedFibonacci, result.getValue()); + } + + @Test + @DisplayName("Should calculate Fibonacci number for input 10") + public void testCallPythonReactor_Fibonacci10() { + // Set up mocks + int input = 10; + int expectedFibonacci = 55; // Fibonacci(10) = 55 + setupPyTranslatorMocks(FIBONACCI_MODULE, FIBONACCI_FUNCTION, expectedFibonacci); + + // Set up reactor with input parameter + setReactorParameter(reactor, ReactorKeysEnum.NUMERIC_VALUE.getKey(), input); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + assertEquals(expectedFibonacci, result.getValue()); + } + + @Test + @DisplayName("Should handle large Fibonacci numbers") + public void testCallPythonReactor_LargeFibonacci() { + // Set up mocks + int input = 20; + int expectedFibonacci = 6765; // Fibonacci(20) = 6765 + setupPyTranslatorMocks(FIBONACCI_MODULE, FIBONACCI_FUNCTION, expectedFibonacci); + + // Set up reactor with input parameter + setReactorParameter(reactor, ReactorKeysEnum.NUMERIC_VALUE.getKey(), input); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + assertEquals(expectedFibonacci, result.getValue()); + } + + @Test + @DisplayName("Should verify argument list passed to Python function") + public void testCallPythonReactor_VerifyArgumentList() { + // Set up mocks with argument capture + int input = 7; + int expectedFibonacci = 13; + + when(pyTranslator.loadPythonModuleFromFile( + eq(insight), + anyString(), + eq(TEST_PROJECT_ID))) + .thenReturn(FIBONACCI_MODULE); + + when(pyTranslator.runFunctionFromLoadedModule( + eq(insight), + eq(FIBONACCI_MODULE), + eq(FIBONACCI_FUNCTION), + anyList())) + .thenAnswer(invocation -> { + // Verify the argument list contains the correct input + @SuppressWarnings("unchecked") + List args = (List) invocation.getArgument(3); + assertEquals(1, args.size()); + assertEquals(input, args.get(0)); + return expectedFibonacci; + }); + + // Set up reactor with input parameter + setReactorParameter(reactor, ReactorKeysEnum.NUMERIC_VALUE.getKey(), input); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result + assertEquals(expectedFibonacci, result.getValue()); + } +} diff --git a/test/reactors/example/HelloReactorTest.java b/test/reactors/example/HelloReactorTest.java new file mode 100644 index 0000000..7ef6193 --- /dev/null +++ b/test/reactors/example/HelloReactorTest.java @@ -0,0 +1,89 @@ +package reactors.example; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import reactors.BaseReactorTest; +import reactors.examples.HelloUserReactor; +import prerna.sablecc2.om.PixelDataType; +import prerna.sablecc2.om.ReactorKeysEnum; +import prerna.sablecc2.om.nounmeta.NounMetadata; + +/** + * Test class for HelloUserReactor functionality. + * Tests various scenarios including default user greeting and custom name + * parameter. + */ +@DisplayName("HelloUserReactor Tests") +public class HelloReactorTest extends BaseReactorTest { + + private HelloUserReactor reactor; + + @BeforeEach + void setup() { + reactor = new HelloUserReactor(); + reactor.setInsight(insight); + reactor.setNounStore(nounStore); + } + + @Test + @DisplayName("Should return greeting with default user name when no name parameter provided") + public void testHelloUserReactor_DefaultUserName() { + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result type + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + + // Verify the greeting contains the test user name + String greeting = (String) result.getValue(); + assertNotNull(greeting); + assertTrue(greeting.contains(TEST_USER_NAME)); + assertTrue(greeting.contains("Hello")); + assertTrue(greeting.contains("Welcome to SEMOSS")); + } + + @Test + @DisplayName("Should return greeting with custom name when name parameter provided") + public void testHelloUserReactor_CustomName() { + // Set up reactor with custom name parameter + String customName = "Alice"; + setReactorParameter(reactor, ReactorKeysEnum.NAME.getKey(), customName); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result type + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + + // Verify the greeting contains the custom name + String greeting = (String) result.getValue(); + assertNotNull(greeting); + assertTrue(greeting.contains(customName)); + assertTrue(greeting.contains("Hello")); + assertTrue(greeting.contains("Welcome to SEMOSS")); + } + + @Test + @DisplayName("Should handle empty string name parameter") + public void testHelloUserReactor_EmptyName() { + // Set up reactor with empty name parameter + setReactorParameter(reactor, ReactorKeysEnum.NAME.getKey(), ""); + + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result type + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + + // Verify the greeting is created (with empty name in this case) + String greeting = (String) result.getValue(); + assertNotNull(greeting); + assertTrue(greeting.contains("Hello")); + } +} diff --git a/test/reactors/example/OpenMCPAppReactorTest.java b/test/reactors/example/OpenMCPAppReactorTest.java new file mode 100644 index 0000000..325e679 --- /dev/null +++ b/test/reactors/example/OpenMCPAppReactorTest.java @@ -0,0 +1,108 @@ +package reactors.example; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import reactors.BaseReactorTest; +import reactors.examples.OpenMCPAppReactor; +import prerna.sablecc2.om.PixelDataType; +import prerna.sablecc2.om.nounmeta.NounMetadata; + +/** + * Test class for OpenMCPAppReactor functionality. + * Tests the MCP App interface opening reactor. + */ +@DisplayName("OpenMCPAppReactor Tests") +public class OpenMCPAppReactorTest extends BaseReactorTest { + + private OpenMCPAppReactor reactor; + + @BeforeEach + void setup() { + reactor = new OpenMCPAppReactor(); + reactor.setInsight(insight); + reactor.setNounStore(nounStore); + } + + @Test + @DisplayName("Should return placeholder message indicating auto-execute not implemented") + public void testOpenMCPAppReactor_ReturnsPlaceholderMessage() { + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify result type + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + + // Verify the result contains expected message + String message = (String) result.getValue(); + assertNotNull(message); + assertTrue(message.contains("auto-execute response")); + assertTrue(message.contains("not yet been implemented")); + } + + @Test + @DisplayName("Should return exact expected placeholder message") + public void testOpenMCPAppReactor_ExactMessage() { + // Execute the reactor + NounMetadata result = reactor.execute(); + + // Verify exact message + String expectedMessage = "This MCP tool's auto-execute response has not yet been implemented."; + assertEquals(expectedMessage, result.getValue()); + } + + @Test + @DisplayName("Should not require any input parameters") + public void testOpenMCPAppReactor_NoParametersRequired() { + // Verify reactor can execute without any parameters set + NounMetadata result = reactor.execute(); + + // Should still return a valid result + assertNotNull(result); + assertEquals(PixelDataType.CONST_STRING, result.getNounType()); + } + + @Test + @DisplayName("Should return reactor description for MCP tool") + public void testOpenMCPAppReactor_Description() { + // Get reactor description + String description = reactor.getReactorDescription(); + + // Verify description is present and contains expected content + assertNotNull(description); + assertTrue(description.contains("SEMOSS Template application")); + assertTrue(description.contains("interact")); + } + + @Test + @DisplayName("Should return expected exact description") + public void testOpenMCPAppReactor_ExactDescription() { + // Get reactor description + String description = reactor.getReactorDescription(); + + // Verify exact description + String expectedDescription = "This tool allows the user to interact with the SEMOSS Template application."; + assertEquals(expectedDescription, description); + } + + @Test + @DisplayName("Should execute successfully multiple times") + public void testOpenMCPAppReactor_MultipleExecutions() { + // Execute the reactor multiple times + NounMetadata result1 = reactor.execute(); + NounMetadata result2 = reactor.execute(); + NounMetadata result3 = reactor.execute(); + + // All results should be identical + assertEquals(result1.getValue(), result2.getValue()); + assertEquals(result2.getValue(), result3.getValue()); + assertEquals(PixelDataType.CONST_STRING, result1.getNounType()); + assertEquals(PixelDataType.CONST_STRING, result2.getNounType()); + assertEquals(PixelDataType.CONST_STRING, result3.getNounType()); + } +} From e1d484f49fd1867b29c00bc18734e24053c14645 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Tue, 25 Nov 2025 12:16:45 -0800 Subject: [PATCH 02/25] ci: unit-tests --- .github/workflows/test.yml | 78 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a46da41 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,78 @@ +name: Run Tests + +on: + push: + pull_request: + branches: [ default-app ] + workflow_dispatch: + +jobs: + test: + name: Run Test Suite + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'zulu' + cache: 'maven' + + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Run tests + run: mvn clean test + + - name: Generate test report + if: always() + uses: dorny/test-reporter@v1 + with: + name: Maven Test Results + path: target/surefire-reports/*.xml + reporter: java-junit + fail-on-error: true + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: | + target/surefire-reports/ + target/site/ + retention-days: 30 + + - name: Publish test summary + if: always() + run: | + echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f target/surefire-reports/TEST-*.xml ]; then + TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + + echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY + echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY + echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY + echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY + + if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY + else + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY + fi + fi From 44c261db9541364df19c41ae672f0e1dede63c6f Mon Sep 17 00:00:00 2001 From: rithvik-doshi <81876806+rithvik-doshi@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:43:47 -0500 Subject: [PATCH 03/25] Comment out GitHub Actions workflow steps For now until we work out how to get the semoss jar --- .github/workflows/test.yml | 134 ++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a46da41..a071cc9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,78 +1,78 @@ -name: Run Tests +# name: Run Tests -on: - push: - pull_request: - branches: [ default-app ] - workflow_dispatch: +# on: +# push: +# pull_request: +# branches: [ default-app ] +# workflow_dispatch: -jobs: - test: - name: Run Test Suite - runs-on: ubuntu-latest +# jobs: +# test: +# name: Run Test Suite +# runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 +# steps: +# - name: Checkout code +# uses: actions/checkout@v4 - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'zulu' - cache: 'maven' +# - name: Set up JDK 21 +# uses: actions/setup-java@v4 +# with: +# java-version: '21' +# distribution: 'zulu' +# cache: 'maven' - - name: Cache Maven packages - uses: actions/cache@v4 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- +# - name: Cache Maven packages +# uses: actions/cache@v4 +# with: +# path: ~/.m2/repository +# key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} +# restore-keys: | +# ${{ runner.os }}-maven- - - name: Run tests - run: mvn clean test +# - name: Run tests +# run: mvn clean test - - name: Generate test report - if: always() - uses: dorny/test-reporter@v1 - with: - name: Maven Test Results - path: target/surefire-reports/*.xml - reporter: java-junit - fail-on-error: true +# - name: Generate test report +# if: always() +# uses: dorny/test-reporter@v1 +# with: +# name: Maven Test Results +# path: target/surefire-reports/*.xml +# reporter: java-junit +# fail-on-error: true - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results - path: | - target/surefire-reports/ - target/site/ - retention-days: 30 +# - name: Upload test results +# if: always() +# uses: actions/upload-artifact@v4 +# with: +# name: test-results +# path: | +# target/surefire-reports/ +# target/site/ +# retention-days: 30 - - name: Publish test summary - if: always() - run: | - echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ -f target/surefire-reports/TEST-*.xml ]; then - TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) +# - name: Publish test summary +# if: always() +# run: | +# echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY +# echo "" >> $GITHUB_STEP_SUMMARY +# if [ -f target/surefire-reports/TEST-*.xml ]; then +# TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) +# FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) +# ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) +# SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY - echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY - echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY - echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY +# echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY +# echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY +# echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY +# echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY - if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY - else - echo "" >> $GITHUB_STEP_SUMMARY - echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY - fi - fi +# if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then +# echo "" >> $GITHUB_STEP_SUMMARY +# echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY +# else +# echo "" >> $GITHUB_STEP_SUMMARY +# echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY +# fi +# fi From 5df6a12f0d892eb78f8b7ece82299c602b992234 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Tue, 25 Nov 2025 12:54:05 -0800 Subject: [PATCH 04/25] fix: improve the python test by calling the actual file --- .../example/CallPythonReactorTest.java | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/test/reactors/example/CallPythonReactorTest.java b/test/reactors/example/CallPythonReactorTest.java index 30aa1ed..a27d704 100644 --- a/test/reactors/example/CallPythonReactorTest.java +++ b/test/reactors/example/CallPythonReactorTest.java @@ -9,6 +9,10 @@ import static org.mockito.Mockito.when; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -38,24 +42,11 @@ void setup() throws IOException { reactor.setInsight(insight); reactor.setNounStore(nounStore); - // Create the Python file in the temp directory - String pythonCode = """ - # sample python function that finds the nth fibonacci number - def nthFibonacci(n: int) -> int: - if n <= 1: - return n - - dp = [0] * (n + 1) - - dp[0] = 0 - dp[1] = 1 - - for i in range(2, n + 1): - dp[i] = dp[i - 1] + dp[i - 2] - - return dp[n] - """; - createPythonFile("nthFibonacci.py", pythonCode); + // Copy the actual Python file from py directory to temp directory + Path sourcePath = Paths.get("py", "nthFibonacci.py"); + Path targetPath = tempDir.resolve("py").resolve("nthFibonacci.py"); + Files.createDirectories(targetPath.getParent()); + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); } @Test From 9be43a90b7ac3e36417c7746e8e36f2e022e2751 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Tue, 2 Dec 2025 16:01:41 -0500 Subject: [PATCH 05/25] ci: test name --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a071cc9..865c8b7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -# name: Run Tests +# name: Run Unit Tests # on: # push: From 40c07d55da38f24a84d4b7cba4a90def6c52c608 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:01:26 -0500 Subject: [PATCH 06/25] ci: rework test and use specific snapshot version and update pom slightly --- .github/workflows/test.yml | 78 ----------------------------- .github/workflows/unit-test.yml | 87 +++++++++++++++++++++++++++++++++ pom.xml | 11 +++++ 3 files changed, 98 insertions(+), 78 deletions(-) delete mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/unit-test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 865c8b7..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,78 +0,0 @@ -# name: Run Unit Tests - -# on: -# push: -# pull_request: -# branches: [ default-app ] -# workflow_dispatch: - -# jobs: -# test: -# name: Run Test Suite -# runs-on: ubuntu-latest - -# steps: -# - name: Checkout code -# uses: actions/checkout@v4 - -# - name: Set up JDK 21 -# uses: actions/setup-java@v4 -# with: -# java-version: '21' -# distribution: 'zulu' -# cache: 'maven' - -# - name: Cache Maven packages -# uses: actions/cache@v4 -# with: -# path: ~/.m2/repository -# key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} -# restore-keys: | -# ${{ runner.os }}-maven- - -# - name: Run tests -# run: mvn clean test - -# - name: Generate test report -# if: always() -# uses: dorny/test-reporter@v1 -# with: -# name: Maven Test Results -# path: target/surefire-reports/*.xml -# reporter: java-junit -# fail-on-error: true - -# - name: Upload test results -# if: always() -# uses: actions/upload-artifact@v4 -# with: -# name: test-results -# path: | -# target/surefire-reports/ -# target/site/ -# retention-days: 30 - -# - name: Publish test summary -# if: always() -# run: | -# echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY -# echo "" >> $GITHUB_STEP_SUMMARY -# if [ -f target/surefire-reports/TEST-*.xml ]; then -# TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) -# FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) -# ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) -# SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - -# echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY -# echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY -# echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY -# echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY - -# if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then -# echo "" >> $GITHUB_STEP_SUMMARY -# echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY -# else -# echo "" >> $GITHUB_STEP_SUMMARY -# echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY -# fi -# fi diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml new file mode 100644 index 0000000..1f7e818 --- /dev/null +++ b/.github/workflows/unit-test.yml @@ -0,0 +1,87 @@ +name: Run Unit Tests + +on: + push: + pull_request: + branches: [ default-app ] + workflow_dispatch: + inputs: + semoss_branch: + description: 'SEMOSS branch to use for jar' + required: true + default: 'dev' + type: choice + options: + - dev + snapshot: + description: 'CI version snapshot' + required: true + default: '5.0.0-alpha-SNAPSHOT' + type: choice + options: + - '5.0.0-alpha-SNAPSHOT' + +jobs: + test: + name: Run Test Suite + runs-on: ubuntu-latest + container: maven:3.9.9-amazoncorretto-21-debian + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Run tests + run: mvn clean test -Dci.version=${{ github.event.inputs.snapshot }} + + - name: Generate test report + if: always() + uses: dorny/test-reporter@v1 + with: + name: Maven Test Results + path: target/surefire-reports/*.xml + reporter: java-junit + fail-on-error: true + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: | + target/surefire-reports/ + target/site/ + retention-days: 30 + + - name: Publish test summary + if: always() + run: | + echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f target/surefire-reports/TEST-*.xml ]; then + TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + + echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY + echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY + echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY + echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY + + if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY + else + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY + fi + fi diff --git a/pom.xml b/pom.xml index 7e7b41e..204958b 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,17 @@ false + + public + Sonatype's Maven repository + https://oss.sonatype.org/content/groups/public + + true + + + false + + 3rdPartyJARs Maven repository From c16eb5b8b4cfe304ce6db2e070f2eaee73107446 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:05:43 -0500 Subject: [PATCH 07/25] fix: fix --- .github/workflows/unit-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 1f7e818..2c5327d 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -40,7 +40,7 @@ jobs: ${{ runner.os }}-maven- - name: Run tests - run: mvn clean test -Dci.version=${{ github.event.inputs.snapshot }} + run: mvn clean test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - name: Generate test report if: always() From 80193cd8ff821dc7e3c44510d3fd680781b718c0 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:09:15 -0500 Subject: [PATCH 08/25] fix: fix --- .github/workflows/unit-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 2c5327d..f5b7dbd 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -40,7 +40,7 @@ jobs: ${{ runner.os }}-maven- - name: Run tests - run: mvn clean test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + run: mvn clean test -DskipTests=true -U -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - name: Generate test report if: always() From e04a3fa016dfa65e66a4624558eb5ee7b40e4db6 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:16:47 -0500 Subject: [PATCH 09/25] chore: oopsy --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 204958b..b80c567 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ true - false + true From ea67ee67231f0dc39b868dee503ab6d4be6d8e2a Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:25:05 -0500 Subject: [PATCH 10/25] ci: fix pom --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index b80c567..65c52c2 100644 --- a/pom.xml +++ b/pom.xml @@ -70,8 +70,17 @@ true + + false + + + + sonatype-snapshots + Sonatype Snapshots + https://central.sonatype.com/repository/maven-snapshots true + always From 2248ed2da23b58ae9ec708650b2ce36926c47a0d Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:36:55 -0500 Subject: [PATCH 11/25] ci: fix script --- .github/workflows/unit-test.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index f5b7dbd..28a5328 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -40,7 +40,13 @@ jobs: ${{ runner.os }}-maven- - name: Run tests - run: mvn clean test -DskipTests=true -U -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + run: | + mvn clean install -DskipTests=true -U -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + mvn clean test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + + - name: Install git + if: always() + run: apt-get update && apt-get install -y git - name: Generate test report if: always() From 8f040fca9f6f18b891d0a2fe03fe06fa3eaf49e3 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:39:34 -0500 Subject: [PATCH 12/25] ci: update commands --- .github/workflows/unit-test.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 28a5328..4c9aa09 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -38,11 +38,12 @@ jobs: key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- + + - name: Maven Clean Install + run: mvn clean install -DskipTests=true -U -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - - name: Run tests - run: | - mvn clean install -DskipTests=true -U -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - mvn clean test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + - name: Run Unit Tests + run: mvn test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - name: Install git if: always() From af02b475a18e7d9bf9fb89bab703e7683bc07ddb Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:46:37 -0500 Subject: [PATCH 13/25] ci: safe directory --- .github/workflows/unit-test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 4c9aa09..30bf641 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -47,7 +47,9 @@ jobs: - name: Install git if: always() - run: apt-get update && apt-get install -y git + run: | + apt-get update && apt-get install -y git + git config --global --add safe.directory /__w/Template/Template - name: Generate test report if: always() From 942674d5e8bdf618cfe2b60c7b2a6156a17e3b80 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:53:39 -0500 Subject: [PATCH 14/25] fix: fix --- .github/workflows/unit-test.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 30bf641..6d9d44f 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -20,6 +20,11 @@ on: type: choice options: - '5.0.0-alpha-SNAPSHOT' + clean_install: + description: 'Run clean install with -U flag' + required: false + default: false + type: boolean jobs: test: @@ -34,13 +39,18 @@ jobs: - name: Cache Maven packages uses: actions/cache@v4 with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + - name: Maven Clean Install + run: | + if [ "${{ github.event.inputs.clean_install }}" = "true" ] || [ -z "${{ github.event.inputs.clean_install }}" ]; then + mvn clean install -U -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + else + mvn install -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + fi restore-keys: | ${{ runner.os }}-maven- - name: Maven Clean Install - run: mvn clean install -DskipTests=true -U -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + run: mvn clean install -U -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - name: Run Unit Tests run: mvn test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} @@ -49,7 +59,7 @@ jobs: if: always() run: | apt-get update && apt-get install -y git - git config --global --add safe.directory /__w/Template/Template + git config --global --add safe.directory '*' - name: Generate test report if: always() From dae69606aec6dafc0687f5a794e3d96729292f5f Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:55:24 -0500 Subject: [PATCH 15/25] fix: oops --- .github/workflows/unit-test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 6d9d44f..c305f46 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -39,6 +39,11 @@ jobs: - name: Cache Maven packages uses: actions/cache@v4 with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Maven Clean Install run: | if [ "${{ github.event.inputs.clean_install }}" = "true" ] || [ -z "${{ github.event.inputs.clean_install }}" ]; then From daf8239cdb570024053a67f20154bd446a8a9648 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:57:34 -0500 Subject: [PATCH 16/25] fix: some weirdness and disabling push for now --- .github/workflows/unit-test.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index c305f46..4f1ced8 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -43,19 +43,16 @@ jobs: key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - + - name: Maven Clean Install run: | if [ "${{ github.event.inputs.clean_install }}" = "true" ] || [ -z "${{ github.event.inputs.clean_install }}" ]; then + echo "Running mvn clean install with -U flag" mvn clean install -U -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} else + echo "Running mvn install without -U flag" mvn install -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} fi - restore-keys: | - ${{ runner.os }}-maven- - - - name: Maven Clean Install - run: mvn clean install -U -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - name: Run Unit Tests run: mvn test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} From 128554c1ccc71dc36c5d8233d7eb9be370ca24b5 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 13:57:46 -0500 Subject: [PATCH 17/25] fix: some weirdness and disabling push for now --- .github/workflows/unit-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 4f1ced8..9cb4733 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -1,7 +1,7 @@ name: Run Unit Tests on: - push: +# push: pull_request: branches: [ default-app ] workflow_dispatch: From b6d5af2eed15f40ef52a0059607be2206d0655e4 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 14:02:35 -0500 Subject: [PATCH 18/25] fix: fix --- .github/workflows/unit-test.yml | 109 ++++++++++++++++---------------- 1 file changed, 53 insertions(+), 56 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 9cb4733..b80fb78 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -6,13 +6,6 @@ on: branches: [ default-app ] workflow_dispatch: inputs: - semoss_branch: - description: 'SEMOSS branch to use for jar' - required: true - default: 'dev' - type: choice - options: - - dev snapshot: description: 'CI version snapshot' required: true @@ -22,7 +15,7 @@ on: - '5.0.0-alpha-SNAPSHOT' clean_install: description: 'Run clean install with -U flag' - required: false + required: true default: false type: boolean @@ -31,6 +24,9 @@ jobs: name: Run Test Suite runs-on: ubuntu-latest container: maven:3.9.9-amazoncorretto-21-debian + env: + SNAPSHOT: ${{ inputs.snapshot }} + CLEAN_INSTALL: ${{ inputs.clean_install }} steps: - name: Checkout code @@ -46,63 +42,64 @@ jobs: - name: Maven Clean Install run: | - if [ "${{ github.event.inputs.clean_install }}" = "true" ] || [ -z "${{ github.event.inputs.clean_install }}" ]; then + if [ "${CLEAN_INSTALL}" = "true" ] || [ -z "${CLEAN_INSTALL}" ]; then echo "Running mvn clean install with -U flag" - mvn clean install -U -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + mvn clean install -U -DskipTests=true -Dci.version="${SNAPSHOT}" else echo "Running mvn install without -U flag" - mvn install -DskipTests=true -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + mvn install -DskipTests=true -Dci.version="${SNAPSHOT}" fi - name: Run Unit Tests - run: mvn test -Dci.version=${{ github.event.inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} - - - name: Install git - if: always() run: | - apt-get update && apt-get install -y git - git config --global --add safe.directory '*' + mvn test -Dci.version="${SNAPSHOT}" + + # - name: Install git + # if: always() + # run: | + # apt-get update && apt-get install -y git + # git config --global --add safe.directory '*' - - name: Generate test report - if: always() - uses: dorny/test-reporter@v1 - with: - name: Maven Test Results - path: target/surefire-reports/*.xml - reporter: java-junit - fail-on-error: true + # - name: Generate test report + # if: always() + # uses: dorny/test-reporter@v1 + # with: + # name: Maven Test Results + # path: target/surefire-reports/*.xml + # reporter: java-junit + # fail-on-error: true - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results - path: | - target/surefire-reports/ - target/site/ - retention-days: 30 + # - name: Upload test results + # if: always() + # uses: actions/upload-artifact@v4 + # with: + # name: test-results + # path: | + # target/surefire-reports/ + # target/site/ + # retention-days: 30 - - name: Publish test summary - if: always() - run: | - echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ -f target/surefire-reports/TEST-*.xml ]; then - TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + # - name: Publish test summary + # if: always() + # run: | + # echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY + # echo "" >> $GITHUB_STEP_SUMMARY + # if [ -f target/surefire-reports/TEST-*.xml ]; then + # TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + # FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + # ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + # SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY - echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY - echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY - echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY + # echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY + # echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY + # echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY + # echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY - if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY - else - echo "" >> $GITHUB_STEP_SUMMARY - echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY - fi - fi + # if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then + # echo "" >> $GITHUB_STEP_SUMMARY + # echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY + # else + # echo "" >> $GITHUB_STEP_SUMMARY + # echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY + # fi + # fi From 3fb274b728ee4a2d59c0c7680ed675b1355d41f1 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 14:06:27 -0500 Subject: [PATCH 19/25] fix: fix --- .github/workflows/unit-test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index b80fb78..b7dc5a2 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -16,8 +16,7 @@ on: clean_install: description: 'Run clean install with -U flag' required: true - default: false - type: boolean + default: "false" jobs: test: @@ -43,6 +42,8 @@ jobs: - name: Maven Clean Install run: | if [ "${CLEAN_INSTALL}" = "true" ] || [ -z "${CLEAN_INSTALL}" ]; then + echo "clean install: ${CLEAN_INSTALL}" + echo "snapshot: ${SNAPSHOT}" echo "Running mvn clean install with -U flag" mvn clean install -U -DskipTests=true -Dci.version="${SNAPSHOT}" else From 11a5f960458f61dee3deed2f1dbc5d8af1959eec Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 14:10:28 -0500 Subject: [PATCH 20/25] fix: fix --- .github/workflows/unit-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index b7dc5a2..874ca33 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -14,7 +14,7 @@ on: options: - '5.0.0-alpha-SNAPSHOT' clean_install: - description: 'Run clean install with -U flag' + description: 'Run clean install with -U flag if true, else false' required: true default: "false" @@ -24,8 +24,8 @@ jobs: runs-on: ubuntu-latest container: maven:3.9.9-amazoncorretto-21-debian env: - SNAPSHOT: ${{ inputs.snapshot }} - CLEAN_INSTALL: ${{ inputs.clean_install }} + SNAPSHOT: ${{ inputs.snapshot || '5.0.0-alpha-SNAPSHOT' }} + CLEAN_INSTALL: ${{ inputs.clean_install || 'false' }} steps: - name: Checkout code From 385a928d0924ca24d64645a41ceb0c4b6dffbd71 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 14:16:28 -0500 Subject: [PATCH 21/25] fix: fix --- .github/workflows/unit-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 874ca33..ef002c2 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -34,12 +34,12 @@ jobs: - name: Cache Maven packages uses: actions/cache@v4 with: - path: ~/.m2/repository + path: /root/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - - name: Maven Clean Install + - name: Maven Install run: | if [ "${CLEAN_INSTALL}" = "true" ] || [ -z "${CLEAN_INSTALL}" ]; then echo "clean install: ${CLEAN_INSTALL}" @@ -53,7 +53,7 @@ jobs: - name: Run Unit Tests run: | - mvn test -Dci.version="${SNAPSHOT}" + mvn test -Dci.version="${SNAPSHOT}" | grep -v "^Progress (1):" # - name: Install git # if: always() From e52736adcb57a22d95bb1173e30e4c331261df09 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 14:31:11 -0500 Subject: [PATCH 22/25] docs: docs and comment --- .github/workflows/unit-test.yml | 5 +- README.md | 1 + test/README.md | 141 ++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index ef002c2..b4d75de 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -1,7 +1,6 @@ name: Run Unit Tests on: -# push: pull_request: branches: [ default-app ] workflow_dispatch: @@ -45,10 +44,10 @@ jobs: echo "clean install: ${CLEAN_INSTALL}" echo "snapshot: ${SNAPSHOT}" echo "Running mvn clean install with -U flag" - mvn clean install -U -DskipTests=true -Dci.version="${SNAPSHOT}" + mvn clean install -U -DskipTests=true -Dci.version="${SNAPSHOT}" | grep -v "^Progress (1):" else echo "Running mvn install without -U flag" - mvn install -DskipTests=true -Dci.version="${SNAPSHOT}" + mvn install -DskipTests=true -Dci.version="${SNAPSHOT}" | grep -v "^Progress (1):" fi - name: Run Unit Tests diff --git a/README.md b/README.md index 9771e8e..fde095b 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ This repository includes several tools to help maintain code quality: - See `client/README.md` for front-end development instructions. - See `java/README.md` for back-end/reactor development. +- See `test/README.md` for comprehensive testing guide and workflow. --- diff --git a/test/README.md b/test/README.md index cee70d8..63dabaa 100644 --- a/test/README.md +++ b/test/README.md @@ -48,6 +48,147 @@ mvn test mvn test -Dtest=HelloReactorTest#testHelloUserReactor_CustomName ``` +## Testing Workflow + +### Development Cycle + +Testing should be an integral part of your reactor development process: + +1. **Design Phase** - Plan your reactor's functionality and identify test scenarios +2. **Implementation** - Write your reactor code in `java/src/reactors/` +3. **Test Creation** - Create corresponding test class in `test/reactors/` +4. **Validation** - Run tests to verify behavior +5. **Iteration** - Fix issues and re-run tests until all pass +6. **Integration** - Add test to suite and commit + +### Recommended Testing Workflow + +#### Option 1: Test-Driven Development (TDD) +Write tests before implementing the reactor: + +```bash +# 1. Create test class first +# test/reactors/example/YourReactorTest.java + +# 2. Run tests (they will fail) +mvn test -Dtest=YourReactorTest + +# 3. Implement reactor to make tests pass +# java/src/reactors/examples/YourReactor.java + +# 4. Run tests again +mvn test -Dtest=YourReactorTest + +# 5. Refactor and repeat until all tests pass +``` + +#### Option 2: Traditional Development +Write reactor first, then add tests: + +```bash +# 1. Implement reactor +# java/src/reactors/examples/YourReactor.java + +# 2. Create comprehensive tests +# test/reactors/example/YourReactorTest.java + +# 3. Run tests to verify +mvn test -Dtest=YourReactorTest + +# 4. Fix any issues discovered +``` + +### Pre-Commit Testing + +Always run tests before committing changes: + +```bash +# Run all tests +mvn test + +# Or run just the tests for modified reactors +mvn test -Dtest=YourModifiedReactorTest + +# Stage and commit only after tests pass +git add . +git commit -m "feat: Add YourReactor with comprehensive tests" +``` + +### Continuous Testing During Development + +For rapid feedback during active development: + +```bash +# Terminal 1: Keep this running +mvn test -Dtest=YourReactorTest + +# Terminal 2: Edit your code +# Make changes to reactor or test + +# Return to Terminal 1 and re-run after each change +``` + +### Integration with SEMOSS Development + +When working with the SEMOSS UI: + +1. **Before "Recompile reactors"** in SEMOSS UI: + ```bash + mvn test # Ensure tests pass + ``` + +2. **After compiling** in SEMOSS UI: + - Test reactor in the application + - If issues found, update tests to cover the bug + - Fix reactor code + - Re-run tests + +3. **Before "Publish files"**: + ```bash + mvn test # Final verification + ``` + +### Multi-Reactor Development + +When working on multiple reactors: + +```bash +# Run tests for specific package +mvn test -Dtest=reactors.example.*Test + +# Or run the full suite +mvn test -Dtest=ReactorTestSuite +``` + +### Debugging Failed Tests + +1. **Read the error message** - JUnit provides detailed failure information +2. **Check mock setup** - Verify mocks are configured correctly +3. **Add debug logging** - Use `System.out.println()` in tests temporarily +4. **Run in debug mode** - Use your IDE's debugger to step through +5. **Isolate the issue** - Run single test method to focus + +```bash +# Run single test method with verbose output +mvn test -Dtest=YourReactorTest#testSpecificScenario -X +``` + +### Workflow Best Practices + +✅ **Do:** +- Run tests frequently during development +- Write tests for bug fixes before fixing the bug +- Keep tests fast and focused +- Run full test suite before pushing to remote +- Update test documentation when adding new tests + +❌ **Don't:** +- Skip writing tests for "simple" reactors +- Commit code with failing tests +- Ignore test failures in CI/CD +- Write overly complex tests that are hard to maintain +- Test implementation details instead of behavior + ## Test Coverage ### HelloUserReactor Tests From deeb89c2ae2029af922c3fa7848cfb22144bdc83 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 14:51:03 -0500 Subject: [PATCH 23/25] ci: report test --- .github/workflows/unit-test.yml | 88 ++++++++++++++++----------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index b4d75de..389c4b8 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -54,52 +54,52 @@ jobs: run: | mvn test -Dci.version="${SNAPSHOT}" | grep -v "^Progress (1):" - # - name: Install git - # if: always() - # run: | - # apt-get update && apt-get install -y git - # git config --global --add safe.directory '*' + - name: Install git + if: always() + run: | + apt-get update && apt-get install -y git + git config --global --add safe.directory '*' - # - name: Generate test report - # if: always() - # uses: dorny/test-reporter@v1 - # with: - # name: Maven Test Results - # path: target/surefire-reports/*.xml - # reporter: java-junit - # fail-on-error: true + - name: Generate test report + if: always() + uses: dorny/test-reporter@v1 + with: + name: Maven Test Results + path: target/surefire-reports/*.xml + reporter: java-junit + fail-on-error: true - # - name: Upload test results - # if: always() - # uses: actions/upload-artifact@v4 - # with: - # name: test-results - # path: | - # target/surefire-reports/ - # target/site/ - # retention-days: 30 + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: | + target/surefire-reports/ + target/site/ + retention-days: 30 - # - name: Publish test summary - # if: always() - # run: | - # echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY - # echo "" >> $GITHUB_STEP_SUMMARY - # if [ -f target/surefire-reports/TEST-*.xml ]; then - # TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - # FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - # ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - # SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + - name: Publish test summary + if: always() + run: | + echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f target/surefire-reports/TEST-*.xml ]; then + TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) + SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - # echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY - # echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY - # echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY - # echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY + echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY + echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY + echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY + echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY - # if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then - # echo "" >> $GITHUB_STEP_SUMMARY - # echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY - # else - # echo "" >> $GITHUB_STEP_SUMMARY - # echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY - # fi - # fi + if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY + else + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY + fi + fi From b3d42813ca00b579e7b7d7167f8e4f740f648e0f Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 14:57:42 -0500 Subject: [PATCH 24/25] ci: report test --- .github/workflows/unit-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 389c4b8..232f52b 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -65,7 +65,7 @@ jobs: uses: dorny/test-reporter@v1 with: name: Maven Test Results - path: target/surefire-reports/*.xml + path: /__w/Template/Template/target/surefire-reports/*.xml reporter: java-junit fail-on-error: true @@ -75,8 +75,8 @@ jobs: with: name: test-results path: | - target/surefire-reports/ - target/site/ + /__w/Template/Template/target/surefire-reports/ + /__w/Template/Template/target/site/ retention-days: 30 - name: Publish test summary From 59c30a03e148d370739d2ae780554c12679c2130 Mon Sep 17 00:00:00 2001 From: Rithvik Doshi Date: Wed, 3 Dec 2025 15:01:13 -0500 Subject: [PATCH 25/25] ci: we r done probably --- .github/workflows/unit-test.yml | 51 +-------------------------------- 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 232f52b..b08eae1 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -53,53 +53,4 @@ jobs: - name: Run Unit Tests run: | mvn test -Dci.version="${SNAPSHOT}" | grep -v "^Progress (1):" - - - name: Install git - if: always() - run: | - apt-get update && apt-get install -y git - git config --global --add safe.directory '*' - - - name: Generate test report - if: always() - uses: dorny/test-reporter@v1 - with: - name: Maven Test Results - path: /__w/Template/Template/target/surefire-reports/*.xml - reporter: java-junit - fail-on-error: true - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results - path: | - /__w/Template/Template/target/surefire-reports/ - /__w/Template/Template/target/site/ - retention-days: 30 - - - name: Publish test summary - if: always() - run: | - echo "## Test Results :test_tube:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ -f target/surefire-reports/TEST-*.xml ]; then - TESTS=$(grep -oP 'tests="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - FAILURES=$(grep -oP 'failures="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - ERRORS=$(grep -oP 'errors="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - SKIPPED=$(grep -oP 'skipped="\K[^"]+' target/surefire-reports/TEST-*.xml | head -1) - - echo "- **Total Tests:** $TESTS" >> $GITHUB_STEP_SUMMARY - echo "- **Failures:** $FAILURES" >> $GITHUB_STEP_SUMMARY - echo "- **Errors:** $ERRORS" >> $GITHUB_STEP_SUMMARY - echo "- **Skipped:** $SKIPPED" >> $GITHUB_STEP_SUMMARY - - if [ "$FAILURES" = "0" ] && [ "$ERRORS" = "0" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY - else - echo "" >> $GITHUB_STEP_SUMMARY - echo "### ❌ Some tests failed!" >> $GITHUB_STEP_SUMMARY - fi - fi + \ No newline at end of file