From a33f3ddd2865e7e374ce367470418cb77e69a06c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cam=20Sa=C3=BCl?= <cammsaul@gmail.com>
Date: Mon, 28 Nov 2016 13:14:54 -0800
Subject: [PATCH] Test fixes & cleanup [ci drivers] :wrench: :shower:

---
 .gitignore                              |   1 +
 test/metabase/driver/bigquery_test.clj  |  62 ------------
 test/metabase/query_processor_test.clj  |  12 ++-
 test/metabase/test/data.clj             | 120 +++++++++---------------
 test/metabase/test/data/bigquery.clj    |   3 +-
 test/metabase/test/data/crate.clj       |  15 +--
 test/metabase/test/data/druid.clj       |   3 +-
 test/metabase/test/data/generic_sql.clj |  17 +---
 test/metabase/test/data/interface.clj   |  19 +++-
 test/metabase/test/data/mongo.clj       |   6 +-
 test/metabase/test/data/oracle.clj      |   7 +-
 test/metabase/test/data/postgres.clj    |  26 +++--
 test/metabase/test/data/redshift.clj    |   9 +-
 test/metabase/test/data/sqlserver.clj   |   9 +-
 14 files changed, 112 insertions(+), 197 deletions(-)

diff --git a/.gitignore b/.gitignore
index 7338012bf78..0eedbcd994b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,4 @@ bin/release/aws-eb/metabase-aws-eb.zip
 /plugins
 /build.xml
 /test-report-*
+/crate-*
diff --git a/test/metabase/driver/bigquery_test.clj b/test/metabase/driver/bigquery_test.clj
index 395fd7a7f8f..d6767253f02 100644
--- a/test/metabase/driver/bigquery_test.clj
+++ b/test/metabase/driver/bigquery_test.clj
@@ -6,68 +6,6 @@
             (metabase.test.data [datasets :refer [expect-with-engine]]
                                 [interface :refer [def-database-definition]])))
 
-;; Make sure that paging works correctly for the bigquery driver when fetching a list of tables
-;; Default page size is 50 so if we have more than that number of tables make sure they all show up
-(def-database-definition ^:private fifty-one-different-tables
-  ["birds_1"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_2"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_3"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_4"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_5"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_6"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_7"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_8"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_9"  [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_10" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_11" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_12" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_13" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_14" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_15" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_16" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_17" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_18" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_19" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_20" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_21" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_22" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_23" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_24" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_25" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_26" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_27" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_28" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_29" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_30" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_31" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_32" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_33" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_34" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_35" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_36" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_37" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_38" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_39" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_40" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_41" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_42" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_43" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_44" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_45" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_46" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_47" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_48" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_49" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_50" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]]
-  ["birds_51" [{:field-name "name", :base-type :type/Text}] [["Rasta"] ["Lucky"]]])
-
-;; only run this test 1 out of every 5 times since it takes like 5-10 minutes just to sync the DB and we don't have all day
-(when (> (rand) 0.80)
-  (expect-with-engine :bigquery
-    51
-    (data/with-temp-db [db fifty-one-different-tables]
-      (count (database/tables db)))))
-
 
 ;; Test native queries
 (expect-with-engine :bigquery
diff --git a/test/metabase/query_processor_test.clj b/test/metabase/query_processor_test.clj
index f73a07c5366..1f1327c551f 100644
--- a/test/metabase/query_processor_test.clj
+++ b/test/metabase/query_processor_test.clj
@@ -5,11 +5,21 @@
   (:require [clojure.set :as set]
             [expectations :refer :all]
             [metabase.driver :as driver]
-            #_[metabase.query-processor :refer :all]
             [metabase.test.data :as data]
             [metabase.test.data.datasets :as datasets]
+            metabase.test.data.interface
             [metabase.util :as u]))
 
+;; make sure all the driver test extension namespaces are loaded <3
+;; if this isn't done some things will get loaded at the wrong time which can end up causing test databases to be created more than once, which fails
+(doseq [engine (keys (driver/available-drivers))]
+  (let [test-ns (symbol (str "metabase.test.data." (name engine)))]
+    (try
+      (require test-ns)
+      (catch Throwable e
+        (println (format "Error loading %s: %s" test-ns (.getMessage e)))))))
+
+
 ;;; ------------------------------------------------------------ Helper Fns + Macros ------------------------------------------------------------
 
 ;; Event-Based DBs aren't tested here, but in `event-query-processor-test` instead.
diff --git a/test/metabase/test/data.clj b/test/metabase/test/data.clj
index c69fd463064..5f23a1336ad 100644
--- a/test/metabase/test/data.clj
+++ b/test/metabase/test/data.clj
@@ -166,95 +166,68 @@
 
 ;; ## Loading / Deleting Test Datasets
 
+(defn- add-extra-metadata!
+  "Add extra metadata like Field base-type, etc."
+  [database-definition db]
+  (doseq [^TableDefinition table-definition (:table-definitions database-definition)]
+    (let [table-name (:table-name table-definition)
+          table      (delay (or  (i/metabase-instance table-definition db)
+                                 (throw (Exception. (format "Table '%s' not loaded from definiton:\n%s\nFound:\n%s"
+                                                            table-name
+                                                            (u/pprint-to-str (dissoc table-definition :rows))
+                                                            (u/pprint-to-str (db/select [Table :schema :name], :db_id (:id db))))))))]
+      (doseq [{:keys [field-name visibility-type special-type], :as field-definition} (:field-definitions table-definition)]
+        (let [field (delay (or (i/metabase-instance field-definition @table)
+                               (throw (Exception. (format "Field '%s' not loaded from definition:\n"
+                                                          field-name
+                                                          (u/pprint-to-str field-definition))))))]
+          (when visibility-type
+            (log/debug (format "SET VISIBILITY TYPE %s.%s -> %s" table-name field-name visibility-type))
+            (db/update! Field (:id @field) :visibility_type (name visibility-type)))
+          (when special-type
+            (log/debug (format "SET SPECIAL TYPE %s.%s -> %s" table-name field-name special-type))
+            (db/update! Field (:id @field) :special_type (u/keyword->qualified-name special-type))))))))
+
+(defn- create-database! [{:keys [database-name], :as database-definition} engine driver]
+  ;; Create the database
+  (i/create-db! driver database-definition)
+  ;; Add DB object to Metabase DB
+  (u/prog1 (db/insert! Database
+             :name    database-name
+             :engine  (name engine)
+             :details (i/database->connection-details driver :db database-definition))
+    ;; sync newly added DB
+    (sync-database/sync-database! <>)
+    ;; add extra metadata for fields
+    (add-extra-metadata! database-definition <>)))
+
 (defn get-or-create-database!
   "Create DBMS database associated with DATABASE-DEFINITION, create corresponding Metabase `Databases`/`Tables`/`Fields`, and sync the `Database`.
-   DATASET-LOADER should be an object that implements `IDatasetLoader`; it defaults to the value returned by the method `dataset-loader` for the
+   DRIVER should be an object that implements `IDatasetLoader`; it defaults to the value returned by the method `driver` for the
    current dataset (`*driver*`), which is H2 by default."
-  ([^DatabaseDefinition database-definition]
+  ([database-definition]
    (get-or-create-database! *driver* database-definition))
-  ([dataset-loader {:keys [database-name], :as ^DatabaseDefinition database-definition}]
-   (let [engine (i/engine dataset-loader)]
+  ([driver database-definition]
+   (let [engine (i/engine driver)]
      (or (i/metabase-instance database-definition engine)
-         (do
-           ;; Create the database
-           (i/create-db! dataset-loader database-definition)
-
-           ;; Add DB object to Metabase DB
-           (let [db (db/insert! Database
-                      :name    database-name
-                      :engine  (name engine)
-                      :details (i/database->connection-details dataset-loader :db database-definition))]
-
-             ;; Sync the database
-             (sync-database/sync-database! db)
-
-             ;; Add extra metadata like Field base-type, etc.
-             (doseq [^TableDefinition table-definition (:table-definitions database-definition)]
-               (let [table-name (:table-name table-definition)
-                     table      (delay (or  (i/metabase-instance table-definition db)
-                                            (throw (Exception. (format "Table '%s' not loaded from definiton:\n%s\nFound:\n%s"
-                                                                       table-name
-                                                                       (u/pprint-to-str (dissoc table-definition :rows))
-                                                                       (u/pprint-to-str (db/select [Table :schema :name], :db_id (:id db))))))))]
-                 (doseq [{:keys [field-name visibility-type special-type], :as field-definition} (:field-definitions table-definition)]
-                   (let [field (delay (or (i/metabase-instance field-definition @table)
-                                          (throw (Exception. (format "Field '%s' not loaded from definition:\n"
-                                                                     field-name
-                                                                     (u/pprint-to-str field-definition))))))]
-                     (when visibility-type
-                       (log/debug (format "SET VISIBILITY TYPE %s.%s -> %s" table-name field-name visibility-type))
-                       (db/update! Field (:id @field) :visibility_type (name visibility-type)))
-                     (when special-type
-                       (log/debug (format "SET SPECIAL TYPE %s.%s -> %s" table-name field-name special-type))
-                       (db/update! Field (:id @field) :special_type (u/keyword->qualified-name special-type)))))))
-             db))))))
-
-(defn remove-database!
-  "Delete Metabase `Database`, `Fields` and `Tables` associated with DATABASE-DEFINITION, then remove the physical database from the associated DBMS.
-   DATASET-LOADER should be an object that implements `IDatasetLoader`; by default it is the value returned by the method `dataset-loader` for the
-   current dataset, bound to `*driver*`."
-  ([^DatabaseDefinition database-definition]
-   (remove-database! *driver* database-definition))
-  ([dataset-loader ^DatabaseDefinition database-definition]
-   ;; Delete the Metabase Database and associated objects
-   (db/cascade-delete! Database :id (:id (i/metabase-instance database-definition (i/engine dataset-loader))))
-
-   ;; now delete the DBMS database
-   (i/destroy-db! dataset-loader database-definition)))
-
-
-(def ^:private loader->loaded-db-def
-  (atom #{}))
-
-(defn destroy-loaded-temp-dbs!
-  "Destroy all temporary databases created by `with-temp-db`."
-  {:expectations-options :after-run}
-  []
-  (binding [db/*disable-db-logging* true]
-    (doseq [[loader dbdef] @loader->loaded-db-def]
-      (try
-        (remove-database! loader dbdef)
-        (catch Throwable e
-          (println "Error destroying database:" e)))))
-  (reset! loader->loaded-db-def #{}))
+         (create-database! database-definition engine driver)))))
 
 
 (defn do-with-temp-db
   "Execute F with DBDEF loaded as the current dataset. F takes a single argument, the `DatabaseInstance` that was loaded and synced from DBDEF."
   [^DatabaseDefinition dbdef, f]
-  (let [loader *driver*
+  (let [driver *driver*
         dbdef  (i/map->DatabaseDefinition dbdef)]
-    (swap! loader->loaded-db-def conj [loader dbdef])
     (binding [db/*disable-db-logging* true]
-      (let [db (get-or-create-database! loader dbdef)]
+      (let [db (get-or-create-database! driver dbdef)]
         (assert db)
-        (assert (db/exists? Database :id (:id db)))
+        (assert (db/exists? Database :id (u/get-id db)))
         (with-db db
           (f db))))))
 
 
 (defmacro with-temp-db
-  "Load and sync DATABASE-DEFINITION with DATASET-LOADER and execute BODY with the newly created `Database` bound to DB-BINDING,
+  "Load and sync DATABASE-DEFINITION with DRIVER and execute BODY with the newly created `Database` bound to DB-BINDING,
    and make it the current database for `metabase.test.data` functions like `id`.
 
      (with-temp-db [db tupac-sightings]
@@ -264,9 +237,8 @@
                                           :aggregation  [\"count\"]
                                           :filter       [\"<\" (:id &events.timestamp) \"1765-01-01\"]}}))
 
-   A given Database is only created once per run of the test suite, and is automatically destroyed at the conclusion of the suite.
-   (The created Database is added to `loader->loaded-db-def`, which can be destroyed with `destroy-loaded-temp-dbs!`, which is automatically ran at the end of the test suite.)"
-  [[db-binding ^DatabaseDefinition database-definition] & body]
+   A given Database is only created once per run of the test suite, and is automatically destroyed at the conclusion of the suite."
+  [[db-binding, ^DatabaseDefinition database-definition] & body]
   `(do-with-temp-db ~database-definition
      (fn [~db-binding]
        ~@body)))
diff --git a/test/metabase/test/data/bigquery.clj b/test/metabase/test/data/bigquery.clj
index 4f920dc52ad..eacaf81f00d 100644
--- a/test/metabase/test/data/bigquery.clj
+++ b/test/metabase/test/data/bigquery.clj
@@ -205,5 +205,4 @@
   (merge i/IDatasetLoaderDefaultsMixin
          {:engine                       (constantly :bigquery)
           :database->connection-details (u/drop-first-arg database->connection-details)
-          :create-db!                   (u/drop-first-arg create-db!)
-          :destroy-db!                  (constantly nil)}))
+          :create-db!                   (u/drop-first-arg create-db!)}))
diff --git a/test/metabase/test/data/crate.clj b/test/metabase/test/data/crate.clj
index f231b0fa62e..3b1ff4b92d1 100644
--- a/test/metabase/test/data/crate.clj
+++ b/test/metabase/test/data/crate.clj
@@ -20,7 +20,7 @@
    :type/Time       "timestamp"})
 
 
-(defn- timestamp->CrateDateTime
+(defn- timestamp->crate-datetime
   [value]
   (cond
     (instance? java.sql.Timestamp value)    (.getTime ^java.sql.Timestamp value)
@@ -34,7 +34,7 @@
   (if (sequential? row-or-rows)
     (map escape-field-names row-or-rows)
     (into {} (for [[k v] row-or-rows]
-               {(sql/escape-field-name k) (timestamp->CrateDateTime v)}))))
+               {(sql/escape-field-name k) (timestamp->crate-datetime v)}))))
 
 (defn- make-load-data-fn
   "Create a `load-data!` function. This creates a function to actually insert a row or rows, wraps it with any WRAP-INSERT-FNS,
@@ -44,7 +44,7 @@
     (let [insert! ((apply comp wrap-insert-fns) (fn [row-or-rows]
                                                   (jdbc/insert-multi!
                                                     (generic/database->spec driver :db dbdef)
-                                                    (keyword (:table-name tabledef))
+                                                    (keyword (i/db-qualified-table-name (name (:database-name dbdef)) (name (:table-name tabledef))))
                                                     (escape-field-names row-or-rows)
                                                     {:transaction? false})))
           rows    (apply list (generic/load-data-get-rows driver dbdef tabledef))]
@@ -63,9 +63,10 @@
           :create-db-sql             (constantly nil)
           :add-fk-sql                (constantly nil)
           :drop-db-if-exists-sql     (constantly nil)
-          :load-data!                (make-load-data-fn generic/load-data-add-ids)})
+          :load-data!                (make-load-data-fn generic/load-data-add-ids)
+          :qualified-name-components (partial i/single-db-qualified-name-components "doc")})
   i/IDatasetLoader
   (merge generic/IDatasetLoaderMixin
-         {:database->connection-details   database->connection-details
-          :engine                         (constantly :crate)
-          :default-schema                 (constantly "doc")}))
+         {:database->connection-details database->connection-details
+          :engine                       (constantly :crate)
+          :default-schema               (constantly "doc")}))
diff --git a/test/metabase/test/data/druid.clj b/test/metabase/test/data/druid.clj
index 118a52b3c18..59d063b122a 100644
--- a/test/metabase/test/data/druid.clj
+++ b/test/metabase/test/data/druid.clj
@@ -21,8 +21,7 @@
   (merge i/IDatasetLoaderDefaultsMixin
          {:engine                       (constantly :druid)
           :database->connection-details database->connection-details
-          :create-db!                   (constantly nil)
-          :destroy-db!                  (constantly nil)}))
+          :create-db!                   (constantly nil)}))
 
 
 
diff --git a/test/metabase/test/data/generic_sql.clj b/test/metabase/test/data/generic_sql.clj
index a412c06bab2..5a93ba82eb1 100644
--- a/test/metabase/test/data/generic_sql.clj
+++ b/test/metabase/test/data/generic_sql.clj
@@ -129,12 +129,9 @@
             (quot (pk-field-name driver)))))
 
 (defn- default-qualified-name-components
-  ([_ db-name]
-   [db-name])
-  ([_ db-name table-name]
-   [table-name])
-  ([_ db-name table-name field-name]
-   [table-name field-name]))
+  ([_ db-name]                       [db-name])
+  ([_ db-name table-name]            [table-name])
+  ([_ db-name table-name field-name] [table-name field-name]))
 
 (defn- default-quote-name [_ nm]
   (str \" nm \"))
@@ -321,14 +318,10 @@
   (doseq [tabledef table-definitions]
     (load-data! driver dbdef tabledef)))
 
-(defn- destroy-db! [driver dbdef]
-  (execute-sql! driver :server dbdef (drop-db-if-exists-sql driver dbdef)))
-
 (def IDatasetLoaderMixin
-  "Mixin for `IGenericSQLDatasetLoader` types to implemnt `create-db!` and `destroy-db!` from `IDatasetLoader`."
+  "Mixin for `IGenericSQLDatasetLoader` types to implement `create-db!` from `IDatasetLoader`."
   (merge i/IDatasetLoaderDefaultsMixin
-         {:create-db!  create-db!
-          :destroy-db! destroy-db!}))
+         {:create-db! create-db!}))
 
 
 ;;; ## Various Util Fns
diff --git a/test/metabase/test/data/interface.clj b/test/metabase/test/data/interface.clj
index 4cb3768fbea..af3208d855d 100644
--- a/test/metabase/test/data/interface.clj
+++ b/test/metabase/test/data/interface.clj
@@ -42,6 +42,20 @@
   ;; take up to last 30 characters because databases like Oracle have limits on the lengths of identifiers
   (apply str (take-last 30 (str/replace (str/lower-case (str database-name \_ table-name)) #"-" "_"))))
 
+(defn single-db-qualified-name-components
+  "Implementation of `qualified-name-components` for drivers like Oracle and Redshift that must use a single existing DB for testing.
+   This implementation simulates separate databases by doing two things:
+
+     1.  Using a \"session schema\" to make sure each test run is isolated from other test runs
+     2.  Embedding the name of the database into table names, e.g. to differentiate \"test_data_categories\" and \"tupac_sightings_categories\".
+
+   To use this implementation, partially bind this function with a SESSION-SCHEMA:
+
+     {:qualified-name-components (partial i/single-db-qualified-name-components my-session-schema-name)}"
+  ([_              _ db-name]                       [db-name])
+  ([session-schema _ db-name table-name]            [session-schema (db-qualified-table-name db-name table-name)])
+  ([session-schema _ db-name table-name field-name] [session-schema (db-qualified-table-name db-name table-name) field-name]))
+
 
 (defprotocol IMetabaseInstance
   (metabase-instance [this context]
@@ -88,11 +102,6 @@
      and add the appropriate data. This method should drop existing databases with the same name if applicable.
      (This refers to creating the actual *DBMS* database itself, *not* a Metabase `Database` object.)")
 
-  (destroy-db! [this, ^DatabaseDefinition database-definition]
-    "Destroy database, if any, associated with DATABASE-DEFINITION.
-     This refers to destroying a *DBMS* database -- removing an H2 file, dropping a Postgres database, etc.
-     This does not need to remove corresponding Metabase definitions -- this is handled by `DatasetLoader`.")
-
   ;; TODO - this would be more useful if DATABASE-DEFINITION was a parameter
   (default-schema ^String [this]
     "*OPTIONAL* Return the default schema name that tables for this DB should be expected to have.")
diff --git a/test/metabase/test/data/mongo.clj b/test/metabase/test/data/mongo.clj
index 883e5b588dd..22e398c61b4 100644
--- a/test/metabase/test/data/mongo.clj
+++ b/test/metabase/test/data/mongo.clj
@@ -44,9 +44,9 @@
   i/IDatasetLoader
   (merge i/IDatasetLoaderDefaultsMixin
          {:create-db!                   (u/drop-first-arg create-db!)
-          :destroy-db!                  (u/drop-first-arg destroy-db!)
           :database->connection-details database->connection-details
           :engine                       (constantly :mongo)
           :format-name                  (fn [_ table-or-field-name]
-                                          (if (= table-or-field-name "id") "_id"
-                                              table-or-field-name))}))
+                                          (if (= table-or-field-name "id")
+                                            "_id"
+                                            table-or-field-name))}))
diff --git a/test/metabase/test/data/oracle.clj b/test/metabase/test/data/oracle.clj
index afe566e8c89..f7ef1d3dc2c 100644
--- a/test/metabase/test/data/oracle.clj
+++ b/test/metabase/test/data/oracle.clj
@@ -65,11 +65,6 @@
           session-schema
           (i/db-qualified-table-name database-name table-name)))
 
-(defn- qualified-name-components
-  ([db-name]                       [db-name])
-  ([db-name table-name]            [session-schema (i/db-qualified-table-name db-name table-name)])
-  ([db-name table-name field-name] [session-schema (i/db-qualified-table-name db-name table-name) field-name]))
-
 (defn- expected-base-type->actual [base-type]
   ;; Oracle doesn't have INTEGERs
   (if (isa? base-type :type/Integer)
@@ -87,7 +82,7 @@
           :field-base-type->sql-type (u/drop-first-arg field-base-type->sql-type)
           :load-data!                generic/load-data-one-at-a-time-parallel!
           :pk-sql-type               (constantly "INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1 INCREMENT BY 1) NOT NULL") ; LOL
-          :qualified-name-components (u/drop-first-arg qualified-name-components)})
+          :qualified-name-components (partial i/single-db-qualified-name-components session-schema)})
 
   i/IDatasetLoader
   (merge generic/IDatasetLoaderMixin
diff --git a/test/metabase/test/data/postgres.clj b/test/metabase/test/data/postgres.clj
index 770cc34eed4..6ca22ba89f5 100644
--- a/test/metabase/test/data/postgres.clj
+++ b/test/metabase/test/data/postgres.clj
@@ -30,11 +30,27 @@
          (when (= context :db)
            {:db database-name})))
 
+(defn- kill-connections-to-db-sql
+  "Return a SQL `SELECT` statement that will kill all connections to a database with DATABASE-NAME."
+  ^String [database-name]
+  (format (str "DO $$ BEGIN\n"
+               "  PERFORM pg_terminate_backend(pg_stat_activity.pid)\n"
+               "  FROM pg_stat_activity\n"
+               "  WHERE pid <> pg_backend_pid()\n"
+               "    AND pg_stat_activity.datname = '%s';\n"
+               "END $$;\n")
+          (name database-name)))
+
+(defn- drop-db-if-exists-sql [driver {:keys [database-name], :as dbdef}]
+  (str (kill-connections-to-db-sql database-name)
+       (generic/default-drop-db-if-exists-sql driver dbdef)))
+
 
 (u/strict-extend PostgresDriver
   generic/IGenericSQLDatasetLoader
   (merge generic/DefaultsMixin
-         {:drop-table-if-exists-sql  generic/drop-table-if-exists-cascade-sql
+         {:drop-db-if-exists-sql     drop-db-if-exists-sql
+          :drop-table-if-exists-sql  generic/drop-table-if-exists-cascade-sql
           :field-base-type->sql-type (u/drop-first-arg field-base-type->sql-type)
           :load-data!                generic/load-data-all-at-once!
           :pk-sql-type               (constantly "SERIAL")})
@@ -45,11 +61,3 @@
           :engine                             (constantly :postgres)
           ;; TODO: this is suspect, but it works
           :has-questionable-timezone-support? (constantly true)}))
-
-
-;; it's super obnoxious when testing locally to have tests fail because someone is already connected to the test-data DB (meaning we can't drop it), so close all connections to it beforehand
-(defn- kill-connections-to-test-data-db!
-  {:expectations-options :before-run}
-  []
-  (generic/query-when-testing! :postgres (fn [] (sql/connection-details->spec (PostgresDriver.) (database->connection-details :server {})))
-    "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pid <> pg_backend_pid() AND pg_stat_activity.datname = 'test-data';"))
diff --git a/test/metabase/test/data/redshift.clj b/test/metabase/test/data/redshift.clj
index 7ea648ca03c..c1521e0f107 100644
--- a/test/metabase/test/data/redshift.clj
+++ b/test/metabase/test/data/redshift.clj
@@ -49,13 +49,6 @@
 (defonce ^:const session-schema-name
   (str "schema_" session-schema-number))
 
-(defn- qualified-name-components
-  ([_ db-name]
-   [db-name])
-  ([_ _ table-name]
-   [session-schema-name table-name])
-  ([_ _ table-name field-name]
-   [session-schema-name table-name field-name]))
 
 (u/strict-extend RedshiftDriver
   generic/IGenericSQLDatasetLoader
@@ -65,7 +58,7 @@
           :drop-table-if-exists-sql  generic/drop-table-if-exists-cascade-sql
           :field-base-type->sql-type (u/drop-first-arg field-base-type->sql-type)
           :pk-sql-type               (constantly "INTEGER IDENTITY(1,1)")
-          :qualified-name-components qualified-name-components})
+          :qualified-name-components (partial i/single-db-qualified-name-components session-schema-name)})
 
   i/IDatasetLoader
   (merge generic/IDatasetLoaderMixin
diff --git a/test/metabase/test/data/sqlserver.clj b/test/metabase/test/data/sqlserver.clj
index 4e653a06862..858ebdac810 100644
--- a/test/metabase/test/data/sqlserver.clj
+++ b/test/metabase/test/data/sqlserver.clj
@@ -69,12 +69,9 @@
     (format "IF object_id('%s.dbo.%s') IS NOT NULL DROP TABLE \"%s\".dbo.\"%s\";" db-name table-name db-name table-name)))
 
 (defn- qualified-name-components
-  ([db-name]
-   [(+suffix db-name)])
-  ([db-name table-name]
-   [(+suffix db-name) "dbo" table-name])
-  ([db-name table-name field-name]
-   [(+suffix db-name) "dbo" table-name field-name]))
+  ([db-name]                       [(+suffix db-name)])
+  ([db-name table-name]            [(+suffix db-name) "dbo" table-name])
+  ([db-name table-name field-name] [(+suffix db-name) "dbo" table-name field-name]))
 
 
 (u/strict-extend SQLServerDriver
-- 
GitLab