Skip to content

Commit

Permalink
util-app: Add App.loadServiceBindings API
Browse files Browse the repository at this point in the history
Summary: Problem

Some users want compile time assurance that a specific implementation
will be used for `LoadService.apply`.

Solution

Provide a new `App.loadServiceBindings` API that allows a specific
implementation to be specified.

Result

Users can have more assurance of which implementation is used. A lint
rule is added to protect against duplicate registrations.

JIRA Issues: csl-6125

Differential Revision: https://phabricator.twitter.biz/D146554
  • Loading branch information
kevinoliver authored and jenkins committed Mar 16, 2018
1 parent 476e635 commit c090167
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
1 change: 1 addition & 0 deletions server/src/main/scala/com/twitter/server/Linters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ trait Linters { app: App =>
TooManyCumulativeGaugesRules() ++
Seq(
SchedulerBlockingRule(),
DuplicateLoadServiceBindings(),
NumberOfStatsReceiversRule(),
StackRegistryDuplicatesRule(ClientRegistry, Set.empty),
StackRegistryDuplicatesRule(ServerRegistry, Set.empty),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.twitter.server.lint

import com.twitter.app.LoadService
import com.twitter.util.lint.{Category, Issue, Rule}

/**
* Lint rule for duplicate calls to `LoadService.bind`.
*/
object DuplicateLoadServiceBindings {

def apply(): Rule = Rule(
Category.Configuration,
"Duplicate calls to `LoadService.bind`",
"""
|`LoadService.bind` allows users to specify a specific
|implementation. If this is getting called multiple
|times for the same interface, it indicates a setup/configuration
|issue that may cause surprises.
""".stripMargin
) {
issues(LoadService.duplicateBindings)
}

/** exposed for testing */
private[lint] def issues(dupes: Set[Class[_]]): Seq[Issue] =
if (dupes.isEmpty) {
Nil
} else {
dupes.map { dupe =>
Issue(s"Duplicate for interface: ${dupe.getName}")
}.toSeq
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.twitter.server.lint

import org.scalatest.FunSuite

class DuplicateLoadServiceBindingsTest extends FunSuite {

private trait TestTrait

test("no duplicates") {
assert(DuplicateLoadServiceBindings.issues(Set.empty).isEmpty)
}

test("includes the names of the duplicates") {
val cls = classOf[TestTrait]
assert(cls.getName == "com.twitter.server.lint.DuplicateLoadServiceBindingsTest$TestTrait")
val issues = DuplicateLoadServiceBindings.issues(Set(cls))
assert(issues.head.details.contains(cls.getName))
}

}

0 comments on commit c090167

Please sign in to comment.