-
Notifications
You must be signed in to change notification settings - Fork 15
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
Database Integration #10
Conversation
@darahayes Verified that locally. It works for me. |
Pull Request Test Coverage Report for Build #46
💛 - Coveralls |
pkg/dao/db.go
Outdated
return err | ||
} | ||
return 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.
Might be worth looking into https://github.com/mattes/migrate for these
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.
Indeed this is something I mentioned on the previous call. Really this PR is still under heavy development. :)
@darahayes I'm basing off of this to just finish exposing the |
pkg/dao/db.go
Outdated
} | ||
if _, err := db.Exec("CREATE TABLE IF NOT EXISTS sdkVersionForClient(clientId varchar(10) not null primary key, version varchar(40) not null, event_time timestamp with time zone)"); err != nil { | ||
return err | ||
} |
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.
@darahayes @wtrocki I actually found out a much better way for the knowledge base.
Now that we're using Postgres, much more complex aggregations are possible. ElasticSearch had limitations...
We can create a view that contains the latest entries for the "mobileAppMetrics" table (created below) and use that in Grafana.
No need for 2nd insertion/update operation nor a separate table.
But we need to create a view:
create view clientKnowledgeBase as select entry.clientId, entry.event_time, entry.data from mobileappmetrics entry inner join (select clientId, max(event_time) as latestEntryTime from mobileappmetrics group by clientId) latestEntry on entry.clientId = latestEntry.clientId and entry.event_time = latestEntryTime;
Doing select * from clientKnowledgeBase
would return the data de-duplicated per client id.
This, however, means that we should use this table only for our metrics, not custom metrics as we would want this view to have entries only for the metrics that needs de-duplication.
I gave this one a try on the POC but haven't checked in anything.
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.
@aliok Sounds really nice. Perhaps you should push it to a branch so we can look at it!
512e8c4
to
f6ff2fa
Compare
@darahayes @aliok PR is good to go from my point view. |
This PR is still in progress. Just finishing out some tests for the
business logic layer and perhaps db integration tests
…On 21 Feb 2018 12:40 p.m., "Wojciech Trocki" ***@***.***> wrote:
@darahayes <https://github.com/darahayes> @aliok
<https://github.com/aliok> PR is good to go from my point view.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#10 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AIQVPCC60GnRmepd2cA_0M58ednmY_luks5tXAy_gaJpZM4SK0Wc>
.
|
1bdb37c
to
687a127
Compare
* AEROGEAR-2044 - test metrics endpoint * AEROGEAR-2044 - use a setup func for creating the server * AEROGEAR-2044 - use Testify for mocking * AEROGEAR-2044 - add test case when there is an impl error in MetricsService (http 500) * AEROGEAR-2044 - use Testify's assertions * AEROGEAR-2044 - add Testify dep to Gopkg * AEROGEAR-2044 - fix tests after rebase * fix: move serialization of metrics data into mobile layer * AEROGEAR-2044 - use built-in errors * Add ping endpoint implementation and tests with mocking * Use `boom` instead of `http.Error` * Remove generated mock * Remove extra ping method * Use testify * Update gopkg
pkg/dao/db.go
Outdated
func Connect() (*sql.DB, error) { | ||
if db != nil { | ||
return db, nil | ||
// var db *sql.DB |
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.
Get that guy out :P
func (m *MetricsDAO) Update() { | ||
|
||
func (m *MetricsDAO) Create(clientId string, metricsData []byte) error { | ||
_, err := m.db.Exec("INSERT INTO mobileappmetrics(clientId, data) VALUES($1, $2)", clientId, metricsData) |
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.
[Optional] mobileappmetrics table is used in various SQL calls. DAO here works fine, but maybe it can also handle the actual table creation logic (to fully extract that there is some SQL/postgre involved) Alternative will be to just use constant for mobileappmetrics
table name. It's not big deal, since we already have abstraction for SQL queries, but creation of the table seems to be leaking that we using sql.db interface.
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.
+1 I think a constant/config item for the database table is the best option
pkg/config/config_test.go
Outdated
|
||
config := GetConfig() | ||
|
||
fmt.Println(config) |
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.
nit keep tests quiet
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.
Thanks! It's been a long day!
pkg/config/config_test.go
Outdated
|
||
config := GetConfig() | ||
|
||
fmt.Println(config) |
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.
same as above
pkg/dao/dao_test.go
Outdated
} | ||
} | ||
|
||
func TestIshealthyWhenDisconnected(t *testing.T) { |
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.
TestIshealthyWhenDisconnected -> TestIsHealthyWhenDisconnected
pkg/dao/dao_test.go
Outdated
dbHandler := DatabaseHandler{} | ||
|
||
err := dbHandler.Connect(config.DBHost, config.DBUser, config.DBPassword, config.DBName, config.SSLMode) | ||
dbHandler.DoInitialSetup() |
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.
should this be after err check
pkg/dao/db.go
Outdated
} | ||
//connection logic | ||
return nil, nil | ||
connStr := fmt.Sprintf("host=%v user=%v password=%v dbname=%v sslmode=%v", dbHost, dbUser, dbPassword, dbName, sslMode) |
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.
may want to consider looking into setting values for
db.SetMaxOpenConns()
db.SetConnMaxLifetime()
as otherwise you can end up with invalid connections. Have a read of what they do and figure out what makes sense for you
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.
+1 I was reading up on them yesterday but I totally forgot about it today!
pkg/dao/db.go
Outdated
return err | ||
} | ||
|
||
// assign db variable declared above |
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.
not sure we need that level of docs on the code 😄
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 actually an outdated comment from when the db was declared at a package level. Good catch!
@darahayes I'll give this a spin locally to understand it better, if you don't mind the wait for merge approval |
@david-martin no problem at all. The docs may need some work so ping me if you have any questions |
} | ||
} | ||
|
||
func TestGetConfigCustomEnvVariables(t *testing.T) { |
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 would suggest looking into table tests. These are heavily used in go. Here is an example https://github.com/aerogear/mobile-cli/blob/master/pkg/cmd/clients_test.go#L37
mock "github.com/stretchr/testify/mock" | ||
) | ||
|
||
type MockMetricsService struct { |
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.
general question, should there be a mock here. Could we inject just a mock dao into the real service here giving us something closer to an e2e test that can run without the db
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 would agree with you on this. I think the kind of testing you're suggesting would give us a much greater ROI. However I'm conscious that this code was already reviewed and merged as part of #14. I'm hoping that this PR doesn't grow any larger than it already is.
I would like to see a new issue/ticket created for e2e style testing. The original goal of this ticket was just the database parts but then two other PRs ended up being merged into this branch. (lesson learned - let's avoid doing that again)
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.
LGTM.
This PR consist of the multiple different PR's that were reviewed. I have reviewed and tested that myself. IMHO It's important to merge that and do verifications with Android and IOS implementations
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 this, with the knowledge there may be fixes/changes as part of integration tests with the sdks as covered by https://issues.jboss.org/browse/AGIOS-654 & https://issues.jboss.org/browse/AGDROID-735
@darahayes I've noticed some failures being present in the console output when I run integration tests locally. It's also in the log of circle ci build (make test-integration-cover part). For some reason, it has exit code 0. Is this expected? |
@psturc Thanks so much for noticing this. The reason for the failing tests is simple. Now the reason why the exit code was still 0 is a little more unclear. Will fix this very soon. |
Update
This PR ended up turning into a mega PR but this is the initial implementation that allows us to store mobile metrics in the database. There are a number of things to be aware of:
event_time
field is populated by Postgres at the time of insert.// +build integration
build tag added at the top of those files. You can run integration + unit tests using the standard test command, but also passing the flagtags=integration
@maleck13 Not sure how you feel about this. I found this solution in this stackoverflow answer. I know it's not as clear as integration tests having their own folder but it's still fairly obvious by looking at the file that the test is an integration test.The original estimate was 4d and I've spent about 3 days on this so far so there's still time to do some housekeeping around docs, build process, release, etc etc.
How to verify
fetch this branch and start the database using docker-compose.
Now start the server using
go run cmd/metrics-api/metrics-api.go
You should see a message like
Now you can try out the
/metrics
endpoint with the following curl request:You should get a the following response:
Note the
timestamp
field in the response corresponds to the client timestamp which is currently not being handled or saved.You can log into the database and verify that the record was created:
I'd love to get your reviews @maleck13 @david-martin @wtrocki