Skip to content

Commit c608dda

Browse files
committed
Fix bug where -container-settings.num-containers
was not being respected. Fix undefined python behavior where during filtering of detections, we were deleting items from the list while iterating over it.
1 parent 8829168 commit c608dda

File tree

3 files changed

+28
-21
lines changed

3 files changed

+28
-21
lines changed

contentctl/actions/test.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,29 +43,32 @@ class TestInputDto:
4343
config: test_common
4444

4545

46-
class TestOutputDto:
47-
results: list
48-
49-
5046
class Test:
5147

52-
def filter_detections(self, input_dto: TestInputDto):
48+
def filter_detections(self, input_dto: TestInputDto)->TestInputDto:
49+
5350
if not input_dto.config.enable_integration_testing:
5451
#Skip all integraiton tests if integration testing is not enabled:
5552
for detection in input_dto.detections:
5653
for test in detection.tests:
5754
if isinstance(test, IntegrationTest):
5855
test.skip("TEST SKIPPED: Skipping all integration tests")
5956

57+
list_after_filtering:List[Detection] = []
6058
#extra filtering which may be removed/modified in the future
6159
for detection in input_dto.detections:
6260
if (detection.status != DetectionStatus.production.value):
6361
#print(f"{detection.name} - Not testing because [STATUS: {detection.status}]")
64-
input_dto.detections.remove(detection)
62+
pass
6563
elif detection.type == AnalyticsType.Correlation:
6664
#print(f"{detection.name} - Not testing because [ TYPE: {detection.type}]")
67-
input_dto.detections.remove(detection)
68-
65+
pass
66+
else:
67+
list_after_filtering.append(detection)
68+
69+
return TestInputDto(list_after_filtering, input_dto.config)
70+
71+
6972
def execute(self, input_dto: TestInputDto) -> bool:
7073

7174

contentctl/contentctl.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,14 @@ def test_common_func(config:test_common):
114114

115115
# Remove detections that we do not want to test because they are
116116
# not production, the correct type, or manual_test only
117-
t.filter_detections(test_input_dto)
117+
filted_test_input_dto = t.filter_detections(test_input_dto)
118118

119119
if config.plan_only:
120120
#Emit the test plan and quit. Do not actually run the test
121-
config.dumpCICDPlanAndQuit(gitServer.getHash(),test_input_dto.detections)
121+
config.dumpCICDPlanAndQuit(gitServer.getHash(),filted_test_input_dto.detections)
122122
return
123123

124-
success = t.execute(test_input_dto)
124+
success = t.execute(filted_test_input_dto)
125125

126126
if success:
127127
#Everything passed!
@@ -212,6 +212,10 @@ def main():
212212
elif type(config) == deploy_rest:
213213
deploy_rest_func(config)
214214
elif type(config) == test or type(config) == test_servers:
215+
if type(config) == test:
216+
#construct the container Infrastructure objects
217+
config.getContainerInfrastructureObjects()
218+
#otherwise, they have already been passed as servers
215219
test_common_func(config)
216220
else:
217221
raise Exception(f"Unknown command line type '{type(config).__name__}'")

contentctl/objects/config.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -689,17 +689,13 @@ class test(test_common):
689689
splunk_api_password: Optional[str] = Field(default=None, exclude = True, description="Splunk API password used for running appinspect or installaing apps from Splunkbase")
690690

691691

692-
@model_validator(mode='after')
693-
def get_test_instances(self)->Self:
694-
695-
if len(self.test_instances) > 0:
696-
return self
692+
def getContainerInfrastructureObjects(self)->Self:
697693
try:
698694
self.test_instances = self.container_settings.getContainers()
699695
return self
700696

701697
except Exception as e:
702-
raise ValueError(f"Error constructing test_instances: {str(e)}")
698+
raise ValueError(f"Error constructing container test_instances: {str(e)}")
703699

704700

705701

@@ -748,20 +744,24 @@ def getAppFilePath(self):
748744
return self.path / "apps.yml"
749745

750746

751-
747+
TEST_ARGS_ENV = "CONTENTCTL_TEST_INFRASTRUCTURES"
752748
class test_servers(test_common):
753749
model_config = ConfigDict(use_enum_values=True,validate_default=True, arbitrary_types_allowed=True)
754750
test_instances:List[Infrastructure] = Field([],description="Test against one or more preconfigured servers.", validate_default=True)
755-
server_info:Optional[str] = Field(None, validate_default=True)
756-
751+
server_info:Optional[str] = Field(None, validate_default=True, description='String of pre-configured servers to use for testing. The list MUST be in the format:\n'
752+
'address,username,web_ui_port,hec_port,api_port;address_2,username_2,web_ui_port_2,hec_port_2,api_port_2'
753+
'\nFor example, the following string will use 2 preconfigured test instances:\n'
754+
'127.0.0.1,firstUser,firstUserPassword,8000,8088,8089;1.2.3.4,secondUser,secondUserPassword,8000,8088,8089\n'
755+
'Note that these test_instances may be hosted on the same system, such as localhost/127.0.0.1 or a docker server, or different hosts.\n'
756+
f'This value may also be passed by setting the environment variable [{TEST_ARGS_ENV}] with the value above.')
757757

758758
@model_validator(mode='before')
759759
@classmethod
760760
def parse_config(cls, data:Any, info: ValidationInfo)->Any:
761761
#Ignore whatever is in the file or defaults, these must be supplied on command line
762762
#if len(v) != 0:
763763
# return v
764-
TEST_ARGS_ENV = "CONTENTCTL_TEST_INFRASTRUCTURES"
764+
765765

766766
if isinstance(data.get("server_info"),str) :
767767
server_info = data.get("server_info")

0 commit comments

Comments
 (0)