GrailsInAction / graina2

Source code for the 2nd edition of Grails in Action
90 stars 92 forks source link

MEAP v13, ch6, Issues with PostControllerSpec (Listing 6.x, Pg. 144) #64

Closed tikeswar closed 10 years ago

tikeswar commented 10 years ago

The test passes the first two tests flash.message == "Successfully created Post" and response.redirectedUrl == "/post/timeline/${chuck.loginId}", but fails at the last line Post.countByUser(chuck) == 1. I get the following:

|  Condition not satisfied:
Post.countByUser(chuck) == 1
     |           |      |
     0           |      false
                 grailstuts.User : 1

The test result above is very puzzling and does not make sense to me. What the book says in the comment (// Ensure the post ended up in the DB), I think that makes more sense. However I have spent quite a bit of time trying to figure out the bug, but no luck yet.

Any help will be highly appreciated. Thank you!

tikeswar commented 10 years ago

Have also posted this in Stackoverflow (http://stackoverflow.com/questions/20688164/a-domain-object-created-in-a-controller-test-does-not-end-up-in-the-database).

marcpa00 commented 10 years ago

Just a shot in the dark : it seems you have removed the password field of User class (on the stackoverflow post at least). Have you cleared and re-created your database after that ?

Le 2013-12-19 à 14:07, tikeswar notifications@github.com a écrit :

Have also posted this in Stackoverflow (http://stackoverflow.com/questions/20688164/a-domain-object-created-in-a-controller-test-does-not-end-up-in-the-database).

— Reply to this email directly or view it on GitHub.

tikeswar commented 10 years ago

Thank you, @marcpa00. I do not think that is the issue as I am using "create-drop" and "mem" for the data source as follows (/conf/DataSource.groovy):

        dataSource {
            dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
            url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
        }

However, I may be wrong and missing something. You mentioned "Have you cleared and re-created your database after that ?" I thought the above settings in the dataSource took care of that, but if not would you kindly let me know what exactly to do to ensure that? Thank you!

marcpa00 commented 10 years ago

I meant the same thing as the "create-drop" setting, so it must be something else.

If you take the integration tests from chapter 5 (ch05/hubbub/test/integration/com/grailsinaction/UserIntegrationSpec.groovy), adapt it to your modified User domain class and run it, does it pass ?

Marc

Le 2013-12-19 à 14:49, tikeswar notifications@github.com a écrit :

Thank you, @marcpa00. I do not think that is the issue as I am using "create-drop" and "mem" for the data source as follows (/conf/DataSource.groovy):

    dataSource {
        dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
        url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
    }

However, I may be wrong and missing something. You mentioned "Have you cleared and re-created your database after that ?" I thought the above settings in the dataSource took care of that, but if not would you kindly let me know what exactly to do to ensure that? Thank you!

— Reply to this email directly or view it on GitHub.

tikeswar commented 10 years ago

Thank you, Marc.

In fact yes, after adapting to the modified domain classes, the integration tests from Ch 5 (ch05/hubbub/test/integration/com/grailsinaction/UserIntegrationSpec.groovy as well as ch05/hubbub/test/integration/com/grailsinaction/PostIntegrationSpec.groovy) pass without any issue.

tikeswar commented 10 years ago

Hi Marc:

Actually the issue I have reported here was even with the "original" User and Post domains. I had to strip down the domain classes for the purpose of posting in the StackOverflow (just to focus on the issue and remove the parts unessential to the issue). But, thank you for pointing that out.

marcpa00 commented 10 years ago

You could turn on sql logging (section "Show me the SQL", page 123 in v12) to see if the user got created correctly when your test ran.

Also, the data source can be configured differently for each of the defined "environments" and I am not sure if it is the "development" environment that is in effect when your run "grails test-app"... Actually, when I run "grails test-app integration:", I see a message saying 'environment set to test', so it is possible that you have the impression your database is in "create-drop" when it is effectively in another mode when you run tests.

Anyway, since this is H2 and a learning environment, you can delete the database files (devDb.h2.db and devDb.trace.db in the hubbub directory in my case) to make sure you have a fresh database.

Marc

Le 2013-12-19 à 15:37, tikeswar notifications@github.com a écrit :

Thank you, Marc.

In fact yes, after adapting to the modified domain classes, the integration tests from Ch 5 (ch05/hubbub/test/integration/com/grailsinaction/UserIntegrationSpec.groovy as well as ch05/hubbub/test/integration/com/grailsinaction/PostIntegrationSpec.groovy) pass without any issue.

— Reply to this email directly or view it on GitHub.

tikeswar commented 10 years ago

Hi Marc:

As you had suggested, I tried to follow the "Show me the SQL", but somehow it did not show me any SQL (which I do not understand why ... I am also a newbie in SQL).

Regarding your second suggestion, I did not find any devDb.h2.db or devDb.trace.db to delete in my directories (probably because I was using "mem" all these time?).

Anyways, after many other tries I found something that helped (the trick was to save the post explicitly), and I have posted that as an answer in StackOverflow. But what I found still puzzles me, and if you could offer any explanation that would be really helpful. Regardless, thanks so much for taking the time to look into this.

pledbrook commented 10 years ago

Thanks for the report.

Which version of Grails are you using? I just tried with Grails 2.2.1 and got a NullPointerException in that test. Upgrading to 2.2.4 fixed that particular problem. Could be a Grails issue.

FYI, you shouldn't even need to explicitly save the User instance in the action to persist the Post. So something is definitely wrong. The cascading save is broken, probably in Grails' mock database implementation that's used during unit tests. I'm guessing that the application works fine when run normally (via run-app for example).

tikeswar commented 10 years ago

Hi Peter:

Thanks for the notes/explanation. I am using [Grails version: 2.3.1, Groovy version: 2.1.8, JVM version: 1.7.0_45]. Is there a way to report this issue to the Grails developers?

"I'm guessing that the application works fine when run normally (via run-app for example)." Yup, the app itself is working fine.

ifrankov commented 9 years ago

Hi Peter,

I have a java 8 and grails version 2.4.3 and I have the same problem. When I try to create post. I recieve that post is created , but no post is created. If I add post.save() than post is created.

   Post createPost(String loginId, String content) {
    println "tst"
    def user = User.findByLoginId(loginId)
    if (user) {
        def post = new Post(content: content)
        user.addToPosts(post)
        if (post.validate() && user.save()) {
            post.save()
            return post
        } else {
            throw new PostException(
                message: "Invalid or empty post", post: post)
        }
    }
    throw new PostException(message: "Invalid User Id")
}

if there is no post.save() no post is saved.

I hope that you will give me a solution.

Thank you very much in advance!

Best regards, Ivo

ifrankov commented 9 years ago

Hi if I use if (post.validate() && user.save(flush: true, failOnError: true)) { Than it is ok. But it is strange becuase in BootStrap it is functioining without problems.

Post createPost(String loginId, String content) {
    println "tst"
    def user = User.findByLoginId(loginId)
    if (user) {
        def post = new Post(content: content)
        user.addToPosts(post)
        if (post.validate() && user.save(flush: true, failOnError: true)) {
        //post.save()
            return post
        } else {
            throw new PostException(
                message: "Invalid or empty post", post: post)
        }
    }
    throw new PostException(message: "Invalid User Id")
}
pledbrook commented 9 years ago

@ifrankov Unfortunately I can't reproduce this issue in a barebones Grails 2.4.3 application. Is the service transactional? How are you verifying the existence of the new post?

Note that if the service is transactional, the session will be flushed automatically when the method returns. So the explicit flush shouldn't be necessary.

ifrankov commented 9 years ago

Hi Peter, 

Is it possible to send me your hubbub project for grails 2.4.3  or 2.4.4. I have an additional problem. Update in Profile doesn't function. 

Thank you in advance! Best regards,  Ivo

Von Samsung Mobile gesendet

-------- Ursprüngliche Nachricht --------
Von: Peter Ledbrook notifications@github.com
Datum:12.01.2015 11:37 (GMT+01:00)
An: GrailsInAction/graina2 graina2@noreply.github.com
Cc: ifrankov i.frankov@googlemail.com
Betreff: Re: [graina2] MEAP v13, ch6, Issues with PostControllerSpec (Listing 6.x, Pg. 144) (#64)
@ifrankov Unfortunately I can't reproduce this issue in a barebones Grails 2.4.3 application. Is the service transactional? How are you verifying the existence of the new post? Note that if the service is transactional, the session will be flushed automatically when the method returns. So the explicit flush shouldn't be necessary. — Reply to this email directly or view it on GitHub.
ifrankov commented 9 years ago

Hi Peter,

I read that it is a general problem in Grails that byte [] causes problem with scaffolding update. Is there some workaround.

Best regards, Ivo

pledbrook commented 9 years ago

Not that I'm aware of. byte[] should be represented as a file upload form if I remember correctly.