Skip to content

Commit 6efda2d

Browse files
committed
Add testcases
Signed-off-by: Divya Madala <divyaasm@amazon.com>
1 parent 097a50d commit 6efda2d

8 files changed

+471
-71
lines changed

src/validation_workflow/deb/validation_deb.py

-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import logging
99
import os
10-
import time
1110

1211
from system.execute import execute
1312
from test_workflow.integ_test.utils import get_password
@@ -27,7 +26,6 @@ def installation(self) -> bool:
2726
set_password = f' env OPENSEARCH_INITIAL_ADMIN_PASSWORD={get_password(str(self.args.version))}' if project == "opensearch" else ""
2827
execute(f'sudo dpkg --purge {project}', ".")
2928
execute(f'sudo {set_password} dpkg -i {os.path.basename(self.args.file_path.get(project))}', str(self.tmp_dir.path))
30-
time.sleep(80)
3129
except:
3230
raise Exception("Failed to install OpenSearch/OpenSearch-Dashboards")
3331
return True

tests/tests_validation_workflow/test_validation_args.py

+24
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,20 @@ def test_dashboards_exception(self) -> None:
8181
self.assertEqual(ValidationArgs().distribution, "rpm")
8282
self.assertEqual(str(ctx.exception), "Missing OpenSearch artifact details! Please provide the valid product names among opensearch and opensearch-dashboards")
8383

84+
@patch("argparse._sys.argv", [VALIDATION_PY, "--version", "2.4.0", "--distribution", "docker", "--os-build-number", "1234", "--osd-build-number", "8393", "--projects", "opensearch", "--using-staging-artifact-only"]) # noqa: E501
85+
def test_docker_exception(self) -> None:
86+
with self.assertRaises(Exception) as ctx:
87+
self.assertEqual(ValidationArgs().projects, ["opensearch"])
88+
self.assertEqual(ValidationArgs().osd_build_number, "1234")
89+
self.assertEqual(str(ctx.exception), "Provide opensearch-dashboards in projects argument to validate OpenSearch-Dashboards")
90+
91+
@patch("argparse._sys.argv", [VALIDATION_PY, "--version", "2.4.0", "--distribution", "docker", "--os-build-number", "1234", "--projects", "opensearch"])
92+
def test_docker_arguments_exception(self) -> None:
93+
with self.assertRaises(Exception) as ctx:
94+
self.assertEqual(ValidationArgs().projects, ["opensearch"])
95+
self.assertEqual(ValidationArgs().osd_build_number, "1234")
96+
self.assertEqual(str(ctx.exception), "Provide either of --validate-digest-only and --using-staging-artifact-only for Docker Validation")
97+
8498
@patch("argparse._sys.argv", [VALIDATION_PY, "--file-path", "opensearch-dashboards=https://opensearch.org/releases/opensearch/2.8.0/opensearch-dashboards-2.8.0-linux-x64.rpm"])
8599
def test_projects_exception(self) -> None:
86100
with self.assertRaises(Exception) as ctx:
@@ -103,3 +117,13 @@ def test_get_distribution_type_tar(self) -> None:
103117
def test_get_distribution_type_yum(self) -> None:
104118
result = ValidationArgs().get_distribution_type(ValidationArgs().file_path)
105119
self.assertEqual(result, "yum")
120+
121+
@patch("argparse._sys.argv", [VALIDATION_PY, "--file-path", "opensearch=https://opensearch.org/releases/opensearch/2.8.0/opensearch--2.8.0-windows-x64.zip"])
122+
def test_get_distribution_type_zip(self) -> None:
123+
result = ValidationArgs().get_distribution_type(ValidationArgs().file_path)
124+
self.assertEqual(result, "zip")
125+
126+
@patch("argparse._sys.argv", [VALIDATION_PY, "--file-path", "opensearch=https://opensearch.org/releases/opensearch/2.8.0/opensearch-2.8.0-linux-arm64.deb"])
127+
def test_get_distribution_type_deb(self) -> None:
128+
result = ValidationArgs().get_distribution_type(ValidationArgs().file_path)
129+
self.assertEqual(result, "deb")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Copyright OpenSearch Contributors
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# The OpenSearch Contributors require contributions made to
5+
# this file be licensed under the Apache-2.0 license or a
6+
# compatible open source license.
7+
8+
import unittest
9+
from unittest.mock import MagicMock, Mock, call, patch
10+
11+
from validation_workflow.deb.validation_deb import ValidateDeb
12+
13+
14+
class TestValidateDeb(unittest.TestCase):
15+
def setUp(self) -> None:
16+
self.mock_args = MagicMock()
17+
self.mock_args.version = "2.3.0"
18+
self.mock_args.arch = "x64"
19+
self.mock_args.projects = ["opensearch"]
20+
self.mock_args.file_path = {"opensearch": "/src/opensearch/opensearch-1.3.12.staging.deb"}
21+
self.mock_args.platform = "linux"
22+
self.mock_args.force_https_check = True
23+
self.mock_args.force_https = True
24+
self.call_methods = ValidateDeb(self.mock_args)
25+
26+
@patch("validation_workflow.deb.validation_deb.execute")
27+
@patch('os.path.basename')
28+
@patch("validation_workflow.deb.validation_deb.get_password")
29+
def test_installation(self, mock_get_pwd: Mock, mock_basename: Mock, mock_system: Mock) -> None:
30+
validate_deb = ValidateDeb(self.mock_args)
31+
mock_basename.side_effect = lambda path: "mocked_filename"
32+
mock_system.side_effect = lambda *args, **kwargs: (0, "stdout_output", "stderr_output")
33+
result = validate_deb.installation()
34+
self.assertTrue(result)
35+
mock_get_pwd.assert_called_with("2.3.0")
36+
37+
@patch("validation_workflow.deb.validation_deb.execute")
38+
@patch("validation_workflow.deb.validation_deb.get_password")
39+
def test_installation_exception_os(self, mock_get_pwd: Mock, mock_execute: Mock) -> None:
40+
validate_deb = ValidateDeb(self.mock_args)
41+
mock_execute.side_effect = Exception("any exception occurred")
42+
with self.assertRaises(Exception) as context:
43+
validate_deb.installation()
44+
45+
mock_get_pwd.assert_called_with("2.3.0")
46+
self.assertEqual(str(context.exception), "Failed to install OpenSearch/OpenSearch-Dashboards")
47+
48+
@patch("validation_workflow.deb.validation_deb.execute", return_value=True)
49+
@patch('validation_workflow.deb.validation_deb.ValidationArgs')
50+
def test_start_cluster(self, mock_validation_args: Mock, mock_system: Mock) -> None:
51+
mock_validation_args.return_value.projects.return_value = ["opensearch", "opensearch-dashboards"]
52+
53+
validate_deb = ValidateDeb(mock_validation_args.return_value)
54+
55+
result = validate_deb.start_cluster()
56+
self.assertTrue(result)
57+
58+
@patch("validation_workflow.deb.validation_deb.execute")
59+
def test_start_cluster_exception_os(self, mock_execute: MagicMock) -> None:
60+
validate_deb = ValidateDeb(self.mock_args)
61+
mock_execute.side_effect = Exception("any exception occurred")
62+
with self.assertRaises(Exception) as context:
63+
validate_deb.start_cluster()
64+
65+
self.assertEqual(str(context.exception), "Failed to Start Cluster")
66+
67+
@patch("validation_workflow.deb.validation_deb.ApiTestCases")
68+
@patch('validation_workflow.validation.Validation.check_cluster_readiness')
69+
def test_validation(self, mock_check_cluster: Mock, mock_test_apis: Mock) -> None:
70+
mock_test_apis_instance = mock_test_apis.return_value
71+
mock_check_cluster.return_value = True
72+
mock_test_apis_instance.test_apis.return_value = (True, 3)
73+
74+
validate_deb = ValidateDeb(self.mock_args)
75+
76+
result = validate_deb.validation()
77+
self.assertTrue(result)
78+
79+
mock_test_apis.assert_called_once()
80+
mock_check_cluster.assert_called_once()
81+
82+
@patch('validation_workflow.deb.validation_deb.ApiTestCases')
83+
@patch('os.path.basename')
84+
@patch('validation_workflow.deb.validation_deb.execute')
85+
@patch('validation_workflow.validation.Validation.check_for_security_plugin')
86+
@patch('validation_workflow.validation.Validation.check_cluster_readiness')
87+
@patch('validation_workflow.tar.validation_tar.ValidationArgs')
88+
def test_validation_without_force_https_check(self, mock_validation_args: Mock, mock_check_cluster: Mock, mock_security: Mock, mock_system: Mock,
89+
mock_basename: Mock, mock_test_apis: Mock) -> None:
90+
mock_validation_args.return_value.version = '2.3.0'
91+
mock_validation_args.return_value.force_https = False
92+
validate_deb = ValidateDeb(mock_validation_args.return_value)
93+
mock_check_cluster.return_value = True
94+
mock_basename.side_effect = lambda path: "mocked_filename"
95+
mock_system.side_effect = lambda *args, **kwargs: (0, "stdout_output", "stderr_output")
96+
mock_security.return_value = True
97+
mock_test_apis_instance = mock_test_apis.return_value
98+
mock_test_apis_instance.test_apis.return_value = (True, 4)
99+
100+
result = validate_deb.validation()
101+
self.assertTrue(result)
102+
mock_check_cluster.assert_called_once()
103+
mock_security.assert_called_once()
104+
105+
@patch('validation_workflow.deb.validation_deb.ValidationArgs')
106+
@patch('validation_workflow.validation.Validation.check_cluster_readiness')
107+
def test_cluster_not_ready(self, mock_check_cluster: Mock, mock_validation_args: Mock) -> None:
108+
mock_validation_args.return_value.version = '2.3.0'
109+
validate_deb = ValidateDeb(mock_validation_args.return_value)
110+
mock_check_cluster.return_value = False
111+
112+
with self.assertRaises(Exception) as context:
113+
validate_deb.validation()
114+
self.assertEqual(str(context.exception), 'Cluster is not ready for API test')
115+
mock_check_cluster.assert_called_once()
116+
117+
@patch("validation_workflow.deb.validation_deb.ApiTestCases")
118+
@patch('validation_workflow.validation.Validation.check_cluster_readiness')
119+
def test_failed_testcases(self, mock_check_cluster: Mock, mock_test_apis: Mock) -> None:
120+
mock_test_apis_instance = mock_test_apis.return_value
121+
mock_check_cluster.return_value = True
122+
mock_test_apis_instance.test_apis.return_value = (False, 2)
123+
validate_deb = ValidateDeb(self.mock_args)
124+
125+
with self.assertRaises(Exception) as context:
126+
validate_deb.validation()
127+
128+
self.assertEqual(str(context.exception), "Not all tests Pass : 2")
129+
130+
mock_test_apis.assert_called_once()
131+
132+
@patch("validation_workflow.deb.validation_deb.execute")
133+
def test_cleanup(self, mock_execute: Mock) -> None:
134+
self.mock_args.projects = ["opensearch", "opensearch-dashboards"]
135+
136+
validate_deb = ValidateDeb(self.mock_args)
137+
result = validate_deb.cleanup()
138+
self.assertTrue(result)
139+
mock_execute.assert_has_calls(
140+
[call("sudo dpkg --purge opensearch", "."), call("sudo dpkg --purge opensearch-dashboards", ".")]
141+
)
142+
143+
@patch("validation_workflow.deb.validation_deb.execute")
144+
def test_cleanup_exception(self, mock_execute: Mock) -> None:
145+
self.mock_args.projects = ["opensearch", "opensearch-dashboards"]
146+
mock_execute.side_effect = Exception("an exception occurred")
147+
validate_deb = ValidateDeb(self.mock_args)
148+
with self.assertRaises(Exception) as context:
149+
validate_deb.cleanup()
150+
151+
self.assertEqual(
152+
str(context.exception),
153+
"Exception occurred either while attempting to stop cluster or removing OpenSearch/OpenSearch-Dashboards. an exception occurred",
154+
)

tests/tests_validation_workflow/test_validation_docker.py

+57-39
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# The OpenSearch Contributors require contributions made to
55
# this file be licensed under the Apache-2.0 license or a
66
# compatible open source license.
7-
7+
import shutil
88
import subprocess
99
import unittest
1010
import urllib.request
@@ -43,13 +43,12 @@ def test_download_artifacts(self, mock_is_container_daemon_running: Mock, mock_v
4343
@patch('validation_workflow.docker.validation_docker.ApiTestCases')
4444
@patch('validation_workflow.docker.validation_docker.ValidateDocker.run_container')
4545
@patch('validation_workflow.docker.validation_docker.InspectDockerImage.inspect_digest')
46-
@patch('time.sleep', return_value=None)
47-
def test_staging(self, mock_time_sleep: Mock, mock_digest: Mock, mock_container: Mock, mock_test: Mock, mock_docker_image: Mock, mock_validation_args: Mock, mock_check_http: Mock) -> None:
46+
def test_staging(self, mock_digest: Mock, mock_container: Mock, mock_test: Mock, mock_docker_image: Mock, mock_validation_args: Mock, mock_check_http: Mock) -> None:
4847
# Set up mock objects
4948
mock_validation_args.return_value.OS_image = 'opensearchstaging/opensearch-os'
5049
mock_validation_args.return_value.version = '1.0.0.1000'
5150
mock_validation_args.return_value.validate_digest_only = False
52-
mock_validation_args.return_value.allow_without_security = False
51+
mock_validation_args.return_value.force_https = False
5352
mock_validation_args.return_value.projects = ["opensearch"]
5453
mock_docker_image.return_value = MagicMock()
5554
mock_container.return_value = (True, 'test_file.yml')
@@ -72,14 +71,33 @@ def test_staging(self, mock_time_sleep: Mock, mock_digest: Mock, mock_container:
7271
mock_test.assert_called_once()
7372
mock_test.assert_has_calls([call(), call().test_apis("1.0.0.1000", ['opensearch'], True)])
7473

74+
@patch('validation_workflow.docker.validation_docker.ValidationArgs')
75+
@patch('validation_workflow.docker.validation_docker.ValidateDocker.run_container')
76+
def test_container_startup_exception(self, mock_container: Mock, mock_validation_args: Mock) -> None:
77+
mock_validation_args.return_value.OS_image = 'opensearchstaging/opensearch-os'
78+
mock_validation_args.return_value.version = '1.0.0.1000'
79+
mock_validation_args.return_value.validate_digest_only = False
80+
mock_validation_args.return_value.force_https = False
81+
mock_validation_args.return_value.projects = ["opensearch"]
82+
mock_container.return_value = (False, 'test_file.yml')
83+
84+
# Create instance of ValidateDocker class
85+
validate_docker = ValidateDocker(mock_validation_args.return_value)
86+
validate_docker.image_ids = {'opensearch': 'images_id_0'}
87+
validate_docker.replacements = [('opensearchproject/opensearch:1', 'images_id_0')]
88+
89+
with self.assertRaises(Exception) as context:
90+
validate_docker.validation()
91+
self.assertEqual(str(context.exception), 'The container failed to start. Exiting the validation.')
92+
mock_container.assert_called_once()
93+
7594
@patch('validation_workflow.docker.validation_docker.ValidateDocker.check_http_request')
7695
@patch('validation_workflow.docker.validation_docker.ValidationArgs')
7796
@patch('validation_workflow.docker.validation_docker.InspectDockerImage')
7897
@patch('validation_workflow.docker.validation_docker.ApiTestCases')
7998
@patch('validation_workflow.docker.validation_docker.ValidateDocker.run_container')
8099
@patch('validation_workflow.docker.validation_docker.InspectDockerImage.inspect_digest')
81-
@patch('time.sleep', return_value=None)
82-
def test_digests(self, mock_time_sleep: Mock, mock_digest: Mock, mock_container: Mock, mock_test: Mock, mock_docker_image: Mock, mock_validation_args: Mock, mock_check_http: Mock) -> None:
100+
def test_digests(self, mock_digest: Mock, mock_container: Mock, mock_test: Mock, mock_docker_image: Mock, mock_validation_args: Mock, mock_check_http: Mock) -> None:
83101
# Set up mock objects
84102
mock_validation_args.return_value.OS_image = 'opensearchstaging/opensearch-os'
85103
mock_validation_args.return_value.version = '1.0.0.1000'
@@ -168,46 +186,46 @@ def test_docker_compose_files_exist(self) -> None:
168186
self.assertTrue(urllib.request.urlopen(docker_compose_file_v1_url).getcode() == 200)
169187
self.assertTrue(urllib.request.urlopen(docker_compose_file_v2_url).getcode() == 200)
170188

171-
# @patch('validation_workflow.docker.validation_docker.ValidateDocker.check_http_request')
189+
@patch('validation_workflow.docker.validation_docker.ValidateDocker.check_cluster_readiness')
172190
@patch('validation_workflow.docker.validation_docker.ValidationArgs')
173-
@patch('validation_workflow.docker.validation_docker.ApiTest.api_get')
174-
def test_check_http_request_success(self, mock_api_test: MagicMock, mock_validation_args: MagicMock) -> None:
175-
mock_validation_args.return_value.test_readiness_urls = {
176-
'https://localhost:9200/': 'opensearch cluster API',
177-
'http://localhost:5601/api/status': 'opensearch-dashboards API',
178-
}
179-
mock_validation_args.return_value.version = '1.0.0'
180-
181-
mock_api_test.return_value = (200, "response")
191+
@patch('validation_workflow.docker.validation_docker.ValidateDocker.run_container')
192+
def test_staging_cluster_not_ready(self, mock_container: Mock, mock_validation_args: Mock, mock_cluster_readiness: Mock) -> None:
193+
mock_validation_args.return_value.OS_image = 'opensearchstaging/opensearch-os'
194+
mock_validation_args.return_value.version = '1.0.0.1000'
195+
mock_validation_args.return_value.validate_digest_only = False
196+
mock_validation_args.return_value.force_https = False
197+
mock_validation_args.return_value.projects = ["opensearch"]
198+
mock_cluster_readiness.return_value = False
199+
mock_container.return_value = (True, 'test_file.yml')
182200

183201
validate_docker = ValidateDocker(mock_validation_args.return_value)
202+
validate_docker.image_ids = {'opensearch': 'images_id_0'}
203+
validate_docker.replacements = [('opensearchproject/opensearch:1', 'images_id_0')]
184204

185-
validate_docker.args.docker_source = 'dockerhub'
186-
187-
result = validate_docker.check_http_request()
188-
189-
self.assertEqual(result, True)
190-
mock_api_test.assert_called()
191-
205+
with self.assertRaises(Exception) as context:
206+
validate_docker.validation()
207+
self.assertEqual(str(context.exception), 'Cluster is not ready for API test.')
208+
mock_cluster_readiness.assert_called_once()
209+
210+
@patch.dict('os.environ', {'OPENSEARCH_INITIAL_ADMIN_PASSWORD': 'admin'})
211+
@patch.object(shutil, "copy2")
212+
@patch.object(subprocess, "check_output")
213+
@patch.object(subprocess, "run")
214+
@patch('validation_workflow.docker.validation_docker.get_password')
215+
@patch('validation_workflow.docker.validation_docker.ValidateDocker.inplace_change')
192216
@patch('validation_workflow.docker.validation_docker.ValidationArgs')
193-
@patch('validation_workflow.docker.validation_docker.ApiTest.api_get')
194-
def test_check_http_request_failure(self, mock_api_test: MagicMock, mock_validation_args: MagicMock) -> None:
195-
mock_validation_args.return_value.test_readiness_urls = {
196-
'https://localhost:9200/': 'opensearch cluster API',
197-
'http://localhost:5601/api/status': 'opensearch-dashboards API',
198-
}
217+
def test_run_container(self, mock_validation_args: Mock, mock_inplace: Mock, mock_password: Mock, mock_subprocess_run: MagicMock,
218+
mock_check_output: MagicMock, mock_copy2: MagicMock) -> None:
219+
image_ids = {"opensearch": "sha1", "opensearch-dashboards": "sha2"}
220+
mock_validation_args.return_value.projects = ["opensearch"]
221+
mock_subprocess_run.return_value = subprocess.CompletedProcess(args='docker-compose -f docker-compose.yml down', returncode=0, stdout=b'', stderr=b'')
222+
mock_password.return_value = "admin"
199223
mock_validation_args.return_value.version = '1.0.0'
200-
201-
mock_api_test.return_value = (400, "response")
202-
203224
validate_docker = ValidateDocker(mock_validation_args.return_value)
204-
205-
validate_docker.args.docker_source = 'dockerhub'
206-
207-
result = validate_docker.check_http_request()
208-
209-
self.assertEqual(result, False)
210-
mock_api_test.assert_called()
225+
result, self._target_yml_file = validate_docker.run_container(image_ids, "2.11.0")
226+
self.assertEqual(result, True)
227+
mock_subprocess_run.assert_called_with(f'docker-compose -f {validate_docker.tmp_dir.path}/docker-compose.yml up -d opensearch-node1 opensearch-node2',
228+
shell=True, stdout=-1, stderr=-1, universal_newlines=True)
211229

212230

213231
if __name__ == '__main__':

0 commit comments

Comments
 (0)