github.com/brycereitano/goa@v0.0.0-20170315073847-8ffa6c85e265/design/apidsl/action_test.go (about) 1 package apidsl_test 2 3 import ( 4 "strconv" 5 6 . "github.com/goadesign/goa/design" 7 . "github.com/goadesign/goa/design/apidsl" 8 "github.com/goadesign/goa/dslengine" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 ) 12 13 var _ = Describe("Action", func() { 14 var name string 15 var dsl func() 16 var action *ActionDefinition 17 18 BeforeEach(func() { 19 dslengine.Reset() 20 name = "" 21 dsl = nil 22 }) 23 24 JustBeforeEach(func() { 25 Resource("res", func() { 26 Action(name, dsl) 27 }) 28 dslengine.Run() 29 if r, ok := Design.Resources["res"]; ok { 30 action = r.Actions[name] 31 } 32 }) 33 34 Context("with only a name and a route", func() { 35 BeforeEach(func() { 36 name = "foo" 37 }) 38 39 It("produces an invalid action", func() { 40 Ω(dslengine.Errors).Should(HaveOccurred()) 41 }) 42 }) 43 44 Context("with a name and DSL defining a route", func() { 45 var route = GET("/:id") 46 47 BeforeEach(func() { 48 name = "foo" 49 dsl = func() { Routing(route) } 50 }) 51 52 It("produces a valid action definition with the route and default status of 200 set", func() { 53 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 54 Ω(action).ShouldNot(BeNil()) 55 Ω(action.Name).Should(Equal(name)) 56 Ω(action.Validate()).ShouldNot(HaveOccurred()) 57 Ω(action.Routes).ShouldNot(BeNil()) 58 Ω(action.Routes).Should(HaveLen(1)) 59 Ω(action.Routes[0]).Should(Equal(route)) 60 }) 61 62 Context("with an empty params DSL", func() { 63 BeforeEach(func() { 64 olddsl := dsl 65 dsl = func() { olddsl(); Params(func() {}) } 66 name = "foo" 67 }) 68 69 It("produces a valid action", func() { 70 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 71 }) 72 }) 73 74 Context("with a metadata", func() { 75 BeforeEach(func() { 76 metadatadsl := func() { Metadata("swagger:extension:x-get", `{"foo":"bar"}`) } 77 route = GET("/:id", metadatadsl) 78 name = "foo" 79 }) 80 81 It("produces a valid action definition with the route with the metadata", func() { 82 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 83 Ω(action).ShouldNot(BeNil()) 84 Ω(action.Name).Should(Equal(name)) 85 Ω(action.Validate()).ShouldNot(HaveOccurred()) 86 Ω(action.Routes).ShouldNot(BeNil()) 87 Ω(action.Routes).Should(HaveLen(1)) 88 Ω(action.Routes[0]).Should(Equal(route)) 89 Ω(action.Routes[0].Metadata).ShouldNot(BeNil()) 90 Ω(action.Routes[0].Metadata).Should(Equal( 91 dslengine.MetadataDefinition{"swagger:extension:x-get": []string{`{"foo":"bar"}`}}, 92 )) 93 }) 94 }) 95 }) 96 97 Context("with a string payload", func() { 98 BeforeEach(func() { 99 name = "foo" 100 dsl = func() { 101 Routing(GET("/:id")) 102 Payload(String) 103 } 104 }) 105 106 It("produces a valid action with the given properties", func() { 107 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 108 Ω(action).ShouldNot(BeNil()) 109 Ω(action.Validate()).ShouldNot(HaveOccurred()) 110 Ω(action.Payload).ShouldNot(BeNil()) 111 Ω(action.Payload.Type).Should(Equal(String)) 112 }) 113 }) 114 115 Context("with a name and DSL defining a description, route, headers, payload and responses", func() { 116 const typeName = "typeName" 117 const description = "description" 118 const headerName = "Foo" 119 120 BeforeEach(func() { 121 Type(typeName, func() { 122 Attribute("name") 123 }) 124 name = "foo" 125 dsl = func() { 126 Description(description) 127 Routing(GET("/:id")) 128 Headers(func() { Header(headerName) }) 129 Payload(typeName) 130 Response(NoContent) 131 } 132 }) 133 134 It("produces a valid action with the given properties", func() { 135 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 136 Ω(action).ShouldNot(BeNil()) 137 Ω(action.Validate()).ShouldNot(HaveOccurred()) 138 Ω(action.Name).Should(Equal(name)) 139 Ω(action.Description).Should(Equal(description)) 140 Ω(action.Routes).Should(HaveLen(1)) 141 Ω(action.Responses).ShouldNot(BeNil()) 142 Ω(action.Responses).Should(HaveLen(1)) 143 Ω(action.Responses).Should(HaveKey("NoContent")) 144 Ω(action.Headers.Type.(Object)).Should(HaveKey(headerName)) 145 Ω(action.Headers).ShouldNot(BeNil()) 146 Ω(action.Headers.Type).Should(BeAssignableToTypeOf(Object{})) 147 Ω(action.Headers.Type.(Object)).Should(HaveLen(1)) 148 Ω(action.Headers.Type.(Object)).Should(HaveKey(headerName)) 149 }) 150 }) 151 152 Context("using a response with a media type modifier", func() { 153 const mtID = "application/vnd.app.foo+json" 154 155 BeforeEach(func() { 156 MediaType(mtID, func() { 157 Attributes(func() { Attribute("foo") }) 158 View("default", func() { Attribute("foo") }) 159 }) 160 name = "foo" 161 dsl = func() { 162 Routing(GET("/:id")) 163 Response(OK, mtID) 164 } 165 }) 166 167 It("produces a response that keeps the modifier", func() { 168 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 169 Ω(action).ShouldNot(BeNil()) 170 Ω(action.Validate()).ShouldNot(HaveOccurred()) 171 Ω(action.Responses).ShouldNot(BeNil()) 172 Ω(action.Responses).Should(HaveLen(1)) 173 Ω(action.Responses).Should(HaveKey("OK")) 174 resp := action.Responses["OK"] 175 Ω(resp.MediaType).Should(Equal(mtID)) 176 }) 177 }) 178 179 Context("using a response template", func() { 180 const tmplName = "tmpl" 181 const respMediaType = "media" 182 const respStatus = 200 183 const respName = "respName" 184 185 BeforeEach(func() { 186 name = "foo" 187 API("test", func() { 188 ResponseTemplate(tmplName, func(status, name string) { 189 st, err := strconv.Atoi(status) 190 if err != nil { 191 dslengine.ReportError(err.Error()) 192 return 193 } 194 Status(st) 195 }) 196 }) 197 }) 198 199 Context("called correctly", func() { 200 BeforeEach(func() { 201 dsl = func() { 202 Routing(GET("/:id")) 203 Response(tmplName, strconv.Itoa(respStatus), respName, func() { 204 Media(respMediaType) 205 }) 206 } 207 }) 208 209 It("defines the response definition using the template", func() { 210 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 211 Ω(action).ShouldNot(BeNil()) 212 Ω(action.Responses).ShouldNot(BeNil()) 213 Ω(action.Responses).Should(HaveLen(1)) 214 Ω(action.Responses).Should(HaveKey(tmplName)) 215 resp := action.Responses[tmplName] 216 Ω(resp.Name).Should(Equal(tmplName)) 217 Ω(resp.Status).Should(Equal(respStatus)) 218 Ω(resp.MediaType).Should(Equal(respMediaType)) 219 }) 220 }) 221 222 Context("called incorrectly", func() { 223 BeforeEach(func() { 224 dsl = func() { 225 Routing(GET("/id")) 226 Response(tmplName, "not an integer", respName, func() { 227 Media(respMediaType) 228 }) 229 } 230 }) 231 232 It("fails", func() { 233 Ω(dslengine.Errors).Should(HaveOccurred()) 234 }) 235 }) 236 }) 237 }) 238 239 var _ = Describe("Payload", func() { 240 Context("with a payload definition", func() { 241 BeforeEach(func() { 242 dslengine.Reset() 243 244 Resource("foo", func() { 245 Action("bar", func() { 246 Routing(GET("")) 247 Payload(func() { 248 Member("name") 249 Required("name") 250 }) 251 }) 252 }) 253 }) 254 255 JustBeforeEach(func() { 256 dslengine.Run() 257 }) 258 259 It("generates the payload type", func() { 260 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 261 Ω(Design).ShouldNot(BeNil()) 262 Ω(Design.Resources).Should(HaveKey("foo")) 263 Ω(Design.Resources["foo"].Actions).Should(HaveKey("bar")) 264 Ω(Design.Resources["foo"].Actions["bar"].Payload).ShouldNot(BeNil()) 265 }) 266 }) 267 268 Context("with an array", func() { 269 BeforeEach(func() { 270 dslengine.Reset() 271 272 Resource("foo", func() { 273 Action("bar", func() { 274 Routing(GET("")) 275 Payload(ArrayOf(Integer)) 276 }) 277 }) 278 }) 279 280 JustBeforeEach(func() { 281 dslengine.Run() 282 }) 283 284 It("sets the payload type", func() { 285 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 286 Ω(Design).ShouldNot(BeNil()) 287 Ω(Design.Resources).Should(HaveKey("foo")) 288 Ω(Design.Resources["foo"].Actions).Should(HaveKey("bar")) 289 Ω(Design.Resources["foo"].Actions["bar"].Payload).ShouldNot(BeNil()) 290 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type).ShouldNot(BeNil()) 291 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.IsArray()).Should(BeTrue()) 292 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.ToArray().ElemType).ShouldNot(BeNil()) 293 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.ToArray().ElemType.Type).Should(Equal(Integer)) 294 }) 295 }) 296 297 Context("with a hash", func() { 298 BeforeEach(func() { 299 dslengine.Reset() 300 301 Resource("foo", func() { 302 Action("bar", func() { 303 Routing(GET("")) 304 Payload(HashOf(String, Integer)) 305 }) 306 }) 307 }) 308 309 JustBeforeEach(func() { 310 dslengine.Run() 311 }) 312 313 It("sets the payload type", func() { 314 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 315 Ω(Design).ShouldNot(BeNil()) 316 Ω(Design.Resources).Should(HaveKey("foo")) 317 Ω(Design.Resources["foo"].Actions).Should(HaveKey("bar")) 318 Ω(Design.Resources["foo"].Actions["bar"].Payload).ShouldNot(BeNil()) 319 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type).ShouldNot(BeNil()) 320 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.IsHash()).Should(BeTrue()) 321 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.ToHash().ElemType).ShouldNot(BeNil()) 322 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.ToHash().KeyType).ShouldNot(BeNil()) 323 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.ToHash().ElemType.Type).Should(Equal(Integer)) 324 Ω(Design.Resources["foo"].Actions["bar"].Payload.Type.ToHash().KeyType.Type).Should(Equal(String)) 325 }) 326 }) 327 328 })