Odyssey
ody_migr_mmth_test.py
1 #!/usr/bin/env python
2 """Test Mammoth connection for all data categories and CU options.
3 
4 This test module contains test cases for testing connection
5 to Mammoth and validating response for all CUs (eg. SCRUBCU)
6 and all data categories (eg. settings, members, etc.).
7 
8 Note: Each test method runs the same test case on multiple
9 CUs and multiple applicable data categories.
10 
11 Usage Example:
12  $ export ODY_MIGR_SECRET_KEY=**** &&\
13  python3 opt/odyssey/tools/bin/ody_migr_mmth_test.py
14 """
15 
16 
17 import unittest
18 import os
19 
20 from ody_migr_mmth_endpoint import MammothMigration
21 from ody_migr_utils import generate_hash, get_valid_json
22 from ody_migr_config import (ENV_MIGR_SECRET_KEY,
23  TEST_USERNAME,
24  TEST_PASSWORD,
25  RESPONSE_KEYS,
26  RESPONSE_HIST_KEYS,
27  EXPECTED_DATA_KEYS,
28  EXPECTED_HASH_DICT,
29  DEFAULT_ERROR_STR,
30  TESTING_SERVER,
31  SUPPORTED_CU_TEST,
32  DATA_CHOICES_FOR_TEST,
33  DATA_OPT_SETTINGS,
34  DATA_OPT_MEMDATA,
35  DATA_OPT_CREATE_HIST,
36  DATA_OPT_GET_HIST,
37  KEY_MEMBERS)
38 import logging
39 # disable logging during testing
40 logging.disable(logging.ERROR)
41 
42 # verify that necessary env variables are exported
43 assert os.getenv(ENV_MIGR_SECRET_KEY) is not None,\
44  "Environment variable: `{}` is not set!".format(ENV_MIGR_SECRET_KEY)
45 
46 
47 class TestMammothMigration(unittest.TestCase):
48  """Test cases for Mammoth connection and received data response."""
49 
50  def setUp(self):
51  """Set up test environment.
52 
53  Prepare essential Mammoth connectors to test connections and
54  data responses.
55  """
56 
57  # Each of the following list stores objects and data for
58  # each combination of data category and supported CU for testing
59  # list of MammothMigration object
60  self.list_of_migrators = []
61  # list of expected pre-generated hashes
62  self.list_of_expected_hashes = []
63  # list of expected urls
64  self.list_of_expected_urls = []
65  # list of http post parameters for memdata
66  self.list_of_http_requests = []
67 
68  # setting up
69  for data_category in DATA_CHOICES_FOR_TEST:
70  for cu in SUPPORTED_CU_TEST:
71  memdata_params = ""
72 
73  if data_category == DATA_OPT_MEMDATA:
74  if cu == "SCRUBCU":
75  memdata_params = {
76  KEY_MEMBERS: get_valid_json([6680, 779999])}
77 
78  elif (cu == "CRUISECU" and
79  data_category == DATA_OPT_MEMDATA):
80  memdata_params = {KEY_MEMBERS: get_valid_json([25198])}
81 
82  this_migrator = MammothMigration(
83  cu,
84  data_category,
85  TESTING_SERVER,
86  TEST_USERNAME,
87  TEST_PASSWORD,
88  params=memdata_params
89  )
90 
91  elif data_category == DATA_OPT_CREATE_HIST:
92  this_migrator = MammothMigration(
93  cu,
94  data_category,
95  TESTING_SERVER,
96  TEST_USERNAME,
97  TEST_PASSWORD,
98  params={"restart": "Y"}
99  )
100 
101  else:
102  this_migrator = MammothMigration(
103  cu,
104  data_category,
105  TESTING_SERVER,
106  TEST_USERNAME,
107  TEST_PASSWORD,
108  )
109 
110  self.list_of_http_requests.append(memdata_params)
111 
112  self.list_of_migrators.append(this_migrator)
113 
114  this_hash = EXPECTED_HASH_DICT[data_category][cu]
115  self.list_of_expected_hashes.append(this_hash)
116 
117  this_url = ("https://{}.homecu.net/hcuadm/mOdysseyMigrExp.prg"
118  "?cu={}&passphrase={}&action={}").format(
119  this_migrator.server,
120  this_migrator.cu,
121  this_hash,
122  this_migrator.data_category)
123  self.list_of_expected_urls.append(this_url)
124 
125  self.default_err_msg = DEFAULT_ERROR_STR
126  self.wrong_username = "sharma_ashish"
127  self.invalid_secret = "some!CrappyS3cR3TF0rT3$tin9"
128 
129  self.expected_response_keys = RESPONSE_KEYS
130  self.expected_response_hist_keys = RESPONSE_HIST_KEYS
131  self.extected_data_keys = EXPECTED_DATA_KEYS
132 
134  """Test authentication code generation.
135 
136  Obtained authentication code must match the expected code
137  generated for valid cu and action when generated with correct
138  SECRET KEY"""
139  for ind, this_expected_hash in enumerate(self.list_of_expected_hashes):
140  this_migrator = self.list_of_migrators[ind]
141  obtained_hash = generate_hash(
142  this_migrator.data_category,
143  this_migrator.cu,
144  os.environ.get(ENV_MIGR_SECRET_KEY)
145  )
146  self.assertEqual(this_expected_hash, obtained_hash)
147 
149  """Test url destination correctness given cu and data_category."""
150  for ind, this_expected_url in enumerate(self.list_of_expected_urls):
151  this_migrator = self.list_of_migrators[ind]
152  obtained_url = this_migrator._dest_url()
153  self.assertEqual(this_expected_url, obtained_url)
154 
156  """Invalid credential should not allow access the Mammoth resources.
157 
158  Expect SystemExit exception raised when tried to authenticate
159  with incorrect credentials
160  """
161 
162  for this_migrator in self.list_of_migrators:
163  this_migrator.username = self.wrong_username
164  with self.assertRaises(SystemExit):
165  this_migrator._initiate_http_request()
166 
168  """Test connection with invalid secret key."""
169 
170  for this_migrator in self.list_of_migrators:
171  original_secret = os.environ.get(ENV_MIGR_SECRET_KEY)
172  os.environ[ENV_MIGR_SECRET_KEY] = self.invalid_secret
173  # populates response dictionary after successful connection
174  this_migrator._initiate_http_request()
175  # but returns with error response message: Invalid passphrase
176  with self.assertRaises((SystemExit)):
177  this_migrator._validate_response()
178  os.environ[ENV_MIGR_SECRET_KEY] = original_secret
179 
181  """Test file not exist for gethistoryfile executed before creation.
182 
183  SOCU, CU that we do not use for testing and is expected not to have
184  memhist.gz and memhist lock file in /home/SOCU/tmp directory in
185  Mammoth. If such files exist, delete first.
186  """
187  this_migrator = MammothMigration(
188  "SOCU",
189  DATA_OPT_GET_HIST,
190  TESTING_SERVER,
191  TEST_USERNAME,
192  TEST_PASSWORD,
193  )
194 
195  this_migrator._initiate_http_request()
196  # must raise SystemExit on error (file doesn't exist)
197  with self.assertRaises(SystemExit):
198  this_migrator._validate_response()
199 
201  """Test successful data (all categories) pull from Mammoth."""
202 
203  for ind, this_migrator in enumerate(self.list_of_migrators):
204  # we only have few cases for memdata and memhist to test
205  if (this_migrator.data_category == DATA_OPT_MEMDATA and
206  self.list_of_http_requests[ind] == ""):
207  continue
208 
209  this_migrator._initiate_http_request()
210 
211  resp = this_migrator.response
212 
213  if this_migrator.data_category == DATA_OPT_CREATE_HIST:
214  self.assertIsInstance(resp, dict)
215 
216  # check expected response keys for createhistoryfile exist
217  for expected_resp_key in self.expected_response_hist_keys:
218  self.assertIn(expected_resp_key, resp.keys())
219 
220  # verify usual conditions of error and file response values
221  chist_error = resp["error"]
222  data_fname = resp["file"]
223  assert (data_fname == "" and chist_error != "") \
224  or (data_fname != "" and chist_error == "")
225 
226  elif this_migrator.data_category == DATA_OPT_GET_HIST:
227  self.assertIsInstance(resp.content, bytes)
228  # history response is a stream of binary content, so will
229  # raise ValueError if tried to decode into json
230  with self.assertRaises((ValueError)):
231  resp.json()
232 
233  # all other data category
234  else:
235  self.assertIsInstance(resp, dict)
236  self.assertEqual(resp["error"], self.default_err_msg)
237 
238  # check that all the expected response keys exist
239  for expected_resp_key in self.expected_response_keys:
240  self.assertIn(expected_resp_key, resp.keys())
241 
242  data_dict = resp["data"]
243 
244  # data keys membership check for memdata
245  if this_migrator.data_category == DATA_OPT_MEMDATA:
246  memdata_true_dict_struct = self.extected_data_keys[
247  this_migrator.data_category]
248 
249  self.assertEqual(len(data_dict.keys()), 1)
250  self.assertEqual(list(data_dict.keys())[0], "account")
251  # verify data keys exist for all the member accounts
252  for member_response in data_dict["account"].keys():
253  self.assertEqual(sorted(
254  data_dict["account"][member_response].keys()),
255  sorted(memdata_true_dict_struct))
256 
257  # simple membership assertion for other data categories
258  else:
259  for expected_data_key in self.extected_data_keys[
260  this_migrator.data_category]:
261  self.assertIn(expected_data_key, data_dict.keys())
262 
263  # validate some obvious data
264  if this_migrator.data_category == DATA_OPT_SETTINGS:
265  # validate exported data for `cuadmin`
266  self.assertEqual(len(data_dict["cuadmin"]), 1)
267  self.assertEqual(data_dict["cuadmin"][
268  0]["cu"].strip(), this_migrator.cu)
269 
270  def tearDown(self):
271  pass
272 
273 
274 if __name__ == "__main__":
275  unittest.main()