Springboot, how to show Banner programmtically at start, again - java

If a springboot application starts, a logo/banner is shown.
I took my own, colored banner in a banner.txt file. It is shown at starts, all is fine.
But I want to repeat my banner after successfull or not successfull start as last startup message. Like: Banner + "runs" or Banner + "do not run".
Something like this:
public static void main( String[] args )
{
try {
SpringApplication.run( ControllerUndMain.class, args );
showLogo();
System.out.println('runs')
} catch(Exception e){
showLogo();
System.out.println('not working')
}
}
This helps our admins and devops to see, that startup phase ends and if applications run or not.
Question: How to show banner programmatically?

I could not found any straight way of doing it. I did a drive into spring code base and found way of doing that. I've tested in my project and its working fine.
Note: I've copied some of the class which are used by spring to print banner. I don't see any issue on reusing in our code base.
Here is a entire code....
Main class which runs springboot application and I've created method to print banner.
public class DemoApplication {
#Autowired
private Environment env;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(DemoApplication.class);
ConfigurableApplicationContext test = app.run(args);
DemoApplication application = new DemoApplication();
application.printBanner(app, test);
}
public void printBanner(SpringApplication app, ConfigurableApplicationContext test) {
ResourceLoader resourceLoader = (app.getResourceLoader() != null ? app.getResourceLoader()
: new DefaultResourceLoader(app.getClassLoader()));
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, null);
Banner banner = bannerPrinter.print(DemoApplication.class, test.getEnvironment());
banner.printBanner(test.getEnvironment(), DemoApplication.class, System.out);
}
}
After adding above code base just copy SpringApplicationBannerPrinter and SpringBootBanner class(You will get those form Spring code base) in your project and run.
Note: 1) I've tested before posing answer here.
2) To make answer short, I've not pasted SpringApplicationBannerPrinter and SpringBootBanner. Let me know if you want me to paste those class in answer

#SpringBootApplication
public class SimpleDemoApplication {
public static void main(String[] args) {
final SpringApplication app;
final ConfigurableApplicationContext context;
app = new SpringApplication(SimpleDemoApplication.class);
context = app.run(args);
print(context);
}
public static void print(ConfigurableApplicationContext context) {
Banner banner = context.getBean(Banner.class);
banner.printBanner(context.getEnvironment(), SimpleDemoApplication.class, System.out);
}
}
Just inject or get over context.getBean the org.springframework.boot.Banner.class. This helps for the good case, if all is fine and context is up.
I dont have a solution for the bad case, if context dont running.

Related

Configuration Properties are not read by Spring boot when setting properties like this "export my_variable=something"

edit: please pay close attention to the question. I want to make changes without having to rebuild and redeploy the application. I want to make changes on the fly.
I have a simple Spring boot application where I am trying to test if an application can read environment variable without having to rebuild and redeploy the application.
I have a simple main class which is also a #RestController
#SpringBootApplication
#RestController
#EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Value("${taco.orders.pageSize}")
private String pageSize;
#GetMapping("/myName")
public String myName() {
return pageSize;
}
int i = 0;
#Scheduled(fixedRate = 2000L)
public void scheduled() {
System.err.println(++i + "-" + pageSize);
}
}
This is what I have in my application.yml file:
taco:
orders:
pageSize: fifty
This print fine "fifty". But when I go to terminal and set a different value for the key, that new value is not reflected.
export TACO_ORDERS_PAGESIZE=NINETY
I have also created a git repo if somebody wants to retry it.
You need to substitute the environment variable in your yaml file.
taco:
orders:
pageSize: {TACO_ORDERS_PAGESIZE : fifty}
The default value for your taco.orders.pageSize is fifty it will be automatically override by your env variable TACO_ORDERS_PAGESIZE NINETY.

Create a TestServer with an already started FakeApplication

I've started integrating in some Selenium tests into the testing framework in Play. I have a class in which I define a lot of special config settings for a FakeApplication, then create that FakeApplication using:
public abstract class FakeApplicationTest {
public static FakeApplication createFakeApp() {
// grab the main application.conf file that is used to start up the Play application
Config config = ConfigFactory.parseFile(new File("conf/application.conf"));
// resolve all variables within this config file with other variables within itself
config = ConfigFactory.load(config);
// create a Configuration object out of this and then turn it into a Map to be modified
Configuration configuration = new Configuration(config);
Map<String, Object> fakeApplicationConf = Maps.newHashMap(configuration.asMap());
...
// CUSTOM CONFIG THINGS HERE
...
return Helpers.fakeApplication(fakeApplicationConf);
}
}
What I would like to be able to do, is use this FakeApplication, start it in a #Before method (using JUnit 4), and then pass that already running FakeApplication to the TestServer which is needed to run the Selenium tests.
public class Checkout extends FluentTest {
public WebDriver webDriver = new FirefoxDriver();
...
public FakeApplication app;
#Before
public void beforeTest() {
app = FakeApplicationTest.createFakeApp();
Helpers.start(app);
FakeApplicationTest.createCleanDb();
...
}
#Test
public void testReviewPage()
running(testServer(3333, app), webDriver, browser -> {
...
}
}
}
What seems to happen when I do this though, is that the existing, running FakeApplication gets ignored/tossed and a new FakeApplication is created and started which is not setup with my custom fakeApplicationConf Map... or, it's stopping the app and restarting it but goes back to only use my default application.conf.
Any ideas on why this is? or if I can somehow accomplish this in a different way?

Play Framework 2.2.2 - Java -Testing Controllers With Mock Objects

Is anyone aware of any examples of testing a Java based Play Framework controller by setting mock objects?
I am using Spring in my Play project so all my controller methods are not static.
Testing the tradional way, Play shows my controller as having static methods and I just cant see a way of how I can inject mocks into my object
Result result = callAction(
controllers.routes.ref.LoginController.authenticate(),
fakeRequest().withFormUrlEncodedBody(TestUtils.SUCCESSFUL_LOGIN_MAP)
);
I have a number of services that need to be called in the LoginController and I would like to set those up as mocks
Any help is greatly appreciated
Thanks
Damien
I was looking for the solution of the same problem. So far the best result I was able to achieve is this:
public class MyObjectControllerTest{
private final MyObjectDAO dao = mock(MyObjectDAO.class);
private final MyObjectController controller = new MyObjectController(dao);
public static FakeApplication fakeApplication;
#BeforeClass
public static void startApp() {
fakeApplication = Helpers.fakeApplication();
Helpers.start(fakeApplication);
}
#AfterClass
public static void stopApp() {
Helpers.stop(fakeApplication);
}
#Test(expected = NotFoundException.class)
public void testFailWithUnknownMyObjectKey() throws Throwable {
when(dao.getByKey(any(UUID.class), any(UUID.class), any(Boolean.class))).thenReturn(null);
controller.get(CassandraUUIDs.timeBased());
}
#Test
public void testGetSuccess(){
MyObject deletedObject = MyObjectTestGenerator.generateMyObject();
deletedObject.setDeleted(true);
when(dao.getByKey(any(UUID.class), any(UUID.class), any(Boolean.class))).thenReturn(deletedObject);
try {
Result result = controller.get(CassandraUUIDs.timeBased());
assertThat(status(result)).isEqualTo(Http.Status.GONE);
assertThat(contentType(result)).isEqualTo(Http.MimeTypes.JSON);
assertThat(contentAsString(result)).isEqualTo(ErrorMsg.OBJECT_DELETED.toJson().toString());
} catch (MyObjectsException e) {
e.printStackTrace();
fail("Failed to send MyObject.get request.");
}
}
}
What I do here is instantiate an instance of the controller class and pass mocked DAO instance. Please note that I don't use static controller methods in my code as well.
One issue with this workaround I found so far is that Action (I have custom one) is not working. But Action can (and probably must) be tested separately.

Wicket Auth/Roles user authentication before testing web Page

I have a web app which use Wicket Auth/Roles to login user and assign roles. (http://wicket.apache.org/learn/projects/authroles.html)
You can refer to this example too: http://www.wicket-library.com/wicket-examples-6.0.x/authentication3/
I have many web pages and I want to login in my application before testing my pages.
My test page extends WebAppTestBase.
Here is my code for WebAppTestBase:
public class WebAppTestBase {
protected WicketTester wicketTester;
private MyAuthenticatedWebApplication myAuthenticatedWebApplication = new MyAuthenticatedWebApplication();
#Before
public void setUp() {
wicketTester = new WicketTester(myAuthenticatedWebApplication);
}
#After
public void tearDown() {
wicketTester.destroy();
}
}
So how I could setUp AuthenticatedWebSession to authenticate my user, so I'll be able to test the other page.
Regards,
This might be an old question, but I stumbled upon this myself and found a reasonable solution that might work for you.
It is quite obvious, but it took me a while to realise that this was the way to do it.
public class MyPageTest {
private static WicketTester tester;
public static final String VALID_ADMIN_USERNAME = "admin";
public static final String VALID_ADMIN_PASSWORD = "1234";
#BeforeClass
public static void beforeTesting() {
tester = new WicketTester(new MyTestApplication());
/*
* Setup your AuthenticatedWebSession to be able to resolve any objects
* it might be depening on. In my case this was an AuthChecker instance that
* I get from Guice dependency injection but this might be very different
* for you.
*/
((MyAuthenticatedWebSession)tester.getSession())
.configureAuthChecker(MyTestApplication.testInjector()
.getInstance(AuthChecker.class));
}
#AfterClass
public static void afterTesting() {
tester.destroy();
}
#Test
public void testAdminOptions() {
// You could consider doing this in a separate #Before annotated method.
// This is basically where the magic happens and the user is logged in.
((AuthenticatedWebSession)tester.getSession()).signIn(
VALID_ADMIN_USERNAME,
VALID_ADMIN_PASSWORD);
// When the user is logged in, you can just start from a page that normally
// requires authentication.
tester.startPage(OverviewPage.class);
tester.assertVisible("myPanel");
}
}

How can I get context of test application itself in ApplicationTestCase<MyApp>?

How can I get context of test application itself in ApplicationTestCase<MyApp>?
I use test application's resources to store some reference data, but I cannot acquire it's context, as far as I see.
I'm trying to do the following:
referenceContents = readRawTextFile(
getSystemContext(),
//test application's res namespace is myApp.test.*
myApp.test.R.raw.reference_file);
where readRawTextFile is simple text reader routine, but the data I get is wrong.
If you need the context of the application you're testing (i.e. MyApp) then this is how you do it:
public class MyAppTest extends ApplicationTestCase<MyApp> {
public MyAppTest () {
super(MyApp.class);
}
public MyAppTest (Class<MyApp> applicationClass) {
super(applicationClass);
}
#Override
protected void setUp() throws Exception {
super.setUp();
createApplication();
}
public void testMyApp() throws Exception {
// Retrieves a file in the res/xml folder named test.xml
XmlPullParser xml = getContext().getResources().getXml(R.xml.test);
assertNull(xml);
}
}
As you can see, you get the context of your application under test using:
getContext()
in your test case.
However if you have two separate projects: One is your application and one is your test project and you need the context of the testproject, then the only choice you have is to extend InstrumentationTestCase instead of ApplicationTestCase - however, this means that you won't be able to obtain a context of the application project, but only a context of your test project.

Categories