-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Metabase tests #20
Conversation
0d9472c
to
db1398c
Compare
da5e6bc
to
999d214
Compare
e41abbd
to
94f36be
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving it since I don't have any refutation to anything, only questions to understand how it works and gain some knowledge.
[driver {:keys [database-name]}] | ||
(format "DROP DATABASE IF EXISTS \"%s\";" (ddl.i/format-name driver database-name))) | ||
|
||
(defmethod sql.tx/add-fk-sql :materialize [& _] nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would happen if Metabase tries to add a FK in Materialize? Is that a possible scenario?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The key part is this config in the driver itself:
(doseq [[feature supported?] {:foreign-keys (not config/is-test?)
By default Metabase assumes that it needs foreign keys in order to do joins, but this is not the case for Materialize and some other DB drivers that they have. So we disable this only during the tests, as otherwise the Metatabase test suite tries to add FKs on the tables which we don't support.
image: postgres:15.3-alpine3.18 | ||
depends_on: | ||
- materialize | ||
command: sh -c 'echo "Waiting for materialized to start..." && sleep 15 && psql -h materialize -U mz_system -d materialize -p 6877 -c "ALTER SYSTEM SET max_tables = 1000;"' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this only because Metabase create many tables during testing? Does Metabase also creates tables in prod?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only for the tests. Metabase creates a lot of tables when initializing the tests. Then it uses the test data to run all the tests.
@@ -3,29 +3,71 @@ | |||
(:require [clojure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it correct to say they we use exactly the Postgres Driver and disable all the troublemaker options (set-timezone
, datetime-diff
, etc.)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep exactly! We first register the Materialize driver and define Postgres as the parent driver, eg:
(driver/register! :materialize, :parent :postgres)
It is very similar to how the Redshift driver is setup as well.
run: yarn build-static-viz | ||
|
||
# Use custom deps.edn containing "user/materialize" alias to include driver sources | ||
- name: Run tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test takes 12 minutes because it tests all the drivers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it only tests Materialize as we add the DRIVERS=materialize
before the clojure command. It's just that there are too many tests, around 15k assertions.
Co-authored-by: Joaquin Colacci <[email protected]>
.github/workflows/tests.yaml
Outdated
- name: Setup Node | ||
uses: actions/setup-node@v2 | ||
with: | ||
node-version: "18" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Metabase 46 uses node 16, starting with 47 we use node 18. (For building static-viz this might not matter though.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing that out. I've gone ahead and reverted back to node 16 for the time being.
CONTRIBUTING.md
Outdated
|
||
```bash | ||
mkdir -p ~/.clojure | ||
cat modules/drivers/materialize/.github/deps.edn | sed -e "s|PWD|$PWD|g" > ~/.clojure/deps.edn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't recommend executing this. Many Clojure developers customize their personal deps.edn
file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I've changed the instructions accordingly.
[metabase [config :as config] [driver :as driver] [util :as u]] | ||
[metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] | ||
[metabase.driver.sql.query-processor :as sql.qp] | ||
[metabase.util.honey-sql-2 :as h2x] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a question of style: it's unconventional to use hierarchical :require
s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! I've updated this accordingly.
src/metabase/driver/materialize.clj
Outdated
(sql-jdbc.common/handle-additional-options | ||
(merge | ||
{:classname "org.postgresql.Driver" | ||
:subprotocol "postgresql" | ||
:subname (str "//" host ":" port "/" db) | ||
:ssl true | ||
:subname (str "//" host ":" port "/" db "?options=--cluster%3D" cluster) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these values be sanitized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just updated this, let me know if this is what you had in mind
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that host
, port
, etc. are user input, we cannot trust them to be safe. We construct a string from them and pass that to the driver. Since we probably cannot fully trust the driver either, we should do everything reasonable to make sure there is nothing suspicious/bad in that string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any suggestions for best practices?
I tried to check how other similar drivers handle this like Redshift here and some other partner drivers like Exasol and ClickHouse but I belive that they also just construct a string and pass it to the driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends on the underlying driver. I'm guessing that
- the resulting string should be a valid URI,
host
should be a host name or IP address,port
should be an integer,db
should be a valid database name, andcluster
should be a valid cluster name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently out of ideas on a good way to fulfill this request, as this seems to be the way that it's currently handled with all other drivers:
https://github.com/metabase/metabase/blob/master/src/metabase/db/spec.clj#L24-L29
|
||
(set! *warn-on-reflection* true) | ||
|
||
(defmethod driver/database-supports? [:materialize :foreign-keys] [_driver _feature _db] (not config/is-test?)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's odd to have this method defined in two places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Removed the duplicate one!
(merge | ||
((get-method tx/aggregate-column-info ::tx/test-extensions) driver ag-type field) | ||
(when (= ag-type :sum) | ||
{:base_type :type/BigInteger})))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(merge | |
((get-method tx/aggregate-column-info ::tx/test-extensions) driver ag-type field) | |
(when (= ag-type :sum) | |
{:base_type :type/BigInteger})))) | |
(cond-> ((get-method tx/aggregate-column-info ::tx/test-extensions) driver ag-type field) | |
(= ag-type :sum) (assoc :base_type :type/BigInteger)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this suggestion!
:type/JSON "JSON" | ||
:type/Time "TIME" | ||
:type/UUID "UUID"}] | ||
(defmethod sql.tx/field-base-type->sql-type [:materialize base-type] [_ _] db-type)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't these inherited from the postgres driver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I don't specify those, one of the tests is failing with the following error:
clojure.lang.ExceptionInfo: Failed to create :materialize 'office-checkins' test database: No test data type mapping for driver :materialize for base type :type/DateTimeWithZoneOffset; add an impl for field-base-type->sql-type.
database-name: "office-checkins"
driver: :materialize
java.lang.Exception: No test data type mapping for driver :materialize for base type :type/DateTimeWithZoneOffset; add an impl for field-base-type->sql-type.
(defn- validate-connection-details | ||
[{:keys [host]}] | ||
(when-not (re-matches #"^[a-zA-Z0-9.-]+$" host) | ||
(throw (IllegalArgumentException. (str "Invalid host: " host))))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume port
should be either an integer or a string encoding one.
This is the initial PR that integrates the Materialize driver with the Metabase tests.