I setup a db in MongoDB called spotlight. To connect to that database, I use the following environment setup in DataSource.groovy:
grails {
mongo {
host = "localhost"
port = 27017
}
}
environments {
development { // MongoDB instance running without --auth flag.
grails {
mongo {
databaseName = "spotlight"
}
}
}
test {
grails { // MongoDB instance running without --auth flag.
mongo {
databaseName = "spotlight"
}
}
}
}
This is my unit test class:
#TestMixin(MongoDbTestMixin)
class BiographySpec extends Specification {
def setup() {
}
def cleanup() {
}
void "given a bio then find() returns that bio object"() {
given:
mongoDomain([Biography])
Biography bio = new Biography()
def nameOf1stImage = "firstImage.png"
def nameOf2ndImage = "secondImage.png"
def nameInBio = "star"
def descriptionOfBio = "a description"
def id = 0;
bio.firstImage = nameOf1stImage
bio.secondImage = nameOf2ndImage
bio.name = nameInBio
bio.description = descriptionOfBio
bio.images = [nameOf1stImage,nameOf2ndImage]
when:
bio.save(flush:true);
id = bio.id
then:
Biography bioFromDb = bio.get(id)
bioFromDb.firstImage == nameOf1stImage
bioFromDb.secondImage == nameOf2ndImage
bioFromDb.name == nameInBio
bioFromDb.description == descriptionOfBio
}
}
I ran grails test-app, and Grails created a biography document in test db, not spotlight db. Is there anything wrong with the way I configure environments setttings in DataSource.groovy ?
Related
I have a test function, that should perform the following task
insert data to db
query db and verify data is as expected
The problem is that in my test, the data has not been committed to the db, like it's stuck in some transactional step, how can I surely commit the data before the second query is executed.
This is a part of my test function, #Rollback(false) is just for development phase.
#Test
#Rollback(false)
....
reportJobManager.saveOutput(savedDef, pipeline, results, null)
reportJobManager.retryRetention(savedDef, listOf(csvDeliverbale))
saveOutput func. sample code
#Transactional
fun saveOutput() {
if (deliverable.type.name == "DATA_RETENTION_RESULT") {
finishedPipeline.postProcessors.forEach {
//it(definition, dbDeliverable)
val dbRetention = ReportRetention(
deliverable = dbDeliverable,
definition = definition,
retryCount = 1L
)
val retentionUploadSaved = retentionRepository.save(dbRetention)
if (retentionUploadSaved.id == null) {
throw IllegalStateException("Retention upload was not saved!")
}
}
}
}
retryRetention func code
fun retryRetention(definition: ReportDefinition, listOfDeliverables: List<Deliverable>) {
retentionRepository.findAll().forEach {
if (it.state.name == "NOT_UPLOADED" && it.retryCount!!.toInt() < 5) {
if (it.deliverable?.success == true) {
it.state = RetentionUploadStatus.UPLOADED
println("RetentionUploadStatus->UPLOADED")
} else {
val schemaService = SchemaServiceImpl()
val schemas = schemaService.initializeSchemas(definition, emptyMap())
val parameters = definition.parameterPolicy.policy(schemas.parametersSchema)
val delivery = deliveryPolicyService.policy<Deliverable>(ValidDeliveryPolicy.RETENTION_ONLY, schemas.deliverySchema)
val deliveryFunction = delivery.createDeliveryStep()
deliveryFunction(parameters, listOfDeliverables)
it.retryCount = it.retryCount!!.plus(1L)
}
retentionRepository.save(it)
}
}
}
If you have a method saveOutput() with #Transactional annotation, you need to add #Transactional above every other method that is calling saveOutput() for the transaction to actually commit.
I am currently using Grails 2.5.4, with the MongoDB plugin (org.grails.plugins:mongodb:6.0.0.RC1) and whenever I try to update a List of any domain class, it doesn't work, example:
Votation class:
class Votation {
String question
int minVotes
List <VoteOption> options
User owner
Chat chat
static belongsTo = [chat: Chat]
static embedded = ['options']
static constraints = {
owner nullable: false
chat nullable: false
//question nullable: false
}
VoteOption class:
class VoteOption {
String option
String url
List <User> voters
static belongsTo = [chat: Chat]
}
When I try to update the list:
//some more code...
Votation votation = Votation.findById(votationId as Long)
VoteOption option = votation.options.find { it.option == votationOption }
User user = User.findOrCreateNew(params.user)
if (option.voters) {
option.voters.add(user) // THIS DOESN'T WORK!
}
else {
option.voters = [user] //This DOES work
}
This is just an example, I have 2 more domain classes that also have Lists, and they don't work either.
Restarting Grails does not fix this, and this also happens on the other developer's computer, so it's not my enviroment. Everything else is saved correctly
Try this
//some more code...
Votation votation = Votation.findById(votationId as Long)
VoteOption option = votation.options.find { it.option == votationOption }
User user = User.findOrCreateNew(params.user)
if (user) {
option.addToVoters(user) // <----
}
option.save(flush:true, failOnError:true)
Ref: http://docs.grails.org/2.1.0/ref/Domain%20Classes/addTo.html
I've problems updating a domain class. I'm using Grails 3.0.9 and MongoDB (for Gorm 5.0.0.RC1)
In my build.gradle:
compile "org.grails.plugins:mongodb:5.0.0.RC1"
compile "org.mongodb:mongodb-driver:3.0.2"
compile "org.grails:grails-datastore-gorm-mongodb:5.0.0.RC1"
runtime 'org.springframework.data:spring-data-mongodb:1.8.1.RELEASE'
compile("org.grails:gorm-mongodb-spring-boot:5.0.0.RC1")
The test:
#Integration
class CompanyControllerIntegrationSpec extends Specification{
def grailsApplication
Company company
RestBuilder rest
def setupData() {
company = Company.buildWithoutSave().save(flush: true, failOnError: true)
}
def setup(){
rest = new RestBuilder()
}
def "test update a company" (){
def company2
given:
setupData()
def id = company.id
when:
RestResponse response = rest.put("http://localhost:${grailsApplication.config.server.port}/${company.companyKey}/company") {
json {
name = "newName"
description = "new Description"
}
}
company2 = Company.findById(id)
then:
response.status == 200
response.json.name == "newName"
company2.name == "newName"
company2.description == "new Description"
}
def cleanup() {
Company.collection.remove(new BasicDBObject())
}
}}
The controller:
class CompanyController extends ExceptionController{
static allowedMethods = ['update':'PUT','show':'GET',
'updateNew':'PUT','showNew':'GET']
CompanyService companyService
def update(String companyKey){
def object = request.JSON?request.JSON:params
Company companyOut = companyService.update(object, companyKey)
render text:companyOut as JSON, status:HttpStatus.OK
}
}
The service:
class CompanyService {
def securityService
def grailsApplication
public Company update(object, String companyKey) throws ForbiddenException, InvalidRequestException, NotFoundException{
Company company = findByKey(companyKey)
if (object.name!=null)
company.name = object.name
if (object.description!=null)
company.description = object.description
if (object.enterprise!=null)
company.enterprise = object.enterprise
if (object.genKey!=null)
company.companyKey = UUID.randomUUID().toString()
if (!company.save(flush:true)){
println company.errors
throw new InvalidRequestException("Some parameters are missing or are invalid: "+company.errors.fieldErrors.field)
}
return company
}
public Company findByKey(String companyKey) throws NotFoundException, ForbiddenException {
if (!companyKey){
throw new ForbiddenException("The company key has not been given")
}
Company company = Company.findByCompanyKey(companyKey)
if (!company){
throw new NotFoundException("No company exists for the given key")
}
return company
}
}
The results of the test are:
- response.status is 200
- response.json.name is "newName"
- company.name is old name ("company 1")
If I don't do the cleanup, the database still have the old value. I've followed the save method, also inside Mongo gorm classes, and I've seen that one problem is that the fields are not being marked as dirty, but don't know why.
With other Domain classes that are similar to this one, the update is done without problems and the properties are marked as dirty.
How do I reset the database inside the FakeApplication using inMemoryDatabase after or before each test? I want the state of the database returned to its initial state after each single test. Either rollback or clearing the database and running SetupData() again is fine.
I have tried many various things. The database is never reset between each test. How do I do this?
When running the following test suite the state of the database continues from test to test. So if I modify some data in Test2 then it is affecting Test3.
trait TestUtil {
/**
* Executes a block of code in a running application.
*/
def running[T](fakeApp: FakeApplication)(block: => T): T = {
synchronized {
try {
Play.start(fakeApp)
setup_data()
block
} finally {
Play.stop()
}
}
}
def setup_data() = {
//add data to the database
}
}
I tried using the above trait to have the Play App stop after each test but it does not help.
#RunWith(classOf[JUnitRunner])
class ConditionTests2 extends Specification with TestUtil {
sequential // Make the tests run sequentially instead of in parallel
// test1
"element with id 1" should {
"should have name PETER" in {
running(new FakeApplication(additionalConfiguration = inMemoryDatabase("test"))) {
// name should be "PETER"
}
}
}
// test2
"renaming element with id 1" should {
"successfully modify element 1" in {
running(new FakeApplication(additionalConfiguration = inMemoryDatabase("test"))) {
// Set Name = "John"
}
}
}
// test3
"element with id 1" should {
"should have name PETER" in {
running(new FakeApplication(additionalConfiguration = inMemoryDatabase("test"))) {
// name should be "PETER"
// fails because name is now JOHN
}
}
}
}
I have a requirement where I have to check in the database if the value of a boolean variable(crawled) is false. If so I have to set it to true. I am finding the record based on the value of a string variable(website). I referenced this link but it didn't help. Please tell me what I am doing wrong.
I tried this:
def p = Website.findByWebsite(website);
if(p['crawled'] == true) {
println "already crawled"
} else {
mongo.website.update( p, new BasicDBObject( '$set', new BasicDBObject( 'crawled', 'false' ) ) )
println "updated object"
}
It gives me an error No such property: mongo for class: cmsprofiler.ResourceController
My domain class is as follows:
class Website{
String website
User user
Boolean crawled
static belongsTo = [user: User]
static constraints = {
website( url:true, unique: ['user'])
}
static hasMany = [resource: Resource]
static mapping = {resource cascade:"all-delete-orphan" }
}
you should be using
Website.mongo.update(...)
or let the framework inject it:
class ResourceController {
def mongo
def list(){
mongo.website.update(...)
}
}
This worked for me. Posting it here in case anyone else has similar requirement.
#Grab(group='com.gmongo', module='gmongo', version='0.9.3')
import com.gmongo.GMongo
#Transactional(readOnly = true)
class ResourceController {
def mongo = new GMongo()
def db = mongo.getDB("resources")
def p = Website.findByWebsite(website)
if(p['crawled']==false){
db.website.update([crawled:false],[$set:[crawled:true]])
}