package io.irontest; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.Option; import com.jayway.jsonpath.spi.json.JacksonJsonProvider; import com.jayway.jsonpath.spi.json.JsonProvider; import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; import com.jayway.jsonpath.spi.mapper.MappingProvider; import com.roskart.dropwizard.jaxws.EndpointBuilder; import com.roskart.dropwizard.jaxws.JAXWSBundle; import io.dropwizard.Application; import io.dropwizard.assets.AssetsBundle; import io.dropwizard.auth.AuthDynamicFeature; import io.dropwizard.auth.basic.BasicCredentialAuthFilter; import io.dropwizard.forms.MultiPartBundle; import io.dropwizard.jdbi3.JdbiFactory; import io.dropwizard.jetty.ConnectorFactory; import io.dropwizard.jetty.HttpConnectorFactory; import io.dropwizard.logging.DefaultLoggingFactory; import io.dropwizard.server.DefaultServerFactory; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import io.dropwizard.views.ViewBundle; import io.irontest.auth.AuthResponseFilter; import io.irontest.auth.ResourceAuthenticator; import io.irontest.auth.ResourceAuthorizer; import io.irontest.auth.SimplePrincipal; import io.irontest.db.*; import io.irontest.models.AppInfo; import io.irontest.models.AppMode; import io.irontest.resources.*; import io.irontest.upgrade.UpgradeCommand; import io.irontest.utils.IronTestUtils; import io.irontest.ws.ArticleSOAP; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.glassfish.jersey.filter.LoggingFilter; import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature; import org.jdbi.v3.core.Jdbi; import java.io.File; import java.io.IOException; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; public class IronTestApplication extends Application<IronTestConfiguration> { private JAXWSBundle jaxWsBundle = new JAXWSBundle(); public static void main(String[] args) throws Exception { new IronTestApplication().run(args); } @Override public String getName() { return "Iron Test"; } @Override public void initialize(Bootstrap<IronTestConfiguration> bootstrap) { bootstrap.addCommand(new UpgradeCommand()); bootstrap.addBundle(new AssetsBundle("/assets/app", "/ui", "index.htm", "ui")); bootstrap.addBundle(new AssetsBundle("/META-INF/resources/webjars", "/ui/lib", null, "lib")); bootstrap.addBundle(new AssetsBundle("/assets/mockserver", "/ui/mockserver", "mockserver.htm", "mockserver")); bootstrap.addBundle(new AssetsBundle("/assets/common", "/ui/common", null, "common")); bootstrap.addBundle(jaxWsBundle); bootstrap.addBundle(new MultiPartBundle()); bootstrap.addBundle(new ViewBundle<IronTestConfiguration>(){ @Override public Map<String, Map<String, String>> getViewConfiguration(IronTestConfiguration config) { return config.getViewRendererConfiguration(); } }); Configuration.setDefaults(new Configuration.Defaults() { private final JsonProvider jsonProvider = new JacksonJsonProvider(); private final MappingProvider mappingProvider = new JacksonMappingProvider(); @Override public JsonProvider jsonProvider() { return jsonProvider; } @Override public MappingProvider mappingProvider() { return mappingProvider; } @Override public Set<Option> options() { return EnumSet.noneOf(Option.class); } }); // configure the Jackson ObjectMapper used by JAX-RS (Jersey) ObjectMapper objectMapper = bootstrap.getObjectMapper(); objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION); IronTestUtils.addMixInsForWireMock(objectMapper); } private boolean isInTeamMode(IronTestConfiguration configuration) { return AppMode.TEAM.toString().equals(configuration.getMode()); } @Override public void run(IronTestConfiguration configuration, Environment environment) throws IOException { final JdbiFactory jdbiFactory = new JdbiFactory(); final Jdbi systemDBJdbi = jdbiFactory.build(environment, configuration.getSystemDatabase(), "systemDatabase"); if (!checkVersion(systemDBJdbi)) { System.out.println("Press Enter to exit."); System.in.read(); System.exit(0); } // Override Java's trusted cacerts with our own trust store if available. // Notice that setting the properties without the trust store being existing could cause unexpected result // at runtime with Java 10 (Java 1.8 does not have the issue), such as failure of SOAP test step run (caused // by 'new SSLContextBuilder().loadTrustMaterial'). if (new File(configuration.getSslTrustStorePath()).exists()) { System.setProperty("javax.net.ssl.trustStore", configuration.getSslTrustStorePath()); System.setProperty("javax.net.ssl.trustStorePassword", configuration.getSslTrustStorePassword()); } // start WireMock server (in the same JVM) WireMockServer wireMockServer = new WireMockServer(options() .extensions(new ResponseTemplateTransformer(true)) .port(Integer.parseInt(configuration.getWireMock().get("port"))) .maxRequestJournalEntries(Integer.parseInt(configuration.getWireMock().get("maxRequestJournalEntries"))) .notifier(new WireMockFileNotifier()) ); wireMockServer.start(); createSystemResources(configuration, environment, systemDBJdbi, wireMockServer); createSampleResources(configuration, environment); } /** * @param systemDBJdbi * @return true if version check finds no problem, false otherwise. */ private boolean checkVersion(Jdbi systemDBJdbi) { DefaultArtifactVersion systemDBVersion = IronTestUtils.getSystemDBVersion(systemDBJdbi); DefaultArtifactVersion jarFileVersion = new DefaultArtifactVersion(Version.VERSION); int comparison = systemDBVersion.compareTo(jarFileVersion); if (comparison == 0) { // system database and the jar file are of the same version return true; } else if (comparison > 0) { // system database version is bigger than the jar file version System.out.printf(IronTestConstants.PROMPT_TEXT_WHEN_SYSTEM_DB_VERSION_IS_BIGGER_THAN_JAR_VERSION, systemDBVersion, jarFileVersion); System.out.println(); return false; } else { // system database version is smaller than the jar file version System.out.printf("System database version %1$s is smaller than jar file version %2$s.%n", systemDBVersion, jarFileVersion); System.out.println("Please download and build the latest release of Iron Test. Under the dist directory, " + "run command 'java -jar <jarFileName> upgrade <IronTest_Home>' to upgrade your existing " + "Iron Test instance."); System.out.println("Follow the instructions to finish upgrade. In the end, you should see in the " + "command line output 'UPGRADE SUCCESS'."); return false; } } private void createSystemResources(IronTestConfiguration configuration, Environment environment, Jdbi systemDBJdbi, WireMockServer wireMockServer) { systemDBJdbi.registerArgument(new PropertiesArgumentFactory()); // create DAO objects final VersionDAO versionDAO = systemDBJdbi.onDemand(VersionDAO.class); final FolderDAO folderDAO = systemDBJdbi.onDemand(FolderDAO.class); final EnvironmentDAO environmentDAO = systemDBJdbi.onDemand(EnvironmentDAO.class); final EndpointDAO endpointDAO = systemDBJdbi.onDemand(EndpointDAO.class); final TestcaseDAO testcaseDAO = systemDBJdbi.onDemand(TestcaseDAO.class); final TeststepDAO teststepDAO = systemDBJdbi.onDemand(TeststepDAO.class); final AssertionDAO assertionDAO = systemDBJdbi.onDemand(AssertionDAO.class); final PropertyExtractorDAO propertyExtractorDAO = systemDBJdbi.onDemand(PropertyExtractorDAO.class); final UtilsDAO utilsDAO = systemDBJdbi.onDemand(UtilsDAO.class); final FolderTreeNodeDAO folderTreeNodeDAO = systemDBJdbi.onDemand(FolderTreeNodeDAO.class); final UserDefinedPropertyDAO udpDAO = systemDBJdbi.onDemand(UserDefinedPropertyDAO.class); final DataTableDAO dataTableDAO = systemDBJdbi.onDemand(DataTableDAO.class); final DataTableColumnDAO dataTableColumnDAO = systemDBJdbi.onDemand(DataTableColumnDAO.class); final DataTableCellDAO dataTableCellDAO = systemDBJdbi.onDemand(DataTableCellDAO.class); final TestcaseRunDAO testcaseRunDAO = systemDBJdbi.onDemand(TestcaseRunDAO.class); final TestcaseIndividualRunDAO testcaseIndividualRunDAO = systemDBJdbi.onDemand(TestcaseIndividualRunDAO.class); final TeststepRunDAO teststepRunDAO = systemDBJdbi.onDemand(TeststepRunDAO.class); final HTTPStubMappingDAO httpStubMappingDAO = systemDBJdbi.onDemand(HTTPStubMappingDAO.class); UserDAO userDAO = null; if (isInTeamMode(configuration)) { userDAO = systemDBJdbi.onDemand(UserDAO.class); } AppInfo appInfo = new AppInfo(); if (isInTeamMode(configuration)) { appInfo.setAppMode(AppMode.TEAM); // ignore bindHost DefaultServerFactory server = (DefaultServerFactory) configuration.getServerFactory(); List<ConnectorFactory> applicationConnectors = server.getApplicationConnectors(); HttpConnectorFactory httpConnectorFactory = (HttpConnectorFactory) applicationConnectors.get(0); httpConnectorFactory.setBindHost(null); // turn on user authentication and authorization environment.jersey().register(new AuthDynamicFeature( new BasicCredentialAuthFilter.Builder<SimplePrincipal>() .setAuthenticator(new ResourceAuthenticator(userDAO)) .setAuthorizer(new ResourceAuthorizer()).buildAuthFilter())); environment.jersey().register(RolesAllowedDynamicFeature.class); environment.jersey().register(new AuthResponseFilter()); } // create database tables // keep the order!!! (there are foreign keys linking some of them) versionDAO.createTableIfNotExists(); versionDAO.insertVersionIfNotExists(); folderDAO.createSequenceIfNotExists(); folderDAO.createTableIfNotExists(); folderDAO.insertARootNodeIfNotExists(); environmentDAO.createSequenceIfNotExists(); environmentDAO.createTableIfNotExists(); endpointDAO.createSequenceIfNotExists(); endpointDAO.createTableIfNotExists(); testcaseDAO.createSequenceIfNotExists(); testcaseDAO.createTableIfNotExists(); teststepDAO.createSequenceIfNotExists(); teststepDAO.createTableIfNotExists(); assertionDAO.createSequenceIfNotExists(); assertionDAO.createTableIfNotExists(); propertyExtractorDAO.createSequenceIfNotExists(); propertyExtractorDAO.createTableIfNotExists(); udpDAO.createSequenceIfNotExists(); udpDAO.createTableIfNotExists(); dataTableColumnDAO.createSequenceIfNotExists(); dataTableColumnDAO.createTableIfNotExists(); dataTableColumnDAO.insertCaptionColumnForTestcasesWithoutDataTableColumn(); dataTableCellDAO.createSequenceIfNotExists(); dataTableCellDAO.createTableIfNotExists(); testcaseRunDAO.createSequenceIfNotExists(); testcaseRunDAO.createTableIfNotExists(); testcaseIndividualRunDAO.createSequenceIfNotExists(); testcaseIndividualRunDAO.createTableIfNotExists(); teststepRunDAO.createSequenceIfNotExists(); teststepRunDAO.createTableIfNotExists(); httpStubMappingDAO.createSequenceIfNotExists(); httpStubMappingDAO.createTableIfNotExists(); if (isInTeamMode(configuration)) { userDAO.createSequenceIfNotExists(); userDAO.createTableIfNotExists(); userDAO.insertBuiltinAdminUserIfNotExists(); } // register APIs environment.jersey().register(new SystemResource(appInfo)); environment.jersey().register(new ManagedEndpointResource(appInfo, endpointDAO)); environment.jersey().register(new TestcaseResource(testcaseDAO, teststepDAO)); environment.jersey().register(new FolderResource(folderDAO, testcaseDAO)); environment.jersey().register(new FolderTreeNodeResource(folderTreeNodeDAO)); environment.jersey().register(new TeststepResource(appInfo, teststepDAO, udpDAO, utilsDAO, dataTableDAO, assertionDAO)); environment.jersey().register(new WSDLResource()); environment.jersey().register(new EnvironmentResource(environmentDAO)); environment.jersey().register(new TestcaseRunResource(testcaseDAO, utilsDAO, testcaseRunDAO, teststepRunDAO, wireMockServer)); environment.jersey().register(new AssertionResource(udpDAO, teststepDAO, dataTableDAO, assertionDAO)); environment.jersey().register(new UDPResource(udpDAO)); environment.jersey().register(new DataTableResource(dataTableDAO, dataTableColumnDAO, dataTableCellDAO)); environment.jersey().register(new HTTPStubResource(httpStubMappingDAO, wireMockServer, udpDAO, dataTableDAO)); environment.jersey().register(new MockServerResource(wireMockServer)); environment.jersey().register(new PropertyExtractorResource(udpDAO, dataTableDAO, propertyExtractorDAO)); if (isInTeamMode(configuration)) { environment.jersey().register(new UserResource(userDAO)); } // if turned on in config.yml, register jersey LoggingFilter (used for logging Iron Test resource oriented HTTP API requests and responses) DefaultLoggingFactory defaultLoggingFactory = (DefaultLoggingFactory) configuration.getLoggingFactory(); if (defaultLoggingFactory.getLoggers().containsKey(LoggingFilter.class.getName())) { environment.jersey().register(new LoggingFilter(Logger.getLogger(LoggingFilter.class.getName()), true)); } // register exception mappers environment.jersey().register(new IronTestLoggingExceptionMapper()); } private void createSampleResources(IronTestConfiguration configuration, Environment environment) { final JdbiFactory jdbiFactory = new JdbiFactory(); final Jdbi jdbi = jdbiFactory.build(environment, configuration.getSampleDatabase(), "sampleDatabase"); // create DAO objects final ArticleDAO articleDAO = jdbi.onDemand(ArticleDAO.class); // create database tables articleDAO.createTableIfNotExists(); // register APIs environment.jersey().register(new ArticleResource(articleDAO)); // register SOAP web services jaxWsBundle.publishEndpoint(new EndpointBuilder("/article", new ArticleSOAP(articleDAO))); } }