Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

First cut

  • Loading branch information...
commit 7bf052410b88a7d53b9e00f2cbd00fdae31b1a79 1 parent 3601779
aldrinm aldrinm authored
6 application.properties
... ... @@ -1,8 +1,10 @@
1 1 #Grails Metadata file
2   -#Thu Feb 09 23:47:44 GMT+05:30 2012
3   -app.grails.version=2.0.0
  2 +#Mon Feb 27 22:56:17 IST 2012
  3 +app.grails.version=2.0.1
4 4 app.name=flavorwocky
5 5 app.servlet.version=2.5
6 6 app.version=0.1
  7 +plugins.hibernate=2.0.1
7 8 plugins.jquery-ui=1.8.15
  9 +plugins.neo4j=1.0.0.M1
8 10 plugins.rest=0.7
80 grails-app/conf/BootStrap.groovy
@@ -2,82 +2,38 @@
2 2 Copyright (c) 2012, Luanne Misquitta
3 3 All rights reserved. See License.txt
4 4 */
5   -import groovyx.net.http.RESTClient
6   -import static groovyx.net.http.ContentType.*
7   -import static groovyx.net.http.ContentType.JSON
  5 +import com.herokuapp.flavorwocky.Category
8 6
9 7 class BootStrap {
10 8
11   - def grailsApplication
12   -
13 9 def init = { servletContext ->
14 10 //check if there are categories in the db
15   - try {
16   - def neo4jTraverseClient = new RESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/node/0/traverse/node")
17   - neo4jTraverseClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
18   - def postBody = [order: 'breadth_first', relationships: [ direction:'all', type:'CATEGORY'], max_depth: 1]
19   - def traverseResp = neo4jTraverseClient.post (contentType:JSON, requestContentType:JSON , body: postBody)
20   - if (traverseResp.status == 200 && traverseResp.data.size()<=0) {
21   - //create ingredient index
22   - createIngredientIndex()
23   - //create Category nodes
24   - createInitialCategories()
25   - }
26   -
27   - } catch (ConnectException ce) {
28   - log.error "Connection to server failed"
29   - log.error ce
  11 + if (Category.count()<=0) {
  12 + createInitialCategories()
30 13 }
31   -
32 14 }
33 15
34   -
35 16 def destroy = {
36 17 }
37 18
38 19 def createInitialCategories() {
39   - def neo4jCreateClient = new RESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/node")
40   - neo4jCreateClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
41   -
42   - //ideally this should be batched.
43   - ['Fish':'darkblue', 'Poultry':'hotpink', 'Meat':'firebrick', 'Herbs and spices':'yellowgreen',
44   - 'Condiments':'goldenrod', 'Eggs and dairy':'wheat', 'Vegetables':'darkgreen', 'Fruits':'lightcoral',
45   - 'Nuts and Grains':'orange', 'Chocolate, Bread and Pastry':'saddlebrown'].each {
46   - def createResp = neo4jCreateClient.post(
47   - body: [name: it.key, catColor: it.value],
48   - requestContentType: JSON,
49   - contentType: JSON)
50   - if (createResp.status == 201) {
51   - log.info "Created category node :: $it"
52   - def newCat = createResp.data.self
53   - //now create the relation with node 0
54   - def relationClient = new RESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/node/0/relationships")
55   - relationClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
56   -
57   - def relationshipResponse = relationClient.post(
58   - body: [to: newCat, type: 'CATEGORY'],
59   - requestContentType: JSON,
60   - contentType: JSON)
61   - if (relationshipResponse.status == 201) {
62   - log.info "Created CATEGORY relationship to :: $it"
63   - }
64   -
  20 + //todo: is this really being batched? need to verify
  21 + Category.withTransaction {
  22 + [
  23 + 'Fish':'darkblue',
  24 + 'Poultry':'hotpink',
  25 + 'Meat':'firebrick',
  26 + 'Herbs and spices':'yellowgreen',
  27 + 'Condiments':'goldenrod',
  28 + 'Eggs and dairy':'wheat',
  29 + 'Vegetables':'darkgreen',
  30 + 'Fruits':'lightcoral',
  31 + 'Nuts and Grains':'orange',
  32 + 'Chocolate, Bread and Pastry':'saddlebrown'
  33 + ].each {
  34 + new Category(name: it.key, catColor: it.value).save(failOnError: true)
65 35 }
66   -
67   -
68 36 }
69 37 }
70 38
71   - def createIngredientIndex() {
72   - def neo4jCreateIndexClient = new RESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/index/node")
73   - neo4jCreateIndexClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
74   - def createResp = neo4jCreateIndexClient.post(
75   - body: [name: 'ingredients'],
76   - requestContentType: JSON,
77   - contentType: JSON)
78   - println createResp.status
79   - if(createResp.status == 201) {
80   - log.info "Created ingredients index"
81   - }
82   - }
83 39 }
2  grails-app/conf/BuildConfig.groovy
@@ -33,11 +33,13 @@ grails.project.dependency.resolution = {
33 33 //mavenRepo "http://repository.codehaus.org"
34 34 //mavenRepo "http://download.java.net/maven/2/"
35 35 //mavenRepo "http://repository.jboss.com/maven2/"
  36 + mavenRepo 'http://m2.neo4j.org/releases'
36 37 }
37 38 dependencies {
38 39 // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
39 40
40 41 // runtime 'mysql:mysql-connector-java:5.1.16'
  42 + compile "org.neo4j:neo4j-rest-graphdb:1.6"
41 43 }
42 44
43 45 plugins {
71 grails-app/conf/DataSource.groovy
... ... @@ -0,0 +1,71 @@
  1 +environments {
  2 + development {
  3 + grails {
  4 + neo4j {
  5 + type = "rest"
  6 + location = "http://localhost:7474/db/data/"
  7 + }
  8 + }
  9 + }
  10 + test {
  11 + grails {
  12 + neo4j {
  13 + type = "rest"
  14 + location = "http://localhost:7474/db/data/"
  15 + }
  16 + }
  17 + }
  18 + production {
  19 + grails {
  20 + neo4j {
  21 + type = "rest"
  22 + location = "http://localhost:7474/db/data/"
  23 + }
  24 + }
  25 + }
  26 +
  27 +}
  28 +
  29 +//dataSource {
  30 +// pooled = true
  31 +// driverClassName = "org.h2.Driver"
  32 +// username = "sa"
  33 +// password = ""
  34 +//}
  35 +//hibernate {
  36 +// cache.use_second_level_cache = true
  37 +// cache.use_query_cache = true
  38 +// cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
  39 +//}
  40 +//// environment specific settings
  41 +//environments {
  42 +// development {
  43 +// dataSource {
  44 +// dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
  45 +// url = "jdbc:h2:mem:devDb;MVCC=TRUE"
  46 +// }
  47 +// }
  48 +// test {
  49 +// dataSource {
  50 +// dbCreate = "update"
  51 +// url = "jdbc:h2:mem:testDb;MVCC=TRUE"
  52 +// }
  53 +// }
  54 +// production {
  55 +// dataSource {
  56 +// dbCreate = "update"
  57 +// url = "jdbc:h2:prodDb;MVCC=TRUE"
  58 +// pooled = true
  59 +// properties {
  60 +// maxActive = -1
  61 +// minEvictableIdleTimeMillis=1800000
  62 +// timeBetweenEvictionRunsMillis=1800000
  63 +// numTestsPerEvictionRun=3
  64 +// testOnBorrow=true
  65 +// testWhileIdle=true
  66 +// testOnReturn=true
  67 +// validationQuery="SELECT 1"
  68 +// }
  69 +// }
  70 +// }
  71 +//}
224 grails-app/controllers/com/herokuapp/flavorwocky/FlavorwockyController.groovy
@@ -13,63 +13,33 @@ class FlavorwockyController {
13 13
14 14 def autosearch() {
15 15 def results
16   - try {
17   - def neo4jSearchClient = new RESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/index/node/ingredients?query=name:${params.term.toLowerCase()}*")
18   - neo4jSearchClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
19   - def resultsResp = neo4jSearchClient.get(contentType: JSON, requestContentType: JSON)
20   - if (resultsResp.status == 200) {
21   - render(contentType: "text/json") {
22   - results = array {
23   - for (r in resultsResp.data) {
24   - result id: Integer.parseInt(r.self.substring(r.self.lastIndexOf('/') + 1)), name: r.data.name, label: r.data.name
25   - }
  16 + if (params.term) {
  17 + render(contentType: "text/json") {
  18 + results = array {
  19 + Ingredient.where { name =~ params.term+'%'}.list().each {
  20 + result id: it.id, name: it.name, label: it.name
26 21 }
27 22 }
28 23 }
29   - } catch (ConnectException ce) {
30   - log.error "Connection to server failed"
31   - log.error ce
32   - render(contentType: "text/json") {
33   - error: ce.toString()
34   - }
  24 + }
  25 + else {
  26 + render "Please provide a search term"
35 27 }
36 28
37 29 }
38 30
39 31 def ping() {
40 32 def serverEndpointOk = false
41   - try {
42   - def pingClient = new RESTClient(grailsApplication.config.neo4j.rest.serverendpoint)
43   - pingClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
44   - def pingResp = pingClient.get(contentType: JSON, requestContentType: JSON)
45   - if (pingResp.status == 200) {
46   - serverEndpointOk = true
47   - }
48   - } catch (ConnectException ce) {
49   - log.error "Connection to server failed"
50   - log.error ce
  33 + //lets just count the Categories and if they are more than 0 then we assume the server is reachable and initialized.
  34 + if (Category.count()>0) {
  35 + serverEndpointOk = true
51 36 }
52   -
53 37 render serverEndpointOk
54 38 }
55 39
56 40 def index() {
57   - def categories
58   - //fetch the categories. This is assumed to be 'CATEGORY' type relationships with node 0
59   - try {
60   - def neo4jTraverseClient = new RESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/node/0/traverse/node")
61   - neo4jTraverseClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
62   - def postBody = [order: 'breadth_first', relationships: [direction: 'all', type: 'CATEGORY'], max_depth: 1]
63   - def traverseResp = neo4jTraverseClient.post(contentType: JSON, requestContentType: JSON, body: postBody)
64   - if (traverseResp.status == 200) {
65   - categories = traverseResp.data.collectEntries { [Integer.parseInt(it.self.substring(it.self.lastIndexOf('/') + 1)), it.data.name] }
66   - }
67   -
68   - } catch (ConnectException ce) {
69   - log.error "Connection to server failed"
70   - log.error ce
71   - }
72   -
  41 + def categories = Category.list()
  42 + //affinity values are hard-coded over here for simplicity
73 43 [categories: categories, affinity: [0.35: 'Tried and tested', 0.45: 'Extremely good', 0.6: 'Good']]
74 44 }
75 45
@@ -77,90 +47,20 @@ class FlavorwockyController {
77 47 * Fetches the nodes references for ingredients if they exists, else creates them
78 48 * @return List of the node references
79 49 */
80   - private List fetchOrCreateNodes(RESTClient restClient, String ingredient1, String ingredient2, String categoryNode1, String categoryNode2) {
81   - List nodeRef = []
82   - def escapedIngredient1 = ingredient1.replace(" ", "%20")
83   - def escapedIngredient2 = ingredient2.replace(" ", "%20")
84   - try {
85   - //fetch the ingredients if they exist
86   - def postBody = [
87   - [method: 'GET', to: '/index/node/ingredients/name/' + escapedIngredient1.toLowerCase(), id: 0],
88   - [method: 'GET', to: '/index/node/ingredients/name/' + escapedIngredient2.toLowerCase(), id: 1]
89   - ]
90   - def createResp = restClient.post(contentType: JSON, requestContentType: JSON, body: postBody)
91   - if (createResp.status == 200) {
92   - postBody = []
93   - createResp.data.body.self.eachWithIndex {selfArr, i ->
94   - if (selfArr.size() <= 0) {
95   - //no such node exists, so create one
96   - postBody.add([method: 'POST', to: '/node', body: [name: i == 0 ? ingredient1 : ingredient2], id: i * 3])
97   - //IS-A relationship to Category
98   - postBody.add([method: 'POST',
99   - to: "{${(i * 3)}}/relationships".toString(),
100   - body: [to: grailsApplication.config.neo4j.rest.serverendpoint + '/' + (i == 0 ? categoryNode1 : categoryNode2), type: 'IS_A'],
101   - id: i * 3 + 1])
102   - postBody.add([method: 'POST',
103   - to: '/index/node/ingredients?unique',
104   - body: [value: i == 0 ? ingredient1.toLowerCase() : ingredient2.toLowerCase(), key: 'name', uri: "{${i * 3}}".toString()],
105   - id: i * 3 + 2])
106   - } else {
107   - //already exists, so just return the value
108   - nodeRef.add selfArr[0] //if there are more than one then it is probably an error!!
109   - }
110   - }
111   - if (postBody.size() > 0) {
112   - createResp = restClient.post(contentType: JSON, requestContentType: JSON, body: postBody)
113   - if (createResp.status == 200) {
114   -
115   - createResp.data.each {
116   - //we know that the id of the created node is either 0 or 3 since we send it with the batch request
117   - if (it.id == 0 || it.id == 3) {
118   - nodeRef.add it.body.self
119   - }
120   - }
121   - //nodeRef.add createResp.data.body.self
122   - }
123   - }
124   - }
  50 + private List fetchOrCreateNodes(String ingredient1, String ingredient2, String categoryNode1, String categoryNode2) {
  51 + def storedIngredients = Ingredient.findAllByNameInList([ingredient1, ingredient2])
125 52
126   - } catch (ConnectException ce) {
127   - log.error "Connection to server failed"
128   - log.error ce
  53 + def ingredient1Instance = storedIngredients.find {it.name==ingredient1}
  54 + def ingredient2Instance = storedIngredients.find {it.name==ingredient2}
  55 + if (!ingredient1Instance) {
  56 + ingredient1Instance = new Ingredient(name: ingredient1, category: Category.get(categoryNode1)).save(failOnError: true)
129 57 }
130 58
131   - return nodeRef
132   - }
133   -
134   - private boolean createRelationship(String from, String to, String relation, String affinity) {
135   - def cypherClient = createRESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/cypher")
136   - try {
137   - //check if this relation already exists
138   - def postBody = [query: 'start n1=node({node1}), n2=node({node2}) match (n1)-[r:PAIRS_WITH]-(n2) return count(r)',
139   - params: ['node1': Integer.parseInt(from.substring(from.lastIndexOf('/') + 1)), 'node2': Integer.parseInt(to.substring(to.lastIndexOf('/') + 1))]]
140   - def createResp = cypherClient.post(contentType: JSON, requestContentType: JSON, body: postBody)
141   - if (createResp.status == 200) {
142   - if (createResp.data.data.size() <= 0) {
143   - //doesn't exist, so now create it
144   - def createClient = createRESTClient("${from}/relationships")
145   - postBody = [to: to, type: relation, data: [wt: affinity]]
146   - createResp = createClient.post(contentType: JSON, requestContentType: JSON, body: postBody)
147   - if (createResp.status == 200) {
148   - return true
149   - }
150   - else {
151   - return false
152   - }
153   - }
154   - return true
155   - }
156   -
157   - } catch (ConnectException ce) {
158   - log.error "Connection to server failed"
159   - log.error ce
  59 + if (!ingredient2Instance) {
  60 + ingredient2Instance = new Ingredient(name: ingredient2, category: Category.get(categoryNode2)).save(failOnError: true)
160 61 }
161 62
162   - return false
163   -
  63 + return [ingredient1Instance, ingredient2Instance]
164 64 }
165 65
166 66 def create() {
@@ -169,15 +69,32 @@ class FlavorwockyController {
169 69 return
170 70 }
171 71
172   - //Experimental Batch feature. Note: this part of the API is expected to change
173   - def createClient = createRESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/batch")
174   - def nodeRef = fetchOrCreateNodes(createClient, params.ingredient1, params.ingredient2, params.category1, params.category2)
175   - //create a PAIRS_WITH relationship between node 1 and node 2 if it doesn't already exist
176   - createRelationship(nodeRef[0], nodeRef[1], 'PAIRS_WITH', params.affinity)
  72 + Ingredient.withTransaction {
  73 + def pairedIngredients = fetchOrCreateNodes(params.ingredient1, params.ingredient2, params.category1, params.category2)
  74 + createRelationship(pairedIngredients)
  75 + }
177 76
178 77 render "done"
179 78 }
180 79
  80 + /**
  81 + * Creates a 'pairings' relationship between pairedIngredients
  82 + * @param pairedIngredients List of 2 ingredients
  83 + * @return true if a relationship was created, false if a relationship already exists
  84 + */
  85 + private boolean createRelationship(List pairedIngredients) {
  86 + def res = Ingredient.cypherStatic("start n1=node({node1}), n2=node({node2}) match (n1)-[r:pairings]-(n2) return count(r)",
  87 + [node1: pairedIngredients[0]?.id, node2: pairedIngredients[1]?.id]
  88 + )
  89 + if (res.iterator().size() <=0 ) {
  90 + //no relationship exists between these two ingredients, so lets create one
  91 + pairedIngredients[0].addToPairings(pairedIngredients[1])
  92 + return true
  93 + }
  94 +
  95 + return false
  96 + }
  97 +
181 98 private RESTClient createRESTClient(String uri) {
182 99 def restClient = new RESTClient(uri)
183 100 restClient.auth.basic grailsApplication.config.neo4j.rest.username, grailsApplication.config.neo4j.rest.password
@@ -190,26 +107,8 @@ class FlavorwockyController {
190 107 if (params.nodeId) {
191 108 def nodeId = Integer.parseInt(params.nodeId) //Integer.parseInt(params.nodeId.substring(params.nodeId.lastIndexOf('/')+1))
192 109 List children = getChildren(1, nodeId, nodeId)
193   -
194   - def cypherClient = createRESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/cypher")
195   - def queryStr = 'start n=node({nodeId}) match (n)-[:IS_A]->(cat) return cat.catColor, n.name'
196   - def postBody = [query: queryStr,
197   - params: ['nodeId': nodeId]]
198   - def catColor = 'lightsteelblue'
199   - def ingredientName
200   - try {
201   - def getNodeResp = cypherClient.post(contentType: JSON, requestContentType: JSON, body: postBody)
202   - if (getNodeResp.status == 200) {
203   - catColor = getNodeResp.data.data.get(0).get(0)
204   - ingredientName = getNodeResp.data.data.get(0).get(1)
205   - }
206   - }
207   - catch (ConnectException ce) {
208   - log.error "Connection to server failed"
209   - log.error ce
210   - }
211   -
212   - def finalStructure = ["name": ingredientName, "catColor": catColor, "wt": 1, "children": children]
  110 + def rootIngredient = Ingredient.get(nodeId)
  111 + def finalStructure = ["name": rootIngredient.name, "catColor": rootIngredient.category.catColor, "wt": 0.5, "children": children]
213 112 render finalStructure as grails.converters.JSON
214 113 } else {
215 114 render "error"
@@ -223,26 +122,15 @@ class FlavorwockyController {
223 122 return null
224 123 }
225 124
226   - def cypherClient = createRESTClient("${grailsApplication.config.neo4j.rest.serverendpoint}/cypher")
227   - def queryStr = 'start n=node({nodeId}), original=node({original}) match (n)-[r:PAIRS_WITH]-(i)-[:IS_A]->(cat) where not(i=original) return i.name,cat.catColor,ID(i),r.wt'
228   - def postBody = [query: queryStr,
229   - params: ['nodeId': nodeId, 'original': parentNodeId]]
230   -
231   - try {
232   - def queryResp = cypherClient.post(contentType: JSON, requestContentType: JSON, body: postBody)
233   - if (queryResp.status == 200) {
234   -
235   - for (row in queryResp.data.data) {
236   - def child = ["name": row.get(0), "catColor": row.get(1), "wt": row.get(3)]
237   - child.put("children", getChildren(depth + 1, row.get(2), nodeId))
238   - childrenList.add(child)
239   - }
240   -
241   - }
242   - }
243   - catch (ConnectException ce) {
244   - log.error "Connection to server failed"
245   - log.error ce
  125 + def res = Ingredient.cypherStatic ("""start n=node({nodeId}), original=node({original})
  126 + match (n)-[r:pairings]-(i)-[:category]->(cat)
  127 + where not(i=original)
  128 + return i.name as name ,cat.catColor as catColor ,ID(i)""",
  129 + [nodeId: nodeId, original: parentNodeId]
  130 + )
  131 + res.iterator().each {
  132 + def child = ["name": it.name, "catColor": it.catColor, "wt": 0.5]
  133 + childrenList.add child
246 134 }
247 135
248 136 return childrenList
@@ -308,7 +196,7 @@ class FlavorwockyController {
308 196 }
309 197 }
310 198
311   - def mapRelation(String src, String target, Map relationshipIndex, List relationJsonArray, Map nodeIndex, float distance) {
  199 + private void mapRelation(String src, String target, Map relationshipIndex, List relationJsonArray, Map nodeIndex, float distance) {
312 200
313 201 if (relationshipIndex.containsKey(src)) {
314 202 if (relationshipIndex.get(src).contains(target)) {
16 grails-app/domain/com/herokuapp/flavorwocky/Category.groovy
... ... @@ -0,0 +1,16 @@
  1 +package com.herokuapp.flavorwocky
  2 +
  3 +import groovy.transform.ToString
  4 +
  5 +@ToString
  6 +class Category {
  7 +
  8 + static mapWith = "neo4j"
  9 +
  10 + String name //Category name
  11 + String catColor //color for the UI display. just for convenience sake for the demo. never do this in a real app.
  12 +
  13 +
  14 + static constraints = {
  15 + }
  16 +}
27 grails-app/domain/com/herokuapp/flavorwocky/Ingredient.groovy
... ... @@ -0,0 +1,27 @@
  1 +package com.herokuapp.flavorwocky
  2 +
  3 +import groovy.transform.ToString
  4 +
  5 +@ToString (includes = 'name')
  6 +class Ingredient {
  7 +
  8 + static mapWith = "neo4j"
  9 +
  10 + String name
  11 + Category category
  12 +
  13 + static hasMany = [pairings: Ingredient]
  14 +
  15 + static constraints = {
  16 + }
  17 +
  18 +/*
  19 + static namedQueries = {
  20 + asdasd { String searchStr ->
  21 + println "are we here ? "+searchStr
  22 + eq (name, "searchStr%")
  23 + }
  24 + }
  25 +*/
  26 +}
  27 +
4 grails-app/views/flavorwocky/index.gsp
@@ -35,12 +35,12 @@ All rights reserved. See License.txt
35 35 <div class="dialog-left">
36 36 <label for="ingredient1">Ingredient 1</label>
37 37 <input type="text" name="ingredient1" id="ingredient1" class="text ui-widget-content ui-corner-all" />
38   - <g:select name="category1" from="${categories}" optionKey="key" optionValue="value"/>
  38 + <g:select name="category1" from="${categories}" optionKey="id" optionValue="name"/>
39 39 </div>
40 40 <div class="dialog-right">
41 41 <label for="ingredient2">Ingredient 2</label>
42 42 <input type="text" name="ingredient2" id="ingredient2" class="text ui-widget-content ui-corner-all" />
43   - <g:select name="category2" from="${categories}" optionKey="key" optionValue="value"/>
  43 + <g:select name="category2" from="${categories}" optionKey="id" optionValue="name"/>
44 44 </div>
45 45 <div class="dialog-somewhere">
46 46 <label for="affinity">Affinity</label>
159 test/unit/com/herokuapp/flavorwocky/CategoryControllerTests.groovy
... ... @@ -0,0 +1,159 @@
  1 +package com.herokuapp.flavorwocky
  2 +
  3 +
  4 +
  5 +import org.junit.*
  6 +import grails.test.mixin.*
  7 +
  8 +@TestFor(CategoryController)
  9 +@Mock(Category)
  10 +class CategoryControllerTests {
  11 +
  12 +
  13 + def populateValidParams(params) {
  14 + assert params != null
  15 + // TODO: Populate valid properties like...
  16 + //params["name"] = 'someValidName'
  17 + }
  18 +
  19 + void testIndex() {
  20 + controller.index()
  21 + assert "/category/list" == response.redirectedUrl
  22 + }
  23 +
  24 + void testList() {
  25 +
  26 + def model = controller.list()
  27 +
  28 + assert model.categoryInstanceList.size() == 0
  29 + assert model.categoryInstanceTotal == 0
  30 + }
  31 +
  32 + void testCreate() {
  33 + def model = controller.create()
  34 +
  35 + assert model.categoryInstance != null
  36 + }
  37 +
  38 + void testSave() {
  39 + controller.save()
  40 +
  41 + assert model.categoryInstance != null
  42 + assert view == '/category/create'
  43 +
  44 + response.reset()
  45 +
  46 + populateValidParams(params)
  47 + controller.save()
  48 +
  49 + assert response.redirectedUrl == '/category/show/1'
  50 + assert controller.flash.message != null
  51 + assert Category.count() == 1
  52 + }
  53 +
  54 + void testShow() {
  55 + controller.show()
  56 +
  57 + assert flash.message != null
  58 + assert response.redirectedUrl == '/category/list'
  59 +
  60 +
  61 + populateValidParams(params)
  62 + def category = new Category(params)
  63 +
  64 + assert category.save() != null
  65 +
  66 + params.id = category.id
  67 +
  68 + def model = controller.show()
  69 +
  70 + assert model.categoryInstance == category
  71 + }
  72 +
  73 + void testEdit() {
  74 + controller.edit()
  75 +
  76 + assert flash.message != null
  77 + assert response.redirectedUrl == '/category/list'
  78 +
  79 +
  80 + populateValidParams(params)
  81 + def category = new Category(params)
  82 +
  83 + assert category.save() != null
  84 +
  85 + params.id = category.id
  86 +
  87 + def model = controller.edit()
  88 +
  89 + assert model.categoryInstance == category
  90 + }
  91 +
  92 + void testUpdate() {
  93 + controller.update()
  94 +
  95 + assert flash.message != null
  96 + assert response.redirectedUrl == '/category/list'
  97 +
  98 + response.reset()
  99 +
  100 +
  101 + populateValidParams(params)
  102 + def category = new Category(params)
  103 +
  104 + assert category.save() != null
  105 +
  106 + // test invalid parameters in update
  107 + params.id = category.id
  108 + //TODO: add invalid values to params object
  109 +
  110 + controller.update()
  111 +
  112 + assert view == "/category/edit"
  113 + assert model.categoryInstance != null
  114 +
  115 + category.clearErrors()
  116 +
  117 + populateValidParams(params)
  118 + controller.update()
  119 +
  120 + assert response.redirectedUrl == "/category/show/$category.id"
  121 + assert flash.message != null
  122 +
  123 + //test outdated version number
  124 + response.reset()
  125 + category.clearErrors()
  126 +
  127 + populateValidParams(params)
  128 + params.id = category.id
  129 + params.version = -1
  130 + controller.update()
  131 +
  132 + assert view == "/category/edit"
  133 + assert model.categoryInstance != null
  134 + assert model.categoryInstance.errors.getFieldError('version')
  135 + assert flash.message != null
  136 + }
  137 +
  138 + void testDelete() {
  139 + controller.delete()
  140 + assert flash.message != null
  141 + assert response.redirectedUrl == '/category/list'
  142 +
  143 + response.reset()
  144 +
  145 + populateValidParams(params)
  146 + def category = new Category(params)
  147 +
  148 + assert category.save() != null
  149 + assert Category.count() == 1
  150 +
  151 + params.id = category.id
  152 +
  153 + controller.delete()
  154 +
  155 + assert Category.count() == 0
  156 + assert Category.get(category.id) == null
  157 + assert response.redirectedUrl == '/category/list'
  158 + }
  159 +}

0 comments on commit 7bf0524

Please sign in to comment.
Something went wrong with that request. Please try again.