Execute HTTP Post in a loop in Groovy (Jenkins) - rest

I'm developing a shared library in Jenkins to help with interacting with an internal API. I can make single call which starts a long running process to create an object. I have to continue to query the API to check for the process' completion.
I'm trying to get this done in using a simple loop, but I keep getting stuck. Here's my function to query the API until it's completed:
def url = new URL("http://myapi/endpoint")
HttpURLConnection = http = (HttpURLConnection) url.openConnection()
http.setDoOutput(true)
http.setRequestMethod('POST')
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
def body = ["string", "anotherstring"].join('=')
OutputStreamWriter osw = new OutputStreamWriter(http.outStream)
osw.write(body)
osw.flush()
osw.close()
for(int i = 0; i < 30; i++) {
Integer counter = 0
http.connect()
response = http.content.text
def status = new JsonSlurperClassic().parseText(response)
// Code to check values here
}
When I run this through a pipeline, the first iteration through the loop works fine. The next iteration bombs with this error:
Caused: java.io.NotSerializableException: sun.net.www.protocol.http.HttpURLConnection
I just started in Groovy, so I feel like I'm trying to do this wrong. I've looked all over trying to find answers and tried several things without any luck.
Thanks in advance.

When running a pipeline job, Jenkins will constantly save the state of the execution so it can be paused and later on resumed, this means that Jenkins must be able to serialize the state of the script and therefore all of the objects that you create in your pipeline must be serializable.
If an object is not serializable you will get the NotSerializableException whenever Jenkins will attempt to serialize your un-serializable object when it save the state.
To overcome this issue you can use the #NonCPS annotation, which will cause Jenkins to execute the function without trying to serialize it. Read more info on this issue at pipeline-best-practice.
While normal Pipeline is restricted to serializable local variables (see appendix at bottom), #NonCPS functions can use more complex, nonserializable types internally (for example regex matchers, etc). Parameters and return types should still be Serializable, however.
There are however some limitations so read the documentation carefully, for example the return value types from #NonCPS methods must be serializable and you can't use any pipeline steps or CPS transformed methods inside a #NonCPS annotated function. Additional info can be found here.
One last thing, to overcome all these issues you can also use the Jenkins HTTP Plugin which includes all the HTTP abilities you will probably need wrapped in an easy to use build in interface.

Related

convert Mono<Order> to Order object

I am trying to explore the reactive programming using drools. I am doing POC to apply the drools rules on the object.
public Mono<Order> findByOrderNo(String orderNo) {
Mono<Order> order = orderDAO.findByOrderNo ( orderNo );
KieSession kieSession = kieContainer.newKieSession("rulesSessionpart2");
kieSession.insert(order); // rules are not getting applied as it requires the object type
//as input
kieSession.fireAllRules();
kieSession.dispose();
return order;
}
This is my test rule:
import com.reactive.practice.springreactor.model.Order
rule "ReturnEligible for Order"
when
orderObject: Order(itemReturnEligible==true)
then
orderObject.setDescription("bdfgdfdfhdf");
end
Here the method kieSession.insert(order) requires an object as input, but in the above code, I am passing Publisher type of Mono.
I tried converting Mono to Order object using block(). As in many documentation suggests it is not recommendable to use as it is blocking the operation.
Is there any other way to convert the Mono to Order Object.
Any help is appreciable.
Thanks
Two answers
1) Use a dedicated testing library like reactor-test
https://projectreactor.io/docs/core/release/reference/#testing
StepVerifier.create(
appendBoomError(source))
.expectNext("thing1")
.expectNext("thing2")
.expectErrorMessage("boom")
.verify();
2) Calling block in a test isn't a problem.
If you unit test method is blocking and must complete before you return then block is arguably the right call to make. But there are still better ways to do this like StepVerifier above.
In reactive style programming, calling block in your production code is almost always a bug unless you are specifically the framework code in a blocking context (e.g. a synchronous servlet API that runs the process). Generally you return a Mono and transform other inputs without having a blocking call.

Calling two functions within another function in Gatling is not working

I am trying to execute multiple HTTP calls within one function
Main:
def requestChain: ChainBuilder = {
feed(feeder(dataSource))
.exec(cleanTransactions("Revoke Transaction"))
}
Now within this method, I am calling 2 other methods which do different http calls. the first call saves the result (Array)in a getLicensesForDevice_TA session variable. When iterating through variable, I am trying to Make another http call based on the elements in the Array. However, it seems that the second call (revokeLicense) for some reason is not executed (The problem does not have to do with the If statement, I already checked that). When calling revokeLicense direkt in the requestChain, it is executed correctly.
private def cleanTransactions(methodeName:String, device:String, returnCode:Integer ): ChainBuilder = {
exec(getLicensesForDevice(methodeName, device, 200))
.foreach("${getLicensesForDevice_TA}", "deleteLicensesForDevice_TA") {
exec(session => {
val gatlingTransactionID = session("deleteLicensesForDevice_TA").as[String].trim
session.set("gatlingTransactionID", gatlingTransactionID)
})
if ("${gatlingTransactionID}".contains("TestTA")){
exec(revokeLicense(methodeName,"${gatlingTransactionID}",204,false))
}else{
exec(session => {
println("No TA will be executed: ${gatlingTransactionID}" )
session
})
}
}
}
That can't work. As explained in Gatling's documentation, you can't use Gatling DSL inside Scala functions. Gatling DSL methods are just builders that build components once at boot time.
Gatling DSL components are immutable ActionBuilder(s) that have to be chained altogether and are only built once on startup. The results is a workflow chain of Action(s). These builders don’t do anything by themselves, they don’t trigger any side effect, they are just definitions. As a result, creating such DSL components at runtime in functions is completely meaningless. If you want conditional paths in your execution flow, use the proper DSL components (doIf, randomSwitch, etc)

How to get the ID of the currently executing ZIO fiber from side effecting code

I know that I can get hold of the ID of the currently executing fiber by calling
ZIO.descriptor.map(_.id)
However, what I want, is an impure function that I can call from side effecting code, lets define it like
def getCurrentFiberId(): Option[FiberId]
so that
for {
fiberId <- ZIO.descriptor.map(_.id)
maybeId <- UIO(getCurrentFiberId())
} yield maybeId.contains(fiberId)
yields true. Is it possible to define such a function, and if so, how? Note that this question is strongly related to How to access fiber local data from side-effecting code in ZIO.
Not possible. That information is contained in an instance of a class called FiberContext which is practically the core of the ZIO Runtime in charge of interpreting the Effects.
Also, such class is internal implementation and understandably package private.
Additionally there's not only one instance for it, but one for each time you unsafeRun an effect and one more each time a fork is interpreted.
As execution of an effect is not bound to a Thread, ThreadLocal is not used and so, no hope of somehow extracting that info the way you want.

Not able to mock the getTimestamp method on mocked Row

I am writing an application that interacts with Cassandra using Scala. While performing unit testing, I am using mockito wherein I am mocking the resultSet and row
val mockedResultSet = mock[ResultSet]
val mockedRow = mock[Row]
Now while mocking the methods of the mockedRow, such as
doReturn("mocked").when(mockedRow).getString("ColumnName")
works fine. However, I am not able to mock the getTimestamp method of the mockedRow. I have tried 2 approaches but was not successful.
First approach
val testDate = "2018-08-23 15:51:12+0530"
val formatter = new SimpleDateFormat("yyyy-mm-dd HH:mm:ssZ")
val date: Date = formatter.parse(testDate)
doReturn(date).when(mockedRow).getTimestamp("ColumnName")
and second approach
when(mockedRow.getTimestamp("column")).thenReturn(Timestamp.valueOf("2018-08-23 15:51:12+0530"))
Both of them return null i.e it does not return the mocked value of the getTimestamp method. I am using cassandra driver core 3.0 dependency in my project.
Any help would br highly appreciated. Thanks in advance !!!
Mocking objects you don't own is usually considered a bad practice, that said, what you can do to try to see what's going on is to verify the interactions with the mock, i.e.
verify(mockedRow).getTimestamp("column")
Given you are getting null out of the mock, that statement should fail, but the failure will show all the actual calls received by the mock (and it's parameters), which should help you to debug.
A way to minimize this kind of problems is to use a mockito session, in standard mockito they can only be used through a JUnit runner, but with mockito-scala you can use them manually like this
MockitoScalaSession().run {
val mockedRow = mock[Row]
when(mockedRow.getTimestamp("column")).thenReturn(Timestamp.valueOf("2018-08-23 15:51:12+0530"))
//Execute your test
}
That code will check that the mock is not being called with anything that hasn't been stubbed for, it will also tell you if you had provided stubs that weren't actually used and a few more things.
If you like that behaviour (and you are using ScalaTest) you can apply it automatically to every test by using MockitoFixture
I'm a developer of mockito-scala btw

gatling after method not reached

Right now I'm having difficulty with a custom gatling feeder despite the fact that it's circular. I'm getting this error:
java.lang.IllegalStateException: Feeder is now empty, stopping engine
I'm reading this is the default behavior. However, I want to make sure each user users a different refurl from the feeder: refUrlFeederBuffer.
Also, why isn't it running my after method? I need my cleanup procedures to run regardless of the success or failure of the simulation. If I don't cleanup I can't restart the test!
var refUrlFeeder: Array [Map[String, String]] = Array()
before {
//create stuff and put the refUrls from it in a map
refUrlFeeder = refUrlFeeder :+ Map("refUrl" -> simpleUrl)
}
after {
// delete whatever I created in the before method
// THIS METHOD DOES NOT EXCUTE if the feeder is emptied
// I need it to execute regardless of errors during the scenario
}
object ImportRecords {
val someXml = "<some xml>"
val feeder = RecordSeqFeederBuilder(refUrlFeeder).circular
val update =
feed(feeder)
exec(http("Update stuff")
.put("${refUrl}")
.body(StringBody(someXml))
.asXML
.check(status.is(200))
)
}
val adminUpdaters = scenario("Admins who do updates").exec(ImportRecords.update) setUp(adminUpdaters.inject(atOnceUsers(1)).protocols(httpConf))
When the feeder runs out of items Gatling stops whole engine. It is exceptional situation which is stated also in exception itself:
[error] java.lang.IllegalStateException: Feeder is now empty, stopping engine
Hook after is called only when simulation is completed. You can receive the errors in sense of logic in your simulation, but not developer bugs. Hook is not called when there is a developer bug, which in this case it is.
Simply running out of feeder is a bug, because it says that your setUp part of simulation is not in correlation with your provided data in this case your feeder.
Btw. what does your setUp part of the simulation looks like?
EDIT: Just looking at your code structure, I'm guessing (while not seeing the whole simulation), that initialisation of your ImportRecords happens before hook before is called and thus your val feeder contains empty array. Making an empty array circular will lead to just another empty array, hence you will get an exception when Gatling tries to take an element from feeder. Try to add:
println(refUrlFeeder)
into initialisation of your object ImportRecords to find out if this is the case.
Good luck