From 34488adb3b9ce4cc94a1a0b9e19b191e1455db86 Mon Sep 17 00:00:00 2001
From: metamben <103100869+metamben@users.noreply.github.com>
Date: Thu, 29 Dec 2022 23:50:33 +0300
Subject: [PATCH] Fix flaky metabase.api.notify-test/post-db-id-test (#27465)

It seems the expectation was that the binding *execute-asynchronously* to false
in the test would affect the binding seen by the server. Instead of this a new
parameter is added to the request that makes the server return only when the
asynchronous operation has completed.
---
 src/metabase/api/notify.clj       | 23 ++++-----
 test/metabase/api/notify_test.clj | 83 +++++++++++++++----------------
 2 files changed, 50 insertions(+), 56 deletions(-)

diff --git a/src/metabase/api/notify.clj b/src/metabase/api/notify.clj
index 82755ebd3d6..484c83f0412 100644
--- a/src/metabase/api/notify.clj
+++ b/src/metabase/api/notify.clj
@@ -11,8 +11,6 @@
    [schema.core :as s]
    [toucan.db :as db]))
 
-(def ^:private ^:dynamic *execute-asynchronously* true)
-
 (api/defendpoint POST "/db/:id"
   "Notification about a potential schema change to one of our `Databases`.
   Caller can optionally specify a `:table_id` or `:table_name` in the body to limit updates to a single
@@ -20,24 +18,21 @@
   regardless if a `:table_id` or `:table_name` is passed.
   This endpoint is secured by an API key that needs to be passed as a `X-METABASE-APIKEY` header which needs to be defined in
   the `MB_API_KEY` [environment variable](https://www.metabase.com/docs/latest/configuring-metabase/environment-variables.html#mb_api_key)"
-  [id :as {{:keys [table_id table_name scan]} :body}]
+  [id :as {{:keys [table_id table_name scan synchronous?]} :body}]
   {table_id   (s/maybe su/IntGreaterThanZero)
    table_name (s/maybe su/NonBlankString)
    scan       (s/maybe (s/enum "full" "schema"))}
   (let [schema?       (when scan (#{"schema" :schema} scan))
         table-sync-fn (if schema? sync-metadata/sync-table-metadata! sync/sync-table!)
-        db-sync-fn    (if schema? sync-metadata/sync-db-metadata! sync/sync-database!)
-        execute!      (fn [thunk]
-                        (if *execute-asynchronously*
-                          (future (thunk))
-                          (thunk)))]
+        db-sync-fn    (if schema? sync-metadata/sync-db-metadata! sync/sync-database!)]
     (api/let-404 [database (db/select-one Database :id id)]
-      (cond
-        table_id   (api/let-404 [table (db/select-one Table :db_id id, :id (int table_id))]
-                     (execute! #(table-sync-fn table)))
-        table_name (api/let-404 [table (db/select-one Table :db_id id, :name table_name)]
-                     (execute! #(table-sync-fn table)))
-        :else      (execute! #(db-sync-fn database)))))
+      (cond-> (cond
+                table_id   (api/let-404 [table (db/select-one Table :db_id id, :id (int table_id))]
+                             (future (table-sync-fn table)))
+                table_name (api/let-404 [table (db/select-one Table :db_id id, :name table_name)]
+                             (future (table-sync-fn table)))
+                :else      (future (db-sync-fn database)))
+        synchronous? deref)))
   {:success true})
 
 
diff --git a/test/metabase/api/notify_test.clj b/test/metabase/api/notify_test.clj
index ee4d74927a8..6ec608da650 100644
--- a/test/metabase/api/notify_test.clj
+++ b/test/metabase/api/notify_test.clj
@@ -2,7 +2,6 @@
   (:require
    [clj-http.client :as http]
    [clojure.test :refer :all]
-   [metabase.api.notify :as api.notify]
    [metabase.http-client :as client]
    [metabase.models.database :as database]
    [metabase.server.middleware.util :as mw.util]
@@ -55,44 +54,44 @@
                       (select-keys (ex-data e) [:status :body])))))))))
 
 (deftest post-db-id-test
-  (binding [api.notify/*execute-asynchronously* false]
-    (mt/test-drivers (mt/normal-drivers)
-      (let [table-name (->> (mt/db) database/tables first :name)
-            post       (fn post-api
-                         ([payload] (post-api payload 200))
-                         ([payload expected-code]
-                          (mt/with-temporary-setting-values [api-key "test-api-key"]
-                            (mt/client :post expected-code (format "notify/db/%d" (u/the-id (mt/db)))
-                                       {:request-options api-headers}
-                                       payload))))]
-        (testing "sync just table when table is provided"
-          (let [long-sync-called? (atom false), short-sync-called? (atom false)]
-            (with-redefs [metabase.sync/sync-table!                        (fn [_table] (reset! long-sync-called? true))
-                          metabase.sync.sync-metadata/sync-table-metadata! (fn [_table] (reset! short-sync-called? true))]
-              (post {:scan :full, :table_name table-name})
-              (is @long-sync-called?)
-              (is (not @short-sync-called?)))))
-        (testing "only a quick sync when quick parameter is provided"
-          (let [long-sync-called? (atom false), short-sync-called? (atom false)]
-            (with-redefs [metabase.sync/sync-table!                        (fn [_table] (reset! long-sync-called? true))
-                          metabase.sync.sync-metadata/sync-table-metadata! (fn [_table] (reset! short-sync-called? true))]
-              (post {:scan :schema, :table_name table-name})
-              (is (not @long-sync-called?))
-              (is @short-sync-called?))))
-        (testing "full db sync by default"
-          (let [full-sync? (atom false)]
-            (with-redefs [metabase.sync/sync-database! (fn [_db] (reset! full-sync? true))]
-              (post {})
-              (is @full-sync?))))
-        (testing "simple sync with params"
-          (let [full-sync?   (atom false)
-                smaller-sync (atom true)]
-            (with-redefs [metabase.sync/sync-database!                  (fn [_db] (reset! full-sync? true))
-                          metabase.sync.sync-metadata/sync-db-metadata! (fn [_db] (reset! smaller-sync true))]
-              (post {:scan :schema})
-              (is (not @full-sync?))
-              (is @smaller-sync))))
-        (testing "errors on unrecognized scan options"
-          (is (= {:errors
-                  {:scan "value may be nil, or if non-nil, value must be one of: `full`, `schema`."}}
-                 (post {:scan :unrecognized} 400))))))))
+  (mt/test-drivers (mt/normal-drivers)
+    (let [table-name (->> (mt/db) database/tables first :name)
+          post       (fn post-api
+                       ([payload] (post-api payload 200))
+                       ([payload expected-code]
+                        (mt/with-temporary-setting-values [api-key "test-api-key"]
+                          (mt/client :post expected-code (format "notify/db/%d" (u/the-id (mt/db)))
+                                     {:request-options api-headers}
+                                     (merge {:synchronous? true}
+                                            payload)))))]
+      (testing "sync just table when table is provided"
+        (let [long-sync-called? (promise), short-sync-called? (promise)]
+          (with-redefs [metabase.sync/sync-table!                        (fn [_table] (deliver long-sync-called? true))
+                        metabase.sync.sync-metadata/sync-table-metadata! (fn [_table] (deliver short-sync-called? true))]
+            (post {:scan :full, :table_name table-name})
+            (is @long-sync-called?)
+            (is (not (realized? short-sync-called?))))))
+      (testing "only a quick sync when quick parameter is provided"
+        (let [long-sync-called? (promise), short-sync-called? (promise)]
+          (with-redefs [metabase.sync/sync-table!                        (fn [_table] (deliver long-sync-called? true))
+                        metabase.sync.sync-metadata/sync-table-metadata! (fn [_table] (deliver short-sync-called? true))]
+            (post {:scan :schema, :table_name table-name})
+            (is (not (realized? long-sync-called?)))
+            (is @short-sync-called?))))
+      (testing "full db sync by default"
+        (let [full-sync? (promise)]
+          (with-redefs [metabase.sync/sync-database! (fn [_db] (deliver full-sync? true))]
+            (post {})
+            (is @full-sync?))))
+      (testing "simple sync with params"
+        (let [full-sync?   (promise)
+              smaller-sync (promise)]
+          (with-redefs [metabase.sync/sync-database!                  (fn [_db] (deliver full-sync? true))
+                        metabase.sync.sync-metadata/sync-db-metadata! (fn [_db] (deliver smaller-sync true))]
+            (post {:scan :schema})
+            (is (not (realized? full-sync?)))
+            (is @smaller-sync))))
+      (testing "errors on unrecognized scan options"
+        (is (= {:errors
+                {:scan "value may be nil, or if non-nil, value must be one of: `full`, `schema`."}}
+               (post {:scan :unrecognized} 400)))))))
-- 
GitLab