github.com/speakeasy-api/sdk-gen-config@v1.14.2/io_test.go (about)

     1  package config
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/speakeasy-api/sdk-gen-config/workspace"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  const testDir = "gen/test"
    14  
    15  func TestLoad_Success(t *testing.T) {
    16  	getUUID = func() string {
    17  		return "123"
    18  	}
    19  
    20  	type args struct {
    21  		langs        []string
    22  		configDir    string
    23  		targetDir    string
    24  		genYaml      string
    25  		lockFile     string
    26  		configSubDir string
    27  	}
    28  	tests := []struct {
    29  		name string
    30  		args args
    31  		want *Config
    32  	}{
    33  		{
    34  			name: "creates config file and lock file if it doesn't exist in the .speakeasy dir",
    35  			args: args{
    36  				langs:        []string{"go"},
    37  				configDir:    testDir,
    38  				targetDir:    testDir,
    39  				configSubDir: ".speakeasy",
    40  			},
    41  			want: &Config{
    42  				Config: &Configuration{
    43  					ConfigVersion: Version,
    44  					Languages: map[string]LanguageConfig{
    45  						"go": {
    46  							Version: "0.0.1",
    47  						},
    48  					},
    49  					Generation: Generation{
    50  						SDKClassName:         "SDK",
    51  						MaintainOpenAPIOrder: true,
    52  						UsageSnippets: &UsageSnippets{
    53  							OptionalPropertyRendering: "withExample",
    54  						},
    55  						Fixes: &Fixes{
    56  							NameResolutionDec2023:                true,
    57  							ParameterOrderingFeb2024:             true,
    58  							RequestResponseComponentNamesFeb2024: true,
    59  						},
    60  						Auth: &Auth{
    61  							OAuth2ClientCredentialsEnabled: true,
    62  						},
    63  						UseClassNamesForArrayFields: true,
    64  					},
    65  					New: map[string]bool{
    66  						"go": true,
    67  					},
    68  				},
    69  				ConfigPath: filepath.Join(os.TempDir(), testDir, ".speakeasy/gen.yaml"),
    70  				LockFile: &LockFile{
    71  					LockVersion: Version,
    72  					ID:          "123",
    73  					Management:  Management{},
    74  					Features:    make(map[string]map[string]string),
    75  				},
    76  			},
    77  		},
    78  		{
    79  			name: "loads and upgrades pre v1.0.0 config file",
    80  			args: args{
    81  				langs:     []string{"go"},
    82  				configDir: testDir,
    83  				targetDir: testDir,
    84  				genYaml:   readTestFile(t, "pre-v100-gen.yaml"),
    85  			},
    86  			want: &Config{
    87  				Config: &Configuration{
    88  					ConfigVersion: Version,
    89  					Languages: map[string]LanguageConfig{
    90  						"go": {
    91  							Version: "1.3.0",
    92  							Cfg: map[string]any{
    93  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
    94  							},
    95  						},
    96  					},
    97  					Generation: Generation{
    98  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
    99  						SDKClassName:  "speakeasy",
   100  						UsageSnippets: &UsageSnippets{
   101  							OptionalPropertyRendering: "withExample",
   102  						},
   103  						Fixes: &Fixes{
   104  							NameResolutionDec2023:                false,
   105  							ParameterOrderingFeb2024:             false,
   106  							RequestResponseComponentNamesFeb2024: false,
   107  						},
   108  						Auth: &Auth{
   109  							OAuth2ClientCredentialsEnabled: false,
   110  						},
   111  					},
   112  					New: map[string]bool{},
   113  				},
   114  				ConfigPath: filepath.Join(os.TempDir(), testDir, "gen.yaml"),
   115  				LockFile: &LockFile{
   116  					LockVersion: Version,
   117  					ID:          "123",
   118  					Management: Management{
   119  						DocChecksum:      "2bba3b8f9d211b02569b3f9aff0d34b4",
   120  						DocVersion:       "0.3.0",
   121  						SpeakeasyVersion: "1.3.1",
   122  						ReleaseVersion:   "1.3.0",
   123  					},
   124  					Features: make(map[string]map[string]string),
   125  				},
   126  			},
   127  		},
   128  		{
   129  			name: "loads v1.0.0 config file",
   130  			args: args{
   131  				langs:        []string{"go"},
   132  				configDir:    testDir,
   133  				targetDir:    testDir,
   134  				genYaml:      readTestFile(t, "v100-gen.yaml"),
   135  				configSubDir: ".speakeasy",
   136  			},
   137  			want: &Config{
   138  				Config: &Configuration{
   139  					ConfigVersion: Version,
   140  					Languages: map[string]LanguageConfig{
   141  						"go": {
   142  							Version: "1.3.0",
   143  							Cfg: map[string]any{
   144  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   145  							},
   146  						},
   147  					},
   148  					Generation: Generation{
   149  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
   150  						SDKClassName:  "speakeasy",
   151  						UsageSnippets: &UsageSnippets{
   152  							OptionalPropertyRendering: "withExample",
   153  						},
   154  						Fixes: &Fixes{
   155  							NameResolutionDec2023:                false,
   156  							ParameterOrderingFeb2024:             false,
   157  							RequestResponseComponentNamesFeb2024: false,
   158  						},
   159  						Auth: &Auth{
   160  							OAuth2ClientCredentialsEnabled: false,
   161  						},
   162  					},
   163  					New: map[string]bool{},
   164  				},
   165  				ConfigPath: filepath.Join(os.TempDir(), testDir, ".speakeasy/gen.yaml"),
   166  				LockFile: &LockFile{
   167  					LockVersion: Version,
   168  					ID:          "123",
   169  					Management: Management{
   170  						DocChecksum:      "2bba3b8f9d211b02569b3f9aff0d34b4",
   171  						DocVersion:       "0.3.0",
   172  						SpeakeasyVersion: "1.3.1",
   173  						ReleaseVersion:   "1.3.0",
   174  					},
   175  					Features: map[string]map[string]string{
   176  						"go": {
   177  							"core": "2.90.0",
   178  						},
   179  					},
   180  				},
   181  			},
   182  		},
   183  		{
   184  			name: "loads v2.0.0 config file",
   185  			args: args{
   186  				langs:        []string{"go"},
   187  				configDir:    testDir,
   188  				targetDir:    testDir,
   189  				genYaml:      readTestFile(t, "v200-gen.yaml"),
   190  				lockFile:     readTestFile(t, "v200-gen.lock"),
   191  				configSubDir: ".speakeasy",
   192  			},
   193  			want: &Config{
   194  				Config: &Configuration{
   195  					ConfigVersion: Version,
   196  					Languages: map[string]LanguageConfig{
   197  						"go": {
   198  							Version: "1.3.0",
   199  							Cfg: map[string]any{
   200  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   201  							},
   202  						},
   203  					},
   204  					Generation: Generation{
   205  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
   206  						SDKClassName:  "speakeasy",
   207  						UsageSnippets: &UsageSnippets{
   208  							OptionalPropertyRendering: "withExample",
   209  						},
   210  						Fixes: &Fixes{
   211  							NameResolutionDec2023:                false,
   212  							ParameterOrderingFeb2024:             false,
   213  							RequestResponseComponentNamesFeb2024: false,
   214  						},
   215  						Auth: &Auth{
   216  							OAuth2ClientCredentialsEnabled: false,
   217  						},
   218  					},
   219  					New: map[string]bool{},
   220  				},
   221  				ConfigPath: filepath.Join(os.TempDir(), testDir, ".speakeasy/gen.yaml"),
   222  				LockFile: &LockFile{
   223  					LockVersion: Version,
   224  					ID:          "0f8fad5b-d9cb-469f-a165-70867728950e",
   225  					Management: Management{
   226  						DocChecksum:      "2bba3b8f9d211b02569b3f9aff0d34b4",
   227  						DocVersion:       "0.3.0",
   228  						SpeakeasyVersion: "1.3.1",
   229  						ReleaseVersion:   "1.3.0",
   230  					},
   231  					Features: map[string]map[string]string{
   232  						"go": {
   233  							"core": "2.90.0",
   234  						},
   235  					},
   236  				},
   237  			},
   238  		},
   239  		{
   240  			name: "loads v2.0.0 config file without existing lock file as a new sdk",
   241  			args: args{
   242  				langs:        []string{"go"},
   243  				configDir:    testDir,
   244  				targetDir:    testDir,
   245  				genYaml:      readTestFile(t, "v200-gen.yaml"),
   246  				configSubDir: ".speakeasy",
   247  			},
   248  			want: &Config{
   249  				Config: &Configuration{
   250  					ConfigVersion: Version,
   251  					Languages: map[string]LanguageConfig{
   252  						"go": {
   253  							Version: "1.3.0",
   254  							Cfg: map[string]any{
   255  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   256  							},
   257  						},
   258  					},
   259  					Generation: Generation{
   260  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
   261  						SDKClassName:  "speakeasy",
   262  						UsageSnippets: &UsageSnippets{
   263  							OptionalPropertyRendering: "withExample",
   264  						},
   265  						Fixes: &Fixes{
   266  							NameResolutionDec2023:                true,
   267  							ParameterOrderingFeb2024:             true,
   268  							RequestResponseComponentNamesFeb2024: true,
   269  						},
   270  						Auth: &Auth{
   271  							OAuth2ClientCredentialsEnabled: true,
   272  						},
   273  						MaintainOpenAPIOrder:        true,
   274  						UseClassNamesForArrayFields: true,
   275  					},
   276  					New: map[string]bool{
   277  						"go": true,
   278  					},
   279  				},
   280  				ConfigPath: filepath.Join(os.TempDir(), testDir, ".speakeasy/gen.yaml"),
   281  				LockFile: &LockFile{
   282  					LockVersion: Version,
   283  					ID:          "123",
   284  					Management:  Management{},
   285  					Features:    make(map[string]map[string]string),
   286  				},
   287  			},
   288  		},
   289  		{
   290  			name: "loads v2.0.0 config file without existing lock file as a new sdk from .gen folder",
   291  			args: args{
   292  				langs:        []string{"go"},
   293  				configDir:    testDir,
   294  				targetDir:    testDir,
   295  				genYaml:      readTestFile(t, "v200-gen.yaml"),
   296  				configSubDir: ".gen",
   297  			},
   298  			want: &Config{
   299  				Config: &Configuration{
   300  					ConfigVersion: Version,
   301  					Languages: map[string]LanguageConfig{
   302  						"go": {
   303  							Version: "1.3.0",
   304  							Cfg: map[string]any{
   305  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   306  							},
   307  						},
   308  					},
   309  					Generation: Generation{
   310  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
   311  						SDKClassName:  "speakeasy",
   312  						UsageSnippets: &UsageSnippets{
   313  							OptionalPropertyRendering: "withExample",
   314  						},
   315  						Fixes: &Fixes{
   316  							NameResolutionDec2023:                true,
   317  							ParameterOrderingFeb2024:             true,
   318  							RequestResponseComponentNamesFeb2024: true,
   319  						},
   320  						Auth: &Auth{
   321  							OAuth2ClientCredentialsEnabled: true,
   322  						},
   323  						MaintainOpenAPIOrder:        true,
   324  						UseClassNamesForArrayFields: true,
   325  					},
   326  					New: map[string]bool{
   327  						"go": true,
   328  					},
   329  				},
   330  				ConfigPath: filepath.Join(os.TempDir(), testDir, ".gen/gen.yaml"),
   331  				LockFile: &LockFile{
   332  					LockVersion: Version,
   333  					ID:          "123",
   334  					Management:  Management{},
   335  					Features:    make(map[string]map[string]string),
   336  				},
   337  			},
   338  		},
   339  		{
   340  			name: "loads v2.0.0 config file from higher level directory",
   341  			args: args{
   342  				langs:     []string{"go"},
   343  				configDir: filepath.Dir(testDir),
   344  				targetDir: testDir,
   345  				genYaml:   readTestFile(t, "v200-gen.yaml"),
   346  				lockFile:  readTestFile(t, "v200-gen.lock"),
   347  			},
   348  			want: &Config{
   349  				Config: &Configuration{
   350  					ConfigVersion: Version,
   351  					Languages: map[string]LanguageConfig{
   352  						"go": {
   353  							Version: "1.3.0",
   354  							Cfg: map[string]any{
   355  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   356  							},
   357  						},
   358  					},
   359  					Generation: Generation{
   360  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
   361  						SDKClassName:  "speakeasy",
   362  						UsageSnippets: &UsageSnippets{
   363  							OptionalPropertyRendering: "withExample",
   364  						},
   365  						Fixes: &Fixes{
   366  							NameResolutionDec2023:                false,
   367  							ParameterOrderingFeb2024:             false,
   368  							RequestResponseComponentNamesFeb2024: false,
   369  						},
   370  						Auth: &Auth{
   371  							OAuth2ClientCredentialsEnabled: false,
   372  						},
   373  					},
   374  					New: map[string]bool{},
   375  				},
   376  				ConfigPath: filepath.Join(os.TempDir(), filepath.Dir(testDir), "gen.yaml"),
   377  				LockFile: &LockFile{
   378  					LockVersion: Version,
   379  					ID:          "0f8fad5b-d9cb-469f-a165-70867728950e",
   380  					Management: Management{
   381  						DocChecksum:      "2bba3b8f9d211b02569b3f9aff0d34b4",
   382  						DocVersion:       "0.3.0",
   383  						SpeakeasyVersion: "1.3.1",
   384  						ReleaseVersion:   "1.3.0",
   385  					},
   386  					Features: map[string]map[string]string{
   387  						"go": {
   388  							"core": "2.90.0",
   389  						},
   390  					},
   391  				},
   392  			},
   393  		},
   394  		{
   395  			name: "loads v100 config file and detects new config for language",
   396  			args: args{
   397  				langs:     []string{"go", "typescript"},
   398  				configDir: testDir,
   399  				targetDir: testDir,
   400  				genYaml:   readTestFile(t, "v100-gen.yaml"),
   401  			},
   402  			want: &Config{
   403  				Config: &Configuration{
   404  					ConfigVersion: Version,
   405  					Languages: map[string]LanguageConfig{
   406  						"go": {
   407  							Version: "1.3.0",
   408  							Cfg: map[string]any{
   409  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   410  							},
   411  						},
   412  						"typescript": {
   413  							Version: "0.0.1",
   414  						},
   415  					},
   416  					Generation: Generation{
   417  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
   418  						SDKClassName:  "speakeasy",
   419  						UsageSnippets: &UsageSnippets{
   420  							OptionalPropertyRendering: "withExample",
   421  						},
   422  						Fixes: &Fixes{
   423  							NameResolutionDec2023:                false,
   424  							ParameterOrderingFeb2024:             false,
   425  							RequestResponseComponentNamesFeb2024: false,
   426  						},
   427  						Auth: &Auth{
   428  							OAuth2ClientCredentialsEnabled: false,
   429  						},
   430  					},
   431  					New: map[string]bool{
   432  						"typescript": true,
   433  					},
   434  				},
   435  				ConfigPath: filepath.Join(os.TempDir(), testDir, "gen.yaml"),
   436  				LockFile: &LockFile{
   437  					LockVersion: Version,
   438  					ID:          "123",
   439  					Management: Management{
   440  						DocChecksum:      "2bba3b8f9d211b02569b3f9aff0d34b4",
   441  						DocVersion:       "0.3.0",
   442  						SpeakeasyVersion: "1.3.1",
   443  						ReleaseVersion:   "1.3.0",
   444  					},
   445  					Features: map[string]map[string]string{
   446  						"go": {
   447  							"core": "2.90.0",
   448  						},
   449  					},
   450  				},
   451  			},
   452  		},
   453  		{
   454  			name: "loads v2.0.0 config file and detects new config for language",
   455  			args: args{
   456  				langs:        []string{"go", "typescript"},
   457  				configDir:    testDir,
   458  				targetDir:    testDir,
   459  				genYaml:      readTestFile(t, "v200-gen.yaml"),
   460  				lockFile:     readTestFile(t, "v200-gen.lock"),
   461  				configSubDir: ".speakeasy",
   462  			},
   463  			want: &Config{
   464  				Config: &Configuration{
   465  					ConfigVersion: Version,
   466  					Languages: map[string]LanguageConfig{
   467  						"go": {
   468  							Version: "1.3.0",
   469  							Cfg: map[string]any{
   470  								"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   471  							},
   472  						},
   473  						"typescript": {
   474  							Version: "0.0.1",
   475  						},
   476  					},
   477  					Generation: Generation{
   478  						BaseServerURL: "https://api.prod.speakeasyapi.dev",
   479  						SDKClassName:  "speakeasy",
   480  						UsageSnippets: &UsageSnippets{
   481  							OptionalPropertyRendering: "withExample",
   482  						},
   483  						Fixes: &Fixes{
   484  							NameResolutionDec2023:                false,
   485  							ParameterOrderingFeb2024:             false,
   486  							RequestResponseComponentNamesFeb2024: false,
   487  						},
   488  						Auth: &Auth{
   489  							OAuth2ClientCredentialsEnabled: false,
   490  						},
   491  					},
   492  					New: map[string]bool{
   493  						"typescript": true,
   494  					},
   495  				},
   496  				ConfigPath: filepath.Join(os.TempDir(), testDir, ".speakeasy/gen.yaml"),
   497  				LockFile: &LockFile{
   498  					LockVersion: Version,
   499  					ID:          "0f8fad5b-d9cb-469f-a165-70867728950e",
   500  					Management: Management{
   501  						DocChecksum:      "2bba3b8f9d211b02569b3f9aff0d34b4",
   502  						DocVersion:       "0.3.0",
   503  						SpeakeasyVersion: "1.3.1",
   504  						ReleaseVersion:   "1.3.0",
   505  					},
   506  					Features: map[string]map[string]string{
   507  						"go": {
   508  							"core": "2.90.0",
   509  						},
   510  					},
   511  				},
   512  			},
   513  		},
   514  	}
   515  	for _, tt := range tests {
   516  		t.Run(tt.name, func(t *testing.T) {
   517  			configDir := filepath.Join(os.TempDir(), tt.args.configDir)
   518  			if tt.args.configSubDir != "" {
   519  				configDir = filepath.Join(configDir, tt.args.configSubDir)
   520  			}
   521  			targetDir := filepath.Join(os.TempDir(), tt.args.targetDir)
   522  
   523  			lockFileDir := filepath.Join(targetDir, tt.args.configSubDir)
   524  			if tt.args.configSubDir == "" {
   525  				lockFileDir = filepath.Join(targetDir, ".speakeasy")
   526  			}
   527  
   528  			err := createTempFile(configDir, "gen.yaml", tt.args.genYaml)
   529  			require.NoError(t, err)
   530  
   531  			err = createTempFile(lockFileDir, "gen.lock", tt.args.lockFile)
   532  			require.NoError(t, err)
   533  
   534  			defer os.RemoveAll(configDir)
   535  			defer os.RemoveAll(targetDir)
   536  
   537  			opts := []Option{
   538  				WithUpgradeFunc(testUpdateLang),
   539  			}
   540  
   541  			for _, lang := range tt.args.langs {
   542  				opts = append(opts, WithLanguages(lang))
   543  			}
   544  
   545  			cfg, err := Load(targetDir, opts...)
   546  			assert.NoError(t, err)
   547  			assert.Equal(t, tt.want, cfg)
   548  			_, err = os.Stat(filepath.Join(configDir, "gen.yaml"))
   549  			assert.NoError(t, err)
   550  			_, err = os.Stat(filepath.Join(lockFileDir, "gen.lock"))
   551  			assert.NoError(t, err)
   552  		})
   553  	}
   554  }
   555  
   556  func TestLoad_BackwardsCompatibility_Success(t *testing.T) {
   557  	getUUID = func() string {
   558  		return "123"
   559  	}
   560  
   561  	// Create new config file in .speakeasy dir
   562  	speakeasyDir := filepath.Join(os.TempDir(), testDir, workspace.SpeakeasyFolder)
   563  	err := createTempFile(speakeasyDir, "gen.yaml", readTestFile(t, "v200-gen.yaml"))
   564  	require.NoError(t, err)
   565  
   566  	// Create old config file in root dir
   567  	rootDir := filepath.Join(os.TempDir(), testDir)
   568  	err = createTempFile(rootDir, "gen.yaml", readTestFile(t, "v100-gen.yaml"))
   569  	require.NoError(t, err)
   570  
   571  	defer os.RemoveAll(speakeasyDir)
   572  	defer os.RemoveAll(rootDir)
   573  
   574  	opts := []Option{
   575  		WithUpgradeFunc(testUpdateLang),
   576  	}
   577  
   578  	opts = append(opts, WithLanguages("go"))
   579  
   580  	cfg, err := Load(rootDir, opts...)
   581  	assert.NoError(t, err)
   582  	assert.Equal(t, &Config{
   583  		Config: &Configuration{
   584  			ConfigVersion: Version,
   585  			Languages: map[string]LanguageConfig{
   586  				"go": {
   587  					Version: "1.3.0",
   588  					Cfg: map[string]any{
   589  						"packageName": "github.com/speakeasy-api/speakeasy-client-sdk-go",
   590  					},
   591  				},
   592  			},
   593  			Generation: Generation{
   594  				BaseServerURL: "https://api.prod.speakeasyapi.dev",
   595  				SDKClassName:  "speakeasy",
   596  				UsageSnippets: &UsageSnippets{
   597  					OptionalPropertyRendering: "withExample",
   598  				},
   599  				Fixes: &Fixes{
   600  					NameResolutionDec2023:                false,
   601  					ParameterOrderingFeb2024:             false,
   602  					RequestResponseComponentNamesFeb2024: false,
   603  				},
   604  				Auth: &Auth{
   605  					OAuth2ClientCredentialsEnabled: false,
   606  				},
   607  			},
   608  			New: map[string]bool{},
   609  		},
   610  		ConfigPath: filepath.Join(os.TempDir(), testDir, "gen.yaml"),
   611  		LockFile: &LockFile{
   612  			LockVersion: Version,
   613  			ID:          "123",
   614  			Management: Management{
   615  				DocChecksum:      "2bba3b8f9d211b02569b3f9aff0d34b4",
   616  				DocVersion:       "0.3.0",
   617  				SpeakeasyVersion: "1.3.1",
   618  				ReleaseVersion:   "1.3.0",
   619  			},
   620  			Features: map[string]map[string]string{
   621  				"go": {
   622  					"core": "2.90.0",
   623  				},
   624  			},
   625  		},
   626  	}, cfg)
   627  	_, err = os.Stat(filepath.Join(rootDir, "gen.yaml"))
   628  	assert.NoError(t, err)
   629  	_, err = os.Stat(filepath.Join(speakeasyDir, "gen.lock"))
   630  	assert.NoError(t, err)
   631  }
   632  
   633  func createTempFile(dir string, fileName, contents string) error {
   634  	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
   635  		return err
   636  	}
   637  
   638  	if contents != "" {
   639  		tmpFile := filepath.Join(dir, fileName)
   640  		if err := os.WriteFile(tmpFile, []byte(contents), os.ModePerm); err != nil {
   641  			return err
   642  		}
   643  	}
   644  
   645  	return nil
   646  }
   647  
   648  func readTestFile(t *testing.T, file string) string {
   649  	t.Helper()
   650  	data, err := os.ReadFile(filepath.Join("testdata", file))
   651  	if err != nil {
   652  		t.Fatal(err)
   653  	}
   654  
   655  	return string(data)
   656  }