gitee.com/kathent/go-swagger@v0.19.0/generator/server_test.go (about) 1 package generator 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "log" 9 "os" 10 "path/filepath" 11 "regexp" 12 "strings" 13 "testing" 14 15 "github.com/go-openapi/analysis" 16 "github.com/go-openapi/loads" 17 "github.com/go-openapi/runtime" 18 "github.com/go-openapi/swag" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 const invalidSpecExample = "../fixtures/bugs/825/swagger.yml" 23 24 // Perform common initialization of template repository before running tests. 25 // This allows to run tests unitarily (e.g. go test -run xxx ). 26 func TestMain(m *testing.M) { 27 templates.LoadDefaults() 28 os.Exit(m.Run()) 29 } 30 31 func testGenOpts() (g GenOpts) { 32 g.Target = "." 33 g.APIPackage = defaultAPIPackage 34 g.ModelPackage = defaultModelPackage 35 g.ServerPackage = defaultServerPackage 36 g.ClientPackage = defaultClientPackage 37 g.Principal = "" 38 g.DefaultScheme = "http" 39 g.IncludeModel = true 40 g.IncludeValidator = true 41 g.IncludeHandler = true 42 g.IncludeParameters = true 43 g.IncludeResponses = true 44 g.IncludeMain = false 45 g.IncludeSupport = true 46 g.ExcludeSpec = true 47 g.TemplateDir = "" 48 g.DumpData = false 49 _ = g.EnsureDefaults() 50 return 51 } 52 53 func testAppGenerator(t testing.TB, specPath, name string) (*appGenerator, error) { 54 specDoc, err := loads.Spec(specPath) 55 if !assert.NoError(t, err) { 56 return nil, err 57 } 58 analyzed := analysis.New(specDoc.Spec()) 59 60 models, err := gatherModels(specDoc, nil) 61 if !assert.NoError(t, err) { 62 return nil, err 63 } 64 65 operations := gatherOperations(analyzed, nil) 66 if len(operations) == 0 { 67 return nil, errors.New("no operations were selected") 68 } 69 70 opts := testGenOpts() 71 opts.Spec = specPath 72 apiPackage := opts.LanguageOpts.MangleName(swag.ToFileName(opts.APIPackage), "api") 73 74 return &appGenerator{ 75 Name: appNameOrDefault(specDoc, name, "swagger"), 76 Receiver: "o", 77 SpecDoc: specDoc, 78 Analyzed: analyzed, 79 Models: models, 80 Operations: operations, 81 Target: ".", 82 DumpData: opts.DumpData, 83 Package: apiPackage, 84 APIPackage: apiPackage, 85 ModelsPackage: opts.LanguageOpts.MangleName(swag.ToFileName(opts.ModelPackage), "definitions"), 86 ServerPackage: opts.LanguageOpts.MangleName(swag.ToFileName(opts.ServerPackage), "server"), 87 ClientPackage: opts.LanguageOpts.MangleName(swag.ToFileName(opts.ClientPackage), "client"), 88 Principal: opts.Principal, 89 DefaultScheme: "http", 90 DefaultProduces: runtime.JSONMime, 91 DefaultConsumes: runtime.JSONMime, 92 GenOpts: &opts, 93 }, nil 94 } 95 96 func TestServer_UrlEncoded(t *testing.T) { 97 log.SetOutput(ioutil.Discard) 98 defer log.SetOutput(os.Stdout) 99 gen, err := testAppGenerator(t, "../fixtures/codegen/simplesearch.yml", "search") 100 if assert.NoError(t, err) { 101 app, err := gen.makeCodegenApp() 102 if assert.NoError(t, err) { 103 buf := bytes.NewBuffer(nil) 104 if assert.NoError(t, templates.MustGet("serverBuilder").Execute(buf, app)) { 105 formatted, err := app.GenOpts.LanguageOpts.FormatContent("search_api.go", buf.Bytes()) 106 if assert.NoError(t, err) { 107 res := string(formatted) 108 assert.Regexp(t, "UrlformConsumer:\\s+runtime\\.DiscardConsumer", res) 109 } else { 110 fmt.Println(buf.String()) 111 } 112 } 113 buf = bytes.NewBuffer(nil) 114 if assert.NoError(t, templates.MustGet("serverConfigureapi").Execute(buf, app)) { 115 formatted, err := app.GenOpts.LanguageOpts.FormatContent("configure_search_api.go", buf.Bytes()) 116 if assert.NoError(t, err) { 117 res := string(formatted) 118 assertInCode(t, "api.UrlformConsumer = runtime.DiscardConsumer", res) 119 } else { 120 fmt.Println(buf.String()) 121 } 122 } 123 } 124 } 125 } 126 127 func TestServer_MultipartForm(t *testing.T) { 128 log.SetOutput(ioutil.Discard) 129 defer log.SetOutput(os.Stdout) 130 gen, err := testAppGenerator(t, "../fixtures/codegen/shipyard.yml", "shipyard") 131 if assert.NoError(t, err) { 132 app, err := gen.makeCodegenApp() 133 if assert.NoError(t, err) { 134 buf := bytes.NewBuffer(nil) 135 if assert.NoError(t, templates.MustGet("serverBuilder").Execute(buf, app)) { 136 formatted, err := app.GenOpts.LanguageOpts.FormatContent("shipyard_api.go", buf.Bytes()) 137 if assert.NoError(t, err) { 138 res := string(formatted) 139 assert.Regexp(t, "MultipartformConsumer:\\s+runtime\\.DiscardConsumer", res) 140 } else { 141 fmt.Println(buf.String()) 142 } 143 } 144 buf = bytes.NewBuffer(nil) 145 if assert.NoError(t, templates.MustGet("serverConfigureapi").Execute(buf, app)) { 146 formatted, err := app.GenOpts.LanguageOpts.FormatContent("configure_shipyard_api.go", buf.Bytes()) 147 if assert.NoError(t, err) { 148 res := string(formatted) 149 assertInCode(t, "api.MultipartformConsumer = runtime.DiscardConsumer", res) 150 } else { 151 fmt.Println(buf.String()) 152 } 153 } 154 } 155 } 156 } 157 158 func TestServer_InvalidSpec(t *testing.T) { 159 log.SetOutput(ioutil.Discard) 160 defer log.SetOutput(os.Stdout) 161 opts := testGenOpts() 162 opts.Spec = invalidSpecExample 163 opts.ValidateSpec = true 164 assert.Error(t, GenerateServer("foo", nil, nil, &opts)) 165 } 166 167 func TestServer_TrailingSlash(t *testing.T) { 168 log.SetOutput(ioutil.Discard) 169 defer log.SetOutput(os.Stdout) 170 gen, err := testAppGenerator(t, "../fixtures/bugs/899/swagger.yml", "trailing slash") 171 if assert.NoError(t, err) { 172 app, err := gen.makeCodegenApp() 173 if assert.NoError(t, err) { 174 buf := bytes.NewBuffer(nil) 175 if assert.NoError(t, templates.MustGet("serverBuilder").Execute(buf, app)) { 176 formatted, err := app.GenOpts.LanguageOpts.FormatContent("shipyard_api.go", buf.Bytes()) 177 if assert.NoError(t, err) { 178 res := string(formatted) 179 assertInCode(t, `o.handlers["GET"]["/trailingslashpath"]`, res) 180 } else { 181 fmt.Println(buf.String()) 182 } 183 } 184 } 185 } 186 } 187 188 func TestServer_Issue987(t *testing.T) { 189 log.SetOutput(ioutil.Discard) 190 defer log.SetOutput(os.Stdout) 191 gen, err := testAppGenerator(t, "../fixtures/bugs/987/swagger.yml", "deeper consumes produces") 192 if assert.NoError(t, err) { 193 app, err := gen.makeCodegenApp() 194 if assert.NoError(t, err) { 195 buf := bytes.NewBuffer(nil) 196 if assert.NoError(t, templates.MustGet("serverBuilder").Execute(buf, app)) { 197 formatted, err := app.GenOpts.LanguageOpts.FormatContent("shipyard_api.go", buf.Bytes()) 198 if assert.NoError(t, err) { 199 res := string(formatted) 200 assertRegexpInCode(t, `JSONConsumer:\s+runtime.JSONConsumer()`, res) 201 assertRegexpInCode(t, `JSONProducer:\s+runtime.JSONProducer()`, res) 202 assertInCode(t, `result["application/json"] = o.JSONConsumer`, res) 203 assertInCode(t, `result["application/json"] = o.JSONProducer`, res) 204 } else { 205 fmt.Println(buf.String()) 206 } 207 } 208 } 209 } 210 } 211 212 func TestServer_FilterByTag(t *testing.T) { 213 log.SetOutput(ioutil.Discard) 214 defer log.SetOutput(os.Stdout) 215 gen, err := testAppGenerator(t, "../fixtures/codegen/simplesearch.yml", "search") 216 if assert.NoError(t, err) { 217 gen.GenOpts.Tags = []string{"search"} 218 app, err := gen.makeCodegenApp() 219 if assert.NoError(t, err) { 220 buf := bytes.NewBuffer(nil) 221 if assert.NoError(t, templates.MustGet("serverBuilder").Execute(buf, app)) { 222 formatted, err := app.GenOpts.LanguageOpts.FormatContent("search_api.go", buf.Bytes()) 223 if assert.NoError(t, err) { 224 res := string(formatted) 225 assertInCode(t, `o.handlers["POST"]["/search"]`, res) 226 assertNotInCode(t, `o.handlers["POST"]["/tasks"]`, res) 227 } else { 228 fmt.Println(buf.String()) 229 } 230 } 231 } 232 } 233 } 234 235 // Checking error handling code: panic on mismatched template 236 // High level test with AppGenerator 237 func badTemplateCall() { 238 log.SetOutput(ioutil.Discard) 239 defer log.SetOutput(os.Stdout) 240 241 gen, err := testAppGenerator(nil, "../fixtures/bugs/899/swagger.yml", "trailing slash") 242 if err != nil { 243 return 244 } 245 app, err := gen.makeCodegenApp() 246 log.SetOutput(ioutil.Discard) 247 if err != nil { 248 return 249 } 250 buf := bytes.NewBuffer(nil) 251 r := templates.MustGet("serverBuilderX").Execute(buf, app) 252 253 // Should never reach here 254 log.Printf("%+v\n", r) 255 } 256 257 func TestServer_BadTemplate(t *testing.T) { 258 log.SetOutput(ioutil.Discard) 259 defer log.SetOutput(os.Stdout) 260 261 assert.Panics(t, badTemplateCall, "templates.MustGet() did not panic() as currently expected") 262 } 263 264 // Checking error handling code: panic on bad parsing template 265 // High level test with AppGenerator 266 func badParseCall() { 267 log.SetOutput(ioutil.Discard) 268 defer log.SetOutput(os.Stdout) 269 270 var badParse = `{{{ define "T1" }}T1{{end}}{{ define "T2" }}T2{{end}}` 271 272 _ = templates.AddFile("badparse", badParse) 273 gen, _ := testAppGenerator(nil, "../fixtures/bugs/899/swagger.yml", "trailing slash") 274 app, _ := gen.makeCodegenApp() 275 log.SetOutput(ioutil.Discard) 276 tpl := templates.MustGet("badparse") 277 278 // Should never reach here 279 buf := bytes.NewBuffer(nil) 280 r := tpl.Execute(buf, app) 281 282 log.Printf("%+v\n", r) 283 } 284 285 func TestServer_ErrorParsingTemplate(t *testing.T) { 286 log.SetOutput(ioutil.Discard) 287 defer log.SetOutput(os.Stdout) 288 289 assert.Panics(t, badParseCall, "templates.MustGet() did not panic() as currently expected") 290 } 291 292 func TestServer_OperationGroups(t *testing.T) { 293 log.SetOutput(ioutil.Discard) 294 defer func() { 295 log.SetOutput(os.Stdout) 296 _ = os.RemoveAll(filepath.Join(".", "restapi")) 297 _ = os.RemoveAll(filepath.Join(".", "search")) 298 _ = os.RemoveAll(filepath.Join(".", "tasks")) 299 }() 300 301 gen, err := testAppGenerator(t, "../fixtures/codegen/simplesearch.yml", "search") 302 if assert.NoError(t, err) { 303 gen.GenOpts.Tags = []string{"search", "tasks"} 304 gen.GenOpts.IncludeModel = false 305 gen.GenOpts.IncludeHandler = true 306 gen.GenOpts.Sections.OperationGroups = []TemplateOpts{ 307 { 308 Name: "opGroupTest", 309 Source: "asset:opGroupTest", 310 Target: "{{ joinFilePath .Target .Name }}", 311 FileName: "{{ (snakize (pascalize .Name)) }}_opgroup_test.gol", 312 }, 313 } 314 err := gen.Generate() 315 // This attempts fails: template not declared 316 assert.Error(t, err) 317 // Tolerates case variations on error message 318 assert.Contains(t, strings.ToLower(err.Error()), "template doesn't exist") 319 320 var opGroupTpl = ` 321 // OperationGroupName={{.Name}} 322 // RootPackage={{.RootPackage}} 323 {{ range .Operations }} 324 // OperationName={{.Name}} 325 {{end}}` 326 _ = templates.AddFile("opGroupTest", opGroupTpl) 327 err = gen.Generate() 328 assert.NoError(t, err) 329 //buf := bytes.NewBuffer(nil) 330 genContent, erf := ioutil.ReadFile("./search/search_opgroup_test.gol") 331 assert.NoError(t, erf, "Generator should have written a file") 332 assert.Contains(t, string(genContent), "// OperationGroupName=search") 333 assert.Contains(t, string(genContent), "// RootPackage=operations") 334 assert.Contains(t, string(genContent), "// OperationName=search") 335 336 genContent, erf = ioutil.ReadFile("./tasks/tasks_opgroup_test.gol") 337 assert.NoError(t, erf, "Generator should have written a file") 338 assert.Contains(t, string(genContent), "// OperationGroupName=tasks") 339 assert.Contains(t, string(genContent), "// RootPackage=operations") 340 assert.Contains(t, string(genContent), "// OperationName=createTask") 341 assert.Contains(t, string(genContent), "// OperationName=deleteTask") 342 assert.Contains(t, string(genContent), "// OperationName=getTasks") 343 assert.Contains(t, string(genContent), "// OperationName=updateTask") 344 } 345 } 346 347 func TestServer_Issue1301(t *testing.T) { 348 log.SetOutput(ioutil.Discard) 349 defer log.SetOutput(os.Stdout) 350 gen, err := testAppGenerator(t, "../fixtures/enhancements/1301/swagger.yml", "custom producers") 351 if assert.NoError(t, err) { 352 app, err := gen.makeCodegenApp() 353 if assert.NoError(t, err) { 354 buf := bytes.NewBuffer(nil) 355 if assert.NoError(t, templates.MustGet("serverBuilder").Execute(buf, app)) { 356 formatted, err := app.GenOpts.LanguageOpts.FormatContent("shipyard_api.go", buf.Bytes()) 357 if assert.NoError(t, err) { 358 res := string(formatted) 359 360 // initialisation in New<Name>API function 361 assertInCode(t, `customConsumers: make(map[string]runtime.Consumer)`, res) 362 assertInCode(t, `customProducers: make(map[string]runtime.Producer)`, res) 363 364 // declaration in struct 365 assertInCode(t, `customConsumers map[string]runtime.Consumer`, res) 366 assertInCode(t, `customProducers map[string]runtime.Producer`, res) 367 assertRegexpInCode(t, `if c, ok := o\.customConsumers\[mt\]; ok \{\s+result\[mt\] = c\s+\}`, res) 368 assertRegexpInCode(t, `if p, ok := o\.customProducers\[mt\]; ok \{\s+result\[mt\] = p\s+\}`, res) 369 assertRegexpInCode(t, `func \(o \*CustomProducersAPI\) RegisterConsumer\(mediaType string, consumer runtime\.Consumer\) \{\s+ o\.customConsumers\[mediaType\] = consumer\s+\}`, res) 370 assertRegexpInCode(t, `func \(o \*CustomProducersAPI\) RegisterProducer\(mediaType string, producer runtime\.Producer\) \{\s+ o\.customProducers\[mediaType\] = producer\s+\}`, res) 371 372 } else { 373 fmt.Println(buf.String()) 374 } 375 } 376 } 377 } 378 } 379 380 func TestServer_Issue1557(t *testing.T) { 381 log.SetOutput(ioutil.Discard) 382 defer log.SetOutput(os.Stdout) 383 gen, err := testAppGenerator(t, "../fixtures/enhancements/1557/swagger.yml", "generate consumer/producer handlers that are not whitelisted") 384 if assert.NoError(t, err) { 385 app, err := gen.makeCodegenApp() 386 if assert.NoError(t, err) { 387 buf := bytes.NewBuffer(nil) 388 if assert.NoError(t, templates.MustGet("serverBuilder").Execute(buf, app)) { 389 formatted, err := app.GenOpts.LanguageOpts.FormatContent("shipyard_api.go", buf.Bytes()) 390 if assert.NoError(t, err) { 391 res := string(formatted) 392 assertRegexpInCode(t, `ApplicationPdfConsumer:\s+runtime.Consumer`, res) 393 assertRegexpInCode(t, `ApplicationPdfProducer:\s+runtime.Producer`, res) 394 assertInCode(t, `result["application/pdf"] = o.ApplicationPdfConsumer`, res) 395 assertInCode(t, `result["application/pdf"] = o.ApplicationPdfProducer`, res) 396 } else { 397 fmt.Println(buf.String()) 398 } 399 } 400 } 401 } 402 } 403 404 func TestServer_Issue1648(t *testing.T) { 405 log.SetOutput(ioutil.Discard) 406 defer log.SetOutput(os.Stdout) 407 gen, err := testAppGenerator(t, "../fixtures/bugs/1648/fixture-1648.yaml", "generate format with missing type in model") 408 if assert.NoError(t, err) { 409 _, err := gen.makeCodegenApp() 410 assert.NoError(t, err) 411 } 412 } 413 414 func TestServer_Issue1746(t *testing.T) { 415 log.SetOutput(ioutil.Discard) 416 targetdir, err := ioutil.TempDir(".", "swagger_server") 417 if err != nil { 418 t.Fatalf("failed to create a test target directory: %v", err) 419 } 420 err = os.Chdir(targetdir) 421 if err != nil { 422 t.Fatalf("failed to create a test target directory: %v", err) 423 } 424 defer func() { 425 if err = os.Chdir(".."); err != nil { 426 t.Log("failed test exist: ", err) 427 } 428 log.SetOutput(os.Stdout) 429 if err = os.RemoveAll(targetdir); err != nil { 430 t.Log("failed test exist: ", err) 431 } 432 }() 433 opts := testGenOpts() 434 435 opts.Target = filepath.Join("x") 436 _ = os.Mkdir(opts.Target, 0755) 437 opts.Spec = filepath.Join("..", "..", "fixtures", "bugs", "1746", "fixture-1746.yaml") 438 tgtSpec := regexp.QuoteMeta(filepath.Join("..", "..", opts.Spec)) 439 440 err = GenerateServer("", nil, nil, &opts) 441 assert.NoError(t, err) 442 gulp, err := ioutil.ReadFile(filepath.Join("x", "restapi", "configure_example_swagger_server.go")) 443 assert.NoError(t, err) 444 tgtPath := regexp.QuoteMeta(filepath.Join("..", "..", opts.Target)) 445 assertRegexpInCode(t, `go:generate swagger generate server.+\-\-target `+tgtPath, string(gulp)) 446 assertRegexpInCode(t, `go:generate swagger generate server.+\-\-name\s+ExampleSwaggerServer`, string(gulp)) 447 assertRegexpInCode(t, `go:generate swagger generate server.+\-\-spec\s+`+tgtSpec, string(gulp)) 448 } 449 450 func doGenAppTemplate(t *testing.T, fixture, template string) string { 451 log.SetOutput(ioutil.Discard) 452 defer log.SetOutput(os.Stdout) 453 gen, err := testAppGenerator(t, fixture, "generate: "+fixture) 454 if !assert.NoError(t, err) { 455 t.FailNow() 456 } 457 app, err := gen.makeCodegenApp() 458 if !assert.NoError(t, err) { 459 t.FailNow() 460 } 461 buf := bytes.NewBuffer(nil) 462 if !assert.NoError(t, templates.MustGet(template).Execute(buf, app)) { 463 t.FailNow() 464 } 465 formatted, err := app.GenOpts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 466 if !assert.NoError(t, err) { 467 t.FailNow() 468 } 469 return string(formatted) 470 } 471 472 func TestServer_Issue1816(t *testing.T) { 473 // fixed regression: gob encoding in $ref 474 res := doGenAppTemplate(t, "../fixtures/bugs/1816/fixture-1816.yaml", "swaggerJsonEmbed") 475 assertNotInCode(t, `"$ref": "#"`, res) 476 477 // fixed regression: gob encoding in operation security requirements 478 res = doGenAppTemplate(t, "../fixtures/bugs/1824/swagger.json", "swaggerJsonEmbed") 479 assertInCode(t, `"api_key": []`, res) 480 assertNotInCode(t, `"api_key": null`, res) 481 }