Can one Given When Then story drive > 1 JBhave Steps? - bdd

I've created a .story file with a Given When Then (GWT).
Contact_List.story
Scenario: Discover Contact
Given I've a contact list of friends
When one of them is online
Then that friend is displayed in a list
I'd like to have two levels of testing (a bunch of fast service layer tests, and a few UI tests). So I created the following using the exact same GWT language:
ServiceSteps.java
#Given("I've a contact list of friends")
...
UISteps.java
#Given("I've a contact list of friends")
....
And Configured JBehave to use both of them:
RunBDDTests.java
...
#Override
public InjectableStepsFactory stepsFactory() {
// varargs, can have more that one steps classes
return new InstanceStepsFactory(configuration(), new ServiceSteps(), new UISteps());
}
...
But, when running this in JUNit, each time I run the tests, it's random as to which Steps class it selects.
How to have it run both steps each time so that one .story file drives > 1 steps class?

This is organized by the Configuration. In JBehave parlance, the Configuration is the class that tells the JBehave framework how to associate *.stories with *Steps.java. In the questioniers example, this is RunBDDTests.java. One option that will associate two steps with a single GWT scenario is to create two Configurations, one for the Service steps and one for the UI steps:
ServiceConfiguration.java
public class ServiceConfiguration extends JUnitStories
{
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new ServiceSteps()); // <- note steps class
}
#Override
protected List<String> storyPaths() {
return new StoryFinder().findPaths(CodeLocations.codeLocationFromClass(this.getClass()), "**/Contact_List.story", ""); //<- note story file name
}
}
UIConfiguration.java
public class UIConfiguration extends JUnitStories
{
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new UISteps()); // <- note steps class
}
#Override
protected List<String> storyPaths() {
return new StoryFinder().findPaths(CodeLocations.codeLocationFromClass(this.getClass()), "**/Contact_List.story", ""); //<- note story file name
}
}
The above two configurations will run two different step files against one .story.

Related

In AutoFac, why does the order of RegisterGeneric calls for my generic repositories only work correctly for the last one registered?

I am working on a .NET 5 targeted ASP.NET API where I need to access three different SQL databases.
I am using AutoFac as my DI (disclaimer: I am new to AutoFac and have only used the ASP.NET Core build in DI in the past).
I am also using the CleanArchitecture framework from Steve Smith (https://github.com/ardalis/CleanArchitecture)
I am using generic repositories, one for each DbContext (representing the 3 different databases).
I have the following code in my startup project's Startup.cs --> ConfigureContainer method;
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new DefaultCoreModule());
builder.RegisterModule(new DefaultInfrastructureModule(_env.EnvironmentName == "Development"));
}
And in my DefaultInfrastructureModeule class, I have the following code;
private void RegisterCommonDependencies(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(IdpRepository<>))
.As(typeof(IRepository<>))
.As(typeof(IReadRepository<>))
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(CdRepository<>))
.As(typeof(IRepository<>))
.As(typeof(IReadRepository<>))
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(M1Repository<>))
.As(typeof(IRepository<>))
.As(typeof(IReadRepository<>))
.InstancePerLifetimeScope();
...
...
...
}
The project compiles and runs. However when I try to call methods, for example the ListAsync method, from the repositories, the only repository that works properly is the one that is the last one listed in the registration sequence.
For example, using the order listed in the code above, a ListAsync call to the M1Repository works as expected, but calls to the ListAsync methods in the IdpRepository or CdRepository fail with a SqlException;
Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name 'User'.
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__169_0(Task`1 result)
Like it doesn't understand the DbContext.Set should query the Users table (plural), not the User table.
Now, if I rearrange the order of the DI registrations and move the registration of the IdpRepository to the last one registered in the order, The ListAsync call then works for the IdpRepository but then the calls to the M1Repository and CdRepository fail with a similar SQL exception.
No matter what order I register them in, only the last one registered works correctly.
All three generic repositories use the same basic design that is used in the CleanArchitecture template. The CdRepository example is shown below;
public class CdRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T>
where T : class
{
public CdRepository(CdDbContext dbContext)
: base(dbContext)
{
}
}
I am sure this is just an AutoFac issue I am not aware of since I am an AutoFac beginner. I just can't seem to resolve it.
Any ideas?
[UPDATE 1]
Here is my ListDepartments endpoint, where I inject a repository.
public class ListDepartments : BaseAsyncEndpoint
.WithRequest<DepartmentListRequest>
.WithResponse<DepartmentListResponse>
{
private readonly IReadRepository<Department> _repository;
public ListDepartments(IReadRepository<Department> repository)
{
_repository = repository;
}
[HttpGet("/Organizations/{OrganizationId}/Departments")]
[SwaggerOperation(
Summary = "Gets a list of all Departments for the specified Organization ID",
Description = "Gets a list of all Departments for the specified Organization ID",
OperationId = "Department.ListDepartments",
Tags = new[] { "OrganizationEndpoints" })
]
public override async Task<ActionResult<DepartmentListResponse>> HandleAsync([FromQuery] DepartmentListRequest request, CancellationToken cancellationToken)
{
var response = new DepartmentListResponse();
response.OrganizationId = request.OrganizationId;
response.Departments = (await _repository.ListAsync(cancellationToken))
.Select(department => new DepartmentListSummaryRecord(department.Id, department.Name))
.ToList();
return Ok(response);
}
}
[Update 2]
After reading the comment from #ssmith, I realized that I needed unique interfaces for each of the 3 generic repositories. What was causing the problem was using the IRepository and IReadRepository interfaces presented in the CleanArchitecture template for each of the three different repository registrations in AutoFac. An obvious example of a brain fart on my part.
Once I created unique interfaces for each of the three repositories, the solution is now working.
Here are the revised repositories;
public class CdRepository<T> : RepositoryBase<T>, ICdReadRepository<T>, ICdRepository<T>
where T : class
{
public CdRepository(CdDbContext dbContext)
: base(dbContext)
{
}
}
public class IdpRepository<T> : RepositoryBase<T>, IIdpReadRepository<T>, IIdpRepository<T>
where T : class
{
public IdpRepository(IdpDbContext dbContext)
: base(dbContext)
{
}
}
public class M1Repository<T> : RepositoryBase<T>, IM1ReadRepository<T>, IM1Repository<T>
where T : class
{
public M1Repository(M1DbContext dbContext)
: base(dbContext)
{
}
}
Here is the revision to my DefaultInfrastructureModule class where I am registering the repositories.
private void RegisterCommonDependencies(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(IdpRepository<>))
.As(typeof(IIdpRepository<>))
.As(typeof(IIdpReadRepository<>))
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(CdRepository<>))
.As(typeof(ICdRepository<>))
.As(typeof(ICdReadRepository<>))
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(M1Repository<>))
.As(typeof(IM1Repository<>))
.As(typeof(IM1ReadRepository<>))
.InstancePerLifetimeScope();
...
...
...
}
Thanks #ssmith for the guidance. :)
Autofac will give you the most recently registered instance type, which is why you're getting the last one. You can actually request (via DI) an IEnumerable<IReadRepository<Department>> in your endpoint class if you want, and Autofac should give you all of the registered instances for that type. That might help you in debugging, or if you want to use some strategy in the endpoint to select which one is the appropriate instance for a given request.

Jenkins API to retrieve a build log in chunks

For a custom monitoring tool I need an API (REST) to fetch the console log of a Jenkins build in chunks.
I know about the /consoleText and /logText/progressive{Text|HTML} APIs, but the problem with this is that sometimes, our build logs get really huge (up to a few GB). I have not found any way using those existing APIs that avoids fetching and transferring the whole log in one piece. This then normally drives the Jenkins master out of memory.
I already have the Java code to efficiently fetch chunks from a file, and I have a basic Jenkins plugin that gets loaded correctly.
What I'm missing is the correct extension point so that I could call my plugin via REST, for example like
http://.../jenkins/job/<jobname>/<buildnr>/myPlugin/logChunk?start=1000&size=1000
Or also, if that is easier
http://.../jenkins/myPlugin/logChunk?start=1000&size=1000&job=<jobName>&build=<buildNr>
I tried to register my plugin with something like (that code below does not work!!)
#Extension
public class JobLogReaderAPI extends TransientActionFactory<T> implements Action {
public void doLogChunk(StaplerRequest req, StaplerResponse rsp) throws IOException {
LOGGER.log(Level.INFO, "## doLogFragment req: {}", req);
LOGGER.log(Level.INFO, "## doLogFragment rsp: {}", rsp);
}
But I failed to find the right encantation to register my plugin action.
Any tips or pointers to existing plugins where I can check how to register this?
This was indeed more simple than I expected :-) It as always: once one understands the plugin system, it just needs a few lines of code.
Turns out all I needed to do was write 2 very simple classes
The "action factory" that get's called by Jenkins and registers an action on the object in question (in my case a "build" or "run"
public class ActionFactory extends TransientBuildActionFactory {
public Collection<? extends Action> createFor(Run target) {
ArrayList<Action> actions = new ArrayList<Action>();
if (target.getLogFile().exists()) {
LogChunkReader newAction = new LogChunkReader(target);
actions.add(newAction);
}
return actions;
}
The class the implements the logic
public class LogChunkReader implements Action {
private Run build;
public LogChunkReader(Run build) {
this.build = build;
}
public String getIconFileName() {
return null;
}
public String getDisplayName() {
return null;
}
public String getUrlName() {
return "logChunk";
}
public Run getBuild() {
return build;
}
public void doReadChunk(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {

Appium PageObject - When / Where to instantiate the page?

In my team we're doing cross platform UI testing using Appium and the Appium Java-Client.
The current structure of our project is something like:
mobile
pages
SignInPage
steps
SignInSteps
The steps are "glued" together using Cucuember.
SignInPage looks something like this:
public class SignInPage {
public SignInPage(AppiumDriver driver) {
PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);
}
// region Identifiers
final String IOS_USERNAME_FIELD = "SignInUsernameField";
final String ANDROID_USERNAME_FIELD = "new UiSelector().resourceIdMatches(\".*id/username.*\")";
final String IOS_PASSWORD_FIELD = "SignInPasswordField";
final String ANDROID_PASSWORD_FIELD = "new UiSelector().resourceIdMatches(\".*id/password_editText.*\")";
final String IOS_SIGN_IN_BUTTON = "SignInButton";
final String ANDROID_SIGN_IN_BUTTON = "new UiSelector().resourceIdMatches(\".*id/signInButton.*\")";
// endregion
#iOSFindBy(accessibility = IOS_USERNAME_FIELD)
#AndroidFindBy(uiAutomator = ANDROID_USERNAME_FIELD)
private MobileElement usernameField;
#iOSFindBy(accessibility = IOS_PASSWORD_FIELD)
#AndroidFindBy(uiAutomator = ANDROID_PASSWORD_FIELD)
private MobileElement passwordField;
#iOSFindBy(accessibility = IOS_SIGN_IN_BUTTON)
#AndroidFindBy(uiAutomator = ANDROID_SIGN_IN_BUTTON)
private MobileElement signInButton;
public MobileElement getUsernameField() {
return usernameField;
}
public MobileElement getPasswordField() {
return passwordField;
}
public MobileElement getSignInButton() {
return signInButton;
}
public void tapUsernameField() {
getUsernameField().click();
}
public void tapSignInButton() {
getSignInButton().click();
}
public void clearUsernameEditText() {
getUsernameField().clear();
}
}
We're not sure in terms of performance and elements lookup where is it best to create an instance of the SignInPage. Currently we have a #Before method in our SignInSteps that is executed before each Gherkin scenario starts (which is not ideal) but it helps us having a SignInPage property in the SignInSteps class that is reused by all the steps.
public class SignInSteps {
private SignInPage signInPage;
AppiumDriver driver;
#Before()
public void setUp() throws MalformedURLException {
driver = TestBase.getInstance().getDriver();
signInPage = new SignInPage(driver);
}
#Given("I fill in the username and password")
public void fill_username_and_password() throws Throwable {
signInPage.tapUsernameField();
signInPage.clearUsernameEditText();
fillEditText(signInPage.getUsernameField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_USERNAME));
fillEditText(signInPage.getPasswordField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_PASSWORD));
}
// Other sign in steps below
}
However I feel that a cleaner approach would be to create the SignInPage as a local variable inside each step method in SignInSteps. Is there any performance impact in creating the page(s) you need in each step?
Also, it's not clear to me, with our current approach (the #Before approach) why exactly does it work even when you create a page for some steps that will be executed later on (so the screen is not even visible at this point).
So maybe the larger question would be how are the elements looked up? Is it when calling PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); or when actually accessing the annotated properties (which would be some kind of lazy initialization approach that from my knowledge Java doesn't have, unless my understanding of Java annotations is wrong).
Sorry for the long post, but these are some things that I want to understand thoroughly. So any help is highly appreciated.
Thank you!
I did some more research (debugging) and I've found the answer:
When you call PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); the annotated properties from the page are set (decorated) via reflection (see AppiumFieldDecorator) with a proxy (ElementInterceptor) that wraps a MobileElement. Each time you call a method on the annotated property you actually call the proxy that looks up the element and forwards the method call. There is no cache in between (as opposed to WidgetInterceptor which I didn't figured out yet where it is used).
So in my case, creating the page once, or in each step doesn't really make a difference because the element lookup is performed each time you interact with it (which I guess it's good, but it might have a performance impact also).
I've also attached a few screenshots below:
Stacktrace when you call PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);
Stacktrace when you call click on an element
Hope this helps others as well understand how the tool works.

How to extend Jenkins job page with new links and icons

I'm developing my first Jenkins plugin and followed the tutorial at wiki.jenkins-ci.org. After adding a BuildStep and generating the results I now want to publish them to the user. I would like to do this via a new link entry on the job page and a corrsponding result view page.
Unfortunatelly I do not find the right extension points for the navigation bar at the left side, the main navigation links in the center as well as the new target page. Can somebody point me in the right direction or give me a link to a tutorial or blog post that explains this scenario?
Thanks
Root Action and Actions are different. The first one goes only to initial page (root), the second one can be attach to a Project/Job or to a Build.
To create a Root Action, just need to create a class that it's:
Annotated with #Extension (so it can be found and automatically
loaded by Jenkins)
Implements RootAction Interface
Override 3 methods: getIconFileName(), getDisplayName() and getUrlName()
For example:
#Extension
public class GoogleRootAction implements RootAction{
#Override
public String getIconFileName() {
return "clipboard.png";
}
#Override
public String getDisplayName() {
return "Google URL";
}
#Override
public String getUrlName() {
return "http://www.google.pt";
}
}
To create an Action at a Project it's more complicated, and there's more than a way, depending of what you want.
But first, the class Action itself is the easy part, since it's very similar to a class RootAction. It's not annotated with #Extension and implements Action interface instead of RootAction.
For example:
public class LatestConsoleProjectAction implements Action {
private AbstractProject<?, ?> project;
#Override
public String getIconFileName() {
return (Jenkins.RESOURCE_PATH + "/images/48x48/terminal.png").replaceFirst("^/", "");
}
#Override
public String getDisplayName() {
return Messages.Latest_Console_Project_Action();
}
#Override
public String getUrlName() {
return "lastBuild/console";
}
public LatestConsoleProjectAction(final AbstractProject<?, ?> project) {
this.project = project;
}
}
The tricky part is to inform jenkins that this class Action exists. As I said, there are different ways.
For instance, one can associate an Action to a Builder or Publisher or other by just overriding getProjectAction() method at those classes.
For example:
#Override
public Action getProjectAction(AbstractProject<?, ?> project) {
return new LatestConsoleProjectAction(project);
}
But this way, the Action link will only show on Project left menu, if the corresponding Builder or Publisher is used by the job (or selected at Job configurations).
Another way, that always shows your Action link on left menu, it's create a factory class to inform jenkins. There are many factories, but at my example I will use TransientProjectActionFactory class.
For this, one will need to create a class that:
It's annotated with #Extensions
Extends TransientProjectActionFactory class (or another Factory class)
Override createFor method to create your class Action associated with Project object
For example:
#Extension
public class LatestConsoleProjectActionFactory extends TransientProjectActionFactory {
#Override
public Collection<? extends Action> createFor(AbstractProject abstractProject) {
return Collections.singletonList(new LatestConsoleProjectAction(abstractProject));
}
}
One can still filter project object to just the projects types you want. The one you don't want, just return Collections.emptyList().
Beside this two ways, I think there are others. You can see this link to reference:
https://wiki.jenkins-ci.org/display/JENKINS/Action+and+its+family+of+subtypes
Although, they refer to addAction method and others, but I couldn't use it (I have 2.19.2 Jenkins version).
Also they refer groovy, but I didn't try it, since I want to stick with Java :)
Btw, my example will create an action link to open console page of last build. Useful to avoid selecting last build and then select his console page.
After a lot of trial and error I figured out the solution.
All in all you need two different things in your project:
1) A class that inherits from ProminentProjectAction:
import hudson.model.ProminentProjectAction;
public class MyProjectAction implements ProminentProjectAction {
#Override
public String getIconFileName() {
// return the path to the icon file
return "/images/jenkins.png";
}
#Override
public String getDisplayName() {
// return the label for your link
return "MyActionLink";
}
#Override
public String getUrlName() {
// defines the suburl, which is appended to ...jenkins/job/jobname
return "myactionpage";
}
}
2) Even more important is that you add this action somehow to your project.
In my case I wanted to show the link if and only if the related build step of my plugin is configured for the actual project. So I took my Builder class and overwrote the getProjectActionsMethod.
public class MyBuilder extends Builder {
...
#Override
public Collection<? extends Action> getProjectActions(AbstractProject<?,?> project) {
List<Action> actions = new ArrayList<>();
actions.add(new MyProjectAction());
return actions;
}
}
Maybe this is not the perfect solution yet (because I'm still trying to figure out how all the artifacts are working together), but it might give people which want to implement the same a good starting point.
The page, which is loaded after clicking the link is defined as index.jelly file under source/main/resources and an underlying package with the name of the package of your Action class appended by its class name (e.g. src/main/resources/org/example/myplugin/MyProjectAction).
As it happens, there was a plugin workshop by Steven Christou at the recent Jenkins User Conference in Boston, which covered this case. You need to add a new RootAction, as shown in the following code from the JUC session
package org.jenkinsci.plugins.JUCBeer;
import hudson.Extension;
import hudson.model.RootAction;
#Extension
public class JenkinsRootAction implements RootAction {
public String getIconFileName() {
return "/images/jenkins.png";
}
public String getDisplayName() {
return "Jenkins home page";
}
public String getUrlName() {
return "http://jenkins-ci.org";
}
}
https://github.com/jenkinsci/s3explorer-plugin is my Jenkins plugin that adds an S3 Explorer link to all Jenkins project's side-panel.
An addition to #dchang comment:
I managed to make this functionality work also on pipelines by extending TransientActionFactory<WorkflowJob>:
#Extension
public static class PipelineLatestConsoleProjectActionFactory extends TransientActionFactory<WorkflowJob> {
#Override
public Class<WorkflowJob> type() {
return WorkflowJob.class;
}
#Nonnull
#Override
public Collection<? extends Action> createFor(#Nonnull WorkflowJob job) {
return Collections.singletonList(new LatestConsoleProjectAction(job));
}
}

Not able to skip scenarios in Jbehave with JunitStory

I have been following lot of posts & threads based on which have integrated
the logic to skip scenarios. Still not able to get it working successfully.
When i put the
"configuredEmbedder().useMetaFilters(Arrays.asList("-skip"));"
OR
"configuredEmbedder().useMetaFilters(Arrays.asList("+skip"));"
in the storyrunner,java file, none of the scenarios are executed.
And when I remove the line, all the scenarios are executed.
My .story file has "Meta skip" in 2 of the 4 scenarios.
Can someone please look into this & let me know what I may have missed.
Below is the class where all the configs reside
public class SampleStory extends JUnitStory {
public SampleStory() {
configuredEmbedder().embedderControls()
.doGenerateViewAfterStories(true)
.doIgnoreFailureInStories(false).doIgnoreFailureInView(true)
.useStoryTimeoutInSecs(60);
configuredEmbedder().useMetaFilters(Arrays.asList("+skip"));
/* removeStartIgnoreCase */
// StringUtils.removeStartIgnoreCase("","");
}
#Override
public Configuration configuration() {
Configuration configuration = new MostUsefulConfiguration();
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
viewResources.put("reports", "ftl/jbehave-reports-with-totals.ftl");
// Where to find the stories
StoryLoader storyLoader;
storyLoader = new LoadFromRelativeFile(
CodeLocations.codeLocationFromClass(this.getClass()));
configuration.useStoryLoader(storyLoader);
StoryReporterBuilder storyReporterBuilder;
storyReporterBuilder = new StoryReporterBuilder();
// storyReporterBuilder.withDefaultFormats();
storyReporterBuilder.withDefaultFormats();
// storyReporterBuilder.withViewResources(viewResources).withFormats(CONSOLE,
// TXT, HTML, XML);
// storyReporterBuilder.withFormats();
// CONSOLE reporting
configuration.useStoryReporterBuilder(storyReporterBuilder);
return configuration;
}
/*
* #Override public Embedder configuredEmbedder() {
* super.configuredEmbedder().useMetaFilters(Arrays.asList("-skip"));
*
*
* return super.configuredEmbedder(); }
*/
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new SampleSteps());
}
Snenairo.story
Scenario: This is scenario 1
Given I say hello
When I say bye
Then whatever
Scenario: This is scenario 2
Meta : #skip
Given I say ello
When I say ye
Then whatever
There is another class where all the binding menthods for g/w/t exists.
Got an reply from the group of the devs of jbehave - there was a syntax error
i did
meta: #skip
but it should have been
meta : #skip
I used #ignore like this in my jbehave scenario and it worked.
Scenario: Employee1 - Delete Employees
Meta:
#ignore

Resources