ExtentReports: detachReporter() method - extentreports

I am using a suite file with multiple suites inside the testng.xml file as follows:
<suite-files>
<suite-file path="suite1"></suite-file>
<suite-file path="suite2"></suite-file>
</suite-files>
I am initializing ExtentReport in BeforeSuite.
private static void initializeExtentReport(Configuration config) {
if (extent == null) {
extent = new ExtentReports();
htmlReporter = new ExtentHtmlReporter("reportLocation");
ClassLoader classLoader = ExtentReportService.class.getClassLoader();
File extentConfigFile = new File(classLoader.getResource("extent-config.xml").getFile());
htmlReporter.loadXMLConfig(extentConfigFile);
extent.attachReporter(htmlReporter);
extent.setSystemInfo("Environment", config.getAutomationServer());
}
}
In AfterSuite, I am calling flush().
So basically the issue is, when the before suite is called for the second suite, The check (extent==null), is coming false. I also went through the JavaDocs for ExtentReports and I found a method detachReporter() there. But I am not able to access by my IDE. Tried many variations but to no fruition.
EDIT:
Right now what really happens is, I am using custom names for reports, so that no two report names are the same. And, when I was using with the same name, the results would be over written in the same file for the suites.

A better approach here is to use a singleton like so:
public class Extent
implements Serializable {
private static final long serialVersionUID = 1L;
private static class ExtentReportsLoader {
private static final ExtentReports INSTANCE = new ExtentReports();
static {
}
}
public static synchronized ExtentReports getInstance() {
return ExtentReportsLoader.INSTANCE;
}
#SuppressWarnings("unused")
private ExtentReports readResolve() {
return ExtentReportsLoader.INSTANCE;
}
}
Usage:
ExtentReports extent = Extent.getInstance();
So your code becomes:
private static void initializeExtentReport(Configuration config) {
extent = Extent.getInstance();
if (extent.getStartedReporters().isEmpty()) {
htmlReporter = new ExtentHtmlReporter("reportLocation");
ClassLoader classLoader = ExtentReportService.class.getClassLoader();
File extentConfigFile = new File(classLoader.getResource("extent-config.xml").getFile());
htmlReporter.loadXMLConfig(extentConfigFile);
extent.attachReporter(htmlReporter);
extent.setSystemInfo("Environment", config.getAutomationServer());
}
}
I would further recommend getting rid of all shared variables for extent/htmlReporter and directly use the Singleton

Related

How to implement structured logging when using NLog in wrapper class

I am having trouble figuring out how I can use the structured logging, when NLog is in a wrapper class. I have an asp.net webapp that calls my nlog wrapper class.
It works fine for regular logging ex. logger.Info("Gets to here.") but i can't get it to work for structured logging calls ex. logger.Info("This is structured logging entry #{param1}", new {Status = "processing"})
This is my Wrapper class for NLog(EventLog.LogManager):
public static void Info(params object[] args)
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
Logger.Log(LogLevel.Info, args);
//This is what I've tried to no avail.
//var ci = new CultureInfo("en-US");
//LogEventInfo le = LogEventInfo.Create(LogLevel.Info, Logger.Name, ci, args);
//le.Parameters = args;
//string test = le.FormattedMessage;
//string test1 = string.Format(le.Parameters[0].ToString(), le.Parameters[1].ToString());
//Logger.Log(typeof(LogManager), le);
}
This is my asp.net application that calls the above method:
public ActionResult Index()
{
EventLog.LogManager.Info("Test #{param1}", new { OrderId = 2, Status = "Processing" });
return View();
}
If anyone can point me in the right direction, it would be greatly appreciated. Thank you in advance.
Try changing into this:
namespace EventLog
{
public static class LogManager
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static void Info(string message, params object[] args)
{
Logger.Info(message, args);
}
}
}

Spring OAuth2 Making `state` param at least 32 characters long

I am attempting to authorize against an external identity provider. Everything seems setup fine, but I keep getting a validation error with my identity provider because the state parameter automatically tacked onto my authorization request is not long enough:
For example:
&state=uYG5DC
The requirements of my IDP say that this state param must be at least 32-characters long. How can I programmatically increase the size of this auto-generated number?
Even if I could generate this number myself, it is not possible to override with other methods I have seen suggested. The following attempt fails because my manual setting of ?state=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz is superceded by the autogenerated param placed after it during the actual request:
#Bean
public OAuth2ProtectedResourceDetails loginGovOpenId() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails() {
#Override
public String getUserAuthorizationUri() {
return super.getUserAuthorizationUri() + "?state=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
}
};
details.setClientId(clientId);
details.setAccessTokenUri(accessTokenUri);
details.setUserAuthorizationUri(userAuthorizationUri);
details.setScope(Arrays.asList("openid", "email"));
details.setPreEstablishedRedirectUri(redirectUri);
details.setUseCurrentUri(true);
return details;
}
The 6-character setting seems to be set here, is there a way to override this?
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/util/RandomValueStringGenerator.java
With the help of this post:
spring security StateKeyGenerator custom instance
I was able to come up with a working solution.
In my configuration class marked with these annotations:
#Configuration
#EnableOAuth2Client
I configured the following beans:
#Bean
public OAuth2ProtectedResourceDetails loginGovOpenId() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
AuthorizationCodeResourceDetails details = new
details.setClientId(clientId);
details.setClientSecret(clientSecret);
details.setAccessTokenUri(accessTokenUri);
details.setUserAuthorizationUri(userAuthorizationUri);
details.setScope(Arrays.asList("openid", "email"));
details.setPreEstablishedRedirectUri(redirectUri);
details.setUseCurrentUri(true);
return details;
}
#Bean
public StateKeyGenerator stateKeyGenerator() {
return new CustomStateKeyGenerator();
}
#Bean
public AccessTokenProvider accessTokenProvider() {
AuthorizationCodeAccessTokenProvider accessTokenProvider = new AuthorizationCodeAccessTokenProvider();
accessTokenProvider.setStateKeyGenerator(stateKeyGenerator());
return accessTokenProvider;
}
#Bean
public OAuth2RestTemplate loginGovOpenIdTemplate(final OAuth2ClientContext clientContext) {
final OAuth2RestTemplate template = new OAuth2RestTemplate(loginGovOpenId(), clientContext);
template.setAccessTokenProvider(accessTokenProvider());
return template;
}
Where my CustomStateKeyGenerator implementation class looks as follows:
public class CustomStateKeyGenerator implements StateKeyGenerator {
// login.gov requires state to be at least 32-characters long
private static int length = 32;
private RandomValueStringGenerator generator = new RandomValueStringGenerator(length);
#Override
public String generateKey(OAuth2ProtectedResourceDetails resource) {
return generator.generate();
}
}

in API, create multiple controller constructor with one parameter

[Route("api/[controller]")]
public class DigitalDocumentController : Controller
{
private IDigitalDocumentService digitalDocumentService;
private IDatabaseInitializer databaseInitializer;
public DigitalDocumentController(IDigitalDocumentService digitalDocumentService)
{
this.digitalDocumentService = digitalDocumentService;
}
public DigitalDocumentController(IDatabaseInitializer databaseInitializer)
{
this.databaseInitializer = databaseInitializer;
}
i want two controller constructor in my project to Mock in xUnit Testing, but there was an error in my swagger interface {
"error": "Multiple constructors accepting all given argument types have been found in type 'i2ana.Web.Controllers.DigitalDocumentController'. There should only be one applicable constructor."
}
can anybody help me how i can do it ?
…
what i am try to do , is to test Uniquness of the Name Field in my database
My testing code:
[Fact]
public void AddNotUniqueName_ReturnsNotFoundObjectResult()
{
var digitalDocument = new DigitalDocument
{
Image = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
CreatedOn = DateTime.Today,
Id = 6,
Location = "temp",
Name = "Flower",
Tages = new List<Tag> { new Tag { Id = 1, Value = "Tag 1" }, new Tag { Id = 1, Value = "Tag 2" } }
};
// Arrange
var mockRepo = new Mock<IDatabaseInitializer>();
mockRepo.Setup(repo => repo.SeedAsync()).Returns(Task.FromResult(AddUniqueDigitalDocument(digitalDocument)));
var controller = new DigitalDocumentController(mockRepo.Object);
// Act
var result = controller.Add(digitalDocument);
// Assert
var viewResult = Assert.IsType<NotFoundObjectResult>(result);
var model = Assert.IsAssignableFrom<int>(viewResult.Value);
Assert.NotEqual(6, model);
}
the "AddUniqueDigitalDocument" returns 6 only to test that the new digitaldocumet is not the same id of my initialize data.
When using dependency injection, you should only have one constructor where all dependencies can be satisfied. Otherwise, how is the DI container to know which constructor to utilize? That's your issue here. Using the Microsoft.Extensions.DependencyInjection package, and since this is a controller you're injecting into, there's only one reasonable way to solve this: don't register one or the other of the services, IDigitalDocumentService or IDatatabaseInitializer. If only one is registered, the service collection will simply use the constructor it has a registered service for.
It's possible with a more featured DI container, you might be able to configure something to allow it choose the proper constructor. How to do that would be entirely dependent on the DI container you end up going with, though, so not much more can be said on the subject at this point. Just realize that the default container (Microsoft.Extensions.DependencyInjection) is intentionally simplistic, so if you needs are more complex, you should sub in a full DI container.
UPDATE
You should be doing integration testing with the test host and an in-memory database. The basic approach is:
public MyTests()
{
_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
_context = _server.Host.Services.GetRequiredService<MyContext>();
_client = _server.CreateClient();
}
In your app's Startup, create a virtual method:
public virtual void ConfigureDatabase(IServiceCollection services)
{
// normal database setup here, e.g.
services.AddDbContext<MyContext>(o =>
o.UseSqlServer(Configuration.GetConnectionString("Foo")));
}
Then, in ConfigureServices, replace your database setup with a call to this method.
Finally, in your test project, create a TestStartup class and override the ConfigureDatabase method:
public class TestStartup : Startup
{
public override void ConfigureDatabase(IServiceCollection services)
{
var databaseName = Guid.NewGuid().ToString();
services.AddDbContext<MyContext>(o =>
o.UseInMemoryDatabase(databaseName));
}
}
Now, in your tests you just make requests against the test client (which is just an HttpClient instance, so it works like any other HttpClient). You start by setting up your database with appropriate test data, and then ensure that the correct response is returned:
// Arrange
_context.Add(new DigitalDocument { Name = "Foo" });
await _context.SaveChanges();
// Act
// Submit a `DigitalDocument` with the same name via `_client`
// Assert
// Inspect the response body for some indication that it was considered invalid. Or you could simply assert that no new `DigitalDocument` was created by querying `_context` (or both)
This is admittedly a lot easier with an API, as with a web application, you're going to invariably need to do some HTML parsing. However, the docs and corresponding sample app help you with that.
Additionally, in actual practice, you'd want to use a test fixture to prevent having to bootstrap a test server for every test. Again, the docs have you covered there. One thing to note, though, is that once you switch to using a fixture, your database will then be persisted between tests. To segregate your test data, make sure that you call EnsureDeleted() on your context before each test. This can be easily done in the test class' constructor:
public class MyTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
private readonly MyContext _context;
public MyTests(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
I don't even like this much bootstrapping code in my tests, though, so I usually inherit from a fixture class instead:
public class TestServerFixture : IClassFixture<WebApplicationFactory<Startup>>
{
protected readonly HttpClient _client;
protected readonly MyContext _context;
public TestServerFixture(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
}
Then, for each test class:
public class MyTests : TestServerFixture
{
public MyTests(WebApplicationFactory<Startup> factory)
: base(factory)
{
}
This may seem like a lot, but most of it is one-time setup. Then, your tests will be much more accurate, more robust, and even easier in many ways.

Unable to use the Page Object in a Test Method. (TestNG)

I m somebody who to new to Automation. I m currently learning Selenium Webdriver with JAVA along with Page Object Model pattern. When I experimenting with the few lines of code I got myself strucked at one point. I created a separate class file for the Page Elements which has the below code.
public class SamplePage {
WebDriver Driver;
public WebElement Gmail_Email_TextBox = Driver.findElement(By.xpath(".//*[#id='Email']"));
public WebElement Gmail_Email_Next_Button = Driver.findElement(By.xpath(".//*[#id='next']"));
public SamplePage(WebDriver Driver) { //This is a constructor.
System.out.println("Constructor");
this.Driver = Driver;
}
}
When try call the above page in another class I get java.lang.NullPointerException. Pls find the code below.
public class SampleTestMethod {
WebDriver Driver;
#BeforeMethod
public void BrowserLaunch() throws InterruptedException {
Driver = Browser.LaunchMozillaFirefox("https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fmail.google.com%2Fmail%2F&service=mail&sacu=1&rip=1");
}
#Test
public void TestCase1() {
SamplePage Sample1 = new SamplePage(Driver);
Sample1.Gmail_Email_TextBox.click();
}
}
Pls clarify me on this. The constructor is not being called at all. This is what I have observed.
Class fields like Gmail_Email_TextBox and Gmail_Email_Next_Button are evaluated as null before constructor's call and never changed afterwards. That is why.
Simply put: initialize those fields in a different place.
You can add a #FindBy annotation to each of them and then just use PageFactory:
SamplePage samplePage = new SamplePage();
PageFactory.initElements(driver, samplePage);
Further info on this.
Follow naming conventions and use camelCase.
Instance variables are initialized before constructor calls.
Check this out to see it yourself:
public class Example {
private String instanceVariable;
private String anotherInstanceVariable = instanceVariable + " appended.";
public Example(String instanceVariable) {
this.instanceVariable = instanceVariable;
}
public static void main(String[] args) {
Example example = new Example("The first one");
System.out.println(example.anotherInstanceVariable);
}
}
instanceVariable is like your driver. anotherInstanceVariable is like any of your WebElements.

spring-integration-dsl: Make Feed-Flow Work

I'm trying to code a RSS-feed reader with a configured set of RSS-feeds. I thought that a good approach is to solve that by coding a prototype-#Bean and call it with each RSS-feed found in the configuration.
However, I guess that I'm missing a point here as the application launches, but nothing happens. I mean the beans are created as I'd expect, but there is no logging happening in that handle()-method:
#Component
public class HomeServerRunner implements ApplicationRunner {
private static final Logger logger = LoggerFactory.getLogger(HomeServerRunner.class);
#Autowired
private Configuration configuration;
#Autowired
private FeedConfigurator feedConfigurator;
#Override
public void run(ApplicationArguments args) throws Exception {
List<IntegrationFlow> feedFlows = configuration.getRssFeeds()
.entrySet()
.stream()
.peek(entry -> System.out.println(entry.getKey()))
.map(entry -> feedConfigurator.feedFlow(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
// this one appears in the log-file and looks good
logger.info("Flows: " + feedFlows);
}
}
#Configuration
public class FeedConfigurator {
private static final Logger logger = LoggerFactory.getLogger(FeedConfigurator.class);
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public IntegrationFlow feedFlow(String name, FeedConfiguration configuration) {
return IntegrationFlows
.from(Feed
.inboundAdapter(configuration.getSource(), getElementName(name, "adapter"))
.feedFetcher(new HttpClientFeedFetcher()),
spec -> spec.poller(Pollers.fixedRate(configuration.getInterval())))
.channel(MessageChannels.direct(getElementName(name, "in")))
.enrichHeaders(spec -> spec.header("feedSource", configuration))
.channel(getElementName(name, "handle"))
//
// it would be nice if the following would show something:
//
.handle(m -> logger.debug("Payload: " + m.getPayload()))
.get();
}
private String getElementName(String name, String postfix) {
name = "feedChannel" + StringUtils.capitalize(name);
if (!StringUtils.isEmpty(postfix)) {
name += "." + postfix;
}
return name;
}
}
What's missing here? It seems as if I need to "start" the flows somehow.
Prototype beans need to be "used" somewhere - if you don't have a reference to it anywhere, no instance will be created.
Further, you can't put an IntegrationFlow #Bean in that scope - it generates a bunch of beans internally which won't be in that scope.
See the answer to this question and its follow-up for one technique you can use to create multiple adapters with different properties.
Alternatively, the upcoming 1.2 version of the DSL has a mechanism to register flows dynamically.

Resources