-
Notifications
You must be signed in to change notification settings - Fork 11
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
[CA-1258] Add a status check to LdapRegistrationDAO and use to check openDJ #519
Conversation
src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/LdapRegistrationDAO.scala
Outdated
Show resolved
Hide resolved
val dbRef = TestSupport.dbRef | ||
val directoryConfig: DirectoryConfig = TestSupport.directoryConfig | ||
val dirURI = new URI(directoryConfig.directoryUrl) | ||
val ldapConnectionPool = new LDAPConnectionPool(new LDAPConnection(dirURI.getHost, dirURI.getPort, directoryConfig.user, directoryConfig.password), directoryConfig.connectionPoolSize) |
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'm a bit concerned about this, because there's no close on the pool? But also I don't know another way to ensure we are testing the real logic. Is there an afterAll or something hook in this file where cleanup can happen?
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.
Didn't get a chance to finish reviewing before I had to run to meetings, but I had a comment here that I wanted to get out for discussion at least.
src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/LdapRegistrationDAO.scala
Show resolved
Hide resolved
@@ -18,6 +17,7 @@ import scala.concurrent.{ExecutionContext, Future} | |||
|
|||
class StatusService( | |||
val directoryDAO: DirectoryDAO, | |||
val registrationDAO: RegistrationDAO, |
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.
Wondering if we shouldn't just be explicit here and say:
val registrationDAO: RegistrationDAO, | |
val ldapRegistrationDAO: LdapRegistrationDAO, |
For this class, we don't want a generic RegistrationDAO
, we explicitly need it to be an LdapRegistrationDAO
in order to satisfy the business requirement. This will require a little refactoring in Boot.scala too I think, but I think it would be worth it. As it is here, I had to trace all the calls back through Boot.scala just to make sure we were passing in the right kind of RegistrationDAO
here, which was annoying in itself, and also doesn't prevent anyone from accidentally breaking this again in the future.
I realize this will mess with tests where we use MockRegistrationDAO
. I don't know the answer off the top of my head and maybe it's something we can sort out with a discussion/mob/pair to see if we can make this better in some way.
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.
We don't actually have a MockRegistrationDAO
, interestingly enough! That said, I think changing it assumes that LDAP is how we communicate to our registration service. I might rather have it be checkRegistrationDBStatus
rather than checkOpenDJStatus
? Given that things changed with Postgres, I don't want to assume LDAP will be the way forwards forever.
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.
Agreed that we typically don't want to assume that LDAP will be the way forwards forever (I hope the RegistrationDAO goes away entirely one day). However, in this case, I'd argue that we want the StatusService
checks to be implementation-specific. Keeping it generic was how we missed this in the first place and didn't check OpenDJ's status for >1 year. If we change the implementation of the RegistrationDAO, we'd want to be forced to change the StatusService
to check the new implementation of it so that we couldn't accidentally leave it checking OpenDJ
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.
Ack. That seems reasonable in rationale to me. I will make the change.
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 went down a rabbit hole on this, specifying it as LDAPRegistrationDao
makes mocking it exceptionally hard, because SBT/Mockito doesn't know how to override a class, only the traits that we use. So the best we could do is spy on it and then override the spy. This is going to be super clunky across our tests. I think the best thing we can do is to rename the variable and make a comment, which will be both simpler, and also provide a check for us against future changes.
src/main/scala/org/broadinstitute/dsde/workbench/sam/service/StatusService.scala
Outdated
Show resolved
Hide resolved
if (session.connection.isValid((2 seconds).toSeconds.intValue())) { | ||
true | ||
} else { | ||
false | ||
} |
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 can be simplified by just returning session.connection.isValid((2 seconds).toSeconds.intValue())
src/test/scala/org/broadinstitute/dsde/workbench/sam/api/TestSamRoutes.scala
Outdated
Show resolved
Hide resolved
private def newStatusService(directoryDAO: DirectoryDAO) = { | ||
new StatusService(directoryDAO, new NoExtensions { | ||
// We need to mock this because Postgres does some automatic setup and gets unhappy with multiple instances of its DAO existing at once. | ||
private def mockDirectoryDAOWithPostgresStatusCheck(dbReferenceOverride: DbReference = dbReference) = { |
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 comment here re: duplicating the checkStatus
implementation
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.
So, this one we can't use the real postgres db, because postgres makes some assumptions that it will only get stood up once within the whole test suite, and we don't want to use a persistent postgres across all the suites here, because we want to have different DBRef objects to manage bringing it down or up, so we can't actually override directoryDao itself. (or at least, I couldn't figure out how to)
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.
Could we fully mock out the DAOs here then? It doesn't feel right to be overriding our mocks with the real implementation. I'd prefer that we either use the real implementation with a real PostgresDirectoryDAO
or we use the mock rather than relying on this combination. This goes for the MockDirectoryDAO
in TestSamRoutes
as well
@@ -18,6 +17,7 @@ import scala.concurrent.{ExecutionContext, Future} | |||
|
|||
class StatusService( | |||
val directoryDAO: DirectoryDAO, | |||
val registrationDAO: RegistrationDAO, |
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.
Agreed that we typically don't want to assume that LDAP will be the way forwards forever (I hope the RegistrationDAO goes away entirely one day). However, in this case, I'd argue that we want the StatusService
checks to be implementation-specific. Keeping it generic was how we missed this in the first place and didn't check OpenDJ's status for >1 year. If we change the implementation of the RegistrationDAO, we'd want to be forced to change the StatusService
to check the new implementation of it so that we couldn't accidentally leave it checking OpenDJ
src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/LdapRegistrationDAO.scala
Show resolved
Hide resolved
Jenkins retest |
Jenkins retest |
Jenkins retest |
.travis.yml
Outdated
@@ -3,7 +3,7 @@ jdk: | |||
dist: trusty | |||
language: scala | |||
scala: | |||
- 2.13.5 | |||
- 2.12.8 |
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 related to the Github actions stuff?
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.
Yes, will revert.
private def newStatusService(directoryDAO: DirectoryDAO) = { | ||
new StatusService(directoryDAO, new NoExtensions { | ||
// We need to mock this because Postgres does some automatic setup and gets unhappy with multiple instances of its DAO existing at once. | ||
private def mockDirectoryDAOWithPostgresStatusCheck(dbReferenceOverride: DbReference = dbReference) = { |
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.
Could we fully mock out the DAOs here then? It doesn't feel right to be overriding our mocks with the real implementation. I'd prefer that we either use the real implementation with a real PostgresDirectoryDAO
or we use the mock rather than relying on this combination. This goes for the MockDirectoryDAO
in TestSamRoutes
as well
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.
One method naming nit, but it's fine.
@@ -11,6 +12,7 @@ import org.broadinstitute.dsde.workbench.sam.util.SamRequestContext | |||
* away from a solution that requires that the Apache proxies query this group, we can remove the RegistrationDAO. | |||
*/ | |||
trait RegistrationDAO { | |||
def getConnectionTarget(): ConnectionType |
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.
Why not getConnectionType
?
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.
Because I am bad at naming :D
Jenkins retest |
1 similar comment
Jenkins retest |
Ticket:
PR checklist