fixtures.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License in the LICENSE file at the
  6. # root of this repository, or online at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from dbt.tests.adapter.hooks import test_model_hooks as core_base
  16. test_materialized_view = """
  17. {{ config(materialized='materialized_view') }}
  18. SELECT * FROM (VALUES ('chicken', 'pig', 'bird'), ('cow', 'horse', 'bird'), (NULL, NULL, NULL)) _ (a, b, c)
  19. """
  20. test_materialized_view_retain_history = """
  21. {{ config(
  22. materialized='materialized_view',
  23. retain_history='1hr'
  24. ) }}
  25. SELECT * FROM (VALUES ('chicken', 'pig', 'bird'), ('cow', 'horse', 'bird'), (NULL, NULL, NULL)) _ (a, b, c)
  26. """
  27. test_materialized_view_index = """
  28. {{ config(
  29. materialized='materialized_view',
  30. indexes=[{'columns': ['a', 'length(a)'], 'name': 'a_idx'}]
  31. ) }}
  32. SELECT * FROM (VALUES ('chicken', 'pig'), ('cow', 'horse')) _ (a, b)
  33. """
  34. test_materialized_view_deploy = """
  35. {{ config(materialized='materialized_view') }}
  36. SELECT val + 1 AS val FROM source_table
  37. """
  38. test_view = """
  39. {{ config(materialized='view') }}
  40. SELECT * FROM (VALUES ('chicken', 'pig', 'bird'), ('cow', 'horse', 'bird'), (NULL, NULL, NULL)) _ (a, b, c)
  41. """
  42. test_view_index = """
  43. {{ config(
  44. materialized='view',
  45. indexes=[{'default': True}]
  46. ) }}
  47. SELECT * FROM (VALUES ('chicken', 'pig'), ('cow', 'horse'), (NULL, NULL)) _ (a, b)
  48. """
  49. test_table_index = """
  50. {{ config(
  51. materialized='table',
  52. indexes=[{'columns': ['a', 'length(a)'], 'name': 'test_table_index_a_idx'}]
  53. ) }}
  54. SELECT * FROM (VALUES ('chicken', 'pig'), ('cow', 'horse')) _ (a, b)
  55. """
  56. test_seed = """
  57. id,value
  58. 1,100
  59. 2,200
  60. 3,300
  61. """.strip()
  62. test_source = """
  63. {{ config(
  64. materialized='source',
  65. database='materialize',
  66. pre_hook="CREATE CONNECTION IF NOT EXISTS kafka_connection TO KAFKA (BROKER '{{ env_var('KAFKA_ADDR', 'localhost:9092') }}', SECURITY PROTOCOL PLAINTEXT)"
  67. )
  68. }}
  69. FROM KAFKA CONNECTION kafka_connection (TOPIC 'testdrive-test-source-1')
  70. FORMAT BYTES
  71. """
  72. test_source_index = """
  73. {{ config(
  74. materialized='source',
  75. indexes=[{'columns': ['data']}]
  76. ) }}
  77. FROM KAFKA CONNECTION kafka_connection (TOPIC 'testdrive-test-source-1')
  78. FORMAT BYTES
  79. """
  80. test_source_cluster = """
  81. {{ config(
  82. materialized='source',
  83. cluster='quickstart'
  84. ) }}
  85. FROM KAFKA CONNECTION kafka_connection (TOPIC 'testdrive-test-source-1')
  86. FORMAT BYTES
  87. """
  88. test_source_table = """
  89. {{ config(
  90. materialized='source_table',
  91. database='materialize'
  92. ) }}
  93. FROM SOURCE {{ ref('test_subsources') }}
  94. (REFERENCE "bids")
  95. """
  96. test_source_table_index = """
  97. {{ config(
  98. materialized='source_table',
  99. database='materialize',
  100. indexes=[{'columns': ['amount']}]
  101. ) }}
  102. FROM SOURCE {{ ref('test_subsources') }}
  103. (REFERENCE "bids")
  104. """
  105. test_subsources = """
  106. {{ config(
  107. materialized='source',
  108. database='materialize'
  109. )
  110. }}
  111. FROM LOAD GENERATOR AUCTION
  112. FOR ALL TABLES;
  113. """
  114. test_sink = """
  115. {{ config(
  116. materialized='sink',
  117. pre_hook="CREATE CONNECTION IF NOT EXISTS kafka_connection TO KAFKA (BROKER '{{ env_var('KAFKA_ADDR', 'localhost:9092') }}', SECURITY PROTOCOL PLAINTEXT)"
  118. )
  119. }}
  120. FROM {{ ref('test_materialized_view') }}
  121. INTO KAFKA CONNECTION kafka_connection (TOPIC 'test-sink')
  122. FORMAT JSON
  123. ENVELOPE DEBEZIUM
  124. """
  125. test_sink_cluster = """
  126. {{ config(
  127. materialized='sink',
  128. cluster='quickstart'
  129. )
  130. }}
  131. FROM {{ ref('test_materialized_view') }}
  132. INTO KAFKA CONNECTION kafka_connection (TOPIC 'test-sink')
  133. FORMAT JSON
  134. ENVELOPE DEBEZIUM
  135. """
  136. test_sink_deploy = """
  137. {{ config(
  138. materialized='sink',
  139. schema='sinks_schema',
  140. cluster='sinks_cluster',
  141. pre_hook="CREATE CONNECTION IF NOT EXISTS kafka_connection TO KAFKA (BROKER '{{ env_var('KAFKA_ADDR', 'localhost:9092') }}', SECURITY PROTOCOL PLAINTEXT)"
  142. )
  143. }}
  144. FROM {{ ref('test_materialized_view_deploy') }}
  145. INTO KAFKA CONNECTION kafka_connection (TOPIC 'testdrive-test-sink-1')
  146. FORMAT JSON
  147. ENVELOPE DEBEZIUM
  148. """
  149. actual_indexes = """
  150. SELECT
  151. o.name as object_name,
  152. ic.index_position::int8,
  153. ic.on_position::int8,
  154. ic.on_expression,
  155. i.name as index_name
  156. FROM mz_indexes i
  157. JOIN mz_index_columns ic ON i.id = ic.index_id
  158. JOIN mz_objects o ON i.on_id = o.id
  159. WHERE i.id LIKE 'u%'
  160. """
  161. expected_indexes = """
  162. object_name,index_position,on_position,on_expression,index_name
  163. test_materialized_view_index,1,1,,a_idx
  164. test_materialized_view_index,2,,pg_catalog.length(a),a_idx
  165. test_source_index,1,1,,test_source_index_data_idx
  166. test_view_index,1,1,,test_view_index_primary_idx
  167. test_table_index,1,1,,test_table_index_a_idx
  168. test_table_index,2,,pg_catalog.length(a),test_table_index_a_idx
  169. test_source_table_index,1,4,,test_source_table_index_amount_idx
  170. """.lstrip()
  171. not_null = """
  172. {{ config(store_failures=true, schema='test', alias='testnull') }}
  173. SELECT *
  174. FROM {{ ref('test_materialized_view') }}
  175. WHERE a IS NULL
  176. """
  177. unique = """
  178. {{ config(store_failures=true, schema='test', alias='testunique') }}
  179. SELECT
  180. a AS unique_field,
  181. count(*) AS num_records
  182. FROM {{ ref('test_materialized_view') }}
  183. WHERE a IS NOT NULL
  184. GROUP BY a
  185. HAVING count(*) > 1
  186. """
  187. expected_base_relation_types = {
  188. "base": "materialized_view",
  189. "view_model": "view",
  190. "table_model": "materialized_view",
  191. "swappable": "materialized_view",
  192. }
  193. test_relation_name_length = """
  194. {{ config(materialized='materialized_view') }}
  195. SELECT * FROM (VALUES ('chicken', 'pig'), ('cow', 'horse'), (NULL, NULL)) _ (a, b)
  196. """
  197. test_hooks = {
  198. "models": {
  199. "test": {
  200. "pre-hook": [
  201. # inside transaction (runs second)
  202. core_base.MODEL_PRE_HOOK,
  203. # outside transaction (runs first)
  204. {
  205. "sql": "select 1 from {{ this.schema }}.on_model_hook",
  206. "transaction": False,
  207. },
  208. ],
  209. "post-hook": [
  210. # outside transaction (runs second)
  211. {
  212. "sql": "select 1 from {{ this.schema }}.on_model_hook",
  213. "transaction": False,
  214. },
  215. # inside transaction (runs first)
  216. core_base.MODEL_POST_HOOK,
  217. ],
  218. }
  219. }
  220. }
  221. test_run_operation = {
  222. # The create and drop table statements here validate that these hooks run
  223. # in the same order that they are defined. Drop before create is an error.
  224. # Also check that the table does not exist below.
  225. "on-run-start": [
  226. "{{ custom_run_hook('start', target, run_started_at, invocation_id) }}",
  227. "create table {{ target.schema }}.start_hook_order_test ( id int )",
  228. "drop table {{ target.schema }}.start_hook_order_test",
  229. "{{ log(env_var('TERM_TEST'), info=True) }}",
  230. ],
  231. "on-run-end": [
  232. "{{ custom_run_hook('end', target, run_started_at, invocation_id) }}",
  233. "create table {{ target.schema }}.end_hook_order_test ( id int )",
  234. "drop table {{ target.schema }}.end_hook_order_test",
  235. "create table {{ target.schema }}.schemas ( schema varchar )",
  236. "insert into {{ target.schema }}.schemas (schema) values {% for schema in schemas %}( '{{ schema }}' ){% if not loop.last %},{% endif %}{% endfor %}",
  237. "create table {{ target.schema }}.db_schemas ( db varchar, schema varchar )",
  238. "insert into {{ target.schema }}.db_schemas (db, schema) values {% for db, schema in database_schemas %}('{{ db }}', '{{ schema }}' ){% if not loop.last %},{% endif %}{% endfor %}",
  239. ],
  240. "seeds": {
  241. "quote_columns": False,
  242. },
  243. }
  244. model_hook = """
  245. create table {schema}.on_model_hook (
  246. test_state TEXT, -- start|end
  247. target_dbname TEXT,
  248. target_host TEXT,
  249. target_name TEXT,
  250. target_schema TEXT,
  251. target_type TEXT,
  252. target_user TEXT,
  253. target_pass TEXT,
  254. target_threads INTEGER,
  255. run_started_at TEXT,
  256. invocation_id TEXT,
  257. thread_id TEXT
  258. )
  259. """
  260. run_hook = """
  261. create table {schema}.on_run_hook (
  262. test_state TEXT, -- start|end
  263. target_dbname TEXT,
  264. target_host TEXT,
  265. target_name TEXT,
  266. target_schema TEXT,
  267. target_type TEXT,
  268. target_user TEXT,
  269. target_pass TEXT,
  270. target_threads INTEGER,
  271. run_started_at TEXT,
  272. invocation_id TEXT,
  273. thread_id TEXT
  274. )
  275. """
  276. nullability_assertions_schema_yml = """
  277. version: 2
  278. models:
  279. - name: test_nullability_assertions_ddl
  280. config:
  281. contract:
  282. enforced: true
  283. columns:
  284. - name: a
  285. data_type: string
  286. constraints:
  287. - type: not_null
  288. - name: b
  289. data_type: string
  290. constraints:
  291. - type: not_null
  292. - name: c
  293. data_type: string
  294. """
  295. contract_invalid_cluster_schema_yml = """
  296. version: 2
  297. models:
  298. - name: test_view
  299. config:
  300. contract:
  301. enforced: true
  302. columns:
  303. - name: a
  304. data_type: string
  305. constraints:
  306. - type: not_null
  307. - name: b
  308. data_type: string
  309. - name: c
  310. data_type: string
  311. """
  312. contract_pseudo_types_yml = """
  313. version: 2
  314. models:
  315. - name: test_pseudo_types
  316. config:
  317. contract:
  318. enforced: true
  319. columns:
  320. - name: a
  321. data_type: map
  322. - name: b
  323. data_type: record
  324. - name: c
  325. data_type: list
  326. """
  327. test_pseudo_types = """
  328. {{ config(materialized='view') }}
  329. SELECT '{a=>1, b=>2}'::map[text=>int] AS a, ROW(1, 2) AS b, LIST[[1,2],[3]] AS c
  330. """
  331. cross_database_reference_schema_yml = """
  332. version: 2
  333. sources:
  334. - name: test_database_1
  335. database: test_database_1
  336. schema: public
  337. tables:
  338. - name: table1
  339. - name: test_database_2
  340. database: test_database_2
  341. schema: public
  342. tables:
  343. - name: table2
  344. models:
  345. - name: cross_db_reference
  346. description: "A model that references tables from two different databases"
  347. columns:
  348. - name: id
  349. description: "The ID from test_database_1.table1 that matches test_database_2.table2"
  350. """
  351. cross_database_reference_sql = """
  352. {{ config(materialized='materialized_view', schema='public') }}
  353. WITH db1_data AS (
  354. SELECT id
  355. FROM {{ source('test_database_1', 'table1') }}
  356. ),
  357. db2_data AS (
  358. SELECT id
  359. FROM {{ source('test_database_2', 'table2') }}
  360. )
  361. SELECT db1_data.id
  362. FROM db1_data
  363. JOIN db2_data ON db1_data.id = db2_data.id
  364. """