@datarecce/ui 0.1.30 → 0.1.31

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 (549) hide show
  1. package/dist/api.d.mts +1 -1
  2. package/dist/api.d.ts +1 -1
  3. package/dist/components.d.mts +1 -1
  4. package/dist/components.d.ts +1 -1
  5. package/dist/hooks.d.mts +1 -1
  6. package/dist/hooks.d.ts +1 -1
  7. package/dist/{index-BNUP2V_N.d.ts → index-B9lSPJTi.d.ts} +184 -2
  8. package/dist/index-B9lSPJTi.d.ts.map +1 -0
  9. package/dist/{index-DOPZuhD8.d.mts → index-IIXVIoOL.d.mts} +253 -71
  10. package/dist/index-IIXVIoOL.d.mts.map +1 -0
  11. package/dist/index.d.mts +2 -2
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +8 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +3 -2
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/styles.css +4 -0
  18. package/dist/theme.d.mts +2 -185
  19. package/dist/theme.d.ts +2 -185
  20. package/dist/types.d.mts +1 -1
  21. package/dist/types.d.ts +1 -1
  22. package/package.json +4 -2
  23. package/recce-source/.editorconfig +26 -0
  24. package/recce-source/.flake8 +37 -0
  25. package/recce-source/.github/ISSUE_TEMPLATE/bug_report.yml +67 -0
  26. package/recce-source/.github/ISSUE_TEMPLATE/custom.md +10 -0
  27. package/recce-source/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
  28. package/recce-source/.github/PULL_REQUEST_TEMPLATE.md +21 -0
  29. package/recce-source/.github/copilot-instructions.md +331 -0
  30. package/recce-source/.github/instructions/backend-instructions.md +541 -0
  31. package/recce-source/.github/instructions/frontend-instructions.md +317 -0
  32. package/recce-source/.github/workflows/build-statics.yaml +72 -0
  33. package/recce-source/.github/workflows/bump.yaml +48 -0
  34. package/recce-source/.github/workflows/integration-tests-cloud.yaml +92 -0
  35. package/recce-source/.github/workflows/integration-tests-sqlmesh.yaml +33 -0
  36. package/recce-source/.github/workflows/integration-tests.yaml +52 -0
  37. package/recce-source/.github/workflows/nightly.yaml +246 -0
  38. package/recce-source/.github/workflows/release.yaml +196 -0
  39. package/recce-source/.github/workflows/tests-js.yaml +58 -0
  40. package/recce-source/.github/workflows/tests-python.yaml +128 -0
  41. package/recce-source/.pre-commit-config.yaml +26 -0
  42. package/recce-source/CLAUDE.md +483 -0
  43. package/recce-source/CODE_OF_CONDUCT.md +128 -0
  44. package/recce-source/CONTRIBUTING.md +107 -0
  45. package/recce-source/LICENSE +201 -0
  46. package/recce-source/Makefile +126 -0
  47. package/recce-source/README.md +182 -0
  48. package/recce-source/RECCE_CLOUD.md +81 -0
  49. package/recce-source/SECURITY.md +25 -0
  50. package/recce-source/docs/PACKAGING.md +340 -0
  51. package/recce-source/docs/README.md +1 -0
  52. package/recce-source/integration_tests/dbt/dbt_project.yml +26 -0
  53. package/recce-source/integration_tests/dbt/models/customers.sql +69 -0
  54. package/recce-source/integration_tests/dbt/models/docs.md +14 -0
  55. package/recce-source/integration_tests/dbt/models/orders.sql +56 -0
  56. package/recce-source/integration_tests/dbt/models/schema.yml +82 -0
  57. package/recce-source/integration_tests/dbt/models/staging/schema.yml +31 -0
  58. package/recce-source/integration_tests/dbt/models/staging/stg_customers.sql +22 -0
  59. package/recce-source/integration_tests/dbt/models/staging/stg_orders.sql +23 -0
  60. package/recce-source/integration_tests/dbt/models/staging/stg_payments.sql +25 -0
  61. package/recce-source/integration_tests/dbt/packages.yml +7 -0
  62. package/recce-source/integration_tests/dbt/profiles.yml +8 -0
  63. package/recce-source/integration_tests/dbt/seeds/raw_customers.csv +101 -0
  64. package/recce-source/integration_tests/dbt/seeds/raw_orders.csv +100 -0
  65. package/recce-source/integration_tests/dbt/seeds/raw_payments.csv +114 -0
  66. package/recce-source/integration_tests/dbt/seeds/raw_statuses.csv +5 -0
  67. package/recce-source/integration_tests/dbt/smoke_test.sh +72 -0
  68. package/recce-source/integration_tests/dbt/smoke_test_cloud.sh +71 -0
  69. package/recce-source/integration_tests/sqlmesh/__init__.py +0 -0
  70. package/recce-source/integration_tests/sqlmesh/audits/assert_item_price_above_zero.sql +9 -0
  71. package/recce-source/integration_tests/sqlmesh/audits/items.sql +7 -0
  72. package/recce-source/integration_tests/sqlmesh/audits/order_items.sql +7 -0
  73. package/recce-source/integration_tests/sqlmesh/config.py +171 -0
  74. package/recce-source/integration_tests/sqlmesh/helper.py +20 -0
  75. package/recce-source/integration_tests/sqlmesh/hooks/__init__.py +0 -0
  76. package/recce-source/integration_tests/sqlmesh/macros/__init__.py +0 -0
  77. package/recce-source/integration_tests/sqlmesh/macros/macros.py +8 -0
  78. package/recce-source/integration_tests/sqlmesh/macros/macros.sql +8 -0
  79. package/recce-source/integration_tests/sqlmesh/macros/utils.py +11 -0
  80. package/recce-source/integration_tests/sqlmesh/metrics/metrics.sql +25 -0
  81. package/recce-source/integration_tests/sqlmesh/models/customer_revenue_by_day.sql +41 -0
  82. package/recce-source/integration_tests/sqlmesh/models/customer_revenue_lifetime.sql +60 -0
  83. package/recce-source/integration_tests/sqlmesh/models/customers.sql +32 -0
  84. package/recce-source/integration_tests/sqlmesh/models/items.py +95 -0
  85. package/recce-source/integration_tests/sqlmesh/models/marketing.sql +15 -0
  86. package/recce-source/integration_tests/sqlmesh/models/order_items.py +95 -0
  87. package/recce-source/integration_tests/sqlmesh/models/orders.py +70 -0
  88. package/recce-source/integration_tests/sqlmesh/models/raw_marketing.py +62 -0
  89. package/recce-source/integration_tests/sqlmesh/models/top_waiters.sql +23 -0
  90. package/recce-source/integration_tests/sqlmesh/models/waiter_as_customer_by_day.sql +29 -0
  91. package/recce-source/integration_tests/sqlmesh/models/waiter_names.sql +10 -0
  92. package/recce-source/integration_tests/sqlmesh/models/waiter_revenue_by_day.sql +29 -0
  93. package/recce-source/integration_tests/sqlmesh/models/waiters.py +62 -0
  94. package/recce-source/integration_tests/sqlmesh/prep_env.sh +16 -0
  95. package/recce-source/integration_tests/sqlmesh/schema.yaml +5 -0
  96. package/recce-source/integration_tests/sqlmesh/seeds/waiter_names.csv +11 -0
  97. package/recce-source/integration_tests/sqlmesh/test_server.sh +29 -0
  98. package/recce-source/integration_tests/sqlmesh/tests/test_customer_revenue_by_day.yaml +63 -0
  99. package/recce-source/integration_tests/sqlmesh/tests/test_order_items.yaml +72 -0
  100. package/recce-source/js/.editorconfig +27 -0
  101. package/recce-source/js/.env.development +5 -0
  102. package/recce-source/js/.husky/pre-commit +29 -0
  103. package/recce-source/js/.nvmrc +1 -0
  104. package/recce-source/js/README.md +39 -0
  105. package/recce-source/js/app/(mainComponents)/DisplayModeToggle.tsx +65 -0
  106. package/recce-source/js/app/(mainComponents)/NavBar.tsx +228 -0
  107. package/recce-source/js/app/(mainComponents)/RecceVersionBadge.tsx +107 -0
  108. package/recce-source/js/app/(mainComponents)/TopBar.tsx +252 -0
  109. package/recce-source/js/app/@lineage/default.tsx +20 -0
  110. package/recce-source/js/app/@lineage/page.tsx +14 -0
  111. package/recce-source/js/app/MainLayout.tsx +170 -0
  112. package/recce-source/js/app/Providers.tsx +49 -0
  113. package/recce-source/js/app/checks/page.tsx +296 -0
  114. package/recce-source/js/app/error.tsx +93 -0
  115. package/recce-source/js/app/favicon.ico +0 -0
  116. package/recce-source/js/app/global-error.tsx +115 -0
  117. package/recce-source/js/app/global.css +82 -0
  118. package/recce-source/js/app/layout.tsx +48 -0
  119. package/recce-source/js/app/lineage/page.tsx +15 -0
  120. package/recce-source/js/app/page.tsx +12 -0
  121. package/recce-source/js/app/query/page.tsx +8 -0
  122. package/recce-source/js/biome.json +313 -0
  123. package/recce-source/js/jest.config.js +34 -0
  124. package/recce-source/js/jest.globals.d.ts +32 -0
  125. package/recce-source/js/jest.setup.js +91 -0
  126. package/recce-source/js/next.config.js +16 -0
  127. package/recce-source/js/package-lock.json +13843 -0
  128. package/recce-source/js/package.json +123 -0
  129. package/recce-source/js/pnpm-lock.yaml +9235 -0
  130. package/recce-source/js/pnpm-workspace.yaml +6 -0
  131. package/recce-source/js/postcss.config.js +5 -0
  132. package/recce-source/js/public/auth_callback.html +68 -0
  133. package/recce-source/js/public/imgs/feedback/thumbs-down.png +0 -0
  134. package/recce-source/js/public/imgs/feedback/thumbs-up.png +0 -0
  135. package/recce-source/js/public/imgs/reload-image.svg +4 -0
  136. package/recce-source/js/public/logo/recce-logo-white.png +0 -0
  137. package/recce-source/js/src/components/AuthModal/AuthModal.tsx +202 -0
  138. package/recce-source/js/src/components/app/AvatarDropdown.tsx +159 -0
  139. package/recce-source/js/src/components/app/EnvInfo.tsx +357 -0
  140. package/recce-source/js/src/components/app/Filename.tsx +388 -0
  141. package/recce-source/js/src/components/app/SetupConnectionPopover.tsx +91 -0
  142. package/recce-source/js/src/components/app/StateExporter.tsx +57 -0
  143. package/recce-source/js/src/components/app/StateImporter.tsx +198 -0
  144. package/recce-source/js/src/components/app/StateSharing.tsx +145 -0
  145. package/recce-source/js/src/components/app/StateSynchronizer.tsx +205 -0
  146. package/recce-source/js/src/components/charts/HistogramChart.tsx +291 -0
  147. package/recce-source/js/src/components/charts/SquareIcon.tsx +51 -0
  148. package/recce-source/js/src/components/charts/TopKSummaryList.tsx +457 -0
  149. package/recce-source/js/src/components/charts/chartTheme.ts +74 -0
  150. package/recce-source/js/src/components/check/CheckBreadcrumb.tsx +97 -0
  151. package/recce-source/js/src/components/check/CheckDescription.tsx +134 -0
  152. package/recce-source/js/src/components/check/CheckDetail.tsx +797 -0
  153. package/recce-source/js/src/components/check/CheckEmptyState.tsx +84 -0
  154. package/recce-source/js/src/components/check/CheckList.tsx +320 -0
  155. package/recce-source/js/src/components/check/LineageDiffView.tsx +32 -0
  156. package/recce-source/js/src/components/check/PresetCheckTemplateView.tsx +48 -0
  157. package/recce-source/js/src/components/check/SchemaDiffView.tsx +290 -0
  158. package/recce-source/js/src/components/check/check.ts +25 -0
  159. package/recce-source/js/src/components/check/timeline/CheckTimeline.tsx +163 -0
  160. package/recce-source/js/src/components/check/timeline/CommentInput.tsx +84 -0
  161. package/recce-source/js/src/components/check/timeline/TimelineEvent.tsx +468 -0
  162. package/recce-source/js/src/components/check/timeline/index.ts +12 -0
  163. package/recce-source/js/src/components/check/utils.ts +12 -0
  164. package/recce-source/js/src/components/data-grid/ScreenshotDataGrid.tsx +333 -0
  165. package/recce-source/js/src/components/data-grid/agGridStyles.css +55 -0
  166. package/recce-source/js/src/components/data-grid/agGridTheme.ts +43 -0
  167. package/recce-source/js/src/components/editor/CodeEditor.tsx +107 -0
  168. package/recce-source/js/src/components/editor/DiffEditor.tsx +162 -0
  169. package/recce-source/js/src/components/editor/index.ts +12 -0
  170. package/recce-source/js/src/components/errorboundary/ErrorBoundary.tsx +87 -0
  171. package/recce-source/js/src/components/histogram/HistogramDiffForm.tsx +147 -0
  172. package/recce-source/js/src/components/histogram/HistogramDiffResultView.tsx +63 -0
  173. package/recce-source/js/src/components/icons/index.tsx +142 -0
  174. package/recce-source/js/src/components/lineage/ActionControl.tsx +63 -0
  175. package/recce-source/js/src/components/lineage/ActionTag.tsx +141 -0
  176. package/recce-source/js/src/components/lineage/ChangeStatusLegend.tsx +46 -0
  177. package/recce-source/js/src/components/lineage/ColumnLevelLineageControl.tsx +327 -0
  178. package/recce-source/js/src/components/lineage/ColumnLevelLineageLegend.tsx +57 -0
  179. package/recce-source/js/src/components/lineage/GraphColumnNode.tsx +199 -0
  180. package/recce-source/js/src/components/lineage/GraphEdge.tsx +59 -0
  181. package/recce-source/js/src/components/lineage/GraphNode.tsx +555 -0
  182. package/recce-source/js/src/components/lineage/LineagePage.tsx +10 -0
  183. package/recce-source/js/src/components/lineage/LineageView.tsx +1384 -0
  184. package/recce-source/js/src/components/lineage/LineageViewContext.tsx +86 -0
  185. package/recce-source/js/src/components/lineage/LineageViewContextMenu.tsx +637 -0
  186. package/recce-source/js/src/components/lineage/LineageViewNotification.tsx +64 -0
  187. package/recce-source/js/src/components/lineage/LineageViewTopBar.tsx +596 -0
  188. package/recce-source/js/src/components/lineage/NodeSqlView.tsx +136 -0
  189. package/recce-source/js/src/components/lineage/NodeTag.tsx +278 -0
  190. package/recce-source/js/src/components/lineage/NodeView.tsx +642 -0
  191. package/recce-source/js/src/components/lineage/SandboxView.tsx +436 -0
  192. package/recce-source/js/src/components/lineage/ServerDisconnectedModalContent.tsx +105 -0
  193. package/recce-source/js/src/components/lineage/SetupConnectionBanner.tsx +52 -0
  194. package/recce-source/js/src/components/lineage/SingleEnvironmentQueryView.tsx +152 -0
  195. package/recce-source/js/src/components/lineage/graph.test.ts +31 -0
  196. package/recce-source/js/src/components/lineage/graph.ts +58 -0
  197. package/recce-source/js/src/components/lineage/lineage.test.ts +169 -0
  198. package/recce-source/js/src/components/lineage/lineage.ts +521 -0
  199. package/recce-source/js/src/components/lineage/styles.css +42 -0
  200. package/recce-source/js/src/components/lineage/styles.tsx +165 -0
  201. package/recce-source/js/src/components/lineage/useMultiNodesAction.ts +352 -0
  202. package/recce-source/js/src/components/lineage/useValueDiffAlertDialog.tsx +108 -0
  203. package/recce-source/js/src/components/onboarding-guide/Notification.tsx +62 -0
  204. package/recce-source/js/src/components/profile/ProfileDiffForm.tsx +134 -0
  205. package/recce-source/js/src/components/profile/ProfileDiffResultView.tsx +245 -0
  206. package/recce-source/js/src/components/query/ChangedOnlyCheckbox.tsx +29 -0
  207. package/recce-source/js/src/components/query/DiffText.tsx +120 -0
  208. package/recce-source/js/src/components/query/QueryDiffResultView.tsx +470 -0
  209. package/recce-source/js/src/components/query/QueryForm.tsx +80 -0
  210. package/recce-source/js/src/components/query/QueryPage.tsx +282 -0
  211. package/recce-source/js/src/components/query/QueryResultView.tsx +180 -0
  212. package/recce-source/js/src/components/query/SetupConnectionGuide.tsx +57 -0
  213. package/recce-source/js/src/components/query/SqlEditor.tsx +245 -0
  214. package/recce-source/js/src/components/query/ToggleSwitch.tsx +84 -0
  215. package/recce-source/js/src/components/query/styles.css +21 -0
  216. package/recce-source/js/src/components/routing/DirectUrlAccess.test.tsx +428 -0
  217. package/recce-source/js/src/components/routing/LineageStatePreservation.test.tsx +311 -0
  218. package/recce-source/js/src/components/routing/Navigation.test.tsx +256 -0
  219. package/recce-source/js/src/components/rowcount/RowCountDiffResultView.tsx +109 -0
  220. package/recce-source/js/src/components/rowcount/delta.ts +11 -0
  221. package/recce-source/js/src/components/run/RunList.tsx +303 -0
  222. package/recce-source/js/src/components/run/RunModal.tsx +191 -0
  223. package/recce-source/js/src/components/run/RunPage.tsx +26 -0
  224. package/recce-source/js/src/components/run/RunResultPane.tsx +454 -0
  225. package/recce-source/js/src/components/run/RunStatusAndDate.tsx +106 -0
  226. package/recce-source/js/src/components/run/RunToolbar.tsx +70 -0
  227. package/recce-source/js/src/components/run/RunView.tsx +196 -0
  228. package/recce-source/js/src/components/run/registry.ts +214 -0
  229. package/recce-source/js/src/components/run/types.ts +14 -0
  230. package/recce-source/js/src/components/schema/ColumnNameCell.test.tsx +169 -0
  231. package/recce-source/js/src/components/schema/ColumnNameCell.tsx +198 -0
  232. package/recce-source/js/src/components/schema/SchemaView.tsx +337 -0
  233. package/recce-source/js/src/components/schema/schemaDiff.ts +32 -0
  234. package/recce-source/js/src/components/schema/style.css +134 -0
  235. package/recce-source/js/src/components/screenshot/ScreenshotBox.tsx +39 -0
  236. package/recce-source/js/src/components/shared/HistoryToggle.tsx +35 -0
  237. package/recce-source/js/src/components/split/Split.tsx +40 -0
  238. package/recce-source/js/src/components/split/styles.css +24 -0
  239. package/recce-source/js/src/components/summary/ChangeSummary.tsx +264 -0
  240. package/recce-source/js/src/components/summary/SchemaSummary.tsx +123 -0
  241. package/recce-source/js/src/components/summary/SummaryView.tsx +29 -0
  242. package/recce-source/js/src/components/timeout/IdleTimeoutBadge.tsx +48 -0
  243. package/recce-source/js/src/components/top-k/TopKDiffForm.tsx +58 -0
  244. package/recce-source/js/src/components/top-k/TopKDiffResultView.tsx +73 -0
  245. package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnGroupHeader.tsx +228 -0
  246. package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnHeader.tsx +113 -0
  247. package/recce-source/js/src/components/ui/dataGrid/defaultRenderCell.tsx +72 -0
  248. package/recce-source/js/src/components/ui/dataGrid/index.ts +23 -0
  249. package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.test.tsx +607 -0
  250. package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.tsx +211 -0
  251. package/recce-source/js/src/components/ui/dataGrid/schemaCells.test.tsx +452 -0
  252. package/recce-source/js/src/components/ui/dataGrid/schemaCells.tsx +142 -0
  253. package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.test.tsx +178 -0
  254. package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.tsx +275 -0
  255. package/recce-source/js/src/components/ui/markdown/ExternalLinkConfirmDialog.tsx +134 -0
  256. package/recce-source/js/src/components/ui/markdown/MarkdownContent.tsx +364 -0
  257. package/recce-source/js/src/components/ui/mui/index.ts +13 -0
  258. package/recce-source/js/src/components/ui/mui-provider.tsx +67 -0
  259. package/recce-source/js/src/components/ui/mui-theme.ts +1039 -0
  260. package/recce-source/js/src/components/ui/mui-utils.ts +113 -0
  261. package/recce-source/js/src/components/ui/toaster.tsx +288 -0
  262. package/recce-source/js/src/components/valuediff/ValueDiffDetailResultView.tsx +217 -0
  263. package/recce-source/js/src/components/valuediff/ValueDiffForm.tsx +246 -0
  264. package/recce-source/js/src/components/valuediff/ValueDiffResultView.tsx +82 -0
  265. package/recce-source/js/src/components/valuediff/shared.ts +33 -0
  266. package/recce-source/js/src/constants/tooltipMessage.ts +3 -0
  267. package/recce-source/js/src/constants/urls.ts +1 -0
  268. package/recce-source/js/src/lib/UrlHash.ts +12 -0
  269. package/recce-source/js/src/lib/api/adhocQuery.ts +70 -0
  270. package/recce-source/js/src/lib/api/axiosClient.ts +9 -0
  271. package/recce-source/js/src/lib/api/cacheKeys.ts +13 -0
  272. package/recce-source/js/src/lib/api/checkEvents.ts +252 -0
  273. package/recce-source/js/src/lib/api/checks.ts +129 -0
  274. package/recce-source/js/src/lib/api/cll.ts +53 -0
  275. package/recce-source/js/src/lib/api/connectToCloud.ts +13 -0
  276. package/recce-source/js/src/lib/api/flag.ts +37 -0
  277. package/recce-source/js/src/lib/api/info.ts +198 -0
  278. package/recce-source/js/src/lib/api/instanceInfo.ts +25 -0
  279. package/recce-source/js/src/lib/api/keepAlive.ts +108 -0
  280. package/recce-source/js/src/lib/api/lineagecheck.ts +35 -0
  281. package/recce-source/js/src/lib/api/localStorageKeys.ts +7 -0
  282. package/recce-source/js/src/lib/api/models.ts +59 -0
  283. package/recce-source/js/src/lib/api/profile.ts +65 -0
  284. package/recce-source/js/src/lib/api/rowcount.ts +19 -0
  285. package/recce-source/js/src/lib/api/runs.ts +174 -0
  286. package/recce-source/js/src/lib/api/schemacheck.ts +31 -0
  287. package/recce-source/js/src/lib/api/select.ts +25 -0
  288. package/recce-source/js/src/lib/api/sessionStorageKeys.ts +8 -0
  289. package/recce-source/js/src/lib/api/state.ts +117 -0
  290. package/recce-source/js/src/lib/api/track.ts +281 -0
  291. package/recce-source/js/src/lib/api/types.ts +284 -0
  292. package/recce-source/js/src/lib/api/user.ts +42 -0
  293. package/recce-source/js/src/lib/api/valuediff.ts +46 -0
  294. package/recce-source/js/src/lib/api/version.ts +40 -0
  295. package/recce-source/js/src/lib/const.ts +9 -0
  296. package/recce-source/js/src/lib/dataGrid/crossFunctionConsistency.test.ts +626 -0
  297. package/recce-source/js/src/lib/dataGrid/dataGridFactory.test.ts +2140 -0
  298. package/recce-source/js/src/lib/dataGrid/dataGridFactory.ts +397 -0
  299. package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.test.ts +132 -0
  300. package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.ts +126 -0
  301. package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.test.ts +1627 -0
  302. package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.ts +140 -0
  303. package/recce-source/js/src/lib/dataGrid/generators/toDataGrid.ts +67 -0
  304. package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.test.ts +142 -0
  305. package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.ts +71 -0
  306. package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.test.ts +258 -0
  307. package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.ts +153 -0
  308. package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.test.ts +951 -0
  309. package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.ts +221 -0
  310. package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.test.ts +395 -0
  311. package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.ts +184 -0
  312. package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.test.ts +884 -0
  313. package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.ts +113 -0
  314. package/recce-source/js/src/lib/dataGrid/index.ts +51 -0
  315. package/recce-source/js/src/lib/dataGrid/propertyBased.test.ts +858 -0
  316. package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.test.ts +482 -0
  317. package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.ts +345 -0
  318. package/recce-source/js/src/lib/dataGrid/shared/dataTypeEdgeCases.test.ts +698 -0
  319. package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.test.tsx +820 -0
  320. package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.tsx +277 -0
  321. package/recce-source/js/src/lib/dataGrid/shared/gridUtils.test.ts +785 -0
  322. package/recce-source/js/src/lib/dataGrid/shared/gridUtils.ts +370 -0
  323. package/recce-source/js/src/lib/dataGrid/shared/index.ts +81 -0
  324. package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.test.ts +909 -0
  325. package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.ts +325 -0
  326. package/recce-source/js/src/lib/dataGrid/shared/simpleColumnBuilder.tsx +240 -0
  327. package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.test.tsx +719 -0
  328. package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.tsx +231 -0
  329. package/recce-source/js/src/lib/dataGrid/shared/validation.test.ts +559 -0
  330. package/recce-source/js/src/lib/dataGrid/shared/validation.ts +367 -0
  331. package/recce-source/js/src/lib/dataGrid/warehouseNamingConventions.test.ts +1117 -0
  332. package/recce-source/js/src/lib/formatSelect.ts +50 -0
  333. package/recce-source/js/src/lib/hooks/ApiConfigContext.tsx +181 -0
  334. package/recce-source/js/src/lib/hooks/IdleTimeoutContext.tsx +177 -0
  335. package/recce-source/js/src/lib/hooks/LineageGraphContext.tsx +512 -0
  336. package/recce-source/js/src/lib/hooks/RecceActionContext.tsx +269 -0
  337. package/recce-source/js/src/lib/hooks/RecceCheckContext.tsx +33 -0
  338. package/recce-source/js/src/lib/hooks/RecceContextProvider.tsx +54 -0
  339. package/recce-source/js/src/lib/hooks/RecceInstanceContext.tsx +129 -0
  340. package/recce-source/js/src/lib/hooks/RecceQueryContext.tsx +98 -0
  341. package/recce-source/js/src/lib/hooks/RecceShareStateContext.tsx +59 -0
  342. package/recce-source/js/src/lib/hooks/ScreenShot.tsx +399 -0
  343. package/recce-source/js/src/lib/hooks/useAppRouter.test.ts +211 -0
  344. package/recce-source/js/src/lib/hooks/useAppRouter.ts +200 -0
  345. package/recce-source/js/src/lib/hooks/useCheckEvents.ts +99 -0
  346. package/recce-source/js/src/lib/hooks/useCheckToast.tsx +14 -0
  347. package/recce-source/js/src/lib/hooks/useClipBoardToast.tsx +27 -0
  348. package/recce-source/js/src/lib/hooks/useCountdownToast.tsx +102 -0
  349. package/recce-source/js/src/lib/hooks/useFeedbackCollectionToast.tsx +130 -0
  350. package/recce-source/js/src/lib/hooks/useGuideToast.tsx +45 -0
  351. package/recce-source/js/src/lib/hooks/useIdleDetection.tsx +185 -0
  352. package/recce-source/js/src/lib/hooks/useModelColumns.tsx +113 -0
  353. package/recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx +13 -0
  354. package/recce-source/js/src/lib/hooks/useRecceServerFlag.tsx +13 -0
  355. package/recce-source/js/src/lib/hooks/useRun.tsx +89 -0
  356. package/recce-source/js/src/lib/hooks/useThemeColors.ts +115 -0
  357. package/recce-source/js/src/lib/mergeKeys.test.ts +89 -0
  358. package/recce-source/js/src/lib/mergeKeys.ts +86 -0
  359. package/recce-source/js/src/lib/result/ResultErrorFallback.tsx +9 -0
  360. package/recce-source/js/src/lib/utils/formatTime.ts +84 -0
  361. package/recce-source/js/src/lib/utils/urls.ts +16 -0
  362. package/recce-source/js/src/utils/DropdownValuesInput.tsx +297 -0
  363. package/recce-source/js/src/utils/formatters.tsx +237 -0
  364. package/recce-source/js/src/utils/transforms.ts +81 -0
  365. package/recce-source/js/tsconfig.json +47 -0
  366. package/recce-source/macros/README.md +8 -0
  367. package/recce-source/macros/recce_athena.sql +73 -0
  368. package/recce-source/pyproject.toml +109 -0
  369. package/recce-source/recce/VERSION +1 -0
  370. package/recce-source/recce/__init__.py +84 -0
  371. package/recce-source/recce/adapter/__init__.py +0 -0
  372. package/recce-source/recce/adapter/base.py +109 -0
  373. package/recce-source/recce/adapter/dbt_adapter/__init__.py +1699 -0
  374. package/recce-source/recce/adapter/dbt_adapter/dbt_version.py +42 -0
  375. package/recce-source/recce/adapter/sqlmesh_adapter.py +141 -0
  376. package/recce-source/recce/apis/__init__.py +0 -0
  377. package/recce-source/recce/apis/check_api.py +203 -0
  378. package/recce-source/recce/apis/check_events_api.py +353 -0
  379. package/recce-source/recce/apis/check_func.py +130 -0
  380. package/recce-source/recce/apis/run_api.py +130 -0
  381. package/recce-source/recce/apis/run_func.py +258 -0
  382. package/recce-source/recce/artifact.py +266 -0
  383. package/recce-source/recce/cli.py +1846 -0
  384. package/recce-source/recce/config.py +127 -0
  385. package/recce-source/recce/connect_to_cloud.py +138 -0
  386. package/recce-source/recce/core.py +334 -0
  387. package/recce-source/recce/diff.py +26 -0
  388. package/recce-source/recce/event/CONFIG +1 -0
  389. package/recce-source/recce/event/SENTRY_DNS +1 -0
  390. package/recce-source/recce/event/__init__.py +304 -0
  391. package/recce-source/recce/event/collector.py +184 -0
  392. package/recce-source/recce/event/track.py +158 -0
  393. package/recce-source/recce/exceptions.py +21 -0
  394. package/recce-source/recce/git.py +77 -0
  395. package/recce-source/recce/github.py +222 -0
  396. package/recce-source/recce/mcp_server.py +861 -0
  397. package/recce-source/recce/models/__init__.py +6 -0
  398. package/recce-source/recce/models/check.py +473 -0
  399. package/recce-source/recce/models/run.py +46 -0
  400. package/recce-source/recce/models/types.py +218 -0
  401. package/recce-source/recce/pull_request.py +124 -0
  402. package/recce-source/recce/run.py +390 -0
  403. package/recce-source/recce/server.py +877 -0
  404. package/recce-source/recce/state/__init__.py +31 -0
  405. package/recce-source/recce/state/cloud.py +644 -0
  406. package/recce-source/recce/state/const.py +26 -0
  407. package/recce-source/recce/state/local.py +56 -0
  408. package/recce-source/recce/state/state.py +119 -0
  409. package/recce-source/recce/state/state_loader.py +174 -0
  410. package/recce-source/recce/summary.py +575 -0
  411. package/recce-source/recce/tasks/__init__.py +23 -0
  412. package/recce-source/recce/tasks/core.py +134 -0
  413. package/recce-source/recce/tasks/dataframe.py +170 -0
  414. package/recce-source/recce/tasks/histogram.py +433 -0
  415. package/recce-source/recce/tasks/lineage.py +19 -0
  416. package/recce-source/recce/tasks/profile.py +298 -0
  417. package/recce-source/recce/tasks/query.py +450 -0
  418. package/recce-source/recce/tasks/rowcount.py +277 -0
  419. package/recce-source/recce/tasks/schema.py +65 -0
  420. package/recce-source/recce/tasks/top_k.py +172 -0
  421. package/recce-source/recce/tasks/utils.py +147 -0
  422. package/recce-source/recce/tasks/valuediff.py +497 -0
  423. package/recce-source/recce/util/__init__.py +4 -0
  424. package/recce-source/recce/util/api_token.py +80 -0
  425. package/recce-source/recce/util/breaking.py +330 -0
  426. package/recce-source/recce/util/cache.py +25 -0
  427. package/recce-source/recce/util/cll.py +355 -0
  428. package/recce-source/recce/util/cloud/__init__.py +15 -0
  429. package/recce-source/recce/util/cloud/base.py +115 -0
  430. package/recce-source/recce/util/cloud/check_events.py +190 -0
  431. package/recce-source/recce/util/cloud/checks.py +242 -0
  432. package/recce-source/recce/util/io.py +120 -0
  433. package/recce-source/recce/util/lineage.py +83 -0
  434. package/recce-source/recce/util/logger.py +25 -0
  435. package/recce-source/recce/util/onboarding_state.py +45 -0
  436. package/recce-source/recce/util/perf_tracking.py +85 -0
  437. package/recce-source/recce/util/pydantic_model.py +22 -0
  438. package/recce-source/recce/util/recce_cloud.py +454 -0
  439. package/recce-source/recce/util/singleton.py +18 -0
  440. package/recce-source/recce/util/startup_perf.py +121 -0
  441. package/recce-source/recce/yaml/__init__.py +58 -0
  442. package/recce-source/recce_cloud/README.md +780 -0
  443. package/recce-source/recce_cloud/VERSION +1 -0
  444. package/recce-source/recce_cloud/__init__.py +24 -0
  445. package/recce-source/recce_cloud/api/__init__.py +17 -0
  446. package/recce-source/recce_cloud/api/base.py +132 -0
  447. package/recce-source/recce_cloud/api/client.py +186 -0
  448. package/recce-source/recce_cloud/api/exceptions.py +26 -0
  449. package/recce-source/recce_cloud/api/factory.py +63 -0
  450. package/recce-source/recce_cloud/api/github.py +106 -0
  451. package/recce-source/recce_cloud/api/gitlab.py +111 -0
  452. package/recce-source/recce_cloud/artifact.py +57 -0
  453. package/recce-source/recce_cloud/ci_providers/__init__.py +9 -0
  454. package/recce-source/recce_cloud/ci_providers/base.py +82 -0
  455. package/recce-source/recce_cloud/ci_providers/detector.py +147 -0
  456. package/recce-source/recce_cloud/ci_providers/github_actions.py +136 -0
  457. package/recce-source/recce_cloud/ci_providers/gitlab_ci.py +130 -0
  458. package/recce-source/recce_cloud/cli.py +434 -0
  459. package/recce-source/recce_cloud/download.py +230 -0
  460. package/recce-source/recce_cloud/hatch_build.py +20 -0
  461. package/recce-source/recce_cloud/pyproject.toml +49 -0
  462. package/recce-source/recce_cloud/upload.py +214 -0
  463. package/recce-source/test.py +0 -0
  464. package/recce-source/tests/__init__.py +0 -0
  465. package/recce-source/tests/adapter/__init__.py +0 -0
  466. package/recce-source/tests/adapter/dbt_adapter/__init__.py +0 -0
  467. package/recce-source/tests/adapter/dbt_adapter/conftest.py +17 -0
  468. package/recce-source/tests/adapter/dbt_adapter/dbt_test_helper.py +298 -0
  469. package/recce-source/tests/adapter/dbt_adapter/test_dbt_adapter.py +25 -0
  470. package/recce-source/tests/adapter/dbt_adapter/test_dbt_cll.py +717 -0
  471. package/recce-source/tests/adapter/dbt_adapter/test_proj/dbt_project.yml +4 -0
  472. package/recce-source/tests/adapter/dbt_adapter/test_proj/manifest.json +1 -0
  473. package/recce-source/tests/adapter/dbt_adapter/test_proj/package-lock.yml +8 -0
  474. package/recce-source/tests/adapter/dbt_adapter/test_proj/packages.yml +7 -0
  475. package/recce-source/tests/adapter/dbt_adapter/test_proj/profiles.yml +6 -0
  476. package/recce-source/tests/adapter/dbt_adapter/test_selector.py +205 -0
  477. package/recce-source/tests/apis/__init__.py +0 -0
  478. package/recce-source/tests/apis/row_count_diff.json +59 -0
  479. package/recce-source/tests/apis/test_check_events_api.py +615 -0
  480. package/recce-source/tests/apis/test_run_func.py +433 -0
  481. package/recce-source/tests/catalog.json +527 -0
  482. package/recce-source/tests/data/manifest/base/catalog.json +1 -0
  483. package/recce-source/tests/data/manifest/base/manifest.json +1 -0
  484. package/recce-source/tests/data/manifest/pr2/catalog.json +1 -0
  485. package/recce-source/tests/data/manifest/pr2/manifest.json +1 -0
  486. package/recce-source/tests/manifest.json +10655 -0
  487. package/recce-source/tests/models/__init__.py +0 -0
  488. package/recce-source/tests/models/test_check.py +731 -0
  489. package/recce-source/tests/models/test_run_models.py +295 -0
  490. package/recce-source/tests/recce_cloud/__init__.py +0 -0
  491. package/recce-source/tests/recce_cloud/test_ci_providers.py +351 -0
  492. package/recce-source/tests/recce_cloud/test_cli.py +735 -0
  493. package/recce-source/tests/recce_cloud/test_client.py +379 -0
  494. package/recce-source/tests/recce_cloud/test_platform_clients.py +483 -0
  495. package/recce-source/tests/recce_state.json +1 -0
  496. package/recce-source/tests/state/test_cloud.py +719 -0
  497. package/recce-source/tests/state/test_local.py +164 -0
  498. package/recce-source/tests/state/test_state_loader.py +211 -0
  499. package/recce-source/tests/tasks/__init__.py +0 -0
  500. package/recce-source/tests/tasks/conftest.py +4 -0
  501. package/recce-source/tests/tasks/test_histogram.py +129 -0
  502. package/recce-source/tests/tasks/test_lineage.py +55 -0
  503. package/recce-source/tests/tasks/test_preset_checks.py +64 -0
  504. package/recce-source/tests/tasks/test_profile.py +397 -0
  505. package/recce-source/tests/tasks/test_query.py +528 -0
  506. package/recce-source/tests/tasks/test_row_count.py +133 -0
  507. package/recce-source/tests/tasks/test_schema.py +122 -0
  508. package/recce-source/tests/tasks/test_top_k.py +77 -0
  509. package/recce-source/tests/tasks/test_utils.py +439 -0
  510. package/recce-source/tests/tasks/test_valuediff.py +361 -0
  511. package/recce-source/tests/test_cli.py +236 -0
  512. package/recce-source/tests/test_cli_mcp_optional.py +45 -0
  513. package/recce-source/tests/test_cloud_listing_cli.py +324 -0
  514. package/recce-source/tests/test_config.py +43 -0
  515. package/recce-source/tests/test_connect_to_cloud.py +82 -0
  516. package/recce-source/tests/test_core.py +174 -0
  517. package/recce-source/tests/test_dbt.py +36 -0
  518. package/recce-source/tests/test_mcp_server.py +505 -0
  519. package/recce-source/tests/test_pull_request.py +130 -0
  520. package/recce-source/tests/test_server.py +202 -0
  521. package/recce-source/tests/test_server_lifespan.py +138 -0
  522. package/recce-source/tests/test_summary.py +73 -0
  523. package/recce-source/tests/util/__init__.py +0 -0
  524. package/recce-source/tests/util/cloud/__init__.py +0 -0
  525. package/recce-source/tests/util/cloud/test_check_events.py +255 -0
  526. package/recce-source/tests/util/cloud/test_checks.py +204 -0
  527. package/recce-source/tests/util/test_api_token.py +119 -0
  528. package/recce-source/tests/util/test_breaking.py +1427 -0
  529. package/recce-source/tests/util/test_cll.py +706 -0
  530. package/recce-source/tests/util/test_lineage.py +122 -0
  531. package/recce-source/tests/util/test_onboarding_state.py +84 -0
  532. package/recce-source/tests/util/test_recce_cloud.py +231 -0
  533. package/recce-source/tox.ini +40 -0
  534. package/recce-source/uv.lock +3928 -0
  535. package/src/api/index.ts +32 -0
  536. package/src/components/index.ts +154 -0
  537. package/src/global.d.ts +14 -0
  538. package/src/hooks/index.ts +56 -0
  539. package/src/index.ts +17 -0
  540. package/src/lib/hooks/RouteConfigContext.ts +139 -0
  541. package/src/lib/hooks/useAppRouter.ts +240 -0
  542. package/src/mui-augmentation.d.ts +139 -0
  543. package/src/theme/index.ts +13 -0
  544. package/src/theme.ts +23 -0
  545. package/src/types/index.ts +23 -0
  546. package/dist/index-BNUP2V_N.d.ts.map +0 -1
  547. package/dist/index-DOPZuhD8.d.mts.map +0 -1
  548. package/dist/theme.d.mts.map +0 -1
  549. package/dist/theme.d.ts.map +0 -1
@@ -0,0 +1,202 @@
1
+ import os
2
+ from datetime import datetime, timezone
3
+
4
+ import pytest
5
+ from fastapi.testclient import TestClient
6
+
7
+ from recce.core import default_context
8
+ from recce.server import app
9
+
10
+ # noinspection PyUnresolvedReferences
11
+ from tests.adapter.dbt_adapter.conftest import dbt_test_helper # noqa: F401
12
+
13
+
14
+ @pytest.fixture
15
+ def temp_folder():
16
+ import tempfile
17
+
18
+ temp_dir = tempfile.mkdtemp()
19
+ yield temp_dir
20
+
21
+ import shutil
22
+
23
+ shutil.rmtree(temp_dir)
24
+
25
+
26
+ @pytest.fixture(autouse=True)
27
+ def init_app_state():
28
+ """Initialize app.state.last_activity for all tests to prevent middleware errors."""
29
+ app.state.last_activity = None
30
+ yield
31
+ # Cleanup after test
32
+ app.state.last_activity = None
33
+
34
+
35
+ def test_health():
36
+ client = TestClient(app)
37
+ response = client.get("/api/health")
38
+ assert response.status_code == 200
39
+ assert response.json() == {"status": "ok"}
40
+
41
+
42
+ def test_stateless(dbt_test_helper):
43
+ context = default_context()
44
+ from recce.state import FileStateLoader
45
+
46
+ context.state_loader = FileStateLoader()
47
+ client = TestClient(app)
48
+ response = client.get("/api/info")
49
+ assert response.status_code == 200
50
+ info = response.json()
51
+ assert info["file_mode"] is False
52
+ assert info["cloud_mode"] is False
53
+
54
+
55
+ def test_file_mode(dbt_test_helper):
56
+ context = default_context()
57
+ from recce.state import FileStateLoader
58
+
59
+ context.state_loader = FileStateLoader(state_file="/tmp/recce_state.json")
60
+ client = TestClient(app)
61
+ response = client.get("/api/info")
62
+ assert response.status_code == 200
63
+ info = response.json()
64
+ assert info["file_mode"] is True
65
+ assert info["filename"] == "recce_state.json"
66
+ assert info["cloud_mode"] is False
67
+
68
+
69
+ def test_saveas_and_rename(dbt_test_helper, temp_folder):
70
+ context = default_context()
71
+ state_file = os.path.join(temp_folder, "recce_state.json")
72
+ state_file2 = os.path.join(temp_folder, "recce_state2.json")
73
+ state_file3 = os.path.join(temp_folder, "recce_state3.json")
74
+ os.makedirs(os.path.join(temp_folder, "dir.json"))
75
+
76
+ from recce.state import FileStateLoader
77
+
78
+ context.state_loader = FileStateLoader(state_file=state_file)
79
+ client = TestClient(app)
80
+
81
+ response = client.post("/api/save", json={"filename": "recce_state2.json"})
82
+ assert response.status_code == 200
83
+ assert os.path.exists(state_file)
84
+
85
+ response = client.post("/api/save-as", json={"filename": "recce_state2.json"})
86
+ assert response.status_code == 200
87
+ assert os.path.exists(state_file2)
88
+ assert context.state_loader.state_file == os.path.join(temp_folder, "recce_state2.json")
89
+
90
+ # Same file
91
+ response = client.post("/api/save-as", json={"filename": "recce_state2.json"})
92
+ assert response.status_code == 400
93
+
94
+ # folder
95
+ response = client.post("/api/save-as", json={"filename": "dir.json"})
96
+ assert response.status_code == 400
97
+
98
+ # Rename
99
+ response = client.post("/api/rename", json={"filename": "recce_state3.json"})
100
+ assert response.status_code == 200
101
+ assert not os.path.exists(state_file2)
102
+ assert os.path.exists(state_file3)
103
+ assert context.state_loader.state_file == os.path.join(temp_folder, "recce_state3.json")
104
+
105
+ # Conflict
106
+ response = client.post("/api/save-as", json={"filename": "recce_state.json"})
107
+ assert response.status_code == 409
108
+ response = client.post("/api/rename", json={"filename": "recce_state.json"})
109
+ assert response.status_code == 409
110
+
111
+ # Overwrite
112
+ response = client.post("/api/save-as", json={"filename": "recce_state.json", "overwrite": True})
113
+ assert response.status_code == 200
114
+ assert context.state_loader.state_file == os.path.join(temp_folder, "recce_state.json")
115
+
116
+
117
+ def test_keep_alive_without_idle_timeout():
118
+ """Test keep-alive endpoint when idle timeout is not configured"""
119
+ client = TestClient(app)
120
+
121
+ # Ensure last_activity is None (idle timeout not configured)
122
+ app.state.last_activity = None
123
+
124
+ response = client.post("/api/keep-alive")
125
+ assert response.status_code == 200
126
+ data = response.json()
127
+ assert data["status"] == "ok"
128
+ assert data["idle_timeout_enabled"] is False
129
+
130
+
131
+ def test_keep_alive_with_idle_timeout():
132
+ """Test keep-alive endpoint resets idle timer when idle timeout is configured"""
133
+ client = TestClient(app)
134
+
135
+ # Set up idle timeout state
136
+ initial_time = datetime.now(timezone.utc)
137
+ app.state.last_activity = {"time": initial_time}
138
+
139
+ # Call keep-alive
140
+ response = client.post("/api/keep-alive")
141
+ assert response.status_code == 200
142
+ data = response.json()
143
+ assert data["status"] == "ok"
144
+ assert data["idle_timeout_enabled"] is True
145
+
146
+ # Verify timer was reset (should be newer than initial time)
147
+ assert app.state.last_activity["time"] >= initial_time
148
+
149
+ # Cleanup
150
+ app.state.last_activity = None
151
+
152
+
153
+ def test_spa_route_checks():
154
+ """Test that /checks route serves index.html correctly via StaticFiles"""
155
+ client = TestClient(app)
156
+ response = client.get("/checks")
157
+ assert response.status_code == 200
158
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
159
+ assert b"<!DOCTYPE html>" in response.content
160
+
161
+
162
+ def test_spa_route_lineage():
163
+ """Test that /lineage route serves index.html correctly via StaticFiles"""
164
+ client = TestClient(app)
165
+ response = client.get("/lineage")
166
+ assert response.status_code == 200
167
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
168
+ assert b"<!DOCTYPE html>" in response.content
169
+
170
+
171
+ def test_spa_route_query():
172
+ """Test that /query route serves index.html correctly via StaticFiles"""
173
+ client = TestClient(app)
174
+ response = client.get("/query")
175
+ assert response.status_code == 200
176
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
177
+ assert b"<!DOCTYPE html>" in response.content
178
+
179
+
180
+ def test_spa_route_with_query_parameters():
181
+ """Test that query parameters work with SPA routes"""
182
+ client = TestClient(app)
183
+ # StaticFiles serves the index.html regardless of query params
184
+ # The actual routing happens client-side in the SPA
185
+ response = client.get("/checks?id=abc-123")
186
+ assert response.status_code == 200
187
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
188
+ assert b"<!DOCTYPE html>" in response.content
189
+
190
+ response = client.get("/lineage?node=model.my_model")
191
+ assert response.status_code == 200
192
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
193
+ assert b"<!DOCTYPE html>" in response.content
194
+
195
+
196
+ def test_nonexistent_route_returns_404():
197
+ """Test that non-existent routes return 404.html with 404 status code"""
198
+ client = TestClient(app)
199
+ response = client.get("/nonexistent-page")
200
+ assert response.status_code == 404
201
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
202
+ assert b"<!DOCTYPE html>" in response.content
@@ -0,0 +1,138 @@
1
+ """Tests for the FastAPI lifespan context manager in recce/server.py"""
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ import pytest
6
+
7
+ from recce.server import AppState, app, lifespan
8
+
9
+
10
+ @pytest.fixture
11
+ def mock_app_state():
12
+ """Create a mock AppState for testing."""
13
+ state = AppState()
14
+ state.command = "server"
15
+ state.state_loader = MagicMock()
16
+ state.kwargs = {"debug": False}
17
+ state.flag = {}
18
+ state.lifetime = None
19
+ state.idle_timeout = None
20
+ return state
21
+
22
+
23
+ @pytest.fixture
24
+ def setup_app_state(mock_app_state):
25
+ """Set up app.state for lifespan tests."""
26
+ original_state = getattr(app, "state", None)
27
+ app.state = mock_app_state
28
+ yield mock_app_state
29
+ app.state = original_state
30
+
31
+
32
+ class TestLifespan:
33
+ """Tests for lifespan setup and teardown."""
34
+
35
+ @pytest.mark.parametrize(
36
+ "command,setup_fn,teardown_fn",
37
+ [
38
+ ("server", "setup_server", "teardown_server"),
39
+ ("preview", "setup_preview", "teardown_preview"),
40
+ ("read-only", "setup_ready_only", "teardown_ready_only"),
41
+ ],
42
+ )
43
+ @pytest.mark.asyncio
44
+ async def test_setup_and_teardown_called_for_command(
45
+ self,
46
+ setup_app_state,
47
+ command,
48
+ setup_fn,
49
+ teardown_fn,
50
+ ):
51
+ """Test that correct setup and teardown are called for each command."""
52
+ setup_app_state.command = command
53
+
54
+ with patch(f"recce.server.{setup_fn}") as mock_setup, patch(f"recce.server.{teardown_fn}") as mock_teardown:
55
+ mock_ctx = MagicMock()
56
+ mock_setup.return_value = mock_ctx
57
+
58
+ async with lifespan(app):
59
+ mock_setup.assert_called_once_with(setup_app_state)
60
+
61
+ if command == "read-only":
62
+ mock_teardown.assert_called_once_with(setup_app_state)
63
+ else:
64
+ mock_teardown.assert_called_once_with(setup_app_state, mock_ctx)
65
+
66
+ @pytest.mark.parametrize(
67
+ "lifetime,idle_timeout,expect_lifetime,expect_idle",
68
+ [
69
+ (3600, 300, True, True), # both set
70
+ (None, None, False, False), # neither set
71
+ (0, 0, False, False), # zero = disabled
72
+ ],
73
+ )
74
+ @pytest.mark.asyncio
75
+ @patch("recce.server.setup_server")
76
+ @patch("recce.server.teardown_server")
77
+ @patch("recce.server.schedule_lifetime_termination")
78
+ @patch("recce.server.schedule_idle_timeout_check")
79
+ async def test_timeout_scheduling(
80
+ self,
81
+ mock_idle_check,
82
+ mock_lifetime,
83
+ mock_teardown,
84
+ mock_setup,
85
+ setup_app_state,
86
+ lifetime,
87
+ idle_timeout,
88
+ expect_lifetime,
89
+ expect_idle,
90
+ ):
91
+ """Test lifetime and idle_timeout scheduling."""
92
+ setup_app_state.command = "server"
93
+ setup_app_state.lifetime = lifetime
94
+ setup_app_state.idle_timeout = idle_timeout
95
+
96
+ async with lifespan(app):
97
+ pass
98
+
99
+ assert mock_lifetime.called == expect_lifetime
100
+ assert mock_idle_check.called == expect_idle
101
+
102
+ @pytest.mark.asyncio
103
+ @patch("recce.server.setup_server")
104
+ @patch("recce.server.teardown_server")
105
+ async def test_debug_logging_enabled(
106
+ self,
107
+ mock_teardown,
108
+ mock_setup,
109
+ setup_app_state,
110
+ ):
111
+ """Test logger set to DEBUG when debug=True."""
112
+ import logging
113
+
114
+ setup_app_state.kwargs = {"debug": True}
115
+
116
+ uvicorn_logger = logging.getLogger("uvicorn")
117
+ original_level = uvicorn_logger.level
118
+
119
+ try:
120
+ async with lifespan(app):
121
+ assert uvicorn_logger.level == logging.DEBUG
122
+ finally:
123
+ uvicorn_logger.setLevel(original_level)
124
+
125
+ @pytest.mark.asyncio
126
+ @patch("recce.server.setup_server")
127
+ @patch("recce.server.teardown_server")
128
+ async def test_kwargs_none_handled(
129
+ self,
130
+ mock_teardown,
131
+ mock_setup,
132
+ setup_app_state,
133
+ ):
134
+ """Test kwargs=None doesn't crash."""
135
+ setup_app_state.kwargs = None
136
+
137
+ async with lifespan(app):
138
+ pass # Should not raise
@@ -0,0 +1,73 @@
1
+ import os
2
+
3
+ import pytest
4
+
5
+ from recce.adapter.dbt_adapter import DbtAdapter, DbtVersion, load_manifest
6
+ from recce.core import RecceContext, set_default_context
7
+ from recce.summary import (
8
+ _build_lineage_graph,
9
+ generate_mermaid_lineage_graph,
10
+ generate_summary_metadata,
11
+ )
12
+
13
+ current_dir = os.path.dirname(os.path.abspath(__file__))
14
+ base_manifest_dir = os.path.join(current_dir, "data", "manifest", "base")
15
+ pr2_manifest_dir = os.path.join(current_dir, "data", "manifest", "pr2") # Pull Request 2l
16
+
17
+
18
+ def test_generate_summary_metadata():
19
+ dbt_version = DbtVersion()
20
+ if dbt_version < "1.8.1":
21
+ pytest.skip("Dbt version is less than 1.8.1")
22
+
23
+ manifest = load_manifest(path=os.path.join(current_dir, "manifest.json"))
24
+ assert manifest is not None
25
+ dbt_adapter = DbtAdapter(curr_manifest=manifest)
26
+ curr_lineage = dbt_adapter.get_lineage()
27
+ base_lineage = dbt_adapter.get_lineage()
28
+
29
+ # Summary with no changes
30
+ generate_summary_metadata(curr_lineage, base_lineage)
31
+
32
+ base_manifest = load_manifest(path=os.path.join(base_manifest_dir, "manifest.json"))
33
+ curr_manifest = load_manifest(path=os.path.join(pr2_manifest_dir, "manifest.json"))
34
+ dbt_adapter = DbtAdapter(curr_manifest=curr_manifest, base_manifest=base_manifest)
35
+ curr_lineage = dbt_adapter.get_lineage()
36
+ base_lineage = dbt_adapter.get_lineage(base=True)
37
+ generate_summary_metadata(curr_lineage, base_lineage)
38
+
39
+
40
+ def test_build_lineage_graph():
41
+ dbt_version = DbtVersion()
42
+ if dbt_version < "1.8.1":
43
+ pytest.skip("Dbt version is less than 1.8.1")
44
+
45
+ base_manifest = load_manifest(path=os.path.join(base_manifest_dir, "manifest.json"))
46
+ curr_manifest = load_manifest(path=os.path.join(pr2_manifest_dir, "manifest.json"))
47
+ dbt_adapter = DbtAdapter(curr_manifest=curr_manifest, base_manifest=base_manifest)
48
+ curr_lineage = dbt_adapter.get_lineage()
49
+ base_lineage = dbt_adapter.get_lineage(base=True)
50
+
51
+ lineage_graph = _build_lineage_graph(curr_lineage, base_lineage)
52
+ # Modified nodes: 3
53
+ # - int_customer_orders: added
54
+ # - int_customer_payments: added
55
+ # - customers: modified
56
+ assert len(lineage_graph.modified_set) == 3
57
+
58
+
59
+ def test_generate_mermaid_lineage_graph():
60
+ dbt_version = DbtVersion()
61
+ if dbt_version < "1.8.1":
62
+ pytest.skip("Dbt version is less than 1.8.1")
63
+
64
+ set_default_context(RecceContext())
65
+ base_manifest = load_manifest(path=os.path.join(base_manifest_dir, "manifest.json"))
66
+ curr_manifest = load_manifest(path=os.path.join(pr2_manifest_dir, "manifest.json"))
67
+ dbt_adapter = DbtAdapter(curr_manifest=curr_manifest, base_manifest=base_manifest)
68
+ curr_lineage = dbt_adapter.get_lineage()
69
+ base_lineage = dbt_adapter.get_lineage(base=True)
70
+ graph = _build_lineage_graph(curr_lineage, base_lineage)
71
+ mermaid_content, is_empty_graph, is_partial_graph = generate_mermaid_lineage_graph(graph)
72
+ assert is_empty_graph is False
73
+ assert is_partial_graph is False
File without changes
File without changes
@@ -0,0 +1,255 @@
1
+ """
2
+ Unit tests for CheckEventsCloud client.
3
+
4
+ Tests the cloud API client for check event operations including
5
+ list, get, create, update, and delete operations.
6
+ """
7
+
8
+ import unittest
9
+ from unittest.mock import MagicMock, patch
10
+
11
+ from recce.util.cloud.check_events import CheckEventsCloud
12
+
13
+
14
+ class TestCheckEventsCloud(unittest.TestCase):
15
+ """Tests for CheckEventsCloud client."""
16
+
17
+ def setUp(self):
18
+ """Set up test fixtures."""
19
+ self.token = "test-api-token"
20
+ self.client = CheckEventsCloud(self.token)
21
+ self.org_id = "org-123"
22
+ self.project_id = "proj-456"
23
+ self.session_id = "sess-789"
24
+ self.check_id = "check-001"
25
+ self.event_id = "event-001"
26
+
27
+ def test_init_with_api_token(self):
28
+ """Test initialization with API token."""
29
+ client = CheckEventsCloud("test-api-token")
30
+ self.assertEqual(client.token, "test-api-token")
31
+ self.assertEqual(client.token_type, "api_token")
32
+
33
+ def test_init_with_github_token(self):
34
+ """Test initialization with GitHub token."""
35
+ client = CheckEventsCloud("ghp_test123")
36
+ self.assertEqual(client.token, "ghp_test123")
37
+ self.assertEqual(client.token_type, "github_token")
38
+
39
+ def test_init_with_none_token_raises(self):
40
+ """Test initialization with None token raises ValueError."""
41
+ with self.assertRaises(ValueError) as ctx:
42
+ CheckEventsCloud(None)
43
+ self.assertIn("Token cannot be None", str(ctx.exception))
44
+
45
+ def test_build_events_url(self):
46
+ """Test URL building for events endpoint."""
47
+ url = self.client._build_events_url(self.org_id, self.project_id, self.session_id, self.check_id)
48
+ expected = (
49
+ f"{self.client.base_url_v2}/organizations/{self.org_id}"
50
+ f"/projects/{self.project_id}/sessions/{self.session_id}"
51
+ f"/checks/{self.check_id}/events"
52
+ )
53
+ self.assertEqual(url, expected)
54
+
55
+
56
+ class TestCheckEventsCloudListEvents(unittest.TestCase):
57
+ """Tests for list_events method."""
58
+
59
+ def setUp(self):
60
+ """Set up test fixtures."""
61
+ self.client = CheckEventsCloud("test-token")
62
+ self.org_id = "org-123"
63
+ self.project_id = "proj-456"
64
+ self.session_id = "sess-789"
65
+ self.check_id = "check-001"
66
+
67
+ @patch.object(CheckEventsCloud, "_request")
68
+ @patch.object(CheckEventsCloud, "_raise_for_status")
69
+ def test_list_events_success(self, mock_raise, mock_request):
70
+ """Test successful list_events call."""
71
+ mock_response = MagicMock()
72
+ mock_response.json.return_value = {
73
+ "events": [
74
+ {"id": "event-1", "event_type": "comment", "content": "Test"},
75
+ {"id": "event-2", "event_type": "approval_change"},
76
+ ]
77
+ }
78
+ mock_request.return_value = mock_response
79
+
80
+ result = self.client.list_events(self.org_id, self.project_id, self.session_id, self.check_id)
81
+
82
+ self.assertEqual(len(result), 2)
83
+ self.assertEqual(result[0]["id"], "event-1")
84
+ mock_request.assert_called_once()
85
+ mock_raise.assert_called_once()
86
+
87
+ @patch.object(CheckEventsCloud, "_request")
88
+ @patch.object(CheckEventsCloud, "_raise_for_status")
89
+ def test_list_events_empty(self, mock_raise, mock_request):
90
+ """Test list_events with no events."""
91
+ mock_response = MagicMock()
92
+ mock_response.json.return_value = {"events": []}
93
+ mock_request.return_value = mock_response
94
+
95
+ result = self.client.list_events(self.org_id, self.project_id, self.session_id, self.check_id)
96
+
97
+ self.assertEqual(result, [])
98
+
99
+ @patch.object(CheckEventsCloud, "_request")
100
+ @patch.object(CheckEventsCloud, "_raise_for_status")
101
+ def test_list_events_includes_deleted(self, mock_raise, mock_request):
102
+ """Test that list_events includes deleted events."""
103
+ mock_response = MagicMock()
104
+ mock_response.json.return_value = {"events": []}
105
+ mock_request.return_value = mock_response
106
+
107
+ self.client.list_events(self.org_id, self.project_id, self.session_id, self.check_id)
108
+
109
+ # Verify include_deleted=True is passed
110
+ call_args = mock_request.call_args
111
+ self.assertIn("params", call_args.kwargs)
112
+ self.assertTrue(call_args.kwargs["params"]["include_deleted"])
113
+
114
+
115
+ class TestCheckEventsCloudGetEvent(unittest.TestCase):
116
+ """Tests for get_event method."""
117
+
118
+ def setUp(self):
119
+ """Set up test fixtures."""
120
+ self.client = CheckEventsCloud("test-token")
121
+ self.org_id = "org-123"
122
+ self.project_id = "proj-456"
123
+ self.session_id = "sess-789"
124
+ self.check_id = "check-001"
125
+ self.event_id = "event-001"
126
+
127
+ @patch.object(CheckEventsCloud, "_request")
128
+ @patch.object(CheckEventsCloud, "_raise_for_status")
129
+ def test_get_event_success(self, mock_raise, mock_request):
130
+ """Test successful get_event call."""
131
+ mock_response = MagicMock()
132
+ mock_response.json.return_value = {
133
+ "event": {
134
+ "id": self.event_id,
135
+ "event_type": "comment",
136
+ "content": "Test comment",
137
+ }
138
+ }
139
+ mock_request.return_value = mock_response
140
+
141
+ result = self.client.get_event(self.org_id, self.project_id, self.session_id, self.check_id, self.event_id)
142
+
143
+ self.assertEqual(result["id"], self.event_id)
144
+ self.assertEqual(result["content"], "Test comment")
145
+ mock_request.assert_called_once_with("GET", unittest.mock.ANY)
146
+
147
+
148
+ class TestCheckEventsCloudCreateComment(unittest.TestCase):
149
+ """Tests for create_comment method."""
150
+
151
+ def setUp(self):
152
+ """Set up test fixtures."""
153
+ self.client = CheckEventsCloud("test-token")
154
+ self.org_id = "org-123"
155
+ self.project_id = "proj-456"
156
+ self.session_id = "sess-789"
157
+ self.check_id = "check-001"
158
+
159
+ @patch.object(CheckEventsCloud, "_request")
160
+ @patch.object(CheckEventsCloud, "_raise_for_status")
161
+ def test_create_comment_success(self, mock_raise, mock_request):
162
+ """Test successful comment creation."""
163
+ mock_response = MagicMock()
164
+ mock_response.json.return_value = {
165
+ "event": {
166
+ "id": "new-event-id",
167
+ "event_type": "comment",
168
+ "content": "New comment",
169
+ }
170
+ }
171
+ mock_request.return_value = mock_response
172
+
173
+ result = self.client.create_comment(self.org_id, self.project_id, self.session_id, self.check_id, "New comment")
174
+
175
+ self.assertEqual(result["id"], "new-event-id")
176
+ self.assertEqual(result["content"], "New comment")
177
+ mock_request.assert_called_once_with("POST", unittest.mock.ANY, json={"content": "New comment"})
178
+
179
+
180
+ class TestCheckEventsCloudUpdateComment(unittest.TestCase):
181
+ """Tests for update_comment method."""
182
+
183
+ def setUp(self):
184
+ """Set up test fixtures."""
185
+ self.client = CheckEventsCloud("test-token")
186
+ self.org_id = "org-123"
187
+ self.project_id = "proj-456"
188
+ self.session_id = "sess-789"
189
+ self.check_id = "check-001"
190
+ self.event_id = "event-001"
191
+
192
+ @patch.object(CheckEventsCloud, "_request")
193
+ @patch.object(CheckEventsCloud, "_raise_for_status")
194
+ def test_update_comment_success(self, mock_raise, mock_request):
195
+ """Test successful comment update."""
196
+ mock_response = MagicMock()
197
+ mock_response.json.return_value = {
198
+ "event": {
199
+ "id": self.event_id,
200
+ "event_type": "comment",
201
+ "content": "Updated content",
202
+ "is_edited": True,
203
+ }
204
+ }
205
+ mock_request.return_value = mock_response
206
+
207
+ result = self.client.update_comment(
208
+ self.org_id,
209
+ self.project_id,
210
+ self.session_id,
211
+ self.check_id,
212
+ self.event_id,
213
+ "Updated content",
214
+ )
215
+
216
+ self.assertEqual(result["content"], "Updated content")
217
+ self.assertTrue(result["is_edited"])
218
+ mock_request.assert_called_once_with("PATCH", unittest.mock.ANY, json={"content": "Updated content"})
219
+
220
+
221
+ class TestCheckEventsCloudDeleteComment(unittest.TestCase):
222
+ """Tests for delete_comment method."""
223
+
224
+ def setUp(self):
225
+ """Set up test fixtures."""
226
+ self.client = CheckEventsCloud("test-token")
227
+ self.org_id = "org-123"
228
+ self.project_id = "proj-456"
229
+ self.session_id = "sess-789"
230
+ self.check_id = "check-001"
231
+ self.event_id = "event-001"
232
+
233
+ @patch.object(CheckEventsCloud, "_request")
234
+ @patch.object(CheckEventsCloud, "_raise_for_status")
235
+ def test_delete_comment_success(self, mock_raise, mock_request):
236
+ """Test successful comment deletion."""
237
+ mock_response = MagicMock()
238
+ mock_request.return_value = mock_response
239
+
240
+ # Should not raise, returns None
241
+ result = self.client.delete_comment(
242
+ self.org_id,
243
+ self.project_id,
244
+ self.session_id,
245
+ self.check_id,
246
+ self.event_id,
247
+ )
248
+
249
+ self.assertIsNone(result)
250
+ mock_request.assert_called_once_with("DELETE", unittest.mock.ANY)
251
+ mock_raise.assert_called_once()
252
+
253
+
254
+ if __name__ == "__main__":
255
+ unittest.main()