JBehave steps makred as PENDING randomly - java

Heyy!
I have a bunch of story files with some scenarios, calling a WSDL service and checking the answer. The step functions have been written properly (as in no exceptions are thrown and it asserts true when it has to and vv.) and the service returns a valid answer.
My problem is in the case of some scenarios, I get steps (which has been defined as And in the story file, after a Given, or a Then) are getting marked as Pending, still IntelliJ puts the same green tick besides it as any other successful step.
The next time I run the test then they usually aren't pending anymore, but these marks coming and going randomly, which is kinda annoying, because I can't be sure if the step has actually been called or if it had any effect.
I can't show a code unfortunately, but one guess of mine is in the case of Given steps I just collect a number of Condition<>-s (from AssertJ) and don't actually do an assertion in the given step, but assert them all in the one and only When step.

Related

Is there any way to guarantee that an ElasticSearch index has been deleted

In some automated tests, I am trying to delete and immediately recreate an index at the start of every test, using ElasticSearch's high-level rest client (version 6.4), as follows:
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
deleteIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
request.mapping("_doc", "{...}", XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);
The problem I have is that, intermittently, my tests fail at the point of creating the index, with an error:
{"error": {"root_cause":[{"type":"resource_already_exists_exception","reason":"index [(index-name)/(UUID)] already exists, ...,}] "status":400}
The more tests I run, the more likely I am to see the error, which seems to be a strong indicator that it's a race condition - presumably when I try to recreate the index, the previous delete operation hasn't always completed.
This is backed-up with the fact that if I put a breakpoint immediately after the delete operation, and manually run a curl request to look at the index that I tried to delete, I find that it's still there some of the time; on those occasions the error above appears if I continue the test.
I've tried asserting the isAcknowledged() method of the response to the delete operation, but that always returns true, even in cases when the error occurs.
I've also tried doing an exists() check before the create operation. Interestingly in that case if I run the tests without breakpoints, the exists() check always returns false (i.e. that the index doesn't exist) even in cases where the error will then occur, but if I put a breakpoint in before the create operation, then the exists() check returns true in cases where the error will happen.
I'm at a bit of a loss. As far as I understand, my requests should be synchronous, and from a comment on this question, this should mean that the delete() operation only returns when the index has definitely been deleted.
I suspect a key part of the problem might be that these tests are running on a cluster of 3 nodes. In setting up the client, I'm only addressing one of the nodes:
client = new RestHighLevelClient(RestClient.builder(new HttpHost("example.com", 9200, "https")));
but I can see that each operation is being replicated to the other two nodes.
When I stop a breakpoint before the create operation, in cases where the index is not deleted, I can see that it's not being deleted on any of the nodes, and it seems not to matter how long I wait, it never gets deleted.
Is there some way I can reliably determine whether the index has been deleted before I create it? Or perhaps something I need to do before I attempt the delete operation, to guarantee that it will succeed?
Hey I think there are quite a few things to think about. For one I'd test everything with curl or some kind of rest client till I start doing anything in code. Might just help you conceptually, but that's just my opinion.
This is one thing you should consider:
"If an external versioning variant is used, the delete operation automatically creates an index if it has not been created before (check out the create index API for manually creating an index)."
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html
Which kind of would explain why exists() would return false. So if external versioning variant is used then the delete option would actually create an index with the same name prior to deleting it.
You mentioned about the fact that you are working with a three node cluster. Something you can try is:
"When making delete requests, you can set the wait_for_active_shards parameter to require a minimum number of shard copies to be active before starting to process the delete request." Here is a super detailed explanation which is certainly worth reading: https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-wait-for-active-shards
I suggest you try:
curl -X DELETE 127.0.0.1:9200/fooindex?wait_for_active_shards=3
You said you have 3 nodes in your cluster,so this means that:"...indexing operation will require 3 active shard copies before proceeding, a requirement which should be met because there are 3 active nodes in the cluster, each one holding a copy of the shard."
This check is probably not 100% water tight since according to the docs here:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-wait-for-active-shards
"It is important to note that this setting greatly reduces the chances of the write operation not writing to the requisite number of shard copies, but it does not completely eliminate the possibility, because this check occurs before the write operation commences. Once the write operation is underway, it is still possible for replication to fail on any number of shard copies but still succeed on the primary. The _shards section of the write operation’s response reveals the number of shard copies on which replication succeeded/failed." so perhaps use this parameter, but have your code check the response to see if any operations failed.
Something you can also try is:
(I can't seem to find good documentation to back this info up)
This should be able to tell you if the cluster isn't ready to accept deletes.
curl -X DELETE 127.0.0.1:9200/index?wait_for_completion=true

How to handle dynamic step in cucumber without AfterStep hook?

I am currently using cucumber(info.cukes)-Selenium to run automation test.
Now, I have a situation where a specific step can occur at any point of the flow.
So, I have to design a cucumber scenario to verify the dynamic page in every step.
How I can implement this without AfterStep hook? (cucumber(info.cukes) won't support AfterStep hook)
Example:
Scenario: Complect the order.
Given: Open URL with chrome browser
When: Login with correct ID and password
Then: Complect the details on step 1
And: Complect the details on step 2
And: Complect the details on step 3
My application has a dynamic page which can appear between any pages, so I need to check if the page is displayed or not in every step and the execute the specifc task when the dynamic page is displayed and then move to the next step in the scenario.
Could you please someone help me to achieve this scenario with cucumber Selenium automation.
Thanks for your help.
When it comes to keeping end-to-end test code DRY, page objects are almost always the answer (or at least, they're a great place to start). Even if you had the AfterStep hook, I'd caution about adding too much implicit stuff there, it can be a real headache to follow the flow and debug, especially for others.
In your case, I could imagine a page object for the three pages in the workflow, and each one has a clickSubmit() method that checks for the URL of the mystery page and completes it if present. Something like
public void clickSubmit() {
click(By.className("submitButton"));
if (driver.getCurrentUrl().contains("mysterypage")) {
MysteryPage mysteryPage = new MysteryPage(driver);
mysteryPage.completeForm();
mysteryPage.clickSumbit();
}
}
Admittedly, its a little strange for a method called clickSubmit to be doing all that, so maybe it would be better for a helper method to exist up in the test, and just be called at the end of each step.
As an afterthought, if you have real business rules around when and where this intermediate page shows up, and it's not just random, it may be worth capturing in the gherkin. If the user really cares that it shows up here and not there, but you made the gherkin blind to its appearance so it always "just works", you could be masking off a bug.

Java Cucumber: creating scenario outlines with dynamic examples

We have a test where basically we need to input a specific value in a web site and make sure another value comes out. The data of the input-output for this is stored in an XML file.
Now we can create a single Scenario that runs once and loops through, submitting each value however we run into some reporting problems, if 2 out of 100 pairs fail we want to know which ones and not just have an assertion error for the whole scenario.
We would get much clearer reporting using a Scenario Outline where all the values are in the examples table. then the scenario itself runs repeatedly and we can fail an individual set as an assertion error and have that kick back clearly in a report.
Problem: we do not want to hard code all the values from the xml into the .feature. it's noisy but also if the values change it's slow to update. we would rather just provide the XML parse it and go, if things change we just drop in an updated XML.
Is there a way to create dynamic examples where we can run the scenario repeatedly, one for each data case, without explicitly defining it in the examples table ?
Using Cucumber for this is a bad idea. You should test this functionality lower down your stack with a unit test.
At some point in your code, after the user has input their value, the value will be passed to a method/function that will return your answer. This is the place to do this sort of testing.
A cucumber test going through the whole stack will upwards of 3 orders of magnitude slower than a well written unit tests. So you could test thousands of pairs of values in your unit test in the time it takes to run one single cuke.
If you do this sort of testing in Cucumber you will quickly end up with a test suite that takes far too long to run, or that can only be run quickly at great expense. This is very damaging to a project.
Cuking should be about one happy path (The user can enter a value and see the result) and maybe a sad path (the user enters a bad value and sees an error/explanation). Anything else needs to be pushed down to unit tests.
The NoraUi framework does exactly what you want to do in your project. The NoraUi code is open source. If you have questions about this framework, you can post an issue with the tag "Question"

My failing Selenium test works manually

I have a Selenium test which has been working as expected for the past 1 month.
Since last week this one test alone fails 8 times out of 10, when the form is saved, throwing a Hibernate "Transient Object Exception". So it doesn't fail 100% but just around 80-90% of the time. But it fails just at that one point when Save button is clicked.
The developers tell me that they have changed nothing at all in the test server in the last one week.
I tried the same form manually about 10 times and it saves perfectly all 10 times.
Could there be something wrong with my Selenium test ?
Any thoughts would be helpful.
The exception means that the object that is fed to hibernate (I'm guessing a Java representation of the form) is not attached to the hibernate scope at the time of saving/updating.
Given that it works manually and not with Selenium, I'm guessing a race condition.
Something like an update/delete being performed while the matching object is not (yet) attached to the hibernate session.
Selenium is quite a bit faster at clicking then a human ;-)
My best bet would have the programmers look at any (async) calls to the database via hibernate and execution order of those calls and see if there are any race conditions possible (or in this case; where).
Have you tried adding a wait command? It may be something as simple as trying to select the element a little to early.

Why does "request.getUserPrincipal().getName()" sometimes return a blank string?

Has somebody an idea, why the getName() method of the UserPrincipal sometimes provides an empty String? Most of the time it returns the correct user name but not every time.
This behaviour does occur randomly. I can start the application, run the command and it works. The next time I start the application and run the command (exactly the same way as before!) it does not work.
Any ideas?
The part where you say, "...start the application and run the command..." is unclear.
What precisely are the steps involved?
HTTP is a text-based protocol. If you capture and observe the requests and responses, I am certain you would observe a difference to which the behavior could be attributed.
My suggestion is to gather more detailed information to point you in the direction of the solution.

Categories

Resources