aplos-nca-saas-sdk 0.0.15__tar.gz → 0.0.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/PKG-INFO +1 -1
  2. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/pyproject.toml +1 -1
  3. aplos_nca_saas_sdk-0.0.17/requirements.dev.txt +1 -0
  4. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/configs/file_upload_config.py +1 -1
  5. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/configs/login_config.py +3 -3
  6. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/configs/nca_execution_config.py +64 -24
  7. aplos_nca_saas_sdk-0.0.15/src/aplos_nca_saas_sdk/integration_testing/main.py → aplos_nca_saas_sdk-0.0.17/src/aplos_nca_saas_sdk/integration_testing/example_main.py +15 -7
  8. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/integration_test_suite.py +9 -9
  9. aplos_nca_saas_sdk-0.0.17/src/aplos_nca_saas_sdk/integration_testing/readme.md +205 -0
  10. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/tests/file_upload_test.py +8 -12
  11. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/tests/nca_analysis_test.py +3 -0
  12. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/nca_analysis.py +23 -13
  13. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/nca_file_download.py +26 -10
  14. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/run_analysis_execution.py +4 -4
  15. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/utilities/commandline_args.py +5 -5
  16. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/utilities/environment_services.py +1 -1
  17. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/version.py +1 -1
  18. aplos_nca_saas_sdk-0.0.15/src/aplos_nca_saas_sdk/integration_testing/readme.md +0 -18
  19. aplos_nca_saas_sdk-0.0.15/src/aplos_nca_saas_sdk/integration_testing/tests/validation_test.py +0 -5
  20. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/.gitignore +0 -0
  21. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/.pypirc +0 -0
  22. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/.vscode/launch.json +0 -0
  23. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/.vscode/settings.json +0 -0
  24. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/LICENSE +0 -0
  25. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/README.md +0 -0
  26. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/devops/pypi/build.py +0 -0
  27. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/devops/pypi/readme.md +0 -0
  28. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/devops/requirements.txt +0 -0
  29. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/docs/images/API_Configuration_blur.png +0 -0
  30. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/docs/images/aplos-nca-commandline-cropped.png +0 -0
  31. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/docs/images/aplos-nca-commandline.png +0 -0
  32. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/mypy.ini +0 -0
  33. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/mypy_checks.py +0 -0
  34. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/readme.md +0 -0
  35. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/requirements.txt +0 -0
  36. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/run-checks.sh +0 -0
  37. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/__init__.py +0 -0
  38. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/configs/_config_base.py +0 -0
  39. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/configs/app_settings_config.py +0 -0
  40. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/configs/config_sample.json +0 -0
  41. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/configs/nca_validation_config.py +0 -0
  42. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/files/executions/config1.json +0 -0
  43. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/files/uploads/input1.csv +0 -0
  44. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/files/uploads/input1.dat +0 -0
  45. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/files/uploads/input1.sas7bdat +0 -0
  46. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/files/uploads/input1.xls +0 -0
  47. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/files/uploads/input1.xlsx +0 -0
  48. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/files/uploads/input1.xpt +0 -0
  49. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/integration_test_base.py +0 -0
  50. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/integration_test_configurations.py +0 -0
  51. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/integration_test_factory.py +0 -0
  52. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/integration_test_response.py +0 -0
  53. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/tests/app_configuration_test.py +0 -0
  54. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/tests/app_login_test.py +0 -0
  55. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/integration_testing/tests/nca_analysis_validation_test.py +0 -0
  56. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/_api_base.py +0 -0
  57. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/aws_cognito.py +0 -0
  58. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/aws_s3_presigned_payload.py +0 -0
  59. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/aws_s3_presigned_upload.py +0 -0
  60. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/nca_app_configuration.py +0 -0
  61. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/nca_authenticator.py +0 -0
  62. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/nca_endpoints.py +0 -0
  63. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/nca_file_upload.py +0 -0
  64. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/nca_resources/nca_validations.py +0 -0
  65. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/sample_files/analysis_files/single_ev/config.json +0 -0
  66. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/sample_files/analysis_files/single_ev/input.csv +0 -0
  67. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/sample_files/analysis_files/single_ev/meta_data.json +0 -0
  68. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/utilities/environment_vars.py +0 -0
  69. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/utilities/file_utility.py +0 -0
  70. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/src/aplos_nca_saas_sdk/utilities/http_utility.py +0 -0
  71. {aplos_nca_saas_sdk-0.0.15 → aplos_nca_saas_sdk-0.0.17}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aplos_nca_saas_sdk
3
- Version: 0.0.15
3
+ Version: 0.0.17
4
4
  Summary: Aplos NCA SaaS SDK
5
5
  Project-URL: Homepage, https://aplosanalytics.com/
6
6
  Project-URL: Documentation, https://docs.aplosanalytics.com/
@@ -26,7 +26,7 @@ keywords = [
26
26
  "Clinical Trials"
27
27
  ]
28
28
 
29
- version = "0.0.15"
29
+ version = "0.0.17"
30
30
  authors = [
31
31
  { name="Eric Wilson", email="eric.wilson@aplosanalytics.com" }
32
32
  ]
@@ -0,0 +1 @@
1
+ mypy
@@ -11,7 +11,7 @@ from aplos_nca_saas_sdk.integration_testing.configs.login_config import (
11
11
  LoginConfig,
12
12
  LoginConfigs,
13
13
  )
14
- from aplos_nca_saas_sdk.utilities.environment_services import EnvironmentServices
14
+
15
15
  from aplos_nca_saas_sdk.utilities.file_utility import FileUtility
16
16
 
17
17
 
@@ -17,13 +17,13 @@ class LoginConfig(ConfigBase):
17
17
  def __init__(
18
18
  self,
19
19
  username: Optional[str] = None,
20
- passord: Optional[str] = None,
20
+ password: Optional[str] = None,
21
21
  host: Optional[str] = None,
22
22
  roles: Optional[List[str]] = None,
23
23
  ):
24
24
  super().__init__()
25
25
  self.__username: Optional[str] = username
26
- self.__password: Optional[str] = passord
26
+ self.__password: Optional[str] = password
27
27
  self.__host: Optional[str] = host
28
28
  self.__roles: List[str] = roles if roles is not None else []
29
29
 
@@ -110,7 +110,7 @@ class LoginConfigs(ConfigBase):
110
110
 
111
111
  @staticmethod
112
112
  def try_load_login(login_config: Dict[str, Any]) -> LoginConfig | None:
113
- """Attempts to intialize a Login from a configuration object"""
113
+ """Attempts to initialize a Login from a configuration object"""
114
114
  login: LoginConfig | None = None
115
115
  if login_config is not None:
116
116
  username = login_config.get("username", None)
@@ -34,6 +34,9 @@ class NCAExecutionConfig(ConfigBase):
34
34
  meta_data: str | dict | None = None,
35
35
  output_dir: str | None = None,
36
36
  unzip_after_download: bool = False,
37
+ data_processing: str | dict | None = None,
38
+ post_processing: str | dict | None = None,
39
+ full_payload: str | dict | None = None,
37
40
  ):
38
41
  super().__init__()
39
42
 
@@ -52,6 +55,9 @@ class NCAExecutionConfig(ConfigBase):
52
55
  self.__meta_data = meta_data
53
56
  self.__output_dir = output_dir
54
57
  self.__unzip_after_download = unzip_after_download
58
+ self.__data_processing = data_processing
59
+ self.__post_processing = post_processing
60
+ self.__full_payload = full_payload
55
61
 
56
62
  @property
57
63
  def login(self) -> LoginConfig:
@@ -83,6 +89,20 @@ class NCAExecutionConfig(ConfigBase):
83
89
  """Indicates if the download should be unzipped"""
84
90
  return self.__unzip_after_download
85
91
 
92
+ @property
93
+ def data_processing(self) -> str | Dict[str, Any] | None:
94
+ """Pre Processing"""
95
+ return self.__data_processing
96
+
97
+ @property
98
+ def post_processing(self) -> str | Dict[str, Any] | None:
99
+ """Post Processing"""
100
+ return self.__post_processing
101
+
102
+ @property
103
+ def full_payload(self) -> str | Dict[str, Any] | None:
104
+ """Full Payload"""
105
+ return self.__full_payload
86
106
 
87
107
  class NCAExecutionConfigs(ConfigBase):
88
108
  """
@@ -106,21 +126,27 @@ class NCAExecutionConfigs(ConfigBase):
106
126
  input_file_path: str,
107
127
  config_data: dict,
108
128
  meta_data: str | dict | None = None,
129
+ data_processing: str | dict | None = None,
130
+ post_processing: str | dict | None = None,
109
131
  output_dir: str | None = None,
110
132
  unzip_after_download: bool = False,
111
133
  enabled: bool = True,
134
+ full_payload: str | dict | None = None,
112
135
  ):
113
136
  """Add an NCA Execution Config"""
114
- nca_excution_config = NCAExecutionConfig(
137
+ nca_execution_config = NCAExecutionConfig(
115
138
  login,
116
139
  input_file_path,
117
140
  config_data,
118
141
  meta_data,
119
142
  output_dir,
120
143
  unzip_after_download,
144
+ data_processing,
145
+ post_processing,
146
+ full_payload,
121
147
  )
122
- nca_excution_config.enabled = enabled
123
- self.__nca_executions.append(nca_excution_config)
148
+ nca_execution_config.enabled = enabled
149
+ self.__nca_executions.append(nca_execution_config)
124
150
 
125
151
  def load(self, test_config: Dict[str, Any]):
126
152
  """Loads the NCA Execution configs from a list of dictionaries"""
@@ -150,41 +176,55 @@ class NCAExecutionConfigs(ConfigBase):
150
176
  if not login:
151
177
  raise RuntimeError("Failed to load the login configuration")
152
178
 
179
+
180
+ full_payload = self.__load_dictionary_data_or_file(key="payload", analysis=analysis, optional=True)
181
+ config_data = self.__load_dictionary_data_or_file(key="config", analysis=analysis, optional=True)
182
+
183
+ if not config_data and not full_payload:
184
+ raise RuntimeError("Failed to load the config data")
185
+
186
+ meta_data = self.__load_dictionary_data_or_file(key="meta", analysis=analysis, optional=True)
187
+ data_cleaning = self.__load_dictionary_data_or_file(key="data_cleaning", analysis=analysis, optional=True)
188
+ post_processing = self.__load_dictionary_data_or_file(key="post_processing", analysis=analysis, optional=True)
189
+
153
190
  self.add(
154
191
  login=login,
155
192
  input_file_path=analysis["file"],
156
- config_data=self.__load_config_data(analysis=analysis),
157
- meta_data=self.__load_meta_data(analysis=analysis),
193
+ config_data=config_data,
194
+ meta_data=meta_data,
158
195
  output_dir=output_dir,
159
196
  unzip_after_download=True,
160
197
  enabled=enabled,
198
+ full_payload=full_payload,
199
+ data_processing=data_cleaning,
200
+ post_processing=post_processing
161
201
  )
162
202
 
163
- def __load_meta_data(self, analysis: Dict[str, Any]) -> Dict[str, Any]:
164
- data: Dict[str, Any] = {}
165
- data = analysis.get("meta", {}).get("data", {})
166
-
167
- return data
168
203
 
169
- def __load_config_data(self, analysis: Dict[str, Any]) -> Dict[str, Any]:
170
- config_data: Dict[str, Any] = {}
171
- config_data = analysis.get("config", {}).get("data")
204
+ def __load_dictionary_data_or_file(self, key: str, analysis: Dict[str, Any], optional: bool = False ) -> Dict[str, Any] | None:
205
+ data: Dict[str, Any] = {}
206
+ data = analysis.get(key, {}).get("data", {})
172
207
 
173
- if config_data:
174
- return config_data
208
+ if data:
209
+ return data
175
210
 
176
- config_file_path: str = analysis.get("config", {}).get("file")
211
+ file_path: str = analysis.get(key, {}).get("file")
177
212
 
178
213
  logger.info(
179
214
  {
180
- "message": "Initializing config_data from file",
181
- "config_data": config_file_path,
215
+ "message": f"Initializing {key} from file",
216
+ "key": key,
217
+ "file_path": file_path,
182
218
  }
183
219
  )
184
- config_path = FileUtility.load_filepath(config_file_path)
185
- if os.path.exists(config_path) is False:
186
- raise RuntimeError(f"Config file not found: {config_path}")
187
- with open(config_path, "r", encoding="utf-8") as f:
188
- config_data = json.load(f)
220
+ path = FileUtility.load_filepath(file_path)
221
+ if os.path.exists(path) is False:
222
+ if optional:
223
+ return None
224
+ raise RuntimeError(f"Data for {key} not found: {path}")
225
+ with open(path, "r", encoding="utf-8") as f:
226
+ data = json.load(f)
227
+
228
+ return data
189
229
 
190
- return config_data
230
+
@@ -16,19 +16,25 @@ from aplos_nca_saas_sdk.integration_testing.integration_test_configurations impo
16
16
 
17
17
 
18
18
  def main():
19
- """Run the tests"""
19
+ """This is an example on how you can run the unit tests"""
20
20
 
21
+ # Optionally use our convenient Environment Services loader
22
+ # which can help during initial testings.
21
23
  evs: EnvironmentServices = EnvironmentServices()
24
+ # see if we have a local .env, .env.uat, etc configured to look up
22
25
  env_file = os.getenv("ENV_FILE")
23
26
  if env_file:
24
27
  # if we have an environment file defined, let's load it
25
28
  evs.load_environment(starting_path=__file__, file_name=env_file)
26
29
 
30
+ # this is where the work begins
27
31
  its: IntegrationTestSuite = IntegrationTestSuite()
28
32
  config: TestConfiguration = TestConfiguration()
29
33
 
30
- # normally we'd pull a test configuration file from Secrets Manager, Parameter Store, or some other secure location
31
- # here we're going to pull the sample file and then override some it's values.
34
+ # here were going to load a config file that is local, for security purpose
35
+ # you should store this in SecretsManager, Parameter Store, a secure S3 bucket etc.
36
+ # the configs typically contain sensitive information like usernames & passwords
37
+ # so be careful where you store it!
32
38
  config_file = os.path.join(
33
39
  Path(__file__).parent,
34
40
  "configs",
@@ -37,14 +43,16 @@ def main():
37
43
  # load it so we can see what it looks like
38
44
  config.load(file_path=config_file)
39
45
 
40
- # override the configuration
41
- # override_config(config)
42
-
46
+ # run the tests
43
47
  its.test(test_config=config)
44
48
 
45
49
 
46
50
  def override_config(config: TestConfiguration):
47
- """Override the configuration for the tests"""
51
+ """
52
+ Override the configuration for the tests.
53
+ This is some sample code how you can use a combination of a config file
54
+ and then override the username/password combos using environment vars.
55
+ """
48
56
  username = os.getenv("TEST_USERNAME")
49
57
  password = os.getenv("TEST_PASSWORD")
50
58
  host = os.getenv("TEST_HOST")
@@ -70,15 +70,15 @@ class IntegrationTestSuite:
70
70
  if self.fail_fast:
71
71
  # just break and let the failure routine handle it
72
72
  break
73
-
74
- test_result["end_time_utc"] = datetime.now(UTC)
75
- self.test_results.append(test_result)
76
-
77
- if test_result["success"]:
78
- logger.info(f"Test {test.name} succeeded")
79
- logger.debug(test_result)
80
- else:
81
- logger.error(test_result)
73
+ finally:
74
+ test_result["end_time_utc"] = datetime.now(UTC)
75
+ self.test_results.append(test_result)
76
+
77
+ if test_result["success"]:
78
+ logger.info(f"Test {test.name} succeeded")
79
+ logger.debug(test_result)
80
+ else:
81
+ logger.error(test_result)
82
82
  # find the failures
83
83
  failures = [test for test in self.test_results if len(test["errors"]) > 0]
84
84
  self.__print_results(start_time, failures)
@@ -0,0 +1,205 @@
1
+ # Integration Test
2
+
3
+ This module runs integration tests against a live environment. The goal is to catch anything before it's deployed.
4
+ However you can also use this as a learning tool or a base on how to use our API's.
5
+
6
+ ## Requirements
7
+ The integration tests will require the following:
8
+ - A valid user Aplos NCA User Account
9
+ - A valid subscription
10
+
11
+
12
+ ### Users
13
+ You will need valid user accounts with the appropriate permissions for the endpoints they are executing.
14
+
15
+ If you are testing permission boundaries then you should set up multiple users with different permissions.
16
+
17
+
18
+ ### Subscriptions
19
+ Your subscription will control how may executions are allowed for user or tenancy. Make sure you have enough executions. If you need
20
+ additional executions, please reach-out to your support contact.
21
+
22
+ ## Running the test
23
+ See the `example_main.py` for updated examples, but in general you follow the code below to run tests. Also, see the `configs` section below
24
+ for guidance on defining what is tested.
25
+
26
+ ```python
27
+ """
28
+ Copyright 2024-2025 Aplos Analytics
29
+ All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
30
+ Property of Aplos Analytics, Utah, USA
31
+ """
32
+
33
+ import os
34
+ from pathlib import Path
35
+ from aplos_nca_saas_sdk.utilities.environment_services import EnvironmentServices
36
+ from aplos_nca_saas_sdk.integration_testing.integration_test_suite import (
37
+ IntegrationTestSuite,
38
+ )
39
+ from aplos_nca_saas_sdk.integration_testing.integration_test_configurations import (
40
+ TestConfiguration,
41
+ )
42
+
43
+
44
+ def main():
45
+ """This is an example on how you can run the unit tests"""
46
+
47
+ # Optionally use our convenient Environment Services loader
48
+ # which can help during initial testings.
49
+ evs: EnvironmentServices = EnvironmentServices()
50
+ # See if we have a local .env, .env.uat, etc configured to look up
51
+ # for local configuration settings
52
+ #
53
+ # Use local .env files when testing locally. As a best practice
54
+ # you should avoid adding these to source control or deployments.
55
+ env_file = os.getenv("ENV_FILE")
56
+ if env_file:
57
+ # if we have an environment file defined, let's load it
58
+ # this will prep our environment with local values.
59
+ evs.load_environment(starting_path=__file__, file_name=env_file)
60
+
61
+ # this is where the work begins
62
+ its: IntegrationTestSuite = IntegrationTestSuite()
63
+ config: TestConfiguration = TestConfiguration()
64
+
65
+ # here were going to load a config file that is local, for security purpose
66
+ # you should store this in SecretsManager, Parameter Store, a secure S3 bucket etc.
67
+ # the configs typically contain sensitive information like usernames & passwords
68
+ # so be careful where you store it!
69
+ config_file = os.path.join(
70
+ Path(__file__).parent,
71
+ "configs",
72
+ os.getenv("TEST_CONFIG_FILE") or "config_sample.json",
73
+ )
74
+ # load it so we can see what it looks like
75
+ config.load(file_path=config_file)
76
+
77
+ # run the tests
78
+ its.test(test_config=config)
79
+
80
+
81
+ ```
82
+
83
+ ### Configs
84
+ Tests are run based on configurations. The following is an example of supported configurations:
85
+
86
+ - Application Configuration Settings
87
+ - Logins & Access
88
+ - Executing an Analysis
89
+ - Running a Validation
90
+
91
+ ```json
92
+ {
93
+ "application_config_test": {
94
+ "purpose": "Tests the application configuration endpoints",
95
+ "hosts": [
96
+ {
97
+ "host": "api.example.com",
98
+ "expected_results": {
99
+ "status_code": 200
100
+ },
101
+ "enabled": true
102
+ },
103
+ {
104
+ "host": "XXXXXXXXXXXXXXXXXXXXX",
105
+ "expected_results": {
106
+ "status_code": 403
107
+ },
108
+ "enabled": false
109
+ }
110
+ ]
111
+ },
112
+ "login_test": {
113
+ "purpose": "Tests the login endpoints",
114
+ "logins": [
115
+ {
116
+ "username": "foo",
117
+ "password": "barr",
118
+ "host": "api.example.com",
119
+ "roles": []
120
+ },
121
+ {
122
+ "username": "XXXXXXXXXXXXXXXXXXXXX",
123
+ "password": "XXXXXXXXXXXXXXXXXXXXX",
124
+ "host": "XXXXXXXXXXXXXXXXXXXXX",
125
+ "roles": [
126
+ "XXXXXXXXXXXXXXXXXXXXX"
127
+ ],
128
+ "enabled": false,
129
+ "expected_results": {
130
+ "exception": "InvalidCredentialsException"
131
+ }
132
+ }
133
+ ]
134
+ },
135
+ "file_upload_test": {
136
+ "purpose": "Tests the file upload endpoints.",
137
+ "notes": "a file can be on the local drive or pulled from a public https source.",
138
+ "login": {
139
+ "purpose": "optional: if present this login is used, unless a specific login is defined for the test",
140
+ "username": "foo",
141
+ "password": "bar",
142
+ "host": "api.example.com"
143
+ },
144
+ "files": [
145
+ {
146
+ "file": "XXXXXXXXXXXXXXXXXXXXX"
147
+ },
148
+ {
149
+ "file": "XXXXXXXXXXXXXXXXXXXXX",
150
+ "login": {
151
+ "purpose": "optional: if present tests an upload for a specific user",
152
+ "username": "XXXXXXXXXXXXXXXXXXXXX",
153
+ "password": "XXXXXXXXXXXXXXXXXXXXX",
154
+ "host": "XXXXXXXXXXXXXXXXXXXXX"
155
+ }
156
+ }
157
+ ]
158
+ },
159
+ "analysis_execution_test": {
160
+ "purpose": "Tests the analysis execution endpoints.",
161
+ "login": {
162
+ "username": "XXXXXXXXXXXXXXXXXXXXX",
163
+ "password": "XXXXXXXXXXXXXXXXXXXXX",
164
+ "host": "XXXXXXXXXXXXXXXXXXXXX"
165
+ },
166
+ "output_dir": "XXXXXXXXXXXXXXXXXXXXX",
167
+ "analyses": [
168
+ {
169
+ "file": "XXXXXXXXXXXXXXXXXXXXX",
170
+ "meta": {},
171
+ "config": {},
172
+ "expected_results": {
173
+ "status_code": 200
174
+ },
175
+ "output_dir": "XXXXXXXXXXXXXXXXXXXXX"
176
+ },
177
+ {
178
+ "file": "XXXXXXXXXXXXXXXXXXXXX",
179
+ "meta": {},
180
+ "config": {},
181
+ "login": {
182
+ "username": "XXXXXXXXXXXXXXXXXXXXX",
183
+ "password": "XXXXXXXXXXXXXXXXXXXXX",
184
+ "host": "XXXXXXXXXXXXXXXXXXXXX"
185
+ },
186
+ "expected_results": {
187
+ "status_code": 200
188
+ }
189
+ }
190
+ ]
191
+ },
192
+ "validation_test": {
193
+ "purpose": "Tests the validation execution.",
194
+ "login": {
195
+ "username": "XXXXXXXXXXXXXXXXXXXXX",
196
+ "password": "XXXXXXXXXXXXXXXXXXXXX",
197
+ "host": "XXXXXXXXXXXXXXXXXXXXX"
198
+ },
199
+ "expected_results": {
200
+ "status_code": 200
201
+ }
202
+ }
203
+ }
204
+
205
+ ```
@@ -5,11 +5,13 @@ Property of Aplos Analytics, Utah, USA
5
5
  """
6
6
 
7
7
  import time
8
- from datetime import datetime, timedelta
9
- from typing import Any, Dict, List
8
+ from typing import Any, Dict
10
9
 
11
- import requests
12
10
  from aws_lambda_powertools import Logger
11
+
12
+ from aplos_nca_saas_sdk.integration_testing.configs.file_upload_config import (
13
+ FileUploadConfig,
14
+ )
13
15
  from aplos_nca_saas_sdk.integration_testing.configs.login_config import LoginConfig
14
16
  from aplos_nca_saas_sdk.integration_testing.integration_test_base import (
15
17
  IntegrationTestBase,
@@ -17,13 +19,9 @@ from aplos_nca_saas_sdk.integration_testing.integration_test_base import (
17
19
  from aplos_nca_saas_sdk.integration_testing.integration_test_response import (
18
20
  IntegrationTestResponse,
19
21
  )
20
- from aplos_nca_saas_sdk.nca_resources.nca_file_upload import NCAFileUpload
21
- from aplos_nca_saas_sdk.nca_resources.nca_file_download import NCAFileDownload
22
22
  from aplos_nca_saas_sdk.nca_resources.nca_authenticator import NCAAuthenticator
23
- from aplos_nca_saas_sdk.utilities.http_utility import HttpUtilities
24
- from aplos_nca_saas_sdk.integration_testing.configs.file_upload_config import (
25
- FileUploadConfig,
26
- )
23
+ from aplos_nca_saas_sdk.nca_resources.nca_file_download import NCAFileDownload
24
+ from aplos_nca_saas_sdk.nca_resources.nca_file_upload import NCAFileUpload
27
25
 
28
26
  logger = Logger()
29
27
 
@@ -46,9 +44,7 @@ class FileUploadTest(IntegrationTestBase):
46
44
  try:
47
45
  # Confirm Login
48
46
  nca_login = self.__login(file_upload.login)
49
- # if not nca_login.cognito.jwt:
50
- # test_response.error = "Failed to authenticate"
51
- # else:
47
+
52
48
  # Confirm Upload
53
49
  upload_response: Dict[str, Any] = self.__upload(
54
50
  nca_login, file_upload.file_path
@@ -66,6 +66,9 @@ class NCAAnalysisTest(IntegrationTestBase):
66
66
  wait_for_results=True,
67
67
  output_directory=nca_execution_config.output_dir,
68
68
  unzip_after_download=False,
69
+ data_processing=nca_execution_config.data_processing,
70
+ post_processing=nca_execution_config.post_processing,
71
+ full_payload=nca_execution_config.full_payload,
69
72
  )
70
73
 
71
74
  # Verify Download
@@ -41,13 +41,16 @@ class NCAAnalysis(NCAApiBaseClass):
41
41
  config_data: dict,
42
42
  *,
43
43
  meta_data: str | dict | None = None,
44
+ post_processing: str | dict | None = None,
45
+ data_processing: str | dict | None = None,
44
46
  wait_for_results: bool = True,
45
47
  max_wait_in_seconds: int = 900,
46
48
  output_directory: str | None = None,
47
49
  unzip_after_download: bool = False,
50
+ full_payload: str | dict | None = None
48
51
  ) -> Dict[str, Any]:
49
52
  """
50
- Executes an analsysis.
53
+ Executes an analysis.
51
54
  - Uploads an analysis file.
52
55
  - Adds the execution to the queue.
53
56
 
@@ -81,7 +84,7 @@ class NCAAnalysis(NCAApiBaseClass):
81
84
  "Unexpected empty file_id when attempting to upload file."
82
85
  )
83
86
 
84
- self.log("\tAdding analyis to the queue.")
87
+ self.log("\tAdding analysis to the queue.")
85
88
  execution_response: Dict[str, Any] = self.__add_to_queue(
86
89
  file_id=file_id,
87
90
  config_data=config_data,
@@ -130,6 +133,9 @@ class NCAAnalysis(NCAApiBaseClass):
130
133
  file_id: str,
131
134
  config_data: dict,
132
135
  meta_data: str | dict | None = None,
136
+ post_processing: str | dict | None = None,
137
+ data_processing: str | dict | None = None,
138
+ full_payload: str | dict | None = None
133
139
  ) -> Dict[str, Any]:
134
140
  """
135
141
  Adds the analysis to the execution queue.
@@ -151,15 +157,19 @@ class NCAAnalysis(NCAApiBaseClass):
151
157
  "Missing config_data. Please provide a valid config_data."
152
158
  )
153
159
  headers = self.authenticator.get_jwt_http_headers()
154
- # to start a new execution we need the location of the file (s3 bucket and object key)
155
- # you basic configuration
156
- # optional meta data
157
-
158
- submission = {
159
- "file": {"id": file_id},
160
- "configuration": config_data,
161
- "meta_data": meta_data,
162
- }
160
+
161
+ submission: Dict[str, Any] = {}
162
+
163
+ if full_payload:
164
+ submission = full_payload
165
+ else:
166
+ submission = {
167
+ "file": {"id": file_id},
168
+ "configuration": config_data,
169
+ "meta_data": meta_data,
170
+ "post_processing": post_processing,
171
+ "data_processing": data_processing
172
+ }
163
173
 
164
174
  response: requests.Response = requests.post(
165
175
  self.endpoints.executions,
@@ -171,13 +181,13 @@ class NCAAnalysis(NCAApiBaseClass):
171
181
 
172
182
  if response.status_code == 403:
173
183
  raise PermissionError(
174
- "Failed to execute. A 403 response occured. "
184
+ "Failed to execute. A 403 response occurred. "
175
185
  "This could a token issue or a url path issue "
176
186
  "By default unknown gateway calls return 403 errors. "
177
187
  )
178
188
  elif response.status_code != 200:
179
189
  raise RuntimeError(
180
- f"Unknown Error occured during executions: {response.status_code}. "
190
+ f"Unknown Error occurred during executions: {response.status_code}. "
181
191
  f"Reason: {response.reason}"
182
192
  )
183
193
 
@@ -5,16 +5,17 @@ Property of Aplos Analytics, Utah, USA
5
5
  """
6
6
 
7
7
  import time
8
- from typing import Any, Dict, List
9
8
  from datetime import datetime, timedelta
9
+ from typing import Any, Dict, List
10
+
11
+ import requests
10
12
  from aws_lambda_powertools import Logger
13
+
11
14
  from aplos_nca_saas_sdk.nca_resources._api_base import NCAApiBaseClass
12
15
  from aplos_nca_saas_sdk.nca_resources.aws_s3_presigned_upload import (
13
16
  S3PresignedUrlUpload,
14
17
  )
15
-
16
18
  from aplos_nca_saas_sdk.utilities.http_utility import HttpUtilities
17
- import requests
18
19
 
19
20
  logger = Logger(service="nca-file-download")
20
21
 
@@ -41,7 +42,8 @@ class NCAFileDownload(NCAApiBaseClass):
41
42
  ValueError: _description_
42
43
 
43
44
  Returns:
44
- Dict: {"file_id": id, "statu_code": 204}
45
+ Dict: {"file_id": id, "status_code": 204, ...}
46
+ 204 Response staus_code is a success
45
47
  """
46
48
  if input_file_path is None or not input_file_path:
47
49
  raise ValueError("Valid input_file_path is required.")
@@ -67,12 +69,19 @@ class NCAFileDownload(NCAApiBaseClass):
67
69
  file_id: str,
68
70
  user_name: str | None = None,
69
71
  password: str | None = None,
72
+ wait_time_in_seconds: float = 5,
73
+ max_tries: float = 12,
74
+ required_workable_state: str = "ready",
70
75
  ) -> Dict[str, Any]:
71
76
  """
72
77
  Downloads a file from the Aplos NCA Cloud
73
78
 
74
79
  Args:
75
80
  file_id (str): the id of the file to download
81
+ user_name Optional(str): the username used to connect. If not specified
82
+ the authenticator is required.
83
+ password Optional(str): the password used to connect. If not specified
84
+ the authenticator is required.
76
85
 
77
86
  Raises:
78
87
  ValueError: _description_
@@ -94,12 +103,17 @@ class NCAFileDownload(NCAApiBaseClass):
94
103
  )
95
104
  self.authenticator.authenticate(username=user_name, password=password)
96
105
 
97
- max_wait_in_minutes: int = 3
98
106
  headers = HttpUtilities.get_headers(self.authenticator.cognito.jwt)
99
107
  current_time = datetime.now()
100
108
 
101
- # Create a timedelta object representing 3 minutes
102
- time_delta = timedelta(minutes=max_wait_in_minutes)
109
+ if max_tries < 0:
110
+ max_tries = 1
111
+ if wait_time_in_seconds < 0:
112
+ wait_time_in_seconds = 1
113
+
114
+ max_wait_time_in_seconds = wait_time_in_seconds * max_tries
115
+ # Create a timedelta object representing x seconds
116
+ time_delta = timedelta(seconds=max_wait_time_in_seconds)
103
117
  # Add the timedelta to the current time
104
118
  max_time = current_time + time_delta
105
119
 
@@ -113,16 +127,18 @@ class NCAFileDownload(NCAApiBaseClass):
113
127
  status = json_response.get("workable_state")
114
128
  complete = status == "ready"
115
129
 
130
+ if not required_workable_state or required_workable_state == "any":
131
+ break
116
132
  if status == "invalid" or len(errors) > 0:
117
133
  break
118
134
  if complete:
119
135
  break
120
136
  if not complete:
121
- time.sleep(5)
137
+ time.sleep(wait_time_in_seconds)
122
138
  if datetime.now() > max_time:
123
139
  error = (
124
- "Timeout attempting to get conversion file status. "
125
- f"The current timeout limit is {max_wait_in_minutes} minutes. "
140
+ "Timeout attempting to get an analysis file. "
141
+ f"The current timeout limit is {max_wait_time_in_seconds} seconds. "
126
142
  "You may need to up the timeout period, or check for errors. "
127
143
  )
128
144
  raise RuntimeError(error)
@@ -48,7 +48,7 @@ def main():
48
48
 
49
49
  wait_for_results = True
50
50
  max_wait_in_seconds = 900 # 15 minutes
51
- resutls = analysis_api.execute(
51
+ results = analysis_api.execute(
52
52
  username=str(args.username),
53
53
  password=str(args.password),
54
54
  input_file_path=str(args.analysis_file),
@@ -60,7 +60,7 @@ def main():
60
60
  )
61
61
 
62
62
  if not wait_for_results:
63
- exec_id = resutls.get("execution", {}).get("execution_id", "")
63
+ exec_id = results.get("execution", {}).get("execution_id", "")
64
64
  print(
65
65
  "Analysis execution has been queued. We're not waiting for the results."
66
66
  )
@@ -69,7 +69,7 @@ def main():
69
69
  print("🙌 Thank you for using the NCA API for an Analysis Execution Demo. 🙌")
70
70
  except Exception as e: # pylint: disable=w0718
71
71
  print(
72
- "🚨 An error occured ... exiting with an error. Please check your settings and try again."
72
+ "🚨 An error occurred ... exiting with an error. Please check your settings and try again."
73
73
  )
74
74
  print(
75
75
  "If you believe this is bug please create a support ticket and include the execution id (if available)."
@@ -83,7 +83,7 @@ def main():
83
83
 
84
84
  def optional_json_loads(data: str | dict) -> str | dict:
85
85
  """
86
- Attempts to load the data as json, fails gracefull and retuns the data is if it fails
86
+ Attempts to load the data as json, fails graceful and returns the data is if it fails
87
87
  Args:
88
88
  data (str): data as string
89
89
 
@@ -39,7 +39,7 @@ class CommandlineArgs:
39
39
  "-c", "--config-file", required=False, help="Path to the configuration file"
40
40
  )
41
41
  self.parser.add_argument(
42
- "-f", "--analyis-file", required=False, help="Path to the analysis file"
42
+ "-f", "--analysis-file", required=False, help="Path to the analysis file"
43
43
  )
44
44
  self.parser.add_argument(
45
45
  "-m", "--metadata-file", required=False, help="Path to the metadata file"
@@ -82,7 +82,7 @@ class CommandlineArgs:
82
82
  self.password: str | None = None
83
83
  self.host: str | None = None
84
84
 
85
- # excuction setup
85
+ # execution setup
86
86
  self.config_file: str | None = None
87
87
  self.config_file_default: str | None = None
88
88
  self.analysis_file: str | None = None
@@ -102,21 +102,21 @@ class CommandlineArgs:
102
102
  Returns:
103
103
  bool: True if they are all valid
104
104
  """
105
- # see if we have any aruments
105
+ # see if we have any arguments
106
106
  args = self.parser.parse_args()
107
107
 
108
108
  self.username = args.username
109
109
  self.password = args.password
110
110
  self.config_file = args.config_file
111
111
  # anything with a dash (in the args) is accessed with an underscore
112
- self.analysis_file = args.analyis_file
112
+ self.analysis_file = args.analysis_file
113
113
  self.host = args.host
114
114
 
115
115
  self.metadata_file = args.metadata_file
116
116
  self.skip = args.skip
117
117
  self.output_directory = args.output_directory
118
118
  self.environment_file = args.environment_file
119
- # no args check to see if they have them in the environmet
119
+ # no args check to see if they have them in the environment
120
120
 
121
121
  # if we have an environment file we'll want to load it before checking any defaults
122
122
  self.check_for_environment_config()
@@ -103,7 +103,7 @@ class EnvironmentServices:
103
103
  if raise_error_if_not_found:
104
104
  searched_paths = "\n".join(paths)
105
105
  raise RuntimeError(
106
- f"Failed to locate the moduel root: {MODULE_ROOT} in: \n {searched_paths}"
106
+ f"Failed to locate the module root: {MODULE_ROOT} in: \n {searched_paths}"
107
107
  )
108
108
 
109
109
  return None
@@ -1,4 +1,4 @@
1
1
  # Aplos NCA SaaS SDK Version File
2
2
  # This is automatically generated during the build process.
3
3
  # DO NOT UPDATE IT DIRECTLY. IT WILL BE OVERWRITTEN.
4
- __version__ = '0.0.15'
4
+ __version__ = '0.0.17'
@@ -1,18 +0,0 @@
1
- # Integration Test
2
-
3
- This module runs integration tests against a live environment. The goal is to catch anything before it's deployed.
4
- However you can also use this as a learning tool or a base on how to use our API's.
5
-
6
- ## Requirements
7
- The integration tests will require the following:
8
-
9
- ### Environment Vars
10
- |Variable Name|Description|
11
- |--|--|
12
- |APLOS_host|The full host name. e.g. app.aplos-nca.com|
13
-
14
-
15
- ### Users
16
- You will need valid user accounts with the appropriate permissions for the endpoints they are executing.
17
-
18
- If you are testing permission bounderies then you should set up multiple users with different permissions.
@@ -1,5 +0,0 @@
1
- """
2
- Copyright 2024-2025 Aplos Analytics
3
- All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
- Property of Aplos Analytics, Utah, USA
5
- """