I am using Vertx and trying to test some parameters that i am getting data from jsonfile, currently it works but i want get this file just through class path so it can be tested from a different computer.
private ConfigRetriever getConfigRetriever() {
ConfigStoreOptions fileStore = new ConfigStoreOptions().setType("file").setOptional(true)
.setConfig(new JsonObject()
.put("path", "/home/user/MyProjects/MicroserviceBoilerPlate/src/test/resources/local_file.json"));
ConfigStoreOptions sysPropsStore = new ConfigStoreOptions().setType("sys");
ConfigRetrieverOptions options = new ConfigRetrieverOptions().addStore(fileStore).addStore(sysPropsStore);
return ConfigRetriever.create(Vertx.vertx(), options);
}
My path as written above starts from /home / dir which makes it impossible to be tested on another machine. My test below uses this config
#Test
public void tourTypes() {
ConfigRetriever retriever = getConfigRetriever();
retriever.getConfig(ar -> {
if (ar.failed()) {
// Failed to retrieve the configuration
} else {
JsonObject config = ar.result();
List<String> extractedIds = YubiParserServiceCustomImplTest.getQueryParameters(config, "tourTypes");
assertEquals(asList("1", "2", "3", "6"), extractedIds);
}
});
}
I want to make the path a class path so i can test it on all environment.
I tried to access class path like this but not sure how it should be
private void fileFinder() {
Path p1 = Paths.get("/test/resources/local_file.json");
Path fileName = p1.getFileName();
}
If you have stored the file inside "src/test/resources" then you can use
InputStream confFile = getClass().getResourceAsStream("/local_file.json");
or
URL url = getClass().getResource("/local_file.json");
inside your test class (example)
IMPORTANT!
In both cases the file names can start with a / or not. If it does, it starts at the root of the classpath. If not, it starts at the package of the class on which the method is called.
Put .json file to /resources folder of your project (here an example).
Then access it via ClassLoader.getResourceAsStream:
InputStream configFile = ClassLoader.getResourceAsStream("path/to/file.json");
JsonObject config = new JsonParser().parse(configFile);
// Then provide this config to Vertx
As I understand, considering the location of your json file, you simply need to do this:
.setConfig(new JsonObject().put("path", "local_file.json"));
See this for reference.
Related
I'm writing a UDF for Pig using Java. It works fine but Pig doesn't give me options to separate environment. What my Pig script is doing is to get Geo location from IP address.
Here's my code on the Geo location part.
private static final String GEO_DB = "GeoLite2-City.mmdb";
private static final String GEO_FILE = "/geo/" + GEO_DB;
public Map<String, Object> geoData(String ipStr) {
Map<String, Object> geoMap = new HashMap<String, Object>();
DatabaseReader reader = new DatabaseReader.Builder(new File(GEO_DB)).build();
// other stuff
}
GeoLite2-City.mmdb exists in HDFS that's why I can refer from absolute path using /geo/GeoLite2-City.mmdb.
However, I can't do that from my JUnit test or I have to create /geo/GeoLite2-City.mmdb on my local machine and Jenkins which is not ideal. I'm trying to figure out a way to make my test passed while using new File(GEO_DB) and not
getClass().getResourceAsStream('./geo/GeoLite2-City.mmdb') because
getClass().getResourceAsStream('./geo/GeoLite2-City.mmdb')
Doesn't work in Hadoop.
And if I run Junit test it would fail because I don't have /geo/GeoLite2-City.mmdb on my local machine.
Is there anyway I can overcome this? I just want my tests to pass without changing the code to be using getClass().getResourceAsStream and I can't if/else around that because Pig doesn't give me a way to pass in parameter or maybe I'm missing something.
And this is my JUnit test
#Test
#Ignore
public void shouldGetGeoData() throws Exception {
String ipTest = "128.101.101.101";
Map<String, Object> geoJson = new LogLine2Json().geoData(ipTest);
assertThat(geoJson.get("lLa").toString(), is(equalTo("44.9759")));
assertThat(geoJson.get("lLo").toString(), is(equalTo("-93.2166")));
}
which it works if I read the database file from resource folder. That's why I have #Ignore
Besides, your whole code looks pretty un-testable.
Every time when you directly call new in your production code, you prevent dependency injection; and thereby you make it much harder to test your code.
The point is to not call new File() within your production code.
Instead, you could use a factory that gives you a "ready to use" DatabaseReader object. Then you can test your factory to do the right thing; and you can mock that factory when testing this code (to return a mocked database reader).
So, that one file instance is just the top of your "testing problems" here.
Honestly: don't write production code first. Do TDD: write test cases first; and you will quickly learn that such production code that you are presenting here is really hard to test. And when you apply TDD, you start from "test perspective", and you will create production code that is really testable.
You have to make the file location configurable. E.g. inject it via constructor. E.g. you could create a non-default constructor for testing only.
public class LogLine2Json {
private static final String DEFAULT_GEO_DB = "GeoLite2-City.mmdb";
private static final String DEFAULT_GEO_FILE = "/geo/" + GEO_DB;
private final String geoFile;
public LogLine2Json() {
this(DEFAULT_GEO_FILE);
}
LogLine2Json(String geoFile) {
this.geoFile = geoFile;
}
public Map<String, Object> geoData(String ipStr) {
Map<String, Object> geoMap = new HashMap<String, Object>();
File file = new File(geoFile);
DatabaseReader reader = new DatabaseReader.Builder(file).build();
// other stuff
}
}
Now you can create a file from the resource and use this file in your test.
public class LogLine2JsonTest {
#Rule
public final TemporaryFolder folder = new TemporaryFolder();
#Test
public void shouldGetGeoData() throws Exception {
File dbFile = copyResourceToFile("/geo/GeoLite2-City.mmdb");
String ipTest = "128.101.101.101";
LogLine2Json logLine2Json = new LogLine2Json(dbFile.getAbsolutePath())
Map<String, Object> geoJson = logLine2Json.geoData(ipTest);
assertThat(geoJson.get("lLa").toString(), is(equalTo("44.9759")));
assertThat(geoJson.get("lLo").toString(), is(equalTo("-93.2166")));
}
private File copyResourceToFile(String name) throws IOException {
InputStream resource = getClass().getResourceAsStream(name);
File file = folder.newFile();
Files.copy(resource, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
return file;
}
}
TemporaryFolder is a JUnit rule that deletes every file that is created during test afterwards.
You may modify the asserts by using the hasToString matcher. This will give you more detailed information in case of a failing test. (And you have to read/write less code.)
assertThat(geoJson.get("lLa"), hasToString("44.9759"));
assertThat(geoJson.get("lLo"), hasToString("-93.2166"));
You don't. Your question embodies a contradiction in terms. Resources are not files and do not live in the file system. You can either distribute the file separately from the JAR and use it as a File or include it in the JAR and use it as a resource. Not both. You have to make up your mind.
I have a specified URL that i cant change i.e.
/opt/local/java/config/npvr.properties
where should i place my file so that the following code can work:
String PROPERTIESFILEPATH1 = "/opt/local/java/config/npvr.properties";
File tmPropertiesFile = new File(PROPERTIESFILEPATH);
Properties properties = new Properties();
if (tmPropertiesFile.exists()) {
.....
}
i have tried placing my file in directory shown below but it didn't work:
My problem is that I can change only the location of property-file without changing the code to solve this problem. Please Help.
The file needs to go in /opt/local/java/config, not [projectdir]/opt/local/java/config. You are putting it in the wrong place
If you are using linux then add this file /opt/local/java/config/ directory location outside of your project.
"OR"
in windows C:\opt\local\java\config\ here.
use getClass().getResourceAsStream to load property file from relative of class
public class Main {
public static void main(String args[]) throws Exception{
String PROPERTIESFILEPATH = "/opt/local/java/config/npvr.properties";
//File tmPropertiesFile = new File(PROPERTIESFILEPATH);
Properties properties = new Properties();
InputStream ins=null;
//ins=new FileInputStream(PROPERTIESFILEPATH);
ins=new Main().getClass().getResourceAsStream(PROPERTIESFILEPATH);
properties.load(ins);
System.out.println(properties.get("Hello"));
}
}
With tomcat 8 I have extend the WebAppClassLoader and add some jar filed from a shared location to the classloader path using addRepository() method. With tomcat 8 addRepository have been removed and new resource implementation have been introduced. I'm still able to use the addUrl method to add jar files. But I would like to implement the new resource based implementation.
I've tried with
DirResourceSet dirResourceSet = new DirResourceSet(getContext().getResources(), "/WEB-INF/lib", "/home/thusitha/lib/runtimes/cxf", "/");
WebResourceRoot webResourceRoot = getContext().getResources();
webResourceRoot.getContext().getResources().addPreResources(dirResourceSet);
But this is not working and still it throws classnotfoundexception
Can someone tell me how to map a directory which contains jars to a particular webapp using Tomcat new resource implementation?
A solution to this problem is to register your resources by overriding the ContextConfig class (org.apache.catalina.startup.ContextConfig). Catalina enters a starting state immediately after it scans your document path for resources. Most of the processing of those resources, such as annotations, is handled by the ContextConfig LifecycleListener. To ensure the resources are added before the context configuration takes place, override the ContextConfig.
final Context currentContext = ctx;
ContextConfig ctxCfg = new ContextConfig() {
#Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
WebResourceRoot webResourcesRoot = currentContext.getResources();
String baseDir = Platform.getBaseDir(); // Server Base Directory
File libDir = new File(baseDir + File.separator + "lib");
DirResourceSet dirResourceSet = null;
try {
dirResourceSet = new DirResourceSet(webResourcesRoot, "/WEB-INF/lib", libDir.getCanonicalPath(), "/");
} catch (IOException e) {
throw new RuntimeException(e);
}
webResourcesRoot.addPostResources(dirResourceSet);
String[] possibleJars = dirResourceSet.list("/WEB-INF/lib");
for(String libfile : possibleJars) {
WebResource possibleJar = dirResourceSet.getResource("/WEB-INF/lib/"+libfile);
System.err.println(String.format("Loading possible jar %s",possibleJar.getCanonicalPath())); // Just checking...
if (possibleJar.isFile() && possibleJar.getName().endsWith(".jar")) {
WebResourceSet resourceSet = new JarResourceSet(webResourcesRoot, "/WEB-INF/classes", possibleJar.getCanonicalPath(),"/");
webResourcesRoot.addPostResources(resourceSet);
}
}
}
super.lifecycleEvent(event);
}
};
ctx.addLifecycleListener(ctxCfg);
This is an undocumented solution that works on Tomcat 8.0.23. Considering the complexity and difficulty of this I can't say it is a better solution than adding jars directly to ClassLoaders.
I'm trying to get a resource (image.png, in the same package as this code) from a static method using this code:
import java.net.*;
public class StaticResource {
public static void main(String[] args) {
URL u = StaticResource.class.getClass().getResource("image.png");
System.out.println(u);
}
}
The output is just 'null'
I've also tried StaticResource.class.getClass().getClassLoader().getResource("image.png");
, it throws a NullPointerException
I've seen other solutions where this works, what am I doing wrong?
Remove the ".getClass()" part.
Just use
URL u = StaticResource.class.getResource("image.png");
Always try to place the resources outside the JAVA code to make it more manageable and reusable by other package's class.
You can try any one
// Read from same package
URL url = StaticResource.class.getResource("c.png");
// Read from same package
InputStream in = StaticResource.class.getResourceAsStream("c.png");
// Read from absolute path
File file = new File("E:/SOFTWARE/TrainPIS/res/drawable/c.png");
// Read from images folder parallel to src in your project
File file = new File("images/c.jpg");
// Read from src/images folder
URL url = StaticResource.class.getResource("/images/c.png")
// Read from src/images folder
InputStream in = StaticResource.class.getResourceAsStream("/images/c.png")
I'm trying to write a test for a Mule flow that will involve dropping a file in a location, waiting for it to be processed by my flow and compare the output to see if it has been transformed correctly. My flow looks as follows:
<flow name="mainFlow" processingStrategy="synchronous">
<file:inbound-endpoint name="fileIn" path="${inboundPath}">
<file:filename-regex-filter pattern="myFile.csv" caseSensitive="true"/>
</file:inbound-endpoint>
...
<file:outbound-endpoint path="${outboundPath}" outputPattern="out.csv"/>
</flow>
Is there a way I can access the inboundPath and outboundPath Mule properties inside of my test class so that I can drop files and wait for output in the correct places?
The test class I'm using is:
public class MappingTest extends BaseFileToFileFunctionalTest {
#Override
protected String getConfigResources() {
return "mappingtest.xml";
}
#Test
public void testMapping() throws Exception {
dropInputFileIntoPlace("myFile.csv");
waitForOutputFile("out.csv", 100);
assertEquals(getExpectedOutputFile("expected-out.csv"), getActualOutputFile("out.csv"));
}
}
Which extends this class:
public abstract class BaseFileToFileFunctionalTest extends FunctionalTestCase {
private static final File INPUT_DIR = new File("/tmp/muletest/input");
private static final File OUTPUT_DIR = new File("/tmp/muletest/output");
private static final Charset CHARSET = Charsets.UTF_8;
#Before
public void setup() {
new File("/tmp/muletest/input").mkdirs();
new File("/tmp/muletest/output").mkdirs();
empty(INPUT_DIR);
empty(OUTPUT_DIR);
}
private void empty(File inputDir) {
for (File file : inputDir.listFiles()) {
file.delete();
}
}
protected File waitForOutputFile(String expectedFileName, int retryAttempts) throws InterruptedException {
boolean polling = true;
int attemptsRemaining = retryAttempts;
File outputFile = new File(OUTPUT_DIR, expectedFileName);
while (polling) {
Thread.sleep(100L);
if (outputFile.exists()) {
polling = false;
}
if (attemptsRemaining == 0) {
VisibleAssertions.fail("Output file did not appear within expected time");
}
attemptsRemaining--;
}
outputFile.deleteOnExit();
return outputFile;
}
protected void dropInputFileIntoPlace(String inputFileResourceName) throws IOException {
File inputFile = new File(INPUT_DIR, inputFileResourceName);
Files.copy(Resources.newInputStreamSupplier(Resources.getResource(inputFileResourceName)), inputFile);
inputFile.deleteOnExit();
}
protected String getActualOutputFile(String outputFileName) throws IOException {
File outputFile = new File(OUTPUT_DIR, outputFileName);
return Files.toString(outputFile, CHARSET);
}
protected String getExpectedOutputFile(String resourceName) throws IOException {
return Resources.toString(Resources.getResource(resourceName), CHARSET);
}
}
As you can see I'm currently creating temporary input/output directories. I'd like to make this part read from the Mule properties if possible? Thanks in advance.
After observing your test classes and code I could see that you want to dynamically create temp folders place files in them. And the flow should read the files from Temp Directory and write output to another Temp directory. Point to be noted is that Mule's Endpoints are created when the configuration is loaded. So the ${inbound} and ${outbound} should be provided to the mule flow by the time they are provided.
So one option can be to create a dummy flow pointing to the temp folders for testing.
or
Create a test properties file pointing to the temp folders and load that to your flow config, so that your flow endpoints will get the temp folder paths.
In any way path cannot be provided to the flow inbound endpoints after they have been created(on config load).
Update1:
As per your comment the solution with option would be like the following.
Seperate the properties loading part of the config into another config.
Like "mapping-core-config.xml,mappingtest.xml" where the mapping-core-config will have the tags to load the properties file.
Now create a test config file for the mapping-core-config.xml file which loads the test properties file. This should be used in your test config. This way without modifying or disturbing your main code, you can test your flows pointing to temp folders.
"mapping-core-test-config.xml,mappingtest.xml"
Note: The test config can reside in the src/test/resources folders.
Hope this helps.