NIFI-16265 - Extract reusable System Test framework from nifi-system-test-suite - #11599
NIFI-16265 - Extract reusable System Test framework from nifi-system-test-suite#11599markap14 wants to merge 4 commits into
Conversation
exceptionfactory
left a comment
There was a problem hiding this comment.
Thanks for putting together this refactored packaging for system tests @markap14.
There is definitely value in support external use of these tests, but on initial read, I'm concerned about the implied visibility of some of these classes.
I have not reviewed the classes in detail to consider the full implications, but do you think that some of the can be package-private, or do all of them need to be public? Classes like the System KeyStore Provider seem like that might not need public visibility.
|
That's fair @exceptionfactory. My intent was to avoid changing anything and instead move everything over exactly as-is. But you're right, moving from test to publicly available it is probably fair to reduce visibility on some of those. |
|
Good catch, thanks @exceptionfactory. I went through the moved classes and checked (via grep across all ~500 existing `*IT` test classes, which live in subpackages of `org.apache.nifi.tests.system`) which ones are actually referenced from outside the framework's own package. `NiFiInstanceProvider`, `AggregateNiFiInstance`, `NiFiInstanceCache`, `NiFiSystemKeyStoreProvider`, and `TroubleshootingTestWatcher` (including the one you called out) have no external consumers - they're only used internally by `NiFiSystemIT` and its factory implementations, so I made them package-private in the latest commit. `NiFiSystemIT`, `NiFiInstance`, `NiFiInstanceFactory`, `InstanceConfiguration`, `SpawnedStandaloneNiFiInstanceFactory`, `SpawnedClusterNiFiInstanceFactory`, `NiFiClientUtil`, and `ExceptionalBooleanSupplier` do need to stay public - they're directly extended/constructed/imported from test classes in other packages today. Rebuilt and reran the sample IT test to confirm nothing broke. |
…test-suite Move NiFiSystemIT and its supporting infrastructure (NiFiInstance, InstanceConfiguration, SpawnedStandaloneNiFiInstanceFactory, NiFiClientUtil, etc.) into a new nifi-system-test-framework module with the classes under src/main/java instead of src/test/java. This lets third-party NAR projects depend on the framework to write their own System Tests against a real spawned NiFi instance, outside of the NiFi source tree, the same way nifi-mock is depended on for unit tests. nifi-system-test-suite now depends on the new module and keeps only its own test resources, extensions, and the *IT test classes that are specific to NiFi's own bundled test extensions.
…m-test-framework Per David Handermann's review feedback, several classes were public only because that didn't matter while they lived in src/test/java. Now that the module is a published artifact, make the ones with no external consumers package-private: NiFiInstanceProvider, AggregateNiFiInstance, NiFiInstanceCache, NiFiSystemKeyStoreProvider, and TroubleshootingTestWatcher. Confirmed via grep that none of the ~500 existing *IT test classes (which live in subpackages) reference these types directly - they're only used internally by NiFiSystemIT and its factory implementations.
7af77de to
241f641
Compare
exceptionfactory
left a comment
There was a problem hiding this comment.
Thanks @markap14, adjusting the visibility on those classes helps focus the supported surface.
My remaining concerns relate to the large number of dependencies that this module pulls in. A number of these are expected based on framework requirements, but it also makes for a large dependency tree that raises some additional questions in terms of maintainability as a more public-facing library. Although not on the same level as something like the nifi-framework-api, making the test framework available as "framework extension" highlights some need to scope down dependencies as much as possible.
With that in mind, what options are available for restructuring the loading process to more clearly distinguish dependencies? Although it would require one additional module, it makes me wonder whether there should be a "system-test-framework-api" and a "system-test-framework" to provide stronger boundaries. Things like Jersey, the Framework Cluster Protocol, and the Python Framework API are among dependencies that seem like they should not bleed into a module intended for extension. Open to options here on possible approaches.
|
@exceptionfactory I'm not sure that I would call this "a module intended for extension." This is a module intended to start up 1 nifi instance or one full cluster of nifi instances in a light-weight manner purely with the goal of verifying behavior against a legit, running instance for automated tests. I don't think we can remove things like Jersey or the Framework Cluster Protocol because doing so would fail to run NiFi as it's run in production. Please correct me if I'm misunderstanding something. |
|
By module for extension, I was referring specifically to At the root, I'm concerned about the lack of encapsulation in the current approach. The design has worked well when everything was co-located in the system test suite, but it seems like just moving out these classes doesn't provide the kind of approach needed for test interfaces versus test implementation. Taking a different perspective, it also raises a question as to whether a Testcontainer approach might be better, as that would encapsulate the entire application, without these types of module contract concerns. I realize this is a significantly different path, but it seems worth considering as an alternative. |
…stem-test-framework
Eliminates the last internal-sounding dependencies from the newly extracted
nifi-system-test-framework module (nifi-framework-core-api, nifi-site-to-site-client,
nifi-utils, nifi-per-process-group-logging) so that the module a third-party NAR
project depends on for System Tests pulls in only what its own code actually needs.
- ConnectorState and AbstractPort.PORT_RELATIONSHIP: replaced with plain String
constants on NiFiSystemIT/NiFiClientUtil, the same treatment already applied to
ClusterRoles/NodeConnectionState. This also touched several nifi-system-test-suite
IT classes that defined their own ConnectorState-typed private helper methods.
- ParameterProviderConfiguration/StandardParameterProviderConfiguration: replaced
with a new ParameterProviderConfig record defined in the framework module.
- SiteToSiteTransportProtocol: RemoteProcessGroupIT now passes the transport
protocol as a plain String ("HTTP"/"RAW").
- FileUtils.deleteFile: replaced with a small private recursive delete in
SpawnedStandaloneNiFiInstanceFactory instead of depending on nifi-utils.
- nifi-per-process-group-logging: dropped outright - unused in the framework
module's source; the suite already declares it separately for the spawned
NiFi instance's own runtime logback configuration.
Verified via mvn install on both modules plus targeted failsafe runs (Connector*IT,
Clustered*IT, RemoteProcessGroupIT, ParameterContextIT, ClassloaderIsolationKeyIT),
all passing.
|
Ahh I see what you're saying now @exceptionfactory. I don't think Testcontainers is really the way we want to go here because that would require that the full docker image be built so it could be usable. That would absolutely make sense for testing extensions such as Processors in a separate service (by uploading the nar, etc). But it wouldn't work for framework-level extensions. That said, I reviewed the pom.xml again and I think I see the concern. With the latest commit we now have basically only 2 sets of dependencies:
The pom that I had factored out did have a few extra dependencies that I was able to eliminate with some simple refactoring:
|
…wSyncIT ParameterProviderConfig import was out of alphabetical order relative to NiFiSystemIT.
Summary
nifi-system-test-frameworkmodule containingNiFiSystemITand its supporting infrastructure (NiFiInstance,InstanceConfiguration,SpawnedStandaloneNiFiInstanceFactory,SpawnedClusterNiFiInstanceFactory,AggregateNiFiInstance,NiFiInstanceCache,NiFiClientUtil,NiFiSystemKeyStoreProvider,TroubleshootingTestWatcher, etc.), moved tosrc/main/javaso the artifact is a normal, publishable dependency rather than test-scoped code trapped insidenifi-system-test-suite.nifi-system-test-framework(as atest-scope dependency, the same waynifi-mockis depended on for unit tests) to write their own System Tests that spawn a real NiFi instance and drive it via the REST client, without needing a full NiFi source checkout.nifi-system-test-suitenow depends on the new module instead of defining these classes itself. It retains all of its own*ITtest classes, test resources, and the NiFi-specificAbstractNarSwapMigrationITbase class (which is tied to internal test-only NARs and isn't generic).org.apache.nifi.tests.system), so none of the ~500 existing*ITtest classes required edits.Test plan
mvn -pl nifi-system-tests/nifi-system-test-framework -am install -DskipTests— new module compiles and installs.mvn -pl nifi-system-tests/nifi-system-test-suite -am install -DskipTests— suite compiles against the new dependency.mvn -pl nifi-system-tests/nifi-system-test-suite verify -Pintegration-tests,skip-unit-tests -Dit.test=ClassloaderIsolationKeyIT— ran a real System Test end-to-end (spawns a NiFi instance) usingNiFiSystemITfrom the extracted module:Tests run: 2, Failures: 0, Errors: 0.