Skip to content
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

MINOR: Added unit tests for ConnectionQuotas #8650

Merged
merged 4 commits into from May 21, 2020

Conversation

apovzner
Copy link
Contributor

Added ConnectionQuotasTest, a unit test for ConnectionQuotas. We test connection limits functionality in SocketServerTest (max connections per IP), and DynamicConnectionQuotaTest (max broker-wide and per listener connection limits), which is an integration test. It is useful to have unit tests that directly test ConnectionQuotas.

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

Copy link
Contributor

@dajac dajac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@apovzner Thanks for the PR. Overall, the logic of the tests looks good to me. I have left a bunch of comments/questions.

Comment on lines 90 to 92
executor.submit((() =>
intercept[RuntimeException](connectionQuotas.inc(externalListener.listenerName, externalListener.defaultClientIp, blockedPercentMeters("EXTERNAL")))): Runnable
).get(5, TimeUnit.SECONDS)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I think that intercept does not assert that the exception is thrown but return the intercepted exception. It would be better to use assertThrown here.
  • Do we really need to use an executor here? It seems that inc should throw immediately if the listener does not exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intercept also verifies the exception. For example, if the exception thrown is different, the test will fail with an error like this: Expected exception java.lang.IllegalArgumentException to be thrown, but kafka.network.TooManyConnectionsException was thrown. If if no exception is thrown, it will fail like this: Expected exception java.lang.IllegalArgumentException to be thrown, but no exception was thrown. From what I see, assertThrown achieves the same behavior as intercept.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About using the executor -- you are right that inc should return immediately in this case. I still used the executor in case the behavior changes and inc blocks. I think it's better to protect the test from this scenario

try {
// verify there is no limit by accepting 10000 connections as fast as possible
val numConnections = 10000
val futures = listeners.values.map( listener =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the space before listener is not needed. i would use curly braces here to stay consistent with the foreach below.

// verify there is no limit by accepting 10000 connections as fast as possible
val numConnections = 10000
val futures = listeners.values.map( listener =>
executor.submit((() => acceptConnections(connectionQuotas, listener, numConnections)): Runnable) )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the space before the last closing parenthesis is not needed.

executor.submit((() => acceptConnections(connectionQuotas, listener, numConnections)): Runnable) )
futures.foreach(_.get(10, TimeUnit.SECONDS))
listeners.values.foreach { listener =>
assertEquals(s"${listener.listenerName.value()}",numConnections, connectionQuotas.get(listener.defaultClientIp))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Number of connections on $listener: to stay consistent with the other tests?
  • nit: a space is missing after the first coma.

Comment on lines 118 to 119
// calling dec() for an IP for which we didn't call inc() should throw an exception
intercept[IllegalArgumentException](connectionQuotas.dec(listener.listenerName, unknownHost))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this does not assert as mentioned earlier. Moreover, I think that this deserves its own unit test as it is not really related to the current one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, moved to a separate test

executor.submit((() => acceptConnections(connectionQuotas, listener, listenerMaxConnections)): Runnable) )
futures.foreach(_.get(5, TimeUnit.SECONDS))
listeners.values.foreach { listener =>
assertEquals(s"${listener.listenerName.value()}", listenerMaxConnections, connectionQuotas.get(listener.defaultClientIp))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number of connections on $listener: to stay consistent with other tests?

Comment on lines 250 to 251
val futures2 = listeners.values.map( listener =>
executor.submit((() => acceptConnections(connectionQuotas, listener, 1)): Runnable) )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: curly braces.

val futures2 = listeners.values.map( listener =>
executor.submit((() => acceptConnections(connectionQuotas, listener, 1)): Runnable) )
futures2.foreach { future =>
intercept[TimeoutException](future.get(1, TimeUnit.SECONDS))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you may want to assert here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see my comment that intercept does assert on both wrong exception or no exception, similar to assertThrown

connectionQuotas.dec(listener.listenerName, listener.defaultClientIp)
}
// all connections should get added
futures.foreach(_.get(5, TimeUnit.SECONDS))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we assert the number of connections after this line?

assertEquals(s"Number of connections on $externalListener:", maxConnectionsPerIp + 2, connectionQuotas.get(externalListener.defaultClientIp))

// connections on the same listener but from a different IP should be accepted
executor.submit((() => acceptConnections(connectionQuotas, externalListener.listenerName, knownHost, maxConnectionsPerIp, 0)): Runnable).get(5, TimeUnit.SECONDS)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A general comment. It would be great if we could break long lines in order to keep them under a reasonable size. I don't know if we have a strict guideline on this but we tend to do it.

@apovzner
Copy link
Contributor Author

@dajac Thanks for your very thorough review. I addressed all your comments.

@rajinisivaram
Copy link
Contributor

ok to test

Copy link
Contributor

@rajinisivaram rajinisivaram left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@apovzner Thanks for the tests, LGTM

@gwenshap
Copy link
Contributor

there was an odd build failure.

retest this please.

@apovzner
Copy link
Contributor Author

It looks like the build couldn't even run tests:

15:15:09 ERROR: Error cloning remote repo 'origin'
...
15:15:18 stderr: fatal: Unable to look up github.com (port 9418) (Name or service not known)

@gwenshap
Copy link
Contributor

ok to test

@mjsax
Copy link
Member

mjsax commented May 20, 2020

Retest this please.

@apovzner
Copy link
Contributor Author

One of the build failures failed due to one of the unit tests added in this PR. It was bug in the test, that was waiting on the wrong future, which had a name similar to another one. I fixed both waiting on the right future and changed variable name so that it is easier to spot.
@mjsax Could you please rerun the tests?

@mjsax
Copy link
Member

mjsax commented May 21, 2020

Retest this please

@mjsax
Copy link
Member

mjsax commented May 21, 2020

Retest this please.

@apovzner
Copy link
Contributor Author

apovzner commented May 21, 2020

JDK 14 build has an unrelated test failure: org.apache.kafka.streams.integration.EosBetaUpgradeIntegrationTest.shouldUpgradeFromEosAlphaToEosBeta[false]

It looks like tests passed on other builds, but it failed to record the results.

@rajinisivaram
Copy link
Contributor

Test failures unrelated, merging to trunk.

@rajinisivaram rajinisivaram merged commit f6781f4 into apache:trunk May 21, 2020
Kvicii pushed a commit to Kvicii/kafka that referenced this pull request May 22, 2020
* 'trunk' of github.com:apache/kafka:
  KAFKA-9980: Fix bug where alterClientQuotas could not set default client quotas (apache#8658)
  KAFKA-9780: Deprecate commit records without record metadata (apache#8379)
  MINOR: Deploy VerifiableClient in constructor to avoid test timeouts (apache#8651)
  MINOR: Added unit tests for ConnectionQuotas (apache#8650)
  MINOR: Correct MirrorMaker2 integration test configs for Connect internal topics (apache#8653)
  KAFKA-9855 - return cached Structs for Schemas with no fields (apache#8472)
  KAFKA-9950: Construct new ConfigDef for MirrorTaskConfig before defining new properties (apache#8608)
  KAFKA-8869: Remove task configs for deleted connectors from config snapshot (apache#8444)
  KAFKA-9409: Supplement immutability of ClusterConfigState class in Connect (apache#7942)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants