|
| 1 | +# Functional Test Validation |
| 2 | +Currently, functional tests are validated using the changes captured on the RDB_MODERN database. This document provides instructions using the tools in this repository to capture the changes performed by MasterEtl on the legacy RDB database. These instructions assume your functional test files `query.sql` and `expected.json` enforce the functional test standards agreed upon by the team including the use of id fields (e.g., `local_id` or `act_uid`) and respective file syntax expected by `reporting-pipeline-service/src/test/java/gov/cdc/nbs/report/pipeline/integration/functional/DataDrivenFunctionalTests.java`. Additionally, `setup.sql` is expected to be completed, but may require changes based on your unique functional tests - <strong>those details are provided here</strong>. |
| 3 | + |
| 4 | +This documentation was produced as a deliverable for the Jira Ticket [APP-473](https://cdc-nbs.atlassian.net/browse/APP-473). |
| 5 | + |
| 6 | +## Process |
| 7 | +These instructions should be performed in the order displayed here. |
| 8 | + |
| 9 | +### 1) Prepare test SQL inputs |
| 10 | + |
| 11 | +1. Create temporary copies of `setup.sql`. |
| 12 | +2. Update all `last_chg_time` values to the current UTC timestamp using `GETDATE()`. |
| 13 | +3. (OPTIONAL) Increment all UIDs declared at the top of `setup.sql` by 1. This step will likely be needed if the instructions were not followed in order, requiring a <em>retry</em>. (ONLY FOR GENERATING DATA!). |
| 14 | + |
| 15 | +### 2) Prepare for tracing and execute SQL in sequence |
| 16 | +4. Run `trace_db_logical_changes.py` pointing to RDB. |
| 17 | +```shell |
| 18 | +python utilities/local-db-tracing/trace_db_logical_changes.py --database RDB --user sa --password PizzaIsGood33\! |
| 19 | +``` |
| 20 | +5. Using `sqlcmd`, execute the SQL files in the most logical order (e.g., first patient, then morbidity report). |
| 21 | +```shell |
| 22 | +sqlcmd -S localhost,3433 -U sa -P "PizzaIsGood33\!" -b -C -i <xxx-myFunctionalTestStep>/setup.sql |
| 23 | +``` |
| 24 | +### 3) Run MasterEtl and capture changes |
| 25 | +7. When the tracing program prompts you to press **ENTER**, run Master ETL. |
| 26 | +8. After MasterEtl has completed, press **ENTER** in the tracing program to capture changes. |
| 27 | +9. Fill in the prompts at your discretion. |
| 28 | +10. Review results in `logical_changes.md` or `logical_changes.json` to focus on relevant changes. |
| 29 | + |
| 30 | +### 4) Update validation artifacts |
| 31 | + |
| 32 | +11. Compare inserts of expected RDB tables to your `query.sql` and `expected.json` files. |
| 33 | + |
| 34 | + i. Ignore the timestamp differences as `GETDATE()` is only used for ensuring MasterEtl picks up the records. |
| 35 | + |
| 36 | + ii. If you modified the values of any ID fields in the copied `setup.sql` you can ignore those as well when comparing your existing validation to the changes. |
| 37 | + |
| 38 | + iii. Carefully review which tables are populated by MasterEtl and be sure to add entries to your validation files for any <em>missing</em> tables. |
| 39 | + |
| 40 | +### 5) Functional Tests |
| 41 | +Execute the functional tests and determine what modifications are needed! |
| 42 | + |
| 43 | +## Example Using Morbidity Report Functional Test Suite |
| 44 | +### Using setup.sql to Create Data on ODSE |
| 45 | +1. The existing `setup.sql` file was copied and all inserts for `last_chg_time` for all tables where updated to use `GETDATE()`. Consider the truncated example below. Note that there were files to copy/modify in this case for creating a patient and creating their morbidity report! |
| 46 | +```sql |
| 47 | +-- dbo.Entity_id (ORIGINAL) |
| 48 | +INSERT INTO [dbo].[entity_id] |
| 49 | + ([entity_uid], |
| 50 | + [entity_id_seq], |
| 51 | + [add_time], |
| 52 | + [assigning_authority_cd], |
| 53 | + [last_chg_time], |
| 54 | + ...) |
| 55 | +VALUES (@dbo_Entity_entity_uid, |
| 56 | + 1, |
| 57 | + N'2026-04-10T20:26:11.673', |
| 58 | + N'GA', |
| 59 | + N'2026-04-10T20:26:11.673', |
| 60 | + ... |
| 61 | +-- dbo.Entity_id (TEMP COPY) |
| 62 | +INSERT INTO [dbo].[entity_id] |
| 63 | + ([entity_uid], |
| 64 | + [entity_id_seq], |
| 65 | + [add_time], |
| 66 | + [assigning_authority_cd], |
| 67 | + [last_chg_time], |
| 68 | + ... |
| 69 | +VALUES (@dbo_Entity_entity_uid, |
| 70 | + 1, |
| 71 | + N'2026-04-23T22:34:46.000', |
| 72 | + N'GA', |
| 73 | + GETDATE(), |
| 74 | + ...) |
| 75 | +``` |
| 76 | +3. Example of incrementing the UIDs and Local ID (ONLY FOR GENERATING DATA!). <strong>You want to avoid this because it will require having to consider the UIDS in your original validation file which can become tedious so that you do not override them with the incremented ones</strong>. |
| 77 | +```sql |
| 78 | +-- ORIGINAL |
| 79 | +DECLARE @dbo_Entity_entity_uid bigint = 20100001 |
| 80 | +DECLARE @dbo_Postal_locator_postal_locator_uid bigint = 20100011 |
| 81 | +DECLARE @dbo_Tele_locator_tele_locator_uid bigint = 20100012 |
| 82 | +DECLARE @dbo_Act_act_uid bigint = 20100013 |
| 83 | +DECLARE @dbo_Act_act_uid_2 bigint = 20100014 |
| 84 | +DECLARE @dbo_Act_act_uid_3 bigint = 20100015 |
| 85 | +DECLARE @dbo_Act_act_uid_4 bigint = 20100016 |
| 86 | +DECLARE @dbo_Act_act_uid_5 bigint = 20100017 |
| 87 | +DECLARE @dbo_Act_act_uid_6 bigint = 20100018 |
| 88 | +... |
| 89 | +DECLARE @dbo_Act_act_uid_15 bigint = 20100027 |
| 90 | +DECLARE @dbo_Person_local_id nvarchar(40) = N'PSN20100000GA01' |
| 91 | +-- TEMP COPY |
| 92 | +DECLARE @dbo_Entity_entity_uid bigint = 20100002 |
| 93 | +DECLARE @dbo_Postal_locator_postal_locator_uid bigint = 20100012 |
| 94 | +DECLARE @dbo_Tele_locator_tele_locator_uid bigint = 20100013 |
| 95 | +DECLARE @dbo_Act_act_uid bigint = 20100028 |
| 96 | +DECLARE @dbo_Act_act_uid_2 bigint = 20100029 |
| 97 | +DECLARE @dbo_Act_act_uid_3 bigint = 20100030 |
| 98 | +DECLARE @dbo_Act_act_uid_4 bigint = 20100031 |
| 99 | +DECLARE @dbo_Act_act_uid_5 bigint = 20100032 |
| 100 | +DECLARE @dbo_Act_act_uid_6 bigint = 20100033 |
| 101 | +... |
| 102 | +DECLARE @dbo_Act_act_uid_15 bigint = 20100042 |
| 103 | +DECLARE @dbo_Person_local_id nvarchar(40) = N'PSN20100000GA02' |
| 104 | +``` |
| 105 | +4. `trace_db_logical_changes.py` was executed pointing to the RDB. |
| 106 | +```shell |
| 107 | +python utilities/local-db-tracing/trace_db_logical_changes.py --database RDB --user sa --password PizzaIsGood33\! |
| 108 | +``` |
| 109 | +5. The following commands were executed to first create the patient, then create their morbidity report: |
| 110 | +```shell |
| 111 | +sqlcmd -S localhost,3433 -U sa -P "PizzaIsGood33\!" -b -C -i 010-addPatient/setup.sql |
| 112 | +``` |
| 113 | +```shell |
| 114 | +sqlcmd -S localhost,3433 -U sa -P "PizzaIsGood33\!" -b -C -i 020-addMorbidityReport/setup.sql |
| 115 | +``` |
| 116 | +6. Press **ENTER** in the python tracing program... |
| 117 | +7. Review the results in `utilities/local-db-tracing/output/20260423-183127-RDB/logical-changes.md`. Sample below: |
| 118 | +## 113. INSERT dbo.MORBIDITY_REPORT |
| 119 | + |
| 120 | +| Metric | Value | |
| 121 | +| --- | --- | |
| 122 | +| Identity | business_keys: MORB_RPT_LOCAL_ID="OBS20100086GA01" | |
| 123 | +| Transaction end | 2026-04-23T22:22:34.720 | |
| 124 | +| LSN | 0x00006bf6000312400004 | |
| 125 | + |
| 126 | +### Inserted Row |
| 127 | + |
| 128 | +| Field | Value | |
| 129 | +| --- | --- | |
| 130 | +| DAYCARE_IND | "N" | |
| 131 | +| DIAGNOSIS_DT | "2026-04-05T00:00:00" | |
| 132 | +| DIE_FROM_ILLNESS_IND | "Y" | |
| 133 | +| ELECTRONIC_IND | "N" | |
| 134 | +| FOOD_HANDLER_IND | "N" | |
| 135 | +| HEALTHCARE_ORG_ASSOCIATE_IND | "UNK" | |
| 136 | +| HOSPITALIZED_IND | "Y" | |
| 137 | +| HSPTL_ADMISSION_DT | "2026-04-03T00:00:00" | |
| 138 | +| JURISDICTION_CD | "130001" | |
| 139 | +| JURISDICTION_NM | "Fulton County" | |
| 140 | +| MORB_RPT_CREATE_BY | 10009282 | |
| 141 | +| MORB_RPT_KEY | 3 | |
| 142 | +| MORB_RPT_LAST_UPDATE_BY | 10009282 | |
| 143 | +| MORB_RPT_LAST_UPDATE_DT | "2026-04-23T22:20:11.717" | |
| 144 | +| MORB_RPT_LOCAL_ID | "OBS20100086GA01" | |
| 145 | +| MORB_RPT_OID | 1300100009 | |
| 146 | +| MORB_RPT_OTHER_SPECIFY | "other something" | |
| 147 | +| MORB_RPT_SHARE_IND | "T" | |
| 148 | +| MORB_RPT_TYPE | "INIT" | |
| 149 | +| MORB_RPT_UID | 20100086 | |
| 150 | +| NURSING_HOME_ASSOCIATE_IND | "Y" | |
| 151 | +| PH_RECEIVE_DT | "2026-04-10T00:00:00" | |
| 152 | +| PREGNANT_IND | "Y" | |
| 153 | +| RDB_LAST_REFRESH_TIME | "2026-04-23T22:22:34.717" | |
| 154 | +| RECORD_STATUS_CD | "ACTIVE" | |
| 155 | +| SUSPECT_FOOD_WTRBORNE_ILLNESS | "N" | |
| 156 | + |
| 157 | +### Updating `query.sql` and `expected.json`. |
| 158 | +The existing files for this functional test suite were accurate based on MasterEtl's output with the exception of 1 table: `MORBIDITY_REPORT`. This table was missing completely from validation! To account for this the following was performed: |
| 159 | +1. A new entry added to `query.sql` to get the columns modified on the table. |
| 160 | +```sql |
| 161 | +... |
| 162 | +-- 5: MORBIDITY_REPORT |
| 163 | +SELECT |
| 164 | + [DAYCARE_IND], |
| 165 | + [DIAGNOSIS_DT], |
| 166 | + [DIE_FROM_ILLNESS_IND], |
| 167 | + [ELECTRONIC_IND], |
| 168 | + [FOOD_HANDLER_IND], |
| 169 | + [HEALTHCARE_ORG_ASSOCIATE_IND], |
| 170 | + [HOSPITALIZED_IND], |
| 171 | + [HSPTL_ADMISSION_DT], |
| 172 | + [JURISDICTION_CD], |
| 173 | + [JURISDICTION_NM], |
| 174 | + [MORB_RPT_CREATE_BY], |
| 175 | + [MORB_RPT_KEY], |
| 176 | + [MORB_RPT_LAST_UPDATE_BY], |
| 177 | + [MORB_RPT_LAST_UPDATE_DT], |
| 178 | + [MORB_RPT_LOCAL_ID], |
| 179 | + [MORB_RPT_OID], |
| 180 | + [MORB_RPT_OTHER_SPECIFY], |
| 181 | + [MORB_RPT_SHARE_IND], |
| 182 | + [MORB_RPT_TYPE], |
| 183 | + [MORB_RPT_UID], |
| 184 | + [NURSING_HOME_ASSOCIATE_IND], |
| 185 | + [PH_RECEIVE_DT], |
| 186 | + [PREGNANT_IND], |
| 187 | + [RDB_LAST_REFRESH_TIME], |
| 188 | + [RECORD_STATUS_CD], |
| 189 | + [SUSPECT_FOOD_WTRBORNE_ILLNESS] |
| 190 | +FROM [RDB_MODERN].[dbo].[MORBIDITY_REPORT] |
| 191 | +WHERE [MORB_RPT_LOCAL_ID] = 'OBS20100027GA01'; |
| 192 | +``` |
| 193 | +2. A new entry added to `expected.json`. |
| 194 | +```json |
| 195 | +... |
| 196 | +"5": [ |
| 197 | + { |
| 198 | + "DAYCARE_IND": "N", |
| 199 | + "DIAGNOSIS_DT": "2026-04-05T00:00:00.000", |
| 200 | + "DIE_FROM_ILLNESS_IND": "Y", |
| 201 | + "ELECTRONIC_IND": "N", |
| 202 | + "FOOD_HANDLER_IND": "N", |
| 203 | + "HEALTHCARE_ORG_ASSOCIATE_IND": "UNK", |
| 204 | + "HOSPITALIZED_IND": "Y", |
| 205 | + "HSPTL_ADMISSION_DT": "2026-04-03T00:00:00.000", |
| 206 | + "JURISDICTION_CD": "130001", |
| 207 | + "JURISDICTION_NM": "Fulton County", |
| 208 | + "MORB_RPT_CREATE_BY": 10009282, |
| 209 | + "MORB_RPT_LAST_UPDATE_BY": 10009282, |
| 210 | + "MORB_RPT_LAST_UPDATE_DT": "2026-04-10T20:26:11.853", |
| 211 | + "MORB_RPT_LOCAL_ID": "OBS20100027GA01", |
| 212 | + "MORB_RPT_OID": 1300100009, |
| 213 | + "MORB_RPT_OTHER_SPECIFY": "other something", |
| 214 | + "MORB_RPT_SHARE_IND": "T", |
| 215 | + "MORB_RPT_TYPE": "INIT", |
| 216 | + "MORB_RPT_UID": 20100027, |
| 217 | + "NURSING_HOME_ASSOCIATE_IND": "Y", |
| 218 | + "PH_RECEIVE_DT": "2026-04-10T00:00:00.000", |
| 219 | + "PREGNANT_IND": "Y", |
| 220 | + "RECORD_STATUS_CD": "ACTIVE", |
| 221 | + "SUSPECT_FOOD_WTRBORNE_ILLNESS": "N" |
| 222 | + } |
| 223 | + ] |
| 224 | +``` |
| 225 | +3. Execute the functional test suite! |
0 commit comments