Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Metabase
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Engineering Digital Service
Metabase
Commits
05859d21
Commit
05859d21
authored
8 years ago
by
Cam Saül
Committed by
GitHub
8 years ago
Browse files
Options
Downloads
Plain Diff
Merge pull request #2909 from metabase/even-more-test-cleanup
Even more test cleanup
parents
e6c042e1
d468bf24
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/metabase/api/database.clj
+5
-4
5 additions, 4 deletions
src/metabase/api/database.clj
test/metabase/api/activity_test.clj
+40
-39
40 additions, 39 deletions
test/metabase/api/activity_test.clj
test/metabase/api/database_test.clj
+209
-206
209 additions, 206 deletions
test/metabase/api/database_test.clj
with
254 additions
and
249 deletions
src/metabase/api/database.clj
+
5
−
4
View file @
05859d21
...
...
@@ -63,9 +63,9 @@
(
defendpoint
POST
"/"
"Add a new `Database`."
[
:as
{{
:keys
[
name
engine
details
is_full_sync
]}
:body
}]
{
name
[
Required
NonEmptyString
]
engine
[
Required
DBEngine
]
details
[
Required
Dict
]}
{
name
[
Required
NonEmptyString
]
engine
[
Required
DBEngine
]
details
[
Required
Dict
]}
(
check-superuser
)
;; this function tries connecting over ssl and non-ssl to establish a connection
;; if it succeeds it returns the `details` that worked, otherwise it returns an error
...
...
@@ -85,7 +85,8 @@
(
if-not
(
false?
(
:valid
details-or-error
))
;; no error, proceed with creation
(
let-500
[
new-db
(
db/insert!
Database,
:name
name,
:engine
engine,
:details
details-or-error,
:is_full_sync
is_full_sync
)]
(
events/publish-event
:database-create
new-db
))
(
events/publish-event
:database-create
new-db
)
new-db
)
;; failed to connect, return error
{
:status
400
:body
details-or-error
})))
...
...
This diff is collapsed.
Click to expand it.
test/metabase/api/activity_test.clj
+
40
−
39
View file @
05859d21
...
...
@@ -9,7 +9,7 @@
[
view-log
:refer
[
ViewLog
]])
[
metabase.test.data
:refer
:all
]
[
metabase.test.data.users
:refer
:all
]
[
metabase.test.util
:refer
[
match-$
random-name
expect-with-temp
resolve-private-fns
]]
[
metabase.test.util
:refer
[
match-$
expect-with-temp
resolve-private-fns
]]
[
metabase.util
:as
u
]))
;; GET /
...
...
@@ -99,17 +99,28 @@
:table
nil
:custom_id
nil
:details
$
})]
(
->>
((
user->client
:crowberto
)
:get
200
"activity"
)
(
map
#
(
dissoc
%
:timestamp
)))
)
(
for
[
activity
((
user->client
:crowberto
)
:get
200
"activity"
)
]
(
dissoc
activity
:timestamp
)))
;; GET /recent_views
;;
;
GET /recent_views
; Things we are testing for:
; 1. ordering is sorted by most recent
; 2. results are filtered to current user
; 3. `:model_object` is hydrated in each result
; 4. we filter out entries where `:model_object` is nil (object doesn't exist)
;; Things we are testing for:
;; 1. ordering is sorted by most recent
;; 2. results are filtered to current user
;; 3. `:model_object` is hydrated in each result
;; 4. we filter out entries where `:model_object` is nil (object doesn't exist)
(
defn-
create-view!
[
user
model
model-id
]
(
db/insert!
ViewLog
:user_id
user
:model
model
:model_id
model-id
:timestamp
(
u/new-sql-timestamp
))
;; we sleep a bit to ensure no events have the same timestamp
;; sadly, MySQL doesn't support milliseconds so we have to wait a second
;; otherwise our records are out of order and this test fails :(
(
Thread/sleep
1000
))
(
expect-with-temp
[
Card
[
card1
{
:name
"rand-name"
:creator_id
(
user->id
:crowberto
)
...
...
@@ -127,47 +138,37 @@
:display
"table"
:dataset_query
{}
:visualization_settings
{}}]]
[{
:cnt
1
:user_id
(
user->id
:crowberto
)
:model
"card"
:model_id
(
:id
card1
)
[{
:cnt
1
:user_id
(
user->id
:crowberto
)
:model
"card"
:model_id
(
:id
card1
)
:model_object
{
:id
(
:id
card1
)
:name
(
:name
card1
)
:description
(
:description
card1
)
:display
(
name
(
:display
card1
))}}
{
:cnt
1
:user_id
(
user->id
:crowberto
)
:model
"dashboard"
:model_id
(
:id
dash1
)
{
:cnt
1
:user_id
(
user->id
:crowberto
)
:model
"dashboard"
:model_id
(
:id
dash1
)
:model_object
{
:id
(
:id
dash1
)
:name
(
:name
dash1
)
:description
(
:description
dash1
)}}
{
:cnt
1
:user_id
(
user->id
:crowberto
)
:model
"card"
:model_id
(
:id
card2
)
{
:cnt
1
:user_id
(
user->id
:crowberto
)
:model
"card"
:model_id
(
:id
card2
)
:model_object
{
:id
(
:id
card2
)
:name
(
:name
card2
)
:description
(
:description
card2
)
:display
(
name
(
:display
card2
))}}]
(
let
[
create-view
(
fn
[
user
model
model-id
]
(
db/insert!
ViewLog
:user_id
user
:model
model
:model_id
model-id
:timestamp
(
u/new-sql-timestamp
))
;; we sleep a bit to ensure no events have the same timestamp
;; sadly, MySQL doesn't support milliseconds so we have to wait a second
;; otherwise our records are out of order and this test fails :(
(
Thread/sleep
1000
))]
(
do
(
create-view
(
user->id
:crowberto
)
"card"
(
:id
card2
))
(
create-view
(
user->id
:crowberto
)
"dashboard"
(
:id
dash1
))
(
create-view
(
user->id
:crowberto
)
"card"
(
:id
card1
))
(
create-view
(
user->id
:crowberto
)
"card"
36478
)
(
create-view
(
user->id
:rasta
)
"card"
(
:id
card1
))
(
->>
((
user->client
:crowberto
)
:get
200
"activity/recent_views"
)
(
map
#
(
dissoc
%
:max_ts
))))))
(
do
(
create-view!
(
user->id
:crowberto
)
"card"
(
:id
card2
))
(
create-view!
(
user->id
:crowberto
)
"dashboard"
(
:id
dash1
))
(
create-view!
(
user->id
:crowberto
)
"card"
(
:id
card1
))
(
create-view!
(
user->id
:crowberto
)
"card"
36478
)
(
create-view!
(
user->id
:rasta
)
"card"
(
:id
card1
))
(
for
[
recent-view
((
user->client
:crowberto
)
:get
200
"activity/recent_views"
)]
(
dissoc
recent-view
:max_ts
))))
;;; activities->referenced-objects, referenced-objects->existing-objects, add-model-exists-info
...
...
This diff is collapsed.
Click to expand it.
test/metabase/api/database_test.clj
+
209
−
206
View file @
05859d21
...
...
@@ -13,22 +13,40 @@
;; HELPER FNS
(
defn
create-db
([
db-name
]
(
create-db
db-name
true
))
([
db-name
full-sync?
]
((
user->client
:crowberto
)
:post
200
"database"
{
:engine
:postgres
:name
db-name
:details
{
:host
"localhost"
:port
5432
:dbname
"fakedb"
:user
"cam"
:ssl
false
}
:is_full_sync
full-sync?
})))
(
defn-
create-db-via-api!
[
options
]
((
user->client
:crowberto
)
:post
200
"database"
(
merge
{
:engine
:postgres
:name
(
tu/random-name
)
:details
{
:host
"localhost"
:port
5432
:dbname
"fakedb"
:user
"cam"
:ssl
false
}
:is_full_sync
true
}
options
)))
(
defn-
do-with-temp-db-created-via-api
[
db-options
f
]
(
let
[
db
(
create-db-via-api!
db-options
)]
(
assert
(
integer?
(
:id
db
)))
(
try
(
f
db
)
(
finally
(
db/cascade-delete!
Database
:id
(
:id
db
))))))
(
defmacro
^
:private
expect-with-temp-db-created-via-api
{
:style/indent
1
}
[[
binding
&
[
options
]]
expected
actual
]
;; use `gensym` instead of auto gensym here so we can be sure it's a unique symbol every time. Otherwise since expectations hashes its body
;; to generate function names it will treat every usage this as the same test and only a single one will end up being ran
(
let
[
result
(
gensym
"result-"
)]
`
(
let
[
~
result
(
delay
(
do-with-temp-db-created-via-api
~
options
(
fn
[
~
binding
]
[
~
expected
~
actual
])))]
(
expect
(
u/ignore-exceptions
(
first
@~
result
))
; in case @result# barfs we don't want the test to succeed (Exception == Exception for expectations)
(
second
@~
result
)))))
(
defn-
db-details
([]
(
db-details
(
db
)))
(
db-details
(
db
)))
([
db
]
(
match-$
db
{
:created_at
$
...
...
@@ -43,23 +61,6 @@
:description
nil
:features
(
mapv
name
(
driver/features
(
driver/engine->driver
(
:engine
db
))))})))
(
defn-
table-details
[
table
]
(
match-$
table
{
:description
$
:entity_type
$
:visibility_type
$
:schema
$
:name
$
:display_name
$
:rows
$
:updated_at
$
:entity_name
$
:active
$
:id
$
:db_id
$
:raw_table_id
$
:created_at
$
}))
;; # DB LIFECYCLE ENDPOINTS
...
...
@@ -76,140 +77,142 @@
;; ## POST /api/database
;; Check that we can create a Database
(
let
[
db-name
(
random-name
)
]
(
expect-eval-actual-first
(
match-$
(
Database
:name
db-name
)
{
:created_at
$
:engine
"postgres"
; string because it's coming back from API instead of DB
:id
$
:details
{
:host
"localhost"
,
:port
5432
,
:dbname
"fakedb"
,
:user
"cam"
,
:ssl
true
}
:updated_at
$
:name
db-nam
e
:is_sample
false
:is_full_sync
false
:organization_id
nil
:description
nil
:features
(
mapv
name
(
driver/features
(
driver/engine->driver
:postgres
)))
})
(
create-db
db-name
false
)))
(
expect-with-temp-db-created-via-api
[
db
{
:is_full_sync
false
}
]
(
match-$
db
{
:created_at
$
:engine
:postgres
:id
$
:details
{
:host
"localhost"
,
:port
5432
,
:dbname
"fakedb"
,
:user
"cam"
,
:ssl
true
}
:updated_at
$
:name
$
:is_sample
fals
e
:is_full_sync
false
:organization_id
nil
:description
nil
:features
(
into
[]
(
driver/features
(
driver/engine->driver
:postgres
)))})
(
Database
(
:id
db
)))
;; ## DELETE /api/database/:id
;; Check that we can delete a Database
(
expect-let
[
db-name
(
random-name
)
{
db-id
:id
}
(
create-db
db-name
)
sel-db-name
(
fn
[]
(
db/select-one-field
:name
Database,
:id
db-id
))]
[
db-name
nil
]
[(
sel-db-name
)
(
do
((
user->client
:crowberto
)
:delete
204
(
format
"database/%d"
db-id
))
(
sel-db-name
))])
(
expect-with-temp-db-created-via-api
[
db
]
false
(
do
((
user->client
:crowberto
)
:delete
204
(
format
"database/%d"
(
:id
db
)))
(
db/exists?
'Database
:id
(
:id
db
))))
;; ## PUT /api/database/:id
;; Check that we can update fields in a Database
(
expect-let
[[
old-name
new-name
]
(
repeatedly
2
random-name
)
{
db-id
:id
}
(
create-db
old-name
)
sel-db
(
fn
[]
(
dissoc
(
into
{}
(
db/select-one
[
Database
:name
:engine
:details
:is_full_sync
]
,
:id
db-id
))
:features
))]
[{
:details
{
:host
"localhost"
,
:port
5432
,
:dbname
"fakedb"
,
:user
"cam"
,
:ssl
true
}
:engine
:postgres
:name
old-name
:is_full_sync
true
}
{
:details
{
:host
"localhost"
,
:port
5432
,
:dbname
"fakedb"
,
:user
"rastacan"
}
:engine
:h2
:name
new-name
:is_full_sync
false
}]
[(
sel-db
)
;; Check that we can update all the fields
(
do
((
user->client
:crowberto
)
:put
200
(
format
"database/%d"
db-id
)
{
:name
new-name
:engine
"h2"
:is_full_sync
false
:details
{
:host
"localhost"
,
:port
5432
,
:dbname
"fakedb"
,
:user
"rastacan"
}})
(
sel-db
))])
(
expect-with-temp-db-created-via-api
[{
db-id
:id
}]
{
:details
{
:host
"localhost"
,
:port
5432
,
:dbname
"fakedb"
,
:user
"rastacan"
}
:engine
:h2
:name
"Cam's Awesome Toucan Database"
:is_full_sync
false
}
(
do
((
user->client
:crowberto
)
:put
200
(
format
"database/%d"
db-id
)
{
:name
"Cam's Awesome Toucan Database"
:engine
"h2"
:is_full_sync
false
:details
{
:host
"localhost"
,
:port
5432
,
:dbname
"fakedb"
,
:user
"rastacan"
}})
(
dissoc
(
into
{}
(
db/select-one
[
Database
:name
:engine
:details
:is_full_sync
]
,
:id
db-id
))
:features
)))
(
defn-
table-details
[
table
]
(
match-$
table
{
:description
$
:entity_type
$
:visibility_type
$
:schema
$
:name
$
:display_name
$
:rows
$
:updated_at
$
:entity_name
$
:active
$
:id
$
:db_id
$
:raw_table_id
$
:created_at
$
}))
;; TODO - this is a test code smell, each test should clean up after itself and this step shouldn't be neccessary. One day we should be able to remove this!
;; If you're writing a test that needs this, fix your brain and your test
(
defn-
^
:deprecated
delete-randomly-created-databases!
"Delete all the randomly created Databases we've made so far. Optionally specify one or more IDs to SKIP."
[
&
{
:keys
[
skip
]}]
(
db/cascade-delete!
Database
:id
[
:not-in
(
into
(
set
skip
)
(
for
[
engine
datasets/all-valid-engines
:let
[
id
(
datasets/when-testing-engine
engine
(
:id
(
get-or-create-test-data-db!
(
driver/engine->driver
engine
))))]
:when
id
]
id
))]))
;; # DATABASES FOR ORG
;; ## GET /api/database
;; Test that we can get all the DBs
for an Org,
ordered by name
;; Test that we can get all the DBs
(
ordered by name
)
;; Database details *should not* come back for Rasta since she's not a superuser
(
let
[
db-name
(
str
"A"
(
random-name
))]
; make sure this name comes before "test-data"
(
expect-eval-actual-first
(
set
(
filter
identity
(
conj
(
for
[
engine
datasets/all-valid-engines
]
(
datasets/when-testing-engine
engine
(
match-$
(
get-or-create-test-data-db!
(
driver/engine->driver
engine
))
{
:created_at
$
:engine
(
name
$engine
)
:id
$
:updated_at
$
:name
"test-data"
:is_sample
false
:is_full_sync
true
:organization_id
nil
:description
nil
:features
(
mapv
name
(
driver/features
(
driver/engine->driver
engine
)))})))
;; (?) I don't remember why we have to do this for postgres but not any other of the bonus drivers
(
match-$
(
Database
:name
db-name
)
(
expect-with-temp-db-created-via-api
[{
db-id
:id
}]
(
set
(
filter
identity
(
conj
(
for
[
engine
datasets/all-valid-engines
]
(
datasets/when-testing-engine
engine
(
match-$
(
get-or-create-test-data-db!
(
driver/engine->driver
engine
))
{
:created_at
$
:engine
"postgres"
:engine
(
name
$engine
)
:id
$
:updated_at
$
:name
$
:name
"test-data"
:is_sample
false
:is_full_sync
true
:organization_id
nil
:description
nil
:features
(
mapv
name
(
driver/features
(
driver/engine->driver
:postgres
)))}))))
(
do
;; Delete all the randomly created Databases we've made so far
(
db/cascade-delete!
Database
:id
[
:not-in
(
filter
identity
(
for
[
engine
datasets/all-valid-engines
]
(
datasets/when-testing-engine
engine
(
:id
(
get-or-create-test-data-db!
(
driver/engine->driver
engine
))))))])
;; Add an extra DB so we have something to fetch besides the Test DB
(
create-db
db-name
)
;; Now hit the endpoint
(
set
((
user->client
:rasta
)
:get
200
"database"
)))))
:features
(
map
name
(
driver/features
(
driver/engine->driver
engine
)))})))
(
match-$
(
Database
db-id
)
{
:created_at
$
:engine
"postgres"
:id
$
:updated_at
$
:name
$
:is_sample
false
:is_full_sync
true
:organization_id
nil
:description
nil
:features
(
map
name
(
driver/features
(
driver/engine->driver
:postgres
)))}))))
(
do
(
delete-randomly-created-databases!
:skip
[
db-id
])
(
set
((
user->client
:rasta
)
:get
200
"database"
))))
;; GET /api/databases (include tables)
(
let
[
db-name
(
str
"A"
(
random-name
))]
; make sure this name comes before "test-data"
(
expect-eval-actual-first
(
set
(
concat
[(
match-$
(
Database
:name
db-name
)
{
:created_at
$
:engine
"postgres"
:id
$
:updated_at
$
:name
$
:is_sample
false
:is_full_sync
true
:organization_id
nil
:description
nil
:tables
[]
:features
(
mapv
name
(
driver/features
(
driver/engine->driver
:postgres
)))})]
(
filter
identity
(
for
[
engine
datasets/all-valid-engines
]
(
datasets/when-testing-engine
engine
(
let
[
database
(
get-or-create-test-data-db!
(
driver/engine->driver
engine
))]
(
match-$
database
{
:created_at
$
:engine
(
name
$engine
)
:id
$
:updated_at
$
:name
"test-data"
:is_sample
false
:is_full_sync
true
:organization_id
nil
:description
nil
:tables
(
->>
(
db/select
Table,
:db_id
(
:id
database
))
(
mapv
table-details
)
(
sort-by
:name
))
:features
(
mapv
name
(
driver/features
(
driver/engine->driver
engine
)))})))))))
(
do
;; Delete all the randomly created Databases we've made so far
(
db/cascade-delete!
Database
:id
[
:not-in
(
set
(
filter
identity
(
for
[
engine
datasets/all-valid-engines
]
(
datasets/when-testing-engine
engine
(
:id
(
get-or-create-test-data-db!
(
driver/engine->driver
engine
)))))))])
;; Add an extra DB so we have something to fetch besides the Test DB
(
create-db
db-name
)
;; Now hit the endpoint
(
set
((
user->client
:rasta
)
:get
200
"database"
:include_tables
true
)))))
(
expect-with-temp-db-created-via-api
[{
db-id
:id
}]
(
set
(
cons
(
match-$
(
Database
db-id
)
{
:created_at
$
:engine
"postgres"
:id
$
:updated_at
$
:name
$
:is_sample
false
:is_full_sync
true
:organization_id
nil
:description
nil
:tables
[]
:features
(
map
name
(
driver/features
(
driver/engine->driver
:postgres
)))})
(
filter
identity
(
for
[
engine
datasets/all-valid-engines
]
(
datasets/when-testing-engine
engine
(
let
[
database
(
get-or-create-test-data-db!
(
driver/engine->driver
engine
))]
(
match-$
database
{
:created_at
$
:engine
(
name
$engine
)
:id
$
:updated_at
$
:name
"test-data"
:is_sample
false
:is_full_sync
true
:organization_id
nil
:description
nil
:tables
(
sort-by
:name
(
for
[
table
(
db/select
Table,
:db_id
(
:id
database
))]
(
table-details
table
)))
:features
(
map
name
(
driver/features
(
driver/engine->driver
engine
)))})))))))
(
do
(
delete-randomly-created-databases!
:skip
[
db-id
])
(
set
((
user->client
:rasta
)
:get
200
"database"
:include_tables
true
))))
;; ## GET /api/meta/table/:id/query_metadata
;; TODO - add in example with Field :values
...
...
@@ -293,65 +296,65 @@
;; ## GET /api/database/:id/tables
;; These should come back in alphabetical order
(
expect
(
let
[
db-id
(
id
)]
[(
match-$
(
Table
(
id
:categories
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"CATEGORIES"
:rows
75
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Categories"
:raw_table_id
$
})
(
match-$
(
Table
(
id
:checkins
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"CHECKINS"
:rows
1000
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Checkins"
:raw_table_id
$
})
(
match-$
(
Table
(
id
:users
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"USERS"
:rows
15
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Users"
:raw_table_id
$
})
(
match-$
(
Table
(
id
:venues
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"VENUES"
:rows
100
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Venues"
:raw_table_id
$
})])
(
let
[
db-id
(
id
)]
[(
match-$
(
Table
(
id
:categories
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"CATEGORIES"
:rows
75
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Categories"
:raw_table_id
$
})
(
match-$
(
Table
(
id
:checkins
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"CHECKINS"
:rows
1000
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Checkins"
:raw_table_id
$
})
(
match-$
(
Table
(
id
:users
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"USERS"
:rows
15
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Users"
:raw_table_id
$
})
(
match-$
(
Table
(
id
:venues
))
{
:description
nil
:entity_type
nil
:visibility_type
nil
:schema
"PUBLIC"
:name
"VENUES"
:rows
100
:updated_at
$
:entity_name
nil
:active
true
:id
$
:db_id
db-id
:created_at
$
:display_name
"Venues"
:raw_table_id
$
})])
((
user->client
:rasta
)
:get
200
(
format
"database/%d/tables"
(
id
))))
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment