github.com/youyuanwu/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  }