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  })