blob: 1f815d3bde6892e6e7437a1fbc6bd59f10e206c5 [file]
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <map>
#include <memory>
#include <chrono>
#include "core/repository/VolatileContentRepository.h"
#include "core/ProcessGroup.h"
#include "core/RepositoryFactory.h"
#include "core/yaml/YamlConfiguration.h"
#include "TailFile.h"
#include "unit/TestBase.h"
#include "unit/Catch.h"
#include "utils/StringUtils.h"
#include "unit/ConfigurationTestController.h"
#include "unit/TestUtils.h"
#include "core/Resource.h"
#include "utils/crypto/property_encryption/PropertyEncryptionUtils.h"
#include "unit/DummyProcessor.h"
#include "catch2/generators/catch_generators.hpp"
using namespace std::literals::chrono_literals;
namespace org::apache::nifi::minifi::test {
TEST_CASE("Test YAML Config Processing", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
SECTION("loading YAML without optional component IDs works") {
static const std::string CONFIG_YAML_WITHOUT_IDS =
R"(
MiNiFi Config Version: 1
Flow Controller:
name: MiNiFi Flow
comment:
Core Properties:
flow controller graceful shutdown period: 10 sec
flow service write delay interval: 500 ms
administrative yield duration: 30 sec
bored yield duration: 10 millis
FlowFile Repository:
partitions: 256
checkpoint interval: 2 mins
always sync: false
Swap:
threshold: 20000
in period: 5 sec
in threads: 1
out period: 5 sec
out threads: 4
Provenance Repository:
provenance rollover time: 1 min
Content Repository:
content claim max appendable size: 10 MB
content claim max flow files: 100
always sync: false
Component Status Repository:
buffer size: 1440
snapshot frequency: 1 min
Security Properties:
keystore: /tmp/ssl/localhost-ks.jks
keystore type: JKS
keystore password: localtest
key password: localtest
truststore: /tmp/ssl/localhost-ts.jks
truststore type: JKS
truststore password: localtest
ssl protocol: TLS
Sensitive Props:
key:
algorithm: PBEWITHMD5AND256BITAES-CBC-OPENSSL
provider: BC
Processors:
- name: TailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
penalization period: 30 sec
yield period: 1 sec
bulletin level: ERROR
run duration nanos: 0
auto-terminated relationships list:
Properties:
File to Tail: logs/minifi-app.log
Rolling Filename Pattern: minifi-app*
Initial Start Position: Beginning of File
Connections:
- name: TailToS2S
source name: TailFile
source relationship name: success
destination name: 8644cbcc-a45c-40e0-964d-5e536e2ada61
max work queue size: 0
max work queue data size: 1 MB
flowfile expiration: 60 sec
queue prioritizer class: org.apache.nifi.prioritizer.NewestFlowFileFirstPrioritizer
Remote Processing Groups:
- name: NiFi Flow
comment:
url: https://localhost:8090/nifi
timeout: 30 secs
yield period: 10 sec
Input Ports:
- id: 8644cbcc-a45c-40e0-964d-5e536e2ada61
name: tailed log
comments:
max concurrent tasks: 1
use compression: false
Provenance Reporting:
comment:
scheduling strategy: TIMER_DRIVEN
scheduling period: 30 sec
host: localhost
port name: provenance
port: 8090
port uuid: 2f389b8d-83f2-48d3-b465-048f28a1cb56
url: https://localhost:8090/
originating url: http://${hostname(true)}:8081/nifi
use compression: true
timeout: 30 secs
batch size: 1000;
)";
std::unique_ptr<core::ProcessGroup> rootFlowConfig = yamlConfig.getRootFromPayload(CONFIG_YAML_WITHOUT_IDS);
REQUIRE(rootFlowConfig);
REQUIRE(rootFlowConfig->findProcessorByName("TailFile"));
minifi::utils::Identifier uuid = rootFlowConfig->findProcessorByName("TailFile")->getUUID();
REQUIRE(uuid);
REQUIRE(!rootFlowConfig->findProcessorByName("TailFile")->getUUIDStr().empty());
REQUIRE(1 == rootFlowConfig->findProcessorByName("TailFile")->getMaxConcurrentTasks());
REQUIRE(core::SchedulingStrategy::TIMER_DRIVEN == rootFlowConfig->findProcessorByName("TailFile")->getSchedulingStrategy());
REQUIRE(1s == rootFlowConfig->findProcessorByName("TailFile")->getSchedulingPeriod());
REQUIRE(30s == rootFlowConfig->findProcessorByName("TailFile")->getPenalizationPeriod());
REQUIRE(1s == rootFlowConfig->findProcessorByName("TailFile")->getYieldPeriod());
REQUIRE(rootFlowConfig->findProcessorByName("TailFile")->getLogBulletinLevel() == logging::LOG_LEVEL::err);
REQUIRE(0s == rootFlowConfig->findProcessorByName("TailFile")->getRunDurationNano());
std::map<std::string, minifi::Connection*> connectionMap;
rootFlowConfig->getConnections(connectionMap);
REQUIRE(2 == connectionMap.size());
// This is a map of UUID->Connection, and we don't know UUID, so just going to loop over it
for (const auto& it : connectionMap) {
REQUIRE(it.second);
REQUIRE(!it.second->getUUIDStr().empty());
REQUIRE(it.second->getDestination());
REQUIRE(it.second->getSource());
REQUIRE(60s == it.second->getFlowExpirationDuration());
}
}
SECTION("missing required field in YAML throws exception") {
static const std::string CONFIG_YAML_NO_RPG_PORT_ID =
R"(
MiNiFi Config Version: 1
Flow Controller:
name: MiNiFi Flow
Processors: []
Connections: []
Remote Processing Groups:
- name: NiFi Flow
comment:
url: https://localhost:8090/nifi
timeout: 30 secs
yield period: 10 sec
Input Ports:
- name: tailed log
comments:
max concurrent tasks: 1
use compression: false
)";
REQUIRE_THROWS_AS(yamlConfig.getRootFromPayload(CONFIG_YAML_NO_RPG_PORT_ID), std::invalid_argument);
}
SECTION("Validated YAML property failure throws exception and logs invalid attribute name") {
static const std::string CONFIG_YAML_EMPTY_RETRY_ATTRIBUTE =
R"(
Flow Controller:
name: MiNiFi Flow
Processors:
- name: RetryFlowFile
class: org.apache.nifi.processors.standard.RetryFlowFile
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list:
Properties:
Retry Attribute: ""
Connections: []
Remote Processing Groups: []
Provenance Reporting:
)";
REQUIRE_THROWS_WITH(yamlConfig.getRootFromPayload(CONFIG_YAML_EMPTY_RETRY_ATTRIBUTE), "Unable to parse configuration file for component named 'RetryFlowFile' because ValidationFailed");
REQUIRE(LogTestController::getInstance().contains("Invalid value was set for property 'Retry Attribute' creating component 'RetryFlowFile'"));
}
}
TEST_CASE("Test YAML v3 Invalid Type", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile To RPG
comment: ''
Core Properties:
flow controller graceful shutdown period: 10 sec
flow service write delay interval: 500 ms
administrative yield duration: 30 sec
bored yield duration: 10 millis
max concurrent threads: 1
variable registry properties: ''
FlowFile Repository:
partitions: 256
checkpoint interval: 2 mins
always sync: false
Swap:
threshold: 20000
in period: 5 sec
in threads: 1
out period: 5 sec
out threads: 4
Content Repository:
content claim max appendable size: 10 MB
content claim max flow files: 100
always sync: false
Provenance Repository:
provenance rollover time: 1 min
implementation: org.apache.nifi.provenance.MiNiFiPersistentProvenanceRepository
Component Status Repository:
buffer size: 1440
snapshot frequency: 1 min
Security Properties:
keystore: ''
keystore type: ''
keystore password: ''
key password: ''
truststore: ''
truststore type: ''
truststore password: ''
ssl protocol: ''
Sensitive Props:
key:
algorithm: PBEWITHMD5AND256BITAES-CBC-OPENSSL
provider: BC
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
penalization period: 30 sec
yield period: 1 sec
run duration nanos: 0
auto-terminated relationships list: []
Properties:
File Location: Local
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
Rolling Filename Pattern:
tail-base-directory:
tail-mode: Single file
tailfile-lookup-frequency: 10 minutes
tailfile-maximum-age: 24 hours
tailfile-recursive-lookup: 'false'
tailfile-rolling-strategy: Fixed name
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections:
- id: b0c0c3cc-0158-1000-0000-000000000000
name: TailFile/success/ac0e798c-0158-1000-0588-cda9b944e011
source id: b0c04f28-0158-1000-0000-000000000000
source relationship names:
- success
destination id: ac0e798c-0158-1000-0588-cda9b944e011
max work queue size: 10000
max work queue data size: 1 GB
flowfile expiration: 0 sec
queue prioritizer class: ''
Remote Process Groups:
- id: b0c09ff0-0158-1000-0000-000000000000
name: ''
url: http://localhost:8080/nifi
comment: ''
timeout: 30 sec
yield period: 10 sec
transport protocol: WRONG
proxy host: ''
proxy port: ''
proxy user: ''
proxy password: ''
local network interface: ''
Input Ports:
- id: aca664f8-0158-1000-a139-92485891d349
name: test2
comment: ''
max concurrent tasks: 1
use compression: false
- id: ac0e798c-0158-1000-0588-cda9b944e011
name: test
comment: ''
max concurrent tasks: 1
use compression: false
Output Ports: []
NiFi Properties Overrides: {}
)";
REQUIRE_THROWS_AS(yamlConfig.getRootFromPayload(TEST_CONFIG_YAML), minifi::Exception);
}
TEST_CASE("Test YAML v3 Config Processing", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile To RPG
comment: ''
Core Properties:
flow controller graceful shutdown period: 10 sec
flow service write delay interval: 500 ms
administrative yield duration: 30 sec
bored yield duration: 10 millis
max concurrent threads: 1
variable registry properties: ''
FlowFile Repository:
partitions: 256
checkpoint interval: 2 mins
always sync: false
Swap:
threshold: 20000
in period: 5 sec
in threads: 1
out period: 5 sec
out threads: 4
Content Repository:
content claim max appendable size: 10 MB
content claim max flow files: 100
always sync: false
Provenance Repository:
provenance rollover time: 1 min
implementation: org.apache.nifi.provenance.MiNiFiPersistentProvenanceRepository
Component Status Repository:
buffer size: 1440
snapshot frequency: 1 min
Security Properties:
keystore: ''
keystore type: ''
keystore password: ''
key password: ''
truststore: ''
truststore type: ''
truststore password: ''
ssl protocol: ''
Sensitive Props:
key:
algorithm: PBEWITHMD5AND256BITAES-CBC-OPENSSL
provider: BC
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
penalization period: 30 sec
yield period: 1 sec
run duration nanos: 0
auto-terminated relationships list: []
Properties:
File Location: Local
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
Rolling Filename Pattern:
tail-base-directory:
tail-mode: Single file
tailfile-lookup-frequency: 10 minutes
tailfile-maximum-age: 24 hours
tailfile-recursive-lookup: 'false'
tailfile-rolling-strategy: Fixed name
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections:
- id: b0c0c3cc-0158-1000-0000-000000000000
name: TailFile/success/ac0e798c-0158-1000-0588-cda9b944e011
source id: b0c04f28-0158-1000-0000-000000000000
source relationship names:
- success
destination id: ac0e798c-0158-1000-0588-cda9b944e011
max work queue size: 10000
max work queue data size: 1 GB
flowfile expiration: 0 sec
queue prioritizer class: ''
Remote Process Groups:
- id: b0c09ff0-0158-1000-0000-000000000000
name: ''
url: http://localhost:8080/nifi
comment: ''
timeout: 20 sec
yield period: 10 sec
transport protocol: RAW
proxy host: ''
proxy port: ''
proxy user: ''
proxy password: ''
local network interface: ''
Input Ports:
- id: ac0e798c-0158-1000-0588-cda9b944e011
name: AmazingInputPort
comment: ''
max concurrent tasks: 1
use compression: true
batch size:
size: 10 B
count: 3
duration: 5 sec
Output Ports: []
NiFi Properties Overrides: {}
)";
std::unique_ptr<core::ProcessGroup> rootFlowConfig = yamlConfig.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(rootFlowConfig);
REQUIRE(rootFlowConfig->findProcessorByName("TailFile"));
minifi::utils::Identifier uuid = rootFlowConfig->findProcessorByName("TailFile")->getUUID();
REQUIRE(uuid);
REQUIRE(!rootFlowConfig->findProcessorByName("TailFile")->getUUIDStr().empty());
REQUIRE(1 == rootFlowConfig->findProcessorByName("TailFile")->getMaxConcurrentTasks());
REQUIRE(core::SchedulingStrategy::TIMER_DRIVEN == rootFlowConfig->findProcessorByName("TailFile")->getSchedulingStrategy());
REQUIRE(1 == rootFlowConfig->findProcessorByName("TailFile")->getMaxConcurrentTasks());
REQUIRE(1s == rootFlowConfig->findProcessorByName("TailFile")->getSchedulingPeriod());
REQUIRE(30s == rootFlowConfig->findProcessorByName("TailFile")->getPenalizationPeriod());
REQUIRE(1s == rootFlowConfig->findProcessorByName("TailFile")->getYieldPeriod());
REQUIRE(0s == rootFlowConfig->findProcessorByName("TailFile")->getRunDurationNano());
std::map<std::string, minifi::Connection*> connectionMap;
rootFlowConfig->getConnections(connectionMap);
REQUIRE(2 == connectionMap.size());
for (const auto& it : connectionMap) {
REQUIRE(it.second);
REQUIRE(!it.second->getUUIDStr().empty());
REQUIRE(it.second->getDestination());
REQUIRE(it.second->getSource());
REQUIRE(0s == it.second->getFlowExpirationDuration());
}
TypedProcessorWrapper<minifi::RemoteProcessGroupPort> port = rootFlowConfig->findProcessorByName("AmazingInputPort");
REQUIRE(port);
CHECK(port->getUUIDStr() == "ac0e798c-0158-1000-0588-cda9b944e011");
CHECK(port.get().getUseCompression() == true);
CHECK(port.get().getBatchSize().value() == 10);
CHECK(port.get().getBatchCount().value() == 3);
CHECK(port.get().getBatchDuration().value() == std::chrono::seconds(5));
CHECK(port.get().getTimeout().value() == std::chrono::seconds(20));
}
TEST_CASE("Test Dynamic Unsupported", "[YamlConfigurationDynamicUnsupported]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
static const std::string TEST_CONFIG_YAML = R"(
Flow Controller:
name: Simple
Processors:
- name: GenerateFlowFile
class: GenerateFlowFile
Properties:
Dynamic Property: Bad
)";
std::unique_ptr<core::ProcessGroup> rootFlowConfig = yamlConfig.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(rootFlowConfig);
REQUIRE(rootFlowConfig->findProcessorByName("GenerateFlowFile"));
const minifi::utils::Identifier uuid = rootFlowConfig->findProcessorByName("GenerateFlowFile")->getUUID();
REQUIRE(uuid);
REQUIRE(!rootFlowConfig->findProcessorByName("GenerateFlowFile")->getUUIDStr().empty());
REQUIRE(LogTestController::getInstance().contains("[warning] Unable to set the dynamic property Dynamic Property"));
}
TEST_CASE("Test Required Property", "[YamlConfigurationRequiredProperty]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
static const std::string TEST_CONFIG_YAML = R"(
Flow Controller:
name: Simple
Processors:
- name: XYZ
class: GetFile
Properties:
Input Directory: ""
Batch Size: 1
)";
bool caught_exception = false;
try {
std::unique_ptr<core::ProcessGroup> rootFlowConfig = yamlConfig.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(rootFlowConfig);
REQUIRE(rootFlowConfig->findProcessorByName("GetFile"));
minifi::utils::Identifier uuid = rootFlowConfig->findProcessorByName("GetFile")->getUUID();
REQUIRE(uuid);
REQUIRE(!rootFlowConfig->findProcessorByName("GetFile")->getUUIDStr().empty());
} catch (const std::exception &e) {
caught_exception = true;
REQUIRE("Unable to parse configuration file for component named 'XYZ' because ValidationFailed" == std::string(e.what()));
}
REQUIRE(caught_exception);
}
TEST_CASE("Test Required Property 2", "[YamlConfigurationRequiredProperty2]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
static const std::string TEST_CONFIG_YAML = R"(
Flow Controller:
name: Simple
Processors:
- name: XYZ
class: GetFile
Properties:
Input Directory: "/"
Batch Size: 1
)";
std::unique_ptr<core::ProcessGroup> rootFlowConfig = yamlConfig.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(rootFlowConfig);
REQUIRE(rootFlowConfig->findProcessorByName("XYZ"));
minifi::utils::Identifier uuid = rootFlowConfig->findProcessorByName("XYZ")->getUUID();
REQUIRE(uuid);
REQUIRE(!rootFlowConfig->findProcessorByName("XYZ")->getUUIDStr().empty());
}
class DummyComponent : public core::ConfigurableComponentImpl, public core::CoreComponentImpl {
public:
DummyComponent() : ConfigurableComponentImpl(), CoreComponentImpl("DummyComponent") {}
bool supportsDynamicProperties() const override {
return false;
}
bool supportsDynamicRelationships() const override {
return false;
}
bool canEdit() override {
return true;
}
};
TEST_CASE("Test YAML Config With Funnel", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
static const std::string CONFIG_YAML_WITH_FUNNEL =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: root
comment: ''
Processors:
- id: 0eac51eb-d76c-4ba6-9f0c-351795b2d243
name: GenerateFlowFile1
class: org.apache.nifi.minifi.processors.GenerateFlowFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 10000 ms
Properties:
Batch Size: '1'
Custom Text: custom1
Data Format: Binary
File Size: 1 kB
Unique FlowFiles: 'true'
- id: 5ec49d9b-673d-4c6f-9108-ab4acce0c1dc
name: GenerateFlowFile2
class: org.apache.nifi.minifi.processors.GenerateFlowFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 10000 ms
Properties:
Batch Size: '1'
Custom Text: other2
Data Format: Binary
File Size: 1 kB
Unique FlowFiles: 'true'
- id: 695658ba-5b6e-4c7d-9c95-5a980b622c1f
name: LogAttribute
class: org.apache.nifi.minifi.processors.LogAttribute
max concurrent tasks: 1
scheduling strategy: EVENT_DRIVEN
auto-terminated relationships list:
- success
Properties:
FlowFiles To Log: '0'
Funnels:
- id: 01a2f910-7050-41c1-8528-942764e7591d
Connections:
- id: 97c6bdfb-3909-499f-9ae5-011cbe8cadaf
name: 01a2f910-7050-41c1-8528-942764e7591d//LogAttribute
source id: 01a2f910-7050-41c1-8528-942764e7591d
source relationship names: []
destination id: 695658ba-5b6e-4c7d-9c95-5a980b622c1f
- id: 353e6bd5-5fca-494f-ae99-02572352c47a
name: GenerateFlowFile2/success/01a2f910-7050-41c1-8528-942764e7591d
source id: 5ec49d9b-673d-4c6f-9108-ab4acce0c1dc
source relationship names:
- success
destination id: 01a2f910-7050-41c1-8528-942764e7591d
- id: 9c02c302-eb4f-4aac-98ed-0f6720a4ff1b
name: GenerateFlowFile1/success/01a2f910-7050-41c1-8528-942764e7591d
source id: 0eac51eb-d76c-4ba6-9f0c-351795b2d243
source relationship names:
- success
destination id: 01a2f910-7050-41c1-8528-942764e7591d
Remote Process Groups: []
)";
std::unique_ptr<core::ProcessGroup> rootFlowConfig = yamlConfig.getRootFromPayload(CONFIG_YAML_WITH_FUNNEL);
REQUIRE(rootFlowConfig);
REQUIRE(rootFlowConfig->findProcessorByName("GenerateFlowFile1"));
REQUIRE(rootFlowConfig->findProcessorByName("GenerateFlowFile2"));
REQUIRE(rootFlowConfig->findProcessorById(minifi::utils::Identifier::parse("01a2f910-7050-41c1-8528-942764e7591d").value()));
std::map<std::string, minifi::Connection*> connectionMap;
rootFlowConfig->getConnections(connectionMap);
REQUIRE(6 == connectionMap.size());
for (const auto& it : connectionMap) {
REQUIRE(it.second);
REQUIRE(!it.second->getUUIDStr().empty());
REQUIRE(it.second->getDestination());
REQUIRE(it.second->getSource());
}
}
TEST_CASE("Test UUID duplication checks", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
for (char i = '1'; i <= '8'; ++i) {
DYNAMIC_SECTION("Changing UUID 00000000-0000-0000-0000-00000000000" << i << " to be a duplicate") {
std::string config_yaml =
R"(
Flow Controller:
name: root
comment: ''
Processors:
- id: 00000000-0000-0000-0000-000000000001
name: GenerateFlowFile1
class: org.apache.nifi.minifi.processors.GenerateFlowFile
- id: 00000000-0000-0000-0000-000000000002
name: LogAttribute
class: org.apache.nifi.minifi.processors.LogAttribute
Funnels:
- id: 00000000-0000-0000-0000-000000000003
- id: 99999999-9999-9999-9999-999999999999
Connections:
- id: 00000000-0000-0000-0000-000000000004
name: 00000000-0000-0000-0000-000000000003//LogAttribute
source id: 00000000-0000-0000-0000-000000000003
source relationship names: []
destination id: 00000000-0000-0000-0000-000000000002
- id: 00000000-0000-0000-0000-000000000005
name: GenerateFlowFile1/success/00000000-0000-0000-0000-000000000003
source id: 00000000-0000-0000-0000-000000000001
source relationship names:
- success
destination id: 00000000-0000-0000-0000-000000000003
Remote Process Groups:
- id: 00000000-0000-0000-0000-000000000006
name: ''
url: http://localhost:8080/nifi
transport protocol: RAW
Input Ports:
- id: 00000000-0000-0000-0000-000000000007
name: test2
max concurrent tasks: 1
use compression: false
Output Ports: []
Controller Services:
- name: SSLContextService
id: 00000000-0000-0000-0000-000000000008
class: SSLContextService
)";
minifi::utils::string::replaceAll(config_yaml, std::string("00000000-0000-0000-0000-00000000000") + i, "99999999-9999-9999-9999-999999999999");
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(config_yaml), "General Operation: UUID 99999999-9999-9999-9999-999999999999 is duplicated in the flow configuration");
}
}
}
TEST_CASE("Configuration is not valid yaml", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
REQUIRE_THROWS(yaml_config.getRootFromPayload("}"));
REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Configuration is not valid yaml"));
}
namespace {
inline constexpr std::string_view TEST_FLOW_WITH_SENSITIVE_PROPERTIES = R"(MiNiFi Config Version: 3
Flow Controller:
name: root
comment: ''
Core Properties:
flow controller graceful shutdown period: 10 sec
flow service write delay interval: 500 ms
administrative yield duration: 30 sec
bored yield duration: 10 millis
max concurrent threads: 1
variable registry properties: ''
FlowFile Repository:
implementation: org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
partitions: 256
checkpoint interval: 2 mins
always sync: false
Swap:
threshold: 20000
in period: 5 sec
in threads: 1
out period: 5 sec
out threads: 4
Content Repository:
implementation: org.apache.nifi.controller.repository.FileSystemRepository
content claim max appendable size: 10 MB
content claim max flow files: 100
content repository archive enabled: false
content repository archive max retention period: 12 hours
content repository archive max usage percentage: 50%
always sync: false
Provenance Repository:
provenance rollover time: 1 min
implementation: org.apache.nifi.provenance.WriteAheadProvenanceRepository
provenance index shard size: 500 MB
provenance max storage size: 1 GB
provenance max storage time: 24 hours
provenance buffer size: 10000
Component Status Repository:
buffer size: 1440
snapshot frequency: 1 min
Security Properties:
keystore: ''
keystore type: ''
keystore password: ''
key password: ''
truststore: ''
truststore type: ''
truststore password: ''
ssl protocol: ''
Sensitive Props:
key:
algorithm: NIFI_PBKDF2_AES_GCM_256
Processors:
- id: 5f69344a-15e6-43ba-911c-7e9dd2595d1c
name: GenerateFlowFile
class: org.apache.nifi.minifi.processors.GenerateFlowFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 10s
penalization period: 30000 ms
yield period: 1000 ms
run duration nanos: 0
auto-terminated relationships list: []
Properties:
Batch Size: '1'
Data Format: Text
File Size: 100 B
Unique FlowFiles: 'true'
- id: f5f77e5d-4df2-4762-8ecc-d0dc07e36921
name: InvokeHTTP
class: org.apache.nifi.minifi.processors.InvokeHTTP
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1000 ms
penalization period: 30000 ms
yield period: 1000 ms
run duration nanos: 0
auto-terminated relationships list:
- success
- response
- failure
- retry
- no retry
Properties:
Always Output Response: 'false'
Connection Timeout: 5 s
Content-type: application/octet-stream
Disable Peer Verification: 'false'
Follow Redirects: 'true'
HTTP Method: POST
Include Date Header: 'true'
Invalid HTTP Header Field Handling Strategy: transform
Penalize on "No Retry": 'false'
Proxy Host: myproxy.com
Proxy Port: '8080'
Read Timeout: 15 s
Remote URL: https://myremoteserver.com
SSL Context Service: a00f8722-2419-44ee-929c-ad68644ad557
Send Message Body: 'true'
Use Chunked Encoding: 'false'
invokehttp-proxy-password: password123
invokehttp-proxy-username: user
send-message-body: 'true'
Controller Services:
- id: a00f8722-2419-44ee-929c-ad68644ad557
name: SSLContextService
type: org.apache.nifi.minifi.controllers.SSLContextService
Properties:
CA Certificate:
Client Certificate:
Passphrase: secret1!!1!
Private Key: /opt/secrets/private-key.pem
Use System Cert Store: 'true'
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections:
- id: 361bf7a6-e63d-4967-95f5-7bbeec3175bc
name: GenerateFlowFile/success/InvokeHTTP
source id: 5f69344a-15e6-43ba-911c-7e9dd2595d1c
source relationship names:
- success
destination id: f5f77e5d-4df2-4762-8ecc-d0dc07e36921
max work queue size: 2000
max work queue data size: 100 MB
flowfile expiration: 0 seconds
queue prioritizer class: ''
Remote Process Groups: []
NiFi Properties Overrides: {}
)";
inline constexpr std::string_view TEST_FLOW_WITH_SENSITIVE_PROPERTIES_ENCRYPTED = R"(MiNiFi Config Version: 3
Flow Controller:
name: root
comment: ""
Core Properties:
flow controller graceful shutdown period: 10 sec
flow service write delay interval: 500 ms
administrative yield duration: 30 sec
bored yield duration: 10 millis
max concurrent threads: 1
variable registry properties: ""
FlowFile Repository:
implementation: org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
partitions: 256
checkpoint interval: 2 mins
always sync: false
Swap:
threshold: 20000
in period: 5 sec
in threads: 1
out period: 5 sec
out threads: 4
Content Repository:
implementation: org.apache.nifi.controller.repository.FileSystemRepository
content claim max appendable size: 10 MB
content claim max flow files: 100
content repository archive enabled: false
content repository archive max retention period: 12 hours
content repository archive max usage percentage: 50%
always sync: false
Provenance Repository:
provenance rollover time: 1 min
implementation: org.apache.nifi.provenance.WriteAheadProvenanceRepository
provenance index shard size: 500 MB
provenance max storage size: 1 GB
provenance max storage time: 24 hours
provenance buffer size: 10000
Component Status Repository:
buffer size: 1440
snapshot frequency: 1 min
Security Properties:
keystore: ""
keystore type: ""
keystore password: ""
key password: ""
truststore: ""
truststore type: ""
truststore password: ""
ssl protocol: ""
Sensitive Props:
key: ~
algorithm: NIFI_PBKDF2_AES_GCM_256
Processors:
- id: 5f69344a-15e6-43ba-911c-7e9dd2595d1c
name: GenerateFlowFile
class: org.apache.nifi.minifi.processors.GenerateFlowFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 10s
penalization period: 30000 ms
yield period: 1000 ms
run duration nanos: 0
auto-terminated relationships list: []
Properties:
Batch Size: 1
Data Format: Text
File Size: 100 B
Unique FlowFiles: true
- id: f5f77e5d-4df2-4762-8ecc-d0dc07e36921
name: InvokeHTTP
class: org.apache.nifi.minifi.processors.InvokeHTTP
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1000 ms
penalization period: 30000 ms
yield period: 1000 ms
run duration nanos: 0
auto-terminated relationships list:
- success
- response
- failure
- retry
- no retry
Properties:
Always Output Response: false
Connection Timeout: 5 s
Content-type: application/octet-stream
Disable Peer Verification: false
Follow Redirects: true
HTTP Method: POST
Include Date Header: true
Invalid HTTP Header Field Handling Strategy: transform
Penalize on "No Retry": false
Proxy Host: myproxy.com
Proxy Port: 8080
Read Timeout: 15 s
Remote URL: https://myremoteserver.com
SSL Context Service: a00f8722-2419-44ee-929c-ad68644ad557
Send Message Body: true
Use Chunked Encoding: false
invokehttp-proxy-password: enc{...}
invokehttp-proxy-username: user
send-message-body: true
Controller Services:
- id: a00f8722-2419-44ee-929c-ad68644ad557
name: SSLContextService
type: org.apache.nifi.minifi.controllers.SSLContextService
Properties:
CA Certificate: ~
Client Certificate: ~
Passphrase: enc{...}
Private Key: /opt/secrets/private-key.pem
Use System Cert Store: true
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections:
- id: 361bf7a6-e63d-4967-95f5-7bbeec3175bc
name: GenerateFlowFile/success/InvokeHTTP
source id: 5f69344a-15e6-43ba-911c-7e9dd2595d1c
source relationship names:
- success
destination id: f5f77e5d-4df2-4762-8ecc-d0dc07e36921
max work queue size: 2000
max work queue data size: 100 MB
flowfile expiration: 0 seconds
queue prioritizer class: ""
Remote Process Groups: []
NiFi Properties Overrides: {}
)";
} // namespace
TEST_CASE("Test serialization", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
std::unique_ptr<core::ProcessGroup> root_flow_definition = yaml_config.getRootFromPayload(std::string{TEST_FLOW_WITH_SENSITIVE_PROPERTIES});
REQUIRE(root_flow_definition);
const std::string serialized_flow_definition = yaml_config.serialize(*root_flow_definition);
// we can't directly compare the encrypted values, because they contain a random nonce
const std::string serialized_flow_definition_masked = std::regex_replace(serialized_flow_definition, std::regex{"enc\\{.*\\}"}, "enc{...}");
CHECK(serialized_flow_definition_masked == TEST_FLOW_WITH_SENSITIVE_PROPERTIES_ENCRYPTED);
}
TEST_CASE("Yaml configuration can use parameter contexts", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: lookup.frequency
description: ''
sensitive: false
value: 12 min
- name: batch_size
description: ''
sensitive: false
value: 12
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Batch Size: "#{batch_size}"
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
tail-mode: Single file
Lookup frequency: "#{lookup.frequency}"
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
NiFi Properties Overrides: {}
)";
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("TailFile");
REQUIRE(proc);
REQUIRE(proc->getProperty("Batch Size") == "12");
REQUIRE(proc->getProperty("Lookup frequency") == "12 min");
}
TEST_CASE("Yaml config should not replace parameter from different parameter context", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: lookup.frequency
description: ''
sensitive: false
value: 12 min
- id: 123e10b7-8e00-3188-9a27-476cca376978
name: other-context
description: my other context
Parameters:
- name: batch_size
description: ''
sensitive: false
value: 1
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Batch Size: "#{batch_size}"
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
tail-mode: Single file
Lookup frequency: "#{lookup.frequency}"
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
NiFi Properties Overrides: {}
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter Operation: Parameter 'batch_size' not found");
}
TEST_CASE("Cannot use the same parameter context name twice", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: lookup.frequency
description: ''
sensitive: false
value: 12 min
- id: 123e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: batch_size
description: ''
sensitive: false
value: 1
Processors: []
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
NiFi Properties Overrides: {}
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter context name 'my-context' already exists, parameter context names must be unique!");
}
TEST_CASE("Cannot use the same parameter name within a parameter context twice", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: lookup.frequency
description: ''
sensitive: false
value: 12 min
- name: lookup.frequency
description: ''
sensitive: false
value: 1 min
Processors: []
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
NiFi Properties Overrides: {}
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML),
"Parameter Operation: Parameter name 'lookup.frequency' already exists, parameter names must be unique within a parameter context!");
}
TEST_CASE("Cannot use non-sensitive parameter in sensitive property", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: my_value
description: ''
sensitive: false
value: value1
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: simple
Sensitive Property: "#{my_value}"
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
NiFi Properties Overrides: {}
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter Operation: Non-sensitive parameter 'my_value' cannot be referenced in a sensitive property");
}
TEST_CASE("Cannot use non-sensitive parameter in sensitive property value sequence", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: my_value
description: ''
sensitive: false
value: value1
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: simple
Sensitive Property:
- value: first value
- value: "#{my_value}"
Controller Services: []
Process Groups: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
NiFi Properties Overrides: {}
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter Operation: Non-sensitive parameter 'my_value' cannot be referenced in a sensitive property");
}
TEST_CASE("Parameters can be used in nested process groups", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: lookup.frequency
description: ''
sensitive: false
value: 12 min
- id: 123e10b7-8e00-3188-9a27-476cca376456
name: sub-context
description: my sub context
Parameters:
- name: batch_size
description: ''
sensitive: false
value: 12
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Batch Size: 1
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
tail-mode: Single file
Lookup frequency: "#{lookup.frequency}"
Controller Services: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
Process Groups:
- id: 2a3aaf32-8574-4fa7-b720-84001f8dde43
name: Sub process group
Processors:
- id: 12304f28-0158-1000-0000-000000000000
name: SubTailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Batch Size: "#{batch_size}"
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
tail-mode: Single file
Lookup frequency: 1 sec
Parameter Context Name: sub-context
)";
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("TailFile");
REQUIRE(proc);
CHECK(proc->getProperty("Batch Size") == "1");
CHECK(proc->getProperty("Lookup frequency") == "12 min");
auto* subproc = flow->findProcessorByName("SubTailFile");
REQUIRE(subproc);
CHECK(subproc->getProperty("Batch Size") == "12");
CHECK(subproc->getProperty("Lookup frequency") == "1 sec");
}
TEST_CASE("Subprocessgroups cannot inherit parameters from parent processgroup", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: lookup.frequency
description: ''
sensitive: false
value: 12 min
- id: 123e10b7-8e00-3188-9a27-476cca376456
name: sub-context
description: my sub context
Parameters:
- name: batch_size
description: ''
sensitive: false
value: 12
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Batch Size: 1
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
tail-mode: Single file
Lookup frequency: "#{lookup.frequency}"
Controller Services: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Parameter Context Name: my-context
Process Groups:
- id: 2a3aaf32-8574-4fa7-b720-84001f8dde43
name: Sub process group
Processors:
- id: 12304f28-0158-1000-0000-000000000000
name: SubTailFile
class: org.apache.nifi.processors.standard.TailFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Batch Size: "#{batch_size}"
File to Tail: ./logs/minifi-app.log
Initial Start Position: Beginning of File
tail-mode: Single file
Lookup frequency: "#{lookup.frequency}"
Parameter Context Name: sub-context
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter Operation: Parameter 'lookup.frequency' not found");
}
TEST_CASE("Cannot use parameters if no parameter context is defined", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{my_value}"
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter Operation: Property references a parameter in its value, but no parameter context was provided.");
}
TEST_CASE("Cannot use parameters in property value sequences if no parameter context is defined", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: TailFile
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property:
- value: "#{first_value}"
- value: "#{second_value}"
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter Operation: Property references a parameter in its value, but no parameter context was provided.");
}
TEST_CASE("Property value sequences can use parameters", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flow
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: first_value
description: ''
sensitive: false
value: value1
- name: second_value
description: ''
sensitive: false
value: value2
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property:
- value: "#{first_value}"
- value: "#{second_value}"
Parameter Context Name: my-context
)";
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
auto values = proc->getAllPropertyValues("Simple Property");
REQUIRE(values);
REQUIRE(values->size() == 2);
CHECK((*values)[0] == "value1");
CHECK((*values)[1] == "value2");
}
TEST_CASE("Dynamic properties can use parameters", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flow
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: first_value
description: ''
sensitive: false
value: value1
- name: second_value
description: ''
sensitive: false
value: value2
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
My Dynamic Property Sequence:
- value: "#{first_value}"
- value: "#{second_value}"
My Dynamic Property: "#{first_value}"
Parameter Context Name: my-context
)";
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
core::Property property("My Dynamic Property Sequence", "");
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
auto values = proc->getAllDynamicPropertyValues("My Dynamic Property Sequence");
REQUIRE(values);
REQUIRE(values->size() == 2);
CHECK((*values)[0] == "value1");
CHECK((*values)[1] == "value2");
REQUIRE(proc->getDynamicProperty("My Dynamic Property") == "value1");
}
TEST_CASE("Test sensitive parameters in sensitive properties", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value = minifi::utils::crypto::property_encryption::encrypt("value1", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value = minifi::utils::crypto::property_encryption::encrypt("#{my_value}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: my_value
description: ''
sensitive: true
value: {encrypted_parameter_value}
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: simple
Sensitive Property: {encrypted_sensitive_property_value}
Parameter Context Name: my-context
)", fmt::arg("encrypted_parameter_value", encrypted_parameter_value), fmt::arg("encrypted_sensitive_property_value", encrypted_sensitive_property_value));
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
REQUIRE(proc->getProperty("Simple Property") == "simple");
REQUIRE(proc->getProperty("Sensitive Property") == "value1");
}
TEST_CASE("Test sensitive parameters in sensitive property value sequence", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value_1 = minifi::utils::crypto::property_encryption::encrypt("value1", *context.sensitive_values_encryptor);
auto encrypted_parameter_value_2 = minifi::utils::crypto::property_encryption::encrypt("value2", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value_1 = minifi::utils::crypto::property_encryption::encrypt("#{my_value_1}", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value_2 = minifi::utils::crypto::property_encryption::encrypt("#{my_value_2}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: my_value_1
description: ''
sensitive: true
value: {encrypted_parameter_value_1}
- name: my_value_2
description: ''
sensitive: true
value: {encrypted_parameter_value_2}
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: simple
Sensitive Property:
- value: {encrypted_sensitive_property_value_1}
- value: {encrypted_sensitive_property_value_2}
Parameter Context Name: my-context
)", fmt::arg("encrypted_parameter_value_1", encrypted_parameter_value_1), fmt::arg("encrypted_parameter_value_2", encrypted_parameter_value_2),
fmt::arg("encrypted_sensitive_property_value_1", encrypted_sensitive_property_value_1), fmt::arg("encrypted_sensitive_property_value_2", encrypted_sensitive_property_value_2));
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
auto values = proc->getAllPropertyValues("Sensitive Property");
REQUIRE(values);
REQUIRE(values->size() == 2);
CHECK((*values)[0] == "value1");
CHECK((*values)[1] == "value2");
}
TEST_CASE("Test parameters in controller services", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value_1 = minifi::utils::crypto::property_encryption::encrypt("secret1!!1!", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value_1 = minifi::utils::crypto::property_encryption::encrypt("#{my_value_1}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: my_value_1
description: ''
sensitive: true
value: {encrypted_parameter_value_1}
- name: my_value_2
description: ''
sensitive: false
value: /opt/secrets/private-key.pem
Processors: []
Controller Services:
- id: a00f8722-2419-44ee-929c-ad68644ad557
name: SSLContextService
type: org.apache.nifi.minifi.controllers.SSLContextService
Properties:
CA Certificate:
Client Certificate:
Passphrase: {encrypted_sensitive_property_value_1}
Private Key: "#{{my_value_2}}"
Use System Cert Store: 'true'
Parameter Context Name: my-context
)", fmt::arg("encrypted_parameter_value_1", encrypted_parameter_value_1), fmt::arg("encrypted_sensitive_property_value_1", encrypted_sensitive_property_value_1));
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* controller = flow->findControllerService("SSLContextService");
REQUIRE(controller);
auto impl = controller->getControllerServiceImplementation();
CHECK(impl->getProperty("Passphrase").value() == "secret1!!1!");
CHECK(impl->getProperty("Private Key").value() == "/opt/secrets/private-key.pem");
}
TEST_CASE("Parameters can be used in controller services in nested process groups", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value_1 = minifi::utils::crypto::property_encryption::encrypt("secret1!!1!", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value_1 = minifi::utils::crypto::property_encryption::encrypt("#{my_value_1}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple TailFile
Parameter Contexts:
- id: 123e10b7-8e00-3188-9a27-476cca376456
name: sub-context
description: my sub context
Parameters:
- name: my_value_1
description: ''
sensitive: true
value: {encrypted_parameter_value_1}
- name: my_value_2
description: ''
sensitive: false
value: /opt/secrets/private-key.pem
Processors: []
Controller Services: []
Input Ports: []
Output Ports: []
Funnels: []
Connections: []
Process Groups:
- id: 2a3aaf32-8574-4fa7-b720-84001f8dde43
name: Sub process group
Processors: []
Controller Services:
- id: a00f8722-2419-44ee-929c-ad68644ad557
name: SSLContextService
type: org.apache.nifi.minifi.controllers.SSLContextService
Properties:
CA Certificate:
Client Certificate:
Passphrase: {encrypted_sensitive_property_value_1}
Private Key: "#{{my_value_2}}"
Use System Cert Store: 'true'
Parameter Context Name: sub-context
)", fmt::arg("encrypted_parameter_value_1", encrypted_parameter_value_1), fmt::arg("encrypted_sensitive_property_value_1", encrypted_sensitive_property_value_1));
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* controller = flow->findControllerService("SSLContextService", core::ProcessGroup::Traverse::IncludeChildren);
REQUIRE(controller);
auto impl = controller->getControllerServiceImplementation();
REQUIRE(impl);
CHECK(impl->getProperty("Passphrase").value() == "secret1!!1!");
CHECK(impl->getProperty("Private Key").value() == "/opt/secrets/private-key.pem");
}
TEST_CASE("Test parameter context inheritance", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_parameter_value = minifi::utils::crypto::property_encryption::encrypt("value1", *context.sensitive_values_encryptor);
auto encrypted_sensitive_property_value = minifi::utils::crypto::property_encryption::encrypt("#{my_new_parameter}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: inherited-context
description: my parameter context
Parameters:
- name: my_new_parameter
description: inherited parameter context
sensitive: true
value: {}
Inherited Parameter Contexts: [base-context]
- id: 521e10b7-8e00-3188-9a27-476cca376351
name: base-context
description: my base parameter context
Parameters:
- name: my_old_parameter
description: ''
sensitive: false
value: old_value
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{{my_old_parameter}}"
Sensitive Property: {}
Parameter Context Name: inherited-context
)", encrypted_parameter_value, encrypted_sensitive_property_value);
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
REQUIRE(proc->getProperty("Simple Property") == "old_value");
REQUIRE(proc->getProperty("Sensitive Property") == "value1");
}
TEST_CASE("Parameter context can not inherit from a itself", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 521e10b7-8e00-3188-9a27-476cca376351
name: base-context
description: my base parameter context
Parameters:
- name: my_old_parameter
description: ''
sensitive: false
value: old_value
Inherited Parameter Contexts:
- base-context
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{my_old_parameter}"
Parameter Context Name: inherited-context
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Inherited parameter context 'base-context' cannot be the same as the parameter context!");
}
TEST_CASE("Parameter context can not inherit from non-existing parameter context", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 521e10b7-8e00-3188-9a27-476cca376351
name: base-context
description: my base parameter context
Parameters:
- name: my_old_parameter
description: ''
sensitive: false
value: old_value
Inherited Parameter Contexts: [unknown]
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{my_old_parameter}"
Parameter Context Name: inherited-context
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Inherited parameter context 'unknown' does not exist!");
}
TEST_CASE("Cycles are not allowed in parameter context inheritance", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 123e10b7-8e00-3188-9a27-476cca376351
name: a-context
description: ''
Parameters:
- name: a_parameter
description: ''
sensitive: false
value: a_value
Inherited Parameter Contexts:
- c-context
- id: 456e10b7-8e00-3188-9a27-476cca376351
name: b-context
description: ''
Parameters:
- name: b_parameter
description: ''
sensitive: false
value: b_value
Inherited Parameter Contexts:
- a-context
- id: 789e10b7-8e00-3188-9a27-476cca376351
name: c-context
description: ''
Parameters:
- name: c_parameter
description: ''
sensitive: false
value: c_value
Inherited Parameter Contexts:
- d-context
- b-context
- id: 101e10b7-8e00-3188-9a27-476cca376351
name: d-context
description: ''
Parameters:
- name: d_parameter
description: ''
sensitive: false
value: d_value
Inherited Parameter Contexts: []
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{{my_old_parameter}}"
Sensitive Property: {}
Parameter Context Name: inherited-context
)";
REQUIRE_THROWS_AS(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), std::invalid_argument);
REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Circular references in Parameter Context inheritance are not allowed. Inheritance cycle was detected in parameter context"));
}
TEST_CASE("Parameter context inheritance order is respected", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: a-context
description: ''
Parameters:
- name: a_parameter
description: ''
sensitive: false
value: 1
- name: b_parameter
description: ''
sensitive: false
value: 2
- id: 521e10b7-8e00-3188-9a27-476cca376351
name: b-context
description: ''
Parameters:
- name: b_parameter
description: ''
sensitive: false
value: 3
- name: c_parameter
description: ''
sensitive: false
value: 4
- id: 123e10b7-8e00-3188-9a27-476cca376351
name: c-context
description: ''
Parameters:
- name: c_parameter
description: ''
sensitive: false
value: 5
Inherited Parameter Contexts:
- b-context
- a-context
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
My A Property: "#{a_parameter}"
My B Property: "#{b_parameter}"
My C Property: "#{c_parameter}"
Parameter Context Name: c-context
)";
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
REQUIRE("1" == proc->getDynamicProperty("My A Property"));
REQUIRE("3" == proc->getDynamicProperty("My B Property"));
REQUIRE("5" == proc->getDynamicProperty("My C Property"));
}
TEST_CASE("Parameter providers can be used for parameter values", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flow
Parameter Providers:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: DummyParameterProvider
type: DummyParameterProvider
Properties:
Dummy1 Value: value1
Dummy2 Value: value2
Dummy3 Value: value3
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{dummy1}"
My Dynamic Property Sequence:
- value: "#{dummy2}"
- value: "#{dummy3}"
Parameter Context Name: dummycontext
)";
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
auto values = proc->getAllDynamicPropertyValues("My Dynamic Property Sequence");
CHECK((*values)[0] == "value2");
CHECK((*values)[1] == "value3");
}
TEST_CASE("Parameter providers can be configured to select which parameters to be sensitive", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_sensitive_property_value = minifi::utils::crypto::property_encryption::encrypt("#{dummy1}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Providers:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: DummyParameterProvider
type: DummyParameterProvider
Properties:
Sensitive Parameter Scope: selected
Sensitive Parameter List: dummy1
Dummy1 Value: value1
Dummy3 Value: value3
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{{dummy3}}"
Sensitive Property: {}
Parameter Context Name: dummycontext
)", encrypted_sensitive_property_value);
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
REQUIRE(proc->getProperty("Sensitive Property") == "value1");
REQUIRE(proc->getProperty("Simple Property") == "value3");
}
TEST_CASE("If sensitive parameter scope is set to selected sensitive parameter list is required", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_sensitive_property_value = minifi::utils::crypto::property_encryption::encrypt("#{dummy1}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Providers:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: DummyParameterProvider
type: DummyParameterProvider
Properties:
Sensitive Parameter Scope: selected
Sensitive Parameter List:
Dummy1 Value: value1
Dummy3 Value: value3
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{{dummy3}}"
Sensitive Property: {}
Parameter Context Name: dummycontext
)", encrypted_sensitive_property_value);
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter Operation: Sensitive Parameter Scope is set to 'selected' but Sensitive Parameter List is empty");
}
TEST_CASE("Parameter providers can be configured to make all parameters sensitive", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
auto context = test_controller.getContext();
auto encrypted_sensitive_property_value = minifi::utils::crypto::property_encryption::encrypt("#{dummy1}", *context.sensitive_values_encryptor);
core::YamlConfiguration yaml_config(context);
static const std::string TEST_CONFIG_YAML =
fmt::format(R"(
MiNiFi Config Version: 3
Flow Controller:
name: flowconfig
Parameter Providers:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: DummyParameterProvider
type: DummyParameterProvider
Properties:
Sensitive Parameter Scope: all
Dummy1 Value: value1
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Sensitive Property: {}
Parameter Context Name: dummycontext
)", encrypted_sensitive_property_value);
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
REQUIRE(proc->getProperty("Sensitive Property") == "value1");
}
TEST_CASE("Parameter context can be inherited from parameter provider generated parameter context", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flow
Parameter Providers:
- id: d26ee5f5-0192-1000-0482-4e333725e089
name: DummyParameterProvider
type: DummyParameterProvider
Properties:
Dummy1 Value: value1
Dummy2 Value: value2
Dummy3 Value: value3
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: my-context
description: my parameter context
Parameters:
- name: file_size
description: ''
sensitive: false
value: 10 B
Inherited Parameter Contexts: [dummycontext]
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{dummy1}"
Parameter Context Name: my-context
)";
std::unique_ptr<core::ProcessGroup> flow = yaml_config.getRootFromPayload(TEST_CONFIG_YAML);
REQUIRE(flow);
auto* proc = flow->findProcessorByName("DummyProcessor");
REQUIRE(proc);
REQUIRE(proc->getProperty("Simple Property") == "value1");
}
TEST_CASE("Parameter context names cannot conflict with parameter provider generated parameter context names", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yaml_config(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: flow
Parameter Providers:
- id: d26ee5f5-0192-1000-0482-4e333725e089
name: DummyParameterProvider
type: DummyParameterProvider
Properties:
Dummy1 Value: value1
Dummy2 Value: value2
Dummy3 Value: value3
Parameter Contexts:
- id: 721e10b7-8e00-3188-9a27-476cca376978
name: dummycontext
description: my parameter context
Parameters:
- name: file_size
description: ''
sensitive: false
value: 10 B
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: DummyProcessor
class: org.apache.nifi.processors.DummyProcessor
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 1 sec
auto-terminated relationships list: [success]
Properties:
Simple Property: "#{dummy1}"
Parameter Context Name: dummycontext
)";
REQUIRE_THROWS_WITH(yaml_config.getRootFromPayload(TEST_CONFIG_YAML), "Parameter provider 'DummyParameterProvider' cannot create parameter context 'dummycontext' because parameter context already "
"exists with no parameter provider or generated by other parameter provider");
}
TEST_CASE("Cannot use invalid property values") {
ConfigurationTestController test_controller;
core::flow::AdaptiveConfiguration config(test_controller.getContext());
auto [file_size_property_str, throws] = GENERATE(
std::make_tuple(R"(12 dogBytes)", true),
std::make_tuple(R"(1 kB)", false),
std::make_tuple(R"(
- value: 1 kB
- value: 2 MB)", false),
std::make_tuple(R"(foo)", true),
std::make_tuple(R"(
- value: 1 kB
- value: bar KB)", true));
const std::string CONFIG_YAML = fmt::format(
R"(
MiNiFi Config Version: 3
Flow Controller:
name: root
comment: ''
Processors:
- id: 0eac51eb-d76c-4ba6-9f0c-351795b2d243
name: GenerateFlowFile1
class: org.apache.nifi.minifi.processors.GenerateFlowFile
max concurrent tasks: 1
scheduling strategy: TIMER_DRIVEN
scheduling period: 10000 ms
Properties:
File Size: {}
)", file_size_property_str);
if (throws) {
REQUIRE_THROWS_WITH(config.getRootFromPayload(CONFIG_YAML), "Unable to parse configuration file for component named 'GenerateFlowFile1' because ValidationFailed");
} else {
REQUIRE_NOTHROW(config.getRootFromPayload(CONFIG_YAML));
}
}
TEST_CASE("Output port can also be used in RPG", "[YamlConfiguration]") {
ConfigurationTestController test_controller;
core::YamlConfiguration yamlConfig(test_controller.getContext());
static const std::string TEST_CONFIG_YAML =
R"(
MiNiFi Config Version: 3
Flow Controller:
name: Simple RPG To PutFile
comment: ''
Processors:
- id: b0c04f28-0158-1000-0000-000000000000
name: PutFile
class: org.apache.nifi.processors.standard.PutFile
max concurrent tasks: 1
scheduling strategy: EVENT_DRIVEN
auto-terminated relationships list: []
Properties: []
Connections:
- id: b0c0c3cc-0158-1000-0000-000000000000
name: ac0e798c-0158-1000-0588-cda9b944e011/success/PutFile
source id: ac0e798c-0158-1000-0588-cda9b944e011
destination id: b0c04f28-0158-1000-0000-000000000000
Remote Process Groups:
- id: b0c09ff0-0158-1000-0000-000000000000
name: ''
url: http://localhost:8080/nifi
comment: ''
timeout: 20 sec
yield period: 10 sec
transport protocol: RAW
Output Ports:
- id: ac0e798c-0158-1000-0588-cda9b944e011
name: AmazingOutputPort
max concurrent tasks: 1
use compression: true
batch size:
size: 10 B
count: 3
duration: 5 sec
Input Ports: []
NiFi Properties Overrides: {}
)";
std::unique_ptr<core::ProcessGroup> rootFlowConfig = yamlConfig.getRootFromPayload(TEST_CONFIG_YAML);
TypedProcessorWrapper<minifi::RemoteProcessGroupPort> port = rootFlowConfig->findProcessorByName("AmazingOutputPort");
REQUIRE(port);
CHECK(port->getUUIDStr() == "ac0e798c-0158-1000-0588-cda9b944e011");
CHECK(port.get().getUseCompression() == true);
CHECK(port.get().getBatchSize().value() == 10);
CHECK(port.get().getBatchCount().value() == 3);
CHECK(port.get().getBatchDuration().value() == std::chrono::seconds(5));
CHECK(port.get().getTimeout().value() == std::chrono::seconds(20));
}
} // namespace org::apache::nifi::minifi::test