Reputation: 13
I am using Spring-Boot project and MongoRepository instead of MongoTemplate.
When using MongoTemplate, one can dynamically set the hostname by using MongoConnectionPool like so:
@Autowired
MongoConnectionPool mongoConn
....
mongoConn.setHostname("127.23.45.89");
mongoConn.setPort(27017);
How do I achieve the same effect using MongoRepository?
I know that I can specified the hostname and port by specifying the
spring.data.mongodb.host=hostname1
spring.data.mongodb.port=27017
in application.properties file.
However I am using GenericContainer to spin up a mongo instance through Docker container to run my unit test. The container dynamically assigned IP Address and port to the mongo instance and thus I need to be able to dynamically set the hostname and port for the MongoRepository at run time.
This is how I am setting up my unit test.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MongoConfiguration.class)
public class HierarchiesServiceImplTests {
private static final Logger log = LoggerFactory.getLogger(HierarchiesServiceImplTests.class);
@Autowired
private HierarchiesService hierarchiesService;
@Autowired
private HierarchyRepository hierarchyRepo;
@BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
startMongo();
}
/**
* Starts a Mongo docker container, and configures the repository factory to use this instance.
*/
private void startMongo() {
GenericContainer mongo = new GenericContainer("mongo:3")
.withExposedPorts(27017);
mongo.start();
String containerIpAddress = mongo.getContainerIpAddress();
int mappedPort = mongo.getMappedPort(27017);
//TODO: set the hostname and port here so that the MongoRepository use this mongo instance instead of the default localhost.
log.info("Container mongo:3 listening on {}:{}", containerIpAddress, mappedPort);
}
This is what I have in my MongoConfiguration.class
@Configuration
@EnableMongoRepositories
@ComponentScan({"com.is.hierarchies.service"})
public class MongoConfiguration {
}
Upvotes: 1
Views: 3369
Reputation: 17085
The container dynamically assigned IP Address and port to the mongo instance and thus I need to be able to dynamically set the hostname and port for the MongoRepository at run time.
You could also override the properties at launch time:
$ java -jar YourApp.jar --spring.data.mongodb.host=hostnamexyz --spring.data.mongodb.port=123
or
$ java -Dspring.data.mongodb.host=hostnamexyz -Dspring.data.mongodb.port=123 -jar YourApp.jar
Or through Docker:
$ docker run -e spring.data.mongodb.host=hostnamexyz -e spring.data.mongodb.port=123 -p 8080:8080 -i -t yourdocker:latest
I only tested the docker command with one -e param
, but I don't see why we couldn't provide more than one!
Upvotes: 2
Reputation: 13
@Alex gave me an idea to make a cleaner solution. Instead of modifying the MongoTemplate in my test suite, I move that code to the MongoConfiguration.java.
Here is how I ended up resolving the problem.
in my MongoConfiguration.class I made the following changes:
@Configuration
@EnableMongoRepositories
@ComponentScan({"com.is.hierarchies.service"})
public class MongoConfiguration extends AbstractMongoConfiguration {
String containerIpAddress;
Integer mappedPort;
@Override
public Mongo mongo() throws Exception {
startMongo();
return new Mongo(containerIpAddress,mappedPort);
}
@Override
public String getDatabaseName() {
return "hierarchies_db";
}
/**
* Starts a Mongo docker container, and configures the repository factory to use this instance.
*/
private void startMongo() {
GenericContainer mongo = new GenericContainer("mongo:3")
.withExposedPorts(27017);
mongo.start();
containerIpAddress = mongo.getContainerIpAddress();
mappedPort = mongo.getMappedPort(27017);
}
}
Upvotes: 0
Reputation: 17085
Override MongoTemplate Bean with yours
You may define an additional @Configuration
class within this test, just to override MongoTemplate
.
MongoRepository
uses a MongoTemplate
to performs its operations, so by defining a @Bean MongoTemplate
, we are able to set the connection details of our choice. And this is then what the Repository
will be using.
The complete code:
RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MongoConfiguration.class)
public class HierarchiesServiceImplTests {
private static final Logger log = LoggerFactory.getLogger(HierarchiesServiceImplTests.class);
private static String containerIpAddress;
private static int mappedPort;
@Autowired
private HierarchiesService hierarchiesService;
@Autowired
private HierarchyRepository hierarchyRepo;
/**
* Starts a Mongo docker container, and configures the repository factory to use this instance.
*/
private void startMongo() {
GenericContainer mongo = new GenericContainer("mongo:3").withExposedPorts(27017);
mongo.start();
containerIpAddress = mongo.getContainerIpAddress();
mappedPort = mongo.getMappedPort(27017);
log.info("Container mongo:3 listening on {}:{}", containerIpAddress, mappedPort);
}
@Configuration
public static class MongoTestConfiguration {
@Bean
@Primary
public MongoTemplate mongoTemplate() throws DataAccessException, Exception{
return createMongoOperations(containerIpAddress, mappedPort, "mydb", "user", "pwd");
}
private MongoTemplate createMongoOperations(String hostname, int port, String dbName, String user, String pwd) throws DataAccessException, Exception {
MongoCredential mongoCredentials = MongoCredential.createScramSha1Credential(user, dbName, pwd.toCharArray());
MongoClient mongoClient = new MongoClient(new ServerAddress(hostname, port), Arrays.asList(mongoCredentials));
Mongo mongo = new SimpleMongoDbFactory(mongoClient, dbName).getDb().getMongo();
return new MongoTemplate(mongo, dbName);
}
}
@BeforeClass
public static void setUp() {
MockitoAnnotations.initMocks(this);
startMongo();
}
What I did:
static
to your setUp methodcontainerIpAddress = mongo.getContainerIpAddress();
Upvotes: 0