@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,505 @@
1
+ import asyncio
2
+ from unittest.mock import MagicMock, patch
3
+
4
+ import pytest
5
+
6
+ # Skip all tests in this module if mcp is not available
7
+ pytest.importorskip("mcp")
8
+
9
+ from recce.core import RecceContext # noqa: E402
10
+ from recce.mcp_server import RecceMCPServer, run_mcp_server # noqa: E402
11
+ from recce.models.types import LineageDiff # noqa: E402
12
+ from recce.server import RecceServerMode # noqa: E402
13
+ from recce.tasks.profile import ProfileDiffTask # noqa: E402
14
+ from recce.tasks.query import QueryDiffTask, QueryTask # noqa: E402
15
+ from recce.tasks.rowcount import RowCountDiffTask # noqa: E402
16
+
17
+
18
+ @pytest.fixture
19
+ def mcp_server():
20
+ """Fixture to create a RecceMCPServer instance for testing"""
21
+ mock_context = MagicMock(spec=RecceContext)
22
+ return RecceMCPServer(mock_context), mock_context
23
+
24
+
25
+ class TestRecceMCPServer:
26
+ """Test cases for the RecceMCPServer class"""
27
+
28
+ def test_server_initialization(self, mcp_server):
29
+ """Test that the MCP server initializes correctly"""
30
+ server, mock_context = mcp_server
31
+ assert server.context == mock_context
32
+ assert server.server is not None
33
+ assert server.server.name == "recce"
34
+
35
+ @pytest.mark.asyncio
36
+ async def test_tool_lineage_diff(self, mcp_server):
37
+ """Test the lineage_diff tool"""
38
+ server, mock_context = mcp_server
39
+ # Mock the lineage diff response
40
+ mock_lineage_diff = MagicMock(spec=LineageDiff)
41
+ mock_lineage_diff.model_dump.return_value = {
42
+ "base": {
43
+ "nodes": {
44
+ "model.project.model_a": {
45
+ "name": "model_a",
46
+ "resource_type": "model",
47
+ "config": {"materialized": "view"},
48
+ },
49
+ "model.project.model_b": {
50
+ "name": "model_b",
51
+ "resource_type": "model",
52
+ },
53
+ },
54
+ "parent_map": {
55
+ "model.project.model_a": [],
56
+ "model.project.model_b": ["model.project.model_a"],
57
+ },
58
+ },
59
+ "current": {
60
+ "nodes": {
61
+ "model.project.model_a": {
62
+ "name": "model_a",
63
+ "resource_type": "model",
64
+ "config": {"materialized": "view"},
65
+ },
66
+ "model.project.model_b": {
67
+ "name": "model_b",
68
+ "resource_type": "model",
69
+ },
70
+ },
71
+ "parent_map": {
72
+ "model.project.model_a": [],
73
+ "model.project.model_b": ["model.project.model_a"],
74
+ },
75
+ },
76
+ "diff": {
77
+ "model.project.model_a": {"change_status": "modified"},
78
+ },
79
+ }
80
+ mock_context.get_lineage_diff.return_value = mock_lineage_diff
81
+ mock_context.adapter.select_nodes.return_value = {
82
+ "model.project.model_a",
83
+ "model.project.model_b",
84
+ }
85
+
86
+ # Execute the method
87
+ result = await server._tool_lineage_diff({})
88
+
89
+ # Verify the result structure
90
+ assert "nodes" in result
91
+ assert "edges" in result
92
+
93
+ # Verify nodes is a DataFrame dict with columns and data
94
+ nodes = result["nodes"]
95
+ assert "columns" in nodes
96
+ assert "data" in nodes
97
+
98
+ # Verify data is a list with 2 rows
99
+ assert isinstance(nodes["data"], list)
100
+ assert len(nodes["data"]) == 2
101
+
102
+ # Verify edges is a DataFrame dict with columns and data
103
+ edges = result["edges"]
104
+ assert "columns" in edges
105
+ assert "data" in edges
106
+ assert isinstance(edges["data"], list)
107
+ # Verify edges contains the parent-child relationship (model_a -> model_b)
108
+ assert len(edges["data"]) == 1
109
+
110
+ mock_context.get_lineage_diff.assert_called_once()
111
+ mock_context.adapter.select_nodes.assert_called()
112
+
113
+ @pytest.mark.asyncio
114
+ async def test_tool_schema_diff(self, mcp_server):
115
+ """Test the schema_diff tool"""
116
+ server, mock_context = mcp_server
117
+ # Mock the lineage diff response with schema information
118
+ mock_lineage_diff = MagicMock(spec=LineageDiff)
119
+ mock_lineage_diff.model_dump.return_value = {
120
+ "base": {
121
+ "nodes": {
122
+ "model.project.model_a": {
123
+ "name": "model_a",
124
+ "resource_type": "model",
125
+ "columns": {
126
+ "id": {"name": "id", "type": "integer"},
127
+ "name": {"name": "name", "type": "text"},
128
+ },
129
+ },
130
+ },
131
+ },
132
+ "current": {
133
+ "nodes": {
134
+ "model.project.model_a": {
135
+ "name": "model_a",
136
+ "resource_type": "model",
137
+ "columns": {
138
+ "id": {"name": "id", "type": "integer"},
139
+ "name": {"name": "name", "type": "text"},
140
+ "age": {"name": "age", "type": "integer"},
141
+ },
142
+ },
143
+ },
144
+ },
145
+ }
146
+ mock_context.get_lineage_diff.return_value = mock_lineage_diff
147
+ mock_context.adapter.select_nodes.return_value = {"model.project.model_a"}
148
+
149
+ # Execute the method
150
+ result = await server._tool_schema_diff({})
151
+
152
+ # Verify the result is a DataFrame dict with columns and data
153
+ assert "columns" in result
154
+ assert "data" in result
155
+ assert "limit" in result
156
+ assert "more" in result
157
+
158
+ # Verify limit and more fields
159
+ assert result["limit"] == 100
160
+ assert isinstance(result["more"], bool)
161
+ assert isinstance(result["data"], list)
162
+ # Verify the data contains the added column
163
+ assert len(result["data"]) > 0
164
+
165
+ mock_context.get_lineage_diff.assert_called_once()
166
+
167
+ @pytest.mark.asyncio
168
+ async def test_tool_row_count_diff(self, mcp_server):
169
+ """Test the row_count_diff tool"""
170
+ server, _ = mcp_server
171
+ # Mock the task execution
172
+ mock_result = {"results": [{"node_id": "model.project.my_model", "base": 100, "current": 105, "diff": 5}]}
173
+
174
+ with patch.object(RowCountDiffTask, "execute", return_value=mock_result):
175
+ result = await server._tool_row_count_diff({"node_names": ["my_model"]})
176
+
177
+ # Verify the result
178
+ assert result == mock_result
179
+ assert "results" in result
180
+
181
+ @pytest.mark.asyncio
182
+ async def test_tool_query(self, mcp_server):
183
+ """Test the query tool"""
184
+ server, _ = mcp_server
185
+ # Mock the task execution
186
+ mock_result = MagicMock()
187
+ mock_result.model_dump.return_value = {
188
+ "columns": ["id", "name"],
189
+ "data": [[1, "Alice"], [2, "Bob"]],
190
+ }
191
+
192
+ with patch.object(QueryTask, "execute", return_value=mock_result):
193
+ result = await server._tool_query({"sql_template": "SELECT * FROM {{ ref('my_model') }}", "base": False})
194
+
195
+ # Verify the result
196
+ assert "columns" in result
197
+ assert "data" in result
198
+ mock_result.model_dump.assert_called_once_with(mode="json")
199
+
200
+ @pytest.mark.asyncio
201
+ async def test_tool_query_with_base_flag(self, mcp_server):
202
+ """Test the query tool with base environment flag"""
203
+ server, _ = mcp_server
204
+ mock_result = {"columns": ["id"], "data": [[1]]}
205
+
206
+ with patch.object(QueryTask, "execute", return_value=mock_result) as mock_execute:
207
+ with patch.object(QueryTask, "__init__", return_value=None):
208
+ task = QueryTask(params={"sql_template": "SELECT 1"})
209
+ task.is_base = True
210
+ task.execute = mock_execute
211
+
212
+ result = await server._tool_query({"sql_template": "SELECT 1", "base": True})
213
+
214
+ # Verify base flag was set (would need to inspect task creation)
215
+ assert result == mock_result
216
+
217
+ @pytest.mark.asyncio
218
+ async def test_tool_query_diff(self, mcp_server):
219
+ """Test the query_diff tool"""
220
+ server, _ = mcp_server
221
+ # Mock the task execution
222
+ mock_result = MagicMock()
223
+ mock_result.model_dump.return_value = {
224
+ "diff": {
225
+ "added": [[3, "Charlie"]],
226
+ "removed": [[1, "Alice"]],
227
+ "modified": [],
228
+ }
229
+ }
230
+
231
+ with patch.object(QueryDiffTask, "execute", return_value=mock_result):
232
+ result = await server._tool_query_diff(
233
+ {
234
+ "sql_template": "SELECT * FROM {{ ref('my_model') }}",
235
+ "primary_keys": ["id"],
236
+ }
237
+ )
238
+
239
+ # Verify the result
240
+ assert "diff" in result
241
+ mock_result.model_dump.assert_called_once_with(mode="json")
242
+
243
+ @pytest.mark.asyncio
244
+ async def test_tool_profile_diff(self, mcp_server):
245
+ """Test the profile_diff tool"""
246
+ server, _ = mcp_server
247
+ # Mock the task execution
248
+ mock_result = MagicMock()
249
+ mock_result.model_dump.return_value = {
250
+ "columns": {
251
+ "id": {
252
+ "base": {"min": 1, "max": 100, "avg": 50.5},
253
+ "current": {"min": 1, "max": 105, "avg": 53.0},
254
+ }
255
+ }
256
+ }
257
+
258
+ with patch.object(ProfileDiffTask, "execute", return_value=mock_result):
259
+ result = await server._tool_profile_diff({"model": "my_model", "columns": ["id"]})
260
+
261
+ # Verify the result
262
+ assert "columns" in result
263
+ mock_result.model_dump.assert_called_once_with(mode="json")
264
+
265
+ @pytest.mark.asyncio
266
+ async def test_tool_list_checks(self, mcp_server):
267
+ """Test the list_checks tool"""
268
+ server, _ = mcp_server
269
+ from uuid import uuid4
270
+
271
+ from recce.models.types import RunType
272
+
273
+ check_id = uuid4()
274
+ mock_check = MagicMock()
275
+ mock_check.check_id = check_id
276
+ mock_check.name = "Test Check"
277
+ mock_check.type = RunType.SCHEMA_DIFF
278
+ mock_check.description = "Test description"
279
+ mock_check.params = {"select": "model_a"}
280
+ mock_check.is_checked = True
281
+ mock_check.is_preset = False
282
+
283
+ mock_check_dao = MagicMock()
284
+ mock_check_dao.list.return_value = [mock_check]
285
+ mock_check_dao.status.return_value = {"total": 1, "approved": 1}
286
+
287
+ with patch("recce.models.CheckDAO", return_value=mock_check_dao):
288
+ result = await server._tool_list_checks({})
289
+
290
+ # Verify the result structure
291
+ assert "checks" in result
292
+ assert "total" in result
293
+ assert "approved" in result
294
+ assert len(result["checks"]) == 1
295
+ assert result["checks"][0]["check_id"] == str(check_id)
296
+ assert result["checks"][0]["name"] == "Test Check"
297
+ assert result["checks"][0]["type"] == "schema_diff"
298
+ assert result["total"] == 1
299
+ assert result["approved"] == 1
300
+
301
+ @pytest.mark.asyncio
302
+ async def test_tool_run_check_row_count_diff(self, mcp_server):
303
+ """Test running a row_count_diff check"""
304
+ server, _ = mcp_server
305
+ from uuid import uuid4
306
+
307
+ from recce.models.types import RunType
308
+
309
+ check_id = uuid4()
310
+ run_id = uuid4()
311
+
312
+ # Create mock check with row_count_diff type
313
+ mock_check = MagicMock()
314
+ mock_check.check_id = check_id
315
+ mock_check.name = "Row Count Check"
316
+ mock_check.type = RunType.ROW_COUNT_DIFF
317
+ mock_check.params = {"node_names": ["model_a"]}
318
+
319
+ # Create mock run
320
+ mock_run = MagicMock()
321
+ mock_run.run_id = run_id
322
+ mock_run.type = RunType.ROW_COUNT_DIFF
323
+ mock_run.result = {"results": [{"node_id": "model.project.model_a", "base": 100, "current": 105, "diff": 5}]}
324
+ mock_run.error = None
325
+ mock_run.check_id = check_id
326
+ mock_run.model_dump.return_value = {
327
+ "run_id": str(run_id),
328
+ "check_id": str(check_id),
329
+ "type": "row_count_diff",
330
+ "result": mock_run.result,
331
+ "error": None,
332
+ }
333
+
334
+ # Mock CheckDAO and submit_run
335
+ mock_check_dao = MagicMock()
336
+ mock_check_dao.find_check_by_id.return_value = mock_check
337
+
338
+ with patch("recce.models.CheckDAO", return_value=mock_check_dao):
339
+ with patch("recce.apis.run_func.submit_run") as mock_submit_run:
340
+ mock_submit_run.return_value = (mock_run, asyncio.sleep(0))
341
+ result = await server._tool_run_check({"check_id": str(check_id)})
342
+
343
+ # Verify the result
344
+ assert "run_id" in result
345
+ assert result["run_id"] == str(run_id)
346
+ assert "type" in result
347
+ assert result["type"] == "row_count_diff"
348
+ assert "check_id" in result
349
+ assert result["check_id"] == str(check_id)
350
+
351
+ @pytest.mark.asyncio
352
+ async def test_tool_run_check_with_lineage_diff(self, mcp_server):
353
+ """Test running a lineage_diff check delegates to _tool_lineage_diff"""
354
+ server, mock_context = mcp_server
355
+ from uuid import uuid4
356
+
357
+ from recce.models.types import LineageDiff, RunType
358
+
359
+ check_id = uuid4()
360
+
361
+ # Create mock check with lineage_diff type
362
+ mock_check = MagicMock()
363
+ mock_check.check_id = check_id
364
+ mock_check.name = "Lineage Check"
365
+ mock_check.type = RunType.LINEAGE_DIFF
366
+ mock_check.params = {"select": "model_a"}
367
+
368
+ # Mock lineage diff response
369
+ mock_lineage_diff = MagicMock(spec=LineageDiff)
370
+ mock_lineage_diff.model_dump.return_value = {
371
+ "base": {"nodes": {}, "parent_map": {}},
372
+ "current": {"nodes": {}, "parent_map": {}},
373
+ "diff": {},
374
+ }
375
+ mock_context.get_lineage_diff.return_value = mock_lineage_diff
376
+ mock_context.adapter.select_nodes.return_value = set()
377
+
378
+ # Mock CheckDAO
379
+ mock_check_dao = MagicMock()
380
+ mock_check_dao.find_check_by_id.return_value = mock_check
381
+
382
+ with patch("recce.models.CheckDAO", return_value=mock_check_dao):
383
+ result = await server._tool_run_check({"check_id": str(check_id)})
384
+
385
+ # Verify the result is from lineage_diff tool (has nodes and edges)
386
+ assert "nodes" in result
387
+ assert "edges" in result
388
+
389
+ @pytest.mark.asyncio
390
+ async def test_tool_run_check_with_schema_diff(self, mcp_server):
391
+ """Test running a schema_diff check delegates to _tool_schema_diff"""
392
+ server, mock_context = mcp_server
393
+ from uuid import uuid4
394
+
395
+ from recce.models.types import LineageDiff, RunType
396
+
397
+ check_id = uuid4()
398
+
399
+ # Create mock check with schema_diff type
400
+ mock_check = MagicMock()
401
+ mock_check.check_id = check_id
402
+ mock_check.name = "Schema Check"
403
+ mock_check.type = RunType.SCHEMA_DIFF
404
+ mock_check.params = {"select": "model_a"}
405
+
406
+ # Mock lineage diff response
407
+ mock_lineage_diff = MagicMock(spec=LineageDiff)
408
+ mock_lineage_diff.model_dump.return_value = {
409
+ "base": {"nodes": {}, "parent_map": {}},
410
+ "current": {"nodes": {}, "parent_map": {}},
411
+ "diff": {},
412
+ }
413
+ mock_context.get_lineage_diff.return_value = mock_lineage_diff
414
+ mock_context.adapter.select_nodes.return_value = set()
415
+
416
+ # Mock CheckDAO
417
+ mock_check_dao = MagicMock()
418
+ mock_check_dao.find_check_by_id.return_value = mock_check
419
+
420
+ with patch("recce.models.CheckDAO", return_value=mock_check_dao):
421
+ result = await server._tool_run_check({"check_id": str(check_id)})
422
+
423
+ # Verify the result is from schema_diff tool (has columns, data, limit, more)
424
+ assert "columns" in result
425
+ assert "data" in result
426
+ assert "limit" in result
427
+ assert "more" in result
428
+
429
+ @pytest.mark.asyncio
430
+ async def test_error_handling(self, mcp_server):
431
+ """Test error handling in tool execution"""
432
+ server, mock_context = mcp_server
433
+ # Make get_lineage_diff raise an exception
434
+ mock_context.get_lineage_diff.side_effect = Exception("Test error")
435
+
436
+ # The method should raise the exception
437
+ with pytest.raises(Exception, match="Test error"):
438
+ await server._tool_lineage_diff({})
439
+
440
+
441
+ class TestRunMCPServer:
442
+ """Test cases for the run_mcp_server function"""
443
+
444
+ @pytest.mark.asyncio
445
+ @patch("recce.mcp_server.load_context")
446
+ @patch.object(RecceMCPServer, "run")
447
+ async def test_run_mcp_server(self, mock_run, mock_load_context):
448
+ """Test the run_mcp_server entry point"""
449
+ # Mock the context
450
+ mock_context = MagicMock(spec=RecceContext)
451
+ mock_load_context.return_value = mock_context
452
+
453
+ # Mock the server run method
454
+ mock_run.return_value = None
455
+
456
+ # Run the server
457
+ await run_mcp_server(project_dir="/test/path")
458
+
459
+ # Verify context was loaded with correct kwargs
460
+ mock_load_context.assert_called_once_with(project_dir="/test/path")
461
+
462
+ # Verify server was run
463
+ mock_run.assert_called_once()
464
+
465
+ @pytest.mark.asyncio
466
+ @patch("recce.mcp_server.load_context")
467
+ async def test_run_mcp_server_context_error(self, mock_load_context):
468
+ """Test run_mcp_server handles context loading errors"""
469
+ # Make load_context raise an exception
470
+ mock_load_context.side_effect = FileNotFoundError("manifest.json not found")
471
+
472
+ # The function should raise the exception
473
+ with pytest.raises(FileNotFoundError):
474
+ await run_mcp_server()
475
+
476
+
477
+ def test_mcp_cli_command_exists():
478
+ """Test that the mcp-server CLI command is registered"""
479
+ from recce.cli import cli
480
+
481
+ # Check that mcp_server is in the CLI commands
482
+ commands = [cmd.name for cmd in cli.commands.values()]
483
+ assert "mcp_server" in commands or "mcp-server" in commands
484
+
485
+
486
+ class TestMCPServerModes:
487
+ """Test cases for MCP server mode functionality"""
488
+
489
+ def test_server_mode_default(self):
490
+ """Test that server mode is the default when not specified"""
491
+ mock_context = MagicMock(spec=RecceContext)
492
+ server = RecceMCPServer(mock_context)
493
+
494
+ # Default mode should be server
495
+ assert server.mode == RecceServerMode.server
496
+
497
+ def test_non_server_mode_restricts_tools(self):
498
+ """Test that non-server mode (preview, read-only) restricts diff tools"""
499
+ mock_context = MagicMock(spec=RecceContext)
500
+ server = RecceMCPServer(mock_context, mode=RecceServerMode.preview)
501
+
502
+ # Verify mode is set correctly
503
+ assert server.mode == RecceServerMode.preview
504
+ # Verify it's not server mode
505
+ assert server.mode != RecceServerMode.server
@@ -0,0 +1,130 @@
1
+ import json
2
+ from unittest.mock import patch
3
+
4
+ import pytest
5
+ import requests
6
+
7
+ from recce.pull_request import _fetch_pr_title, fetch_pr_metadata_from_event_path
8
+
9
+
10
+ @pytest.fixture
11
+ def mock_github_event(tmp_path, monkeypatch):
12
+ event_data = {
13
+ "number": 1,
14
+ "pull_request": {
15
+ "_links": {
16
+ "html": {"href": "https://github.com/xyz/abc/pull/1"},
17
+ "self": {"href": "api_url_here"},
18
+ }
19
+ },
20
+ }
21
+ event_file = tmp_path / "github_event.json"
22
+ with open(event_file, "w") as f:
23
+ json.dump(event_data, f)
24
+
25
+ monkeypatch.setenv("GITHUB_EVENT_PATH", str(event_file))
26
+ monkeypatch.setenv("GITHUB_REPOSITORY", "abc/xyz")
27
+
28
+
29
+ @pytest.fixture
30
+ def mock_github_token(monkeypatch):
31
+ monkeypatch.setenv("GITHUB_TOKEN", "github_token_here")
32
+
33
+
34
+ class MockResponse:
35
+ def __init__(self, status_code, json_data=None):
36
+ self.status_code = status_code
37
+ self.json_data = json_data
38
+
39
+ def json(self):
40
+ return self.json_data
41
+
42
+
43
+ @pytest.fixture
44
+ def mock_get_request_success(monkeypatch):
45
+ def mock_get(*args, **kwargs):
46
+ return MockResponse(200, json_data={"title": "Update README.md"})
47
+
48
+ monkeypatch.setattr(requests, "get", mock_get)
49
+
50
+
51
+ @pytest.fixture
52
+ def mock_get_request_failure(monkeypatch):
53
+ def mock_get(*args, **kwargs):
54
+ return MockResponse(404)
55
+
56
+ monkeypatch.setattr(requests, "get", mock_get)
57
+
58
+
59
+ def test_fetch_pr_metadata(mock_github_event, mock_github_token, mock_get_request_success):
60
+ result = fetch_pr_metadata_from_event_path()
61
+
62
+ assert result is not None
63
+ assert result["github_pr_id"] == 1
64
+ assert result["github_pr_url"] == "https://github.com/xyz/abc/pull/1"
65
+ assert result["github_pr_title"] == "Update README.md"
66
+ assert result["github_repository"] == "abc/xyz"
67
+
68
+
69
+ def test_fetch_pr_metadata_no_event(mock_get_request_success, monkeypatch):
70
+ monkeypatch.delenv("GITHUB_EVENT_PATH", raising=False)
71
+
72
+ result = fetch_pr_metadata_from_event_path()
73
+
74
+ assert result is None
75
+
76
+
77
+ def test_fetch_pr_metadata_request_error(mock_github_event, mock_get_request_failure):
78
+ result = fetch_pr_metadata_from_event_path()
79
+
80
+ assert result is not None
81
+ assert result["github_pr_id"] == 1
82
+ assert result["github_pr_url"] == "https://github.com/xyz/abc/pull/1"
83
+ assert result["github_pr_title"] is None
84
+
85
+
86
+ def test_fetch_pr_metadata_exception(mock_github_event, monkeypatch):
87
+ monkeypatch.setenv("GITHUB_EVENT_PATH", "nonexistent_path")
88
+
89
+ result = fetch_pr_metadata_from_event_path()
90
+
91
+ assert result is None
92
+
93
+
94
+ def test_fetch_pr_metadata_no_token(mock_github_event):
95
+ with patch.dict("os.environ", clear=True):
96
+ result = fetch_pr_metadata_from_event_path()
97
+
98
+ assert result is None
99
+
100
+
101
+ def test_fetch_pr_title(mock_github_token, mock_get_request_success):
102
+ result = _fetch_pr_title("api_url_here")
103
+
104
+ assert result == "Update README.md"
105
+
106
+
107
+ def test_fetch_pr_title_request_error(mock_github_token, mock_get_request_failure):
108
+ result = _fetch_pr_title("api_url_here")
109
+
110
+ assert result is None
111
+
112
+
113
+ def test_fetch_pr_title_exception(mock_github_token, monkeypatch):
114
+ monkeypatch.setenv("GITHUB_TOKEN", "github_token_here")
115
+
116
+ def mock_get(*args, **kwargs):
117
+ raise Exception("Test exception")
118
+
119
+ monkeypatch.setattr(requests, "get", mock_get)
120
+
121
+ result = _fetch_pr_title("api_url_here")
122
+
123
+ assert result is None
124
+
125
+
126
+ def test_fetch_pr_title_no_token():
127
+ with patch.dict("os.environ", clear=True):
128
+ result = _fetch_pr_title("api_url_here")
129
+
130
+ assert result is None