1717
1818package org.apache.jmeter.protocol.bolt.sampler
1919
20+ import io.mockk.every
21+ import io.mockk.justRun
22+ import io.mockk.mockk
2023import org.apache.jmeter.protocol.bolt.config.BoltConnectionElement
2124import org.apache.jmeter.samplers.Entry
25+ import org.apache.jmeter.samplers.SampleResult
2226import org.apache.jmeter.threads.JMeterContextService
2327import org.apache.jmeter.threads.JMeterVariables
28+ import org.junit.jupiter.api.Assertions.assertEquals
29+ import org.junit.jupiter.api.Assertions.assertFalse
30+ import org.junit.jupiter.api.Assertions.assertTrue
31+ import org.junit.jupiter.api.BeforeEach
32+ import org.junit.jupiter.api.Test
2433import org.neo4j.driver.Driver
2534import org.neo4j.driver.Record
2635import org.neo4j.driver.Result
@@ -29,166 +38,156 @@ import org.neo4j.driver.exceptions.ClientException
2938import org.neo4j.driver.summary.ResultSummary
3039import org.neo4j.driver.summary.SummaryCounters
3140
32- import spock.lang.Specification
41+ class BoltSamplerTest {
42+ lateinit var sampler: BoltSampler
43+ lateinit var entry: Entry
44+ lateinit var session: Session
3345
34- class BoltSamplerSpec extends Specification {
35-
36- BoltSampler sampler
37- Entry entry
38- Session session
39-
40- def setup() {
41- sampler = new BoltSampler ()
42- entry = new Entry ()
43- def driver = Mock ( Driver )
44- def boltConfig = new BoltConnectionElement ()
45- def variables = new JMeterVariables ()
46+ @BeforeEach
47+ fun setup () {
48+ sampler = BoltSampler ()
49+ entry = Entry ()
50+ session = mockk< Session > {
51+ justRun { close() }
52+ }
53+ val driver = mockk< Driver > {
54+ every { session(any()) } returns session
55+ }
56+ val boltConfig = BoltConnectionElement ()
57+ val variables = JMeterVariables ()
4658 // ugly but could not find a better way to pass the driver to the sampler...
4759 variables.putObject(BoltConnectionElement .BOLT_CONNECTION , driver)
48- JMeterContextService .getContext().setVariables( variables)
60+ JMeterContextService .getContext().variables = variables
4961 entry.addConfigElement(boltConfig)
50- session = Mock (Session )
51- driver.session(_) >> session
5262 }
5363
54- def " should execute return success on successful query" () {
55- given:
56- sampler.setCypher(" MATCH x" )
57- session.run (" MATCH x" , [: ], _) >> getEmptyQueryResult()
58- when :
59- def response = sampler.sample(entry)
60- then:
61- response.isSuccessful()
62- response.isResponseCodeOK()
63- def str = response.getResponseDataAsString()
64- str.contains(" Summary:" )
65- str.endsWith(" Records: Skipped" )
66- response.getSampleCount() == 1
67- response.getErrorCount() == 0
68- // The sampler was executed, so start and end times should be set
69- response.getStartTime() > 0
70- response.getEndTime() > 0
64+ @Test
65+ fun `should execute return success on successful query` () {
66+ sampler.cypher = " MATCH x"
67+ every {
68+ session.run (" MATCH x" , mapOf (), any())
69+ } returns getEmptyQueryResult()
70+ val response = sampler.sample(entry)
71+
72+ assertSuccessResult(response, " Records: Skipped" )
73+ }
74+
75+ private fun assertSuccessResult (response : SampleResult , responseDataTail : String ) {
76+ val str = response.responseDataAsString
77+ assertTrue(str.contains(" Summary:" ), " response contains 'Summary:', got '$str '" )
78+ assertTrue(str.endsWith(responseDataTail), " response ends with '$responseDataTail ', got '$str '" )
79+ assertTrue(response.isSuccessful, " .isSuccessful()" )
80+ assertTrue(response.isResponseCodeOK, " .isResponseCodeOK()" )
81+ assertEquals(1 , response.sampleCount, " .sampleCount" )
82+ assertEquals(0 , response.errorCount, " .errorCount" )
83+ assertSamplerStarted(response)
84+ }
85+
86+ private fun assertSamplerStarted (response : SampleResult ) {
87+ assertTrue(response.startTime > 0 , " The sampler was executed, so start and end times should be set" )
88+ assertTrue(response.endTime > 0 , " The sampler was executed, so start and end times should be set" )
7189 }
7290
73- def " should not display results by default" () {
74- given:
75- sampler.setCypher(" MATCH x" )
76- session.run (" MATCH x" , [: ], _) >> getPopulatedQueryResult()
77- when :
78- def response = sampler.sample(entry)
79- then:
80- response.isSuccessful()
81- response.isResponseCodeOK()
82- def str = response.getResponseDataAsString()
83- str.contains(" Summary:" )
84- str.endsWith(" Records: Skipped" )
85- response.getSampleCount() == 1
86- response.getErrorCount() == 0
91+ private fun assertFailureResult (
92+ response : SampleResult ,
93+ responseCode : String ,
94+ message : String ,
95+ samplerStarted : Boolean
96+ ) {
97+ val str = response.responseDataAsString
98+ assertFalse(str.contains(" Summary:" ), " response contains 'Summary:', got $str " )
99+ assertTrue(str.contains(message), " response contains '$message ', got $str " )
100+ assertFalse(response.isSuccessful, " .isSuccessful()" )
101+ assertFalse(response.isResponseCodeOK, " .isResponseCodeOK()" )
102+ assertEquals(responseCode, response.responseCode, " .responseCode" )
103+ assertEquals(1 , response.sampleCount, " .sampleCount" )
104+ assertEquals(1 , response.errorCount, " .errorCount" )
105+ if (samplerStarted) {
106+ assertSamplerStarted(response)
107+ } else {
108+ assertSamplerNotStarted(response)
109+ }
87110 }
88111
89- def " should display results if asked" () {
90- given:
91- sampler.setCypher(" MATCH x" )
92- sampler.setRecordQueryResults(true )
93- session.run (" MATCH x" , [: ], _) >> getPopulatedQueryResult()
94- when :
95- def response = sampler.sample(entry)
96- then:
97- response.isSuccessful()
98- response.isResponseCodeOK()
99- def str = response.getResponseDataAsString()
100- str.contains(" Summary:" )
101- str.endsWith(" Mock for type 'Record'" )
102- response.getSampleCount() == 1
103- response.getErrorCount() == 0
104- // The sampler was executed, so start and end times should be set
105- response.getStartTime() > 0
106- response.getEndTime() > 0
112+ private fun assertSamplerNotStarted (response : SampleResult ) {
113+ assertEquals(0 , response.startTime, " The sampler fails at parameter preparation, so no time is recorded" )
114+ assertEquals(0 , response.endTime, " The sampler fails at parameter preparation, so no time is recorded" )
107115 }
108116
109- def " should return error on failed query" () {
110- given:
111- sampler.setCypher(" MATCH x" )
112- session.run (" MATCH x" , [: ], _) >> { throw new RuntimeException (" a message" ) }
113- when :
114- def response = sampler.sample(entry)
115- then:
116- ! response.isSuccessful()
117- ! response.isResponseCodeOK()
118- response.getResponseCode() == " 500"
119- def str = response.getResponseDataAsString()
120- str.contains(" a message" )
121- response.getSampleCount() == 1
122- response.getErrorCount() == 1
123- // The sampler was executed, so start and end times should be set
124- response.getStartTime() > 0
125- response.getEndTime() > 0
117+ @Test
118+ fun `should not display results by default` () {
119+ sampler.cypher = " MATCH x"
120+ every {
121+ session.run (" MATCH x" , mapOf (), any())
122+ } returns getPopulatedQueryResult()
123+ val response = sampler.sample(entry)
124+
125+ assertSuccessResult(response, " Records: Skipped" )
126126 }
127127
128- def " should return error on invalid parameters" () {
129- given:
130- sampler.setCypher(" MATCH x" )
131- sampler.setParams(" {invalid}" )
132- when :
133- def response = sampler.sample(entry)
134- then:
135- ! response.isSuccessful()
136- ! response.isResponseCodeOK()
137- response.getResponseCode() == " 500"
138- def str = response.getResponseDataAsString()
139- str.contains(" Unexpected character" )
140- response.getSampleCount() == 1
141- response.getErrorCount() == 1
142- // The sampler fails at parameter preparation, so no time is recorded
143- response.getStartTime() == 0
144- response.getEndTime() == 0
145- response.getTime() == 0
128+ @Test
129+ fun `should display results if asked` () {
130+ sampler.cypher = " MATCH x"
131+ sampler.isRecordQueryResults = true
132+ every {
133+ session.run (" MATCH x" , mapOf (), any())
134+ } returns getPopulatedQueryResult()
135+ val response = sampler.sample(entry)
136+ assertSuccessResult(response, " Mock for type 'Record'" )
146137 }
147138
148- def " should return db error code" () {
149- given:
150- sampler.setCypher(" MATCH x" )
151- session.run (" MATCH x" , [: ], _) >> { throw new ClientException (" a code" , " a message" ) }
152- when :
153- def response = sampler.sample(entry)
154- then:
155- response.getResponseCode() == " a code"
139+ @Test
140+ fun `should return error on failed query` () {
141+ sampler.cypher = " MATCH x"
142+ every { session.run (" MATCH x" , mapOf (), any()) } throws RuntimeException (" a message" )
143+ val response = sampler.sample(entry)
144+
145+ assertFailureResult(response, " 500" , " a message" , samplerStarted = true )
156146 }
157147
158- def " should ignore invalid timeout values" () {
159- given:
160- sampler.setCypher(" MATCH x" )
161- sampler.setTxTimeout(- 1 )
162- session.run (" MATCH x" , [: ], _) >> getEmptyQueryResult()
163- when :
164- def response = sampler.sample(entry)
165- then:
166- response.isSuccessful()
167- response.isResponseCodeOK()
168- def str = response.getResponseDataAsString()
169- str.contains(" Summary:" )
170- str.endsWith(" Records: Skipped" )
171- response.getSampleCount() == 1
172- response.getErrorCount() == 0
148+ @Test
149+ fun `should return error on invalid parameters` () {
150+ sampler.cypher = " MATCH x"
151+ sampler.params = " {invalid}"
152+ val response = sampler.sample(entry)
153+
154+ assertFailureResult(response, " 500" , " Unexpected character" , samplerStarted = false )
173155 }
174156
175- def getEmptyQueryResult() {
176- def queryResult = Mock (Result )
177- def summary = Mock (ResultSummary )
178- queryResult.consume() >> summary
179- SummaryCounters counters = Mock (SummaryCounters )
180- summary.counters() >> counters
181- return queryResult
157+ @Test
158+ fun `should return db error code` () {
159+ sampler.cypher = " MATCH x"
160+ every { session.run (" MATCH x" , mapOf (), any()) } throws ClientException (" a code" , " a message" )
161+ val response = sampler.sample(entry)
162+ assertEquals(" a code" , response.responseCode)
182163 }
183164
184- def getPopulatedQueryResult() {
185- def queryResult = Mock (Result )
186- def summary = Mock (ResultSummary )
187- def list = [Mock (Record ), Mock (Record ), Mock (Record )]
188- queryResult.consume() >> summary
189- queryResult.list() >> list
190- SummaryCounters counters = Mock (SummaryCounters )
191- summary.counters() >> counters
192- return queryResult
165+ @Test
166+ fun `should ignore invalid timeout values` () {
167+ sampler.cypher = " MATCH x"
168+ sampler.txTimeout = - 1
169+ every { session.run (" MATCH x" , mapOf (), any()) } returns getEmptyQueryResult()
170+ val response = sampler.sample(entry)
171+ assertSuccessResult(response, " Records: Skipped" )
193172 }
173+
174+ private fun getEmptyQueryResult () =
175+ mockk<Result > {
176+ every { consume() } returns mockk<ResultSummary > {
177+ every { counters() } returns mockk<SummaryCounters >(relaxed = true )
178+ }
179+ }
180+
181+ @Suppress(" LABEL_NAME_CLASH" )
182+ private fun getPopulatedQueryResult () =
183+ mockk<Result > {
184+ every { consume() } returns mockk<ResultSummary > {
185+ every { counters() } returns mockk<SummaryCounters >(relaxed = true )
186+ }
187+ every { list() } returns listOf (
188+ mockk<Record > { every { this @mockk.toString() } returns " Mock for type 'Record'" },
189+ mockk<Record > { every { this @mockk.toString() } returns " Mock for type 'Record'" },
190+ mockk<Record > { every { this @mockk.toString() } returns " Mock for type 'Record'" },
191+ )
192+ }
194193}
0 commit comments