Skip to content
Snippets Groups Projects
Commit c7831c5c authored by Cam Saul's avatar Cam Saul
Browse files

rework some of the test data stuff

parent 92ff768e
No related branches found
No related tags found
No related merge requests found
Showing
with 328 additions and 124 deletions
......@@ -20,7 +20,6 @@
(expect-expansion 0)
(expect-let 1)
(expect-with-all-drivers 1)
(expect-with-data-loaded 1)
(ins 1)
(let-400 1)
(let-404 1)
......
......@@ -74,12 +74,6 @@
(config/config-str :mb-db-user)
(config/config-str :mb-db-pass))))
(defn test-db-conn
"Simple test of a JDBC connection."
[jdbc-db]
(let [result (first (jdbc/query jdbc-db ["select 7 as num"] :row-fn :num))]
(assert (= 7 result) "JDBC Connection Test FAILED")))
;; ## MIGRATE
......@@ -98,16 +92,22 @@
(def ^:private setup-db-has-been-called?
(atom false))
(def ^:private db-can-connect? (u/runtime-resolved-fn 'metabase.driver 'can-connect?))
(defn setup-db
"Do general perparation of database by validating that we can connect.
Caller can specify if we should run any pending database migrations."
[& {:keys [auto-migrate]
:or {auto-migrate true}}]
(reset! setup-db-has-been-called? true)
(log/info "Setting up DB specs...")
(let [jdbc-db (setup-jdbc-db)
korma-db (setup-korma-db)]
;; Test DB connection and throw exception if we have any troubles connecting
(test-db-conn jdbc-db)
(log/info "Verifying Database Connection ...")
(assert (db-can-connect? {:engine (config/config-kw :mb-db-type)
:details {:conn_str (metabase-db-conn-str)}})
"Unable to connect to Metabase DB.")
(log/info "Verify Database Connection ... CHECK")
;; Run through our DB migration process and make sure DB is fully prepared
(if auto-migrate
......
......@@ -5,9 +5,10 @@
[korma.core :refer :all]
[metabase.config :as config]
[metabase.db :refer :all]
[metabase.driver.generic-sql.native :as native]
[metabase.driver.query-processor :as qp]
(metabase.driver.generic-sql [native :as native]
[util :refer :all])
[metabase.driver.generic-sql.query-processor.annotate :as annotate]
[metabase.driver.generic-sql.util :refer :all]
(metabase.models [database :refer [Database]]
[field :refer [Field]]
[table :refer [Table]])))
......@@ -234,7 +235,7 @@
(defn- log-query
"Log QUERY Dictionary and the korma form and SQL that the Query Processor translates it to."
[{:keys [source_table] :as query} forms]
(when-not *jdbc-metadata* ; HACK. If *jdbc-metadata* is bound we're probably doing a DB sync. Don't log its hundreds of QP calls, which make it hard to debug.
(when-not qp/*disable-qp-logging*
(log/debug
"\n********************"
"\nSOURCE TABLE: " source_table
......
(ns metabase.driver.mongo.query-processor
(:refer-clojure :exclude [find sort])
(:require [clojure.core.match :refer [match]]
[clojure.tools.logging :as log]
[colorize.core :as color]
(monger [collection :as mc]
[core :as mg]
......@@ -32,10 +33,10 @@
(with-mongo-connection [_ (sel :one :fields [Database :details] :id database-id)]
(case (keyword query-type)
:query (let [generated-query (process-structured (:query query))]
;; ; TODO - log/debug
(println (color/magenta "\n******************** Generated Monger Query: ********************\n"
(with-out-str (clojure.pprint/pprint generated-query))
"*****************************************************************\n"))
(when-not qp/*disable-qp-logging*
(log/debug (color/magenta "\n******************** Generated Monger Query: ********************\n"
(with-out-str (clojure.pprint/pprint generated-query))
"*****************************************************************\n")))
(->> (eval generated-query)
(annotate-results (:query query))))
:native (->> (eval-raw-command (:query (:native query)))
......
......@@ -11,6 +11,9 @@
(def ^:dynamic *query* "The structured query we're currently processing, before any preprocessing occurs (i.e. the `:query` part of the API call body)"
nil)
(def ^:dynamic *disable-qp-logging* "Should we disable logging for the QP? (e.g., during sync we probably want to turn it off to keep logs less cluttered)."
false)
(defn preprocess [{query-type :type :as query}]
(case (keyword query-type)
:query (preprocess-structured query)
......
......@@ -5,7 +5,8 @@
[colorize.core :as color]
[korma.core :as k]
[metabase.db :refer :all]
[metabase.driver.interface :refer :all]
(metabase.driver [interface :refer :all]
[query-processor :as qp])
[metabase.driver.sync.queries :as queries]
(metabase.models [field :refer [Field] :as field]
[foreign-key :refer [ForeignKey]]
......@@ -27,52 +28,54 @@
(defn sync-database!
"Sync DATABASE and all its Tables and Fields."
[driver database]
(sync-in-context driver database
(fn []
(log/info (color/blue (format "Syncing database %s..." (:name database))))
(let [active-table-names (active-table-names driver database)
table-name->id (sel :many :field->id [Table :name] :db_id (:id database) :active true)]
(assert (set? active-table-names) "active-table-names should return a set.")
(assert (every? string? active-table-names) "active-table-names should return the names of Tables as *strings*.")
;; First, let's mark any Tables that are no longer active as such.
;; These are ones that exist in table-name->id but not in active-table-names.
(log/debug "Marking inactive tables...")
(doseq [[table-name table-id] table-name->id]
(when-not (contains? active-table-names table-name)
(upd Table table-id :active false)
(log/info (format "Marked table %s.%s as inactive." (:name database) table-name))
;; We need to mark driver Table's Fields as inactive so we don't expose them in UI such as FK selector (etc.) This can happen in the background
(future (k/update Field
(k/where {:table_id table-id})
(k/set-fields {:active false})))))
;; Next, we'll create new Tables (ones that came back in active-table-names but *not* in table-name->id)
(log/debug "Creating new tables...")
(let [existing-table-names (set (keys table-name->id))]
(doseq [active-table-name active-table-names]
(when-not (contains? existing-table-names active-table-name)
(ins Table :db_id (:id database), :active true, :name active-table-name)
(log/info (format "Found new table: %s.%s" (:name database) active-table-name))))))
;; Now sync the active tables
(log/debug "Syncing active tables...")
(->> (sel :many Table :db_id (:id database) :active true)
(map #(assoc % :db (delay database))) ; replace default delays with ones that reuse database (and don't require a DB call)
(sync-database-active-tables! driver))
(log/info (color/blue (format "Finished syncing database %s." (:name database)))))))
(binding [qp/*disable-qp-logging* true]
(sync-in-context driver database
(fn []
(log/info (color/blue (format "Syncing database %s..." (:name database))))
(let [active-table-names (active-table-names driver database)
table-name->id (sel :many :field->id [Table :name] :db_id (:id database) :active true)]
(assert (set? active-table-names) "active-table-names should return a set.")
(assert (every? string? active-table-names) "active-table-names should return the names of Tables as *strings*.")
;; First, let's mark any Tables that are no longer active as such.
;; These are ones that exist in table-name->id but not in active-table-names.
(log/debug "Marking inactive tables...")
(doseq [[table-name table-id] table-name->id]
(when-not (contains? active-table-names table-name)
(upd Table table-id :active false)
(log/info (format "Marked table %s.%s as inactive." (:name database) table-name))
;; We need to mark driver Table's Fields as inactive so we don't expose them in UI such as FK selector (etc.) This can happen in the background
(future (k/update Field
(k/where {:table_id table-id})
(k/set-fields {:active false})))))
;; Next, we'll create new Tables (ones that came back in active-table-names but *not* in table-name->id)
(log/debug "Creating new tables...")
(let [existing-table-names (set (keys table-name->id))]
(doseq [active-table-name active-table-names]
(when-not (contains? existing-table-names active-table-name)
(ins Table :db_id (:id database), :active true, :name active-table-name)
(log/info (format "Found new table: %s.%s" (:name database) active-table-name))))))
;; Now sync the active tables
(log/debug "Syncing active tables...")
(->> (sel :many Table :db_id (:id database) :active true)
(map #(assoc % :db (delay database))) ; replace default delays with ones that reuse database (and don't require a DB call)
(sync-database-active-tables! driver))
(log/info (color/blue (format "Finished syncing database %s." (:name database))))))))
(defn sync-table!
"Sync a *single* TABLE by running all the sync steps for it.
This is used *instead* of `sync-database!` when syncing just one Table is desirable."
[driver table]
(let [database @(:db table)]
(sync-in-context driver database
(fn []
(sync-database-active-tables! driver [table])))))
(binding [qp/*disable-qp-logging* true]
(sync-in-context driver database
(fn []
(sync-database-active-tables! driver [table]))))))
;; ### sync-database-active-tables! -- runs the sync-table steps over sequence of Tables
......@@ -264,7 +267,6 @@
(extend-protocol ISyncDriverFieldPercentUrls ; Default implementation
Object
(field-percent-urls [this field]
(log/warn (color/red (format "Using default (read: slow) implementation of field-percent-urls for driver %s." (.getName (class this)))))
(assert (extends? ISyncDriverFieldValues (class this))
"A sync driver implementation that doesn't implement ISyncDriverFieldPercentURLs must implement ISyncDriverFieldValues.")
(let [field-values (field-values-lazy-seq this field)]
......@@ -312,7 +314,6 @@
(extend-protocol ISyncDriverFieldAvgLength ; Default implementation
Object
(field-avg-length [this field]
(log/warn (color/red (format "Using default (read: slow) implementation of field-avg-length for driver %s." (.getName (class this)))))
(assert (extends? ISyncDriverFieldValues (class this))
"A sync driver implementation that doesn't implement ISyncDriverFieldAvgLength must implement ISyncDriverFieldValues.")
(let [field-values (field-values-lazy-seq this field)
......
......@@ -18,7 +18,9 @@
:can_read (delay (org-can-read organization_id))
:can_write (delay (org-can-write organization_id))))
(defmethod pre-cascade-delete Database [_ {:keys [id]}]
(defmethod pre-cascade-delete Database [_ {:keys [id] :as database}]
(if (= (:engine database) :mongo)
(throw (Exception. "WHY ARE WE DESTROYING MONGO DB!")))
(cascade-delete 'metabase.models.table/Table :db_id id)
(cascade-delete 'metabase.models.query/Query :database_id id))
......
......@@ -2,6 +2,7 @@
"Tests for /api/meta/table endpoints."
(:require [expectations :refer :all]
[metabase.db :refer :all]
[metabase.driver.mongo.test-data :as mongo-data :refer [mongo-test-db-id]]
[metabase.http-client :as http]
[metabase.middleware.auth :as auth]
(metabase.models [field :refer [Field]]
......@@ -21,10 +22,22 @@
;; ## GET /api/meta/table?org
;; These should come back in alphabetical order and include relevant metadata
(expect [{:description nil, :entity_type nil, :name "CATEGORIES", :rows 75, :entity_name nil, :active true, :id (table->id :categories), :db_id @db-id}
{:description nil, :entity_type nil, :name "CHECKINS", :rows 1000, :entity_name nil, :active true, :id (table->id :checkins), :db_id @db-id}
{:description nil, :entity_type nil, :name "USERS", :rows 15, :entity_name nil, :active true, :id (table->id :users), :db_id @db-id}
{:description nil, :entity_type nil, :name "VENUES", :rows 100, :entity_name nil, :active true, :id (table->id :venues), :db_id @db-id}]
(expect [{:description nil, :entity_type nil, :name "CATEGORIES", :rows 75, :entity_name nil, :active true,
:id (table->id :categories), :db_id @db-id}
{:description nil, :entity_type nil, :name "CHECKINS", :rows 1000, :entity_name nil, :active true,
:id (table->id :checkins), :db_id @db-id}
{:description nil, :entity_type nil, :name "USERS", :rows 15, :entity_name nil, :active true,
:id (table->id :users), :db_id @db-id}
{:description nil, :entity_type nil, :name "VENUES", :rows 100, :entity_name nil, :active true,
:id (table->id :venues), :db_id @db-id}
{:description nil, :entity_type nil, :name "categories", :rows 75, :entity_name nil, :active true,
:id (mongo-data/table-name->id :categories), :db_id @mongo-test-db-id}
{:description nil, :entity_type nil, :name "checkins", :rows 1000, :entity_name nil, :active true,
:id (mongo-data/table-name->id :checkins), :db_id @mongo-test-db-id}
{:description nil, :entity_type nil, :name "users", :rows 15, :entity_name nil, :active true,
:id (mongo-data/table-name->id :users), :db_id @mongo-test-db-id}
{:description nil, :entity_type nil, :name "venues", :rows 100, :entity_name nil, :active true,
:id (mongo-data/table-name->id :venues), :db_id @mongo-test-db-id}]
(->> ((user->client :rasta) :get 200 "meta/table" :org @org-id)
(map #(dissoc % :db :created_at :updated_at)))) ; don't care about checking nested DB, and not sure how to compare `:created_at` / `:updated_at`
......
......@@ -3,6 +3,7 @@
(:require [expectations :refer :all]
[korma.core :refer :all]
[metabase.db :refer :all]
[metabase.driver.mongo.test-data :as mongo-test-data]
(metabase.models [database :refer [Database]]
[query :refer [Query]]
[query-execution :refer [QueryExecution]])
......@@ -35,7 +36,6 @@
{:name "Read Only", :id 1}
{:name "Read & Write", :id 2}]}
(do
@test-db ; force lazy creation of test data / Metabase DB if it doesn't already exist
(cascade-delete Database :organization_id @org-id :id [not= (:id @test-db)]) ; delete any other rando test DBs made by other tests
((user->client :rasta) :get 200 "query/form_input" :org @org-id)))
......
......@@ -13,7 +13,7 @@
[]
(let [{query-id :id} (create-query)
query-execution ((user->client :rasta) :post 200 (format "query/%d" query-id))]
(Thread/sleep 100) ; Give it 100ms to finish
(Thread/sleep 200) ; Give it 200ms to finish
query-execution))
;; ## GET /result/:id
......
......@@ -29,24 +29,37 @@
;; ## MONGO-TEST-DB + OTHER DELAYS
(def mongo-test-db
"A delay that fetches or creates the Mongo test `Database`.
If DB is created, `load-data` and `sync-database!` are called to get the DB in a state that we can use for testing."
(delay (or (sel :one Database :name mongo-test-db-name)
(let [db (ins Database
:organization_id @org-id
:name mongo-test-db-name
:engine :mongo
:details {:conn_str mongo-test-db-conn-str})]
(log/debug (color/cyan "Loading Mongo test data..."))
(load-data)
(driver/sync-database! db)
(log/debug (color/cyan "Done."))
db))))
(def mongo-test-db-id
"A Delay that returns the ID of `mongo-test-db`, forcing creation of it if needed."
(delay (:id @mongo-test-db)))
(defn destroy!
"Remove `Database`, `Tables`, and `Fields` for the Mongo test DB."
[]
#_(cascade-delete Database :name mongo-test-db-name))
(defonce
^{:doc "A delay that fetches or creates the Mongo test `Database`.
If DB is created, `load-data` and `sync-database!` are called to get the DB in a state that we can use for testing."}
mongo-test-db
(delay (let [db (or (sel :one Database :name mongo-test-db-name)
(let [db (ins Database
:organization_id @org-id
:name mongo-test-db-name
:engine :mongo
:details {:conn_str mongo-test-db-conn-str})]
(log/debug (color/cyan "Loading Mongo test data..."))
(load-data)
(driver/sync-database! db)
(log/debug (color/cyan "Done."))
db))]
(assert (and (map? db)
(integer? (:id db))
(exists? Database :id (:id db))))
db)))
(defonce
^{:doc "A Delay that returns the ID of `mongo-test-db`, forcing creation of it if needed."}
mongo-test-db-id
(delay (let [id (:id @mongo-test-db)]
(assert (integer? id))
id)))
;; ## FNS FOR GETTING RELEVANT TABLES / FIELDS
......@@ -58,7 +71,12 @@
[table-name]
{:pre [(keyword? table-name)]
:post [(map? %)]}
(sel :one Table :db_id @mongo-test-db-id :name (name table-name)))
(assert (exists? Database :id @mongo-test-db-id)
(format "Database with ID %d no longer exists!?" @mongo-test-db-id))
(or (sel :one Table :db_id @mongo-test-db-id :name (name table-name))
(println (colorize.core/red "db_id: " @mongo-test-db-id "\n"
"db: " (with-out-str (clojure.pprint/pprint (sel :one Database :id @mongo-test-db-id))) "\n"
"name: " (name table-name)))))
(def ^{:arglists '([table-name])} table-name->id
"Return ID of `Table` for Mongo test database (memoized).
......
......@@ -39,13 +39,6 @@
[:venues :name]
[:venues :price]])
(defmacro expect-with-data-loaded
"Like `expect`, but forces the test database to be loaded/synced/etc. before running the test."
[expected actual]
`(expect (do @mongo-test-db
~expected)
~actual))
(defn- table-name->fake-table
"Return an object that can be passed like a `Table` to driver sync functions."
[table-name]
......@@ -107,7 +100,7 @@
(i/active-table-names mongo/driver @mongo-test-db))
;; ### table->column-names
(expect-with-data-loaded
(expect
[#{:_id :name}
#{:_id :date :venue_id :user_id}
#{:_id :name :last_login}
......@@ -117,7 +110,7 @@
(map table->column-names)))
;; ### field->base-type
(expect-with-data-loaded
(expect
[:IntegerField ; categories._id
:TextField ; categories.name
:IntegerField ; checkins._id
......@@ -158,7 +151,7 @@
;; ## Big-picture tests for the way data should look post-sync
;; Test that Tables got synced correctly, and row counts are correct
(expect-with-data-loaded
(expect
[{:rows 75, :active true, :name "categories"}
{:rows 1000, :active true, :name "checkins"}
{:rows 15, :active true, :name "users"}
......@@ -166,19 +159,22 @@
(sel :many :fields [Table :name :active :rows] :db_id @mongo-test-db-id (k/order :name)))
;; Test that Fields got synced correctly, and types are correct
(expect-with-data-loaded
[({:special_type :id, :base_type :IntegerField, :field_type :info, :active true, :name "_id"}
{:special_type :category, :base_type :DateField, :field_type :info, :active true, :name "last_login"}
{:special_type :category, :base_type :TextField, :field_type :info, :active true, :name "name"})
({:special_type :id, :base_type :IntegerField, :field_type :info, :active true, :name "_id"}
{:special_type :category, :base_type :DateField, :field_type :info, :active true, :name "last_login"}
{:special_type :category, :base_type :TextField, :field_type :info, :active true, :name "name"})
({:special_type :id, :base_type :IntegerField, :field_type :info, :active true, :name "_id"}
{:special_type :category, :base_type :DateField, :field_type :info, :active true, :name "last_login"}
{:special_type :category, :base_type :TextField, :field_type :info, :active true, :name "name"})
({:special_type :id, :base_type :IntegerField, :field_type :info, :active true, :name "_id"}
{:special_type :category, :base_type :DateField, :field_type :info, :active true, :name "last_login"}
{:special_type :category, :base_type :TextField, :field_type :info, :active true, :name "name"})]
(expect
[[{:special_type :id, :base_type :IntegerField, :name "_id"}
{:special_type :category, :base_type :DateField, :name "last_login"}
{:special_type :category, :base_type :TextField, :name "name"}]
[{:special_type :id, :base_type :IntegerField, :name "_id"}
{:special_type :category, :base_type :DateField, :name "last_login"}
{:special_type :category, :base_type :TextField, :name "name"}]
[{:special_type :id, :base_type :IntegerField, :name "_id"}
{:special_type :category, :base_type :DateField, :name "last_login"}
{:special_type :category, :base_type :TextField, :name "name"}]
[{:special_type :id, :base_type :IntegerField, :name "_id"}
{:special_type :category, :base_type :DateField, :name "last_login"}
{:special_type :category, :base_type :TextField, :name "name"}]]
(let [table->fields (fn [table-name]
(sel :many :fields [Field :name :active :field_type :base_type :special_type] :table_id (table-name->id :users) (k/order :name)))]
(mapv table->fields table-names)))
(sel :many :fields [Field :name :base_type :special_type]
:active true
:table_id (table-name->id :users)
(k/order :name)))]
(map table->fields table-names)))
......@@ -53,7 +53,8 @@
(binding [*driver-data* driver-data#
*db* db#
*db-id* (:id db#)]
(assert (integer? *db-id*))
(assert (and (integer? *db-id*)
(map? *db*)))
~@body)))
(defmacro expect-with-all-drivers
......@@ -82,16 +83,16 @@
:post [(integer? %)]}
(:id (->table table-name)))
#_(def ^{:arglists '([table-name])} table-name->id
"Given keyword TABLE-NAME, fetch ID of corresponding `Table` in `*db*`."
(let [-table-name->id (memoize (fn [db-id table-name]
{:pre [(integer? db-id)
(keyword? table-name)]
:post [(integer? %)]}
(sel :one :id Table :db_id db-id :name (name table-name))))]
(fn [table-name]
{:pre [(integer? *db-id*)]}
(-table-name->id *db-id* table-name))))
;; (def ^{:arglists '([table-name])} table-name->id
;; "Given keyword TABLE-NAME, fetch ID of corresponding `Table` in `*db*`."
;; (let [-table-name->id (memoize (fn [db-id table-name]
;; {:pre [(integer? db-id)
;; (keyword? table-name)]
;; :post [(integer? %)]}
;; (sel :one :id Table :db_id db-id :name (name table-name))))]
;; (fn [table-name]
;; {:pre [(integer? *db-id*)]}
;; (-table-name->id *db-id* table-name))))
;; ## Driver-Independent QP Tests
......
(ns metabase.test.data
"Eventual replacement for `metabase.test-data`.
Designed to handle multiple test data sets more nicely."
(:require [clojure.tools.logging :as log]
[colorize.core :as color]
[metabase.db :refer :all]
[metabase.driver :as driver]
(metabase.models [database :refer [Database]]
[org :refer [Org]])
(metabase.test.data [interface :as i]))
(:import metabase.test.data.h2.H2TestData
metabase.test.data.mongo.MongoTestData))
;; ## Test Org
(def ^:const ^:private test-org-name "Test Organization")
(def test-org
(delay (or (sel :one Org :name test-org-name)
(ins Org
:name test-org-name
:slug "test"
:inherits true))))
(def test-org-id
(delay (:id @test-org)))
;; ## Test Data Instances
(def h2 (H2TestData.))
(def mongo (MongoTestData.))
(def engine-name->test-data
{:h2 h2
:mongo mongo})
(def ^:dynamic *engine*
:h2)
(defn test-data []
(engine-name->test-data *engine*))
(defmacro with-test-data [engine-name & body]
`(binding [*engine* ~engine-name]
(assert (test-data))
~@body))
;; ## Implementation-Agnostic Fns
(defn load! []
(log/debug (color/cyan (format "Loading %s test data..." (name *engine*))))
(i/load! (test-data))
(let [db (ins Database
:engine *engine*
:organization_id @test-org-id
:name (db-name (test-data))
:details {:conn_str (connection-str (test-data))})]
(driver/sync-database! db)
(log/debug (color/green "Done."))
db))
(defn db []
(let [db (or (sel :one Database :name (i/db-name (test-data)))
(load!))]
(assert (map? db))
db))
(def db-id
(let [engine-name->db-id (memoize
(fn [engine-name]
{:post [(integer? engine-name)]}
(with-test-data engine-name
(:id (db)))))])
(fn []
(engine-name->db-id *engine*)))
(defn destroy! []
(cascade-delete Database :name (db-name (test-data))))
(defn table-name->table [table-name]
{:pre [(keyword? table-name)]
:post [(map? %)]}
(i/table-name->table (test-data) (db-id) table-name))
(def table-name->id
(let [engine+table-name->id (memoize
(fn [engine-name table-name]
{:pre [(keyword? table-name)]
:post [(integer? %)]}
(with-test-data engine-name
(i/table-name->id (test-data) (db-id) table-name))))]
(fn [table-name]
(engine+table-name->id *engine* table-name))))
(defn field-name->field [table-name field-name]
{:pre [(keyword? table-name)
(keyword? field-name)]
:post [(map? %)]}
(i/field-name->field (test-data) table-name field-name))
(defn field-name->id [table-name field-name]
{:pre [(keyword? table-name)
(keyword? field-name)]
:post [(integer? %)]}
(i/field-name->id (test-data) table-name field-name))
;; ## Fns that Run Across *All* Test Datasets
(defn load-all! []
(doseq [[engine test-data] engine-name->test-data]
(i/load! test-data)
(log/debug (color/green "Ok."))))
(ns metabase.test.data.h2
(:require [metabase.test.data.interface :refer :all]))
(deftype H2TestData []
TestData
(load! [_])
(db-name [_]
"Test Database")
(connection-str [_]
(let [filename (format "%s/target/test-data" (System/getProperty "user.dir"))]
(format "file:%s;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1" filename))))
(ns metabase.test.data.interface
"`TestData` protocol.")
(defprotocol TestData
;; Loading
(load! [this]
"Load test data, if needed. This should create relevant data, and call `metabase.driver.sync-database!`.")
;; DB
(db-name [this]
"Name to use for test `Database`.")
(connection-str [this]
"Connection string to use to connect to test `Database`.")
;; Fetching Fns
(table-name->table [this db-id table-name])
(field-name->field [this table-name field-name]))
(ns metabase.test.data.mongo
(:require [metabase.db :refer :all]
(metabase.models [table :refer [Table]])
[metabase.test.data.interface :refer :all]))
(deftype MongoTestData []
TestData
(load! [_])
(db-name [_]
"Mongo Test")
(connection-str [_]
"mongodb://localhost/metabase-test")
(table-name->table [_ db-id table-name]
(sel :one Table :db_id db-id :name table-name))
(field-name->field [_ table-name field-name]))
......@@ -6,7 +6,8 @@
(metabase [core :as core]
[db :as db]
[task :as task]
[test-data :refer :all])))
[test-data :as h2-test-data])
[metabase.driver.mongo.test-data :as mongo-test-data]))
(declare clear-test-db)
......@@ -24,11 +25,17 @@
[]
(log/info "Starting up Metabase unit test runner")
;; clear out any previous test data that's lying around
(log/info "Clearing out test DB...")
(clear-test-db)
;; setup the db and migrate up to current schema
(log/info "Setting up test DB and running migrations...")
(db/setup-db :auto-migrate true)
;; this causes the test data to be loaded
@test-db
(log/info "Loading test data: h2...")
@h2-test-data/test-db
(assert (integer? @h2-test-data/db-id))
(log/info "Loading test data: mongo...")
(mongo-test-data/destroy!)
@mongo-test-data/mongo-test-db
(assert (integer? @mongo-test-data/mongo-test-db-id))
;; startup test web server
(core/start-jetty)
;; start the task runner
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment