github.com/arduino/arduino-cloud-cli@v0.0.0-20240517070944-e7a449561083/config/credentials_test.go (about) 1 // This file is part of arduino-cloud-cli. 2 // 3 // Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/) 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published 7 // by the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18 package config 19 20 import ( 21 "os" 22 "testing" 23 24 "encoding/json" 25 26 "github.com/google/go-cmp/cmp" 27 ) 28 29 func TestRetrieveCredentials(t *testing.T) { 30 var ( 31 validSecret = "qaRZGEbnQNNvmaeTLqy8Bxs22wLZ6H7obIiNSveTLPdoQuylANnuy6WBOw16XoqH" 32 validClient = "CQ4iZ5sebOfhGRwUn3IV0r1YFMNrMTIx" 33 validOrganization = "dc6a6159-3cd5-41a2-b391-553b1351cd98" 34 validConfig = &Credentials{Client: validClient, Secret: validSecret} 35 validWithOptionalConfig = &Credentials{Client: validClient, Secret: validSecret, Organization: validOrganization} 36 invalidConfig = &Credentials{Client: "", Secret: validSecret} 37 clientEnv = EnvPrefix + "_CLIENT" 38 secretEnv = EnvPrefix + "_SECRET" 39 organizationEnv = EnvPrefix + "_ORGANIZATION" 40 ) 41 42 tests := []struct { 43 name string 44 pre func() 45 post func() 46 wantedConfig *Credentials 47 wantedErr bool 48 }{ 49 { 50 name: "valid credentials with only mandatory params written in env", 51 pre: func() { 52 os.Setenv(clientEnv, validConfig.Client) 53 os.Setenv(secretEnv, validConfig.Secret) 54 }, 55 post: func() { 56 os.Unsetenv(clientEnv) 57 os.Unsetenv(secretEnv) 58 }, 59 wantedConfig: validConfig, 60 wantedErr: false, 61 }, 62 63 { 64 name: "valid credentials with optional params written in env", 65 pre: func() { 66 os.Setenv(clientEnv, validWithOptionalConfig.Client) 67 os.Setenv(secretEnv, validWithOptionalConfig.Secret) 68 os.Setenv(organizationEnv, validWithOptionalConfig.Organization) 69 }, 70 post: func() { 71 os.Unsetenv(clientEnv) 72 os.Unsetenv(secretEnv) 73 os.Unsetenv(organizationEnv) 74 }, 75 wantedConfig: validWithOptionalConfig, 76 wantedErr: false, 77 }, 78 79 { 80 name: "invalid credentials written in env", 81 pre: func() { 82 os.Setenv(clientEnv, validConfig.Client) 83 os.Setenv(secretEnv, "") 84 }, 85 post: func() { 86 os.Unsetenv(clientEnv) 87 os.Unsetenv(secretEnv) 88 }, 89 wantedConfig: nil, 90 wantedErr: true, 91 }, 92 93 { 94 name: "valid credentials written in parent of cwd", 95 pre: func() { 96 parent := "test-parent" 97 cwd := "test-parent/test-cwd" 98 os.MkdirAll(cwd, os.FileMode(0777)) 99 // Write valid credentials in parent dir 100 os.Chdir(parent) 101 b, _ := json.Marshal(validConfig) 102 os.WriteFile(CredentialsFilename+".json", b, os.FileMode(0777)) 103 // Cwd has no credentials file 104 os.Chdir("test-cwd") 105 }, 106 post: func() { 107 os.Chdir("../..") 108 os.RemoveAll("test-parent") 109 }, 110 wantedConfig: validConfig, 111 wantedErr: false, 112 }, 113 114 { 115 name: "valid credentials with optional params written in parent of cwd", 116 pre: func() { 117 parent := "test-parent" 118 cwd := "test-parent/test-cwd" 119 os.MkdirAll(cwd, os.FileMode(0777)) 120 // Write valid credentials in parent dir 121 os.Chdir(parent) 122 b, _ := json.Marshal(validWithOptionalConfig) 123 os.WriteFile(CredentialsFilename+".json", b, os.FileMode(0777)) 124 // Cwd has no credentials file 125 os.Chdir("test-cwd") 126 }, 127 post: func() { 128 os.Chdir("../..") 129 os.RemoveAll("test-parent") 130 }, 131 wantedConfig: validWithOptionalConfig, 132 wantedErr: false, 133 }, 134 135 { 136 name: "invalid credentials written in cwd, ignore credentials of parent dir", 137 pre: func() { 138 parent := "test-parent" 139 cwd := "test-parent/test-cwd" 140 os.MkdirAll(cwd, os.FileMode(0777)) 141 // Write valid credentials in parent dir 142 os.Chdir(parent) 143 b, _ := json.Marshal(validConfig) 144 os.WriteFile(CredentialsFilename+".json", b, os.FileMode(0777)) 145 // Write invalid credentials in cwd 146 os.Chdir("test-cwd") 147 b, _ = json.Marshal(invalidConfig) 148 os.WriteFile(CredentialsFilename+".json", b, os.FileMode(0777)) 149 }, 150 post: func() { 151 os.Chdir("../..") 152 os.RemoveAll("test-parent") 153 os.Unsetenv(clientEnv) 154 os.Unsetenv(secretEnv) 155 }, 156 wantedConfig: nil, 157 wantedErr: true, 158 }, 159 160 { 161 name: "invalid credentials written in env, ignore valid credentials of cwd", 162 pre: func() { 163 cwd := "test-cwd" 164 os.MkdirAll(cwd, os.FileMode(0777)) 165 // Write valid credentials in cwd 166 os.Chdir(cwd) 167 b, _ := json.Marshal(validConfig) 168 os.WriteFile(CredentialsFilename+".json", b, os.FileMode(0777)) 169 // Write invalid credentials in env 170 os.Setenv(clientEnv, validConfig.Client) 171 os.Setenv(secretEnv, "") 172 }, 173 post: func() { 174 os.Chdir("..") 175 os.RemoveAll("test-cwd") 176 }, 177 wantedConfig: nil, 178 wantedErr: true, 179 }, 180 } 181 182 for _, tt := range tests { 183 t.Run(tt.name, func(t *testing.T) { 184 tt.pre() 185 got, err := RetrieveCredentials() 186 tt.post() 187 188 if tt.wantedErr && err == nil { 189 t.Errorf("Expected an error, but got nil") 190 } 191 if !tt.wantedErr && err != nil { 192 t.Errorf("Expected nil error, but got: %v", err) 193 } 194 195 if !cmp.Equal(got, tt.wantedConfig) { 196 t.Errorf("Wrong credentials received, diff:\n%s", cmp.Diff(tt.wantedConfig, got)) 197 } 198 }) 199 } 200 } 201 202 func TestValidate(t *testing.T) { 203 var ( 204 validSecret = "qaRZGEbnQNNvmaeTLqy8Bxs22wLZ6H7obIiNSveTLPdoQuylANnuy6WBOw16XoqH" 205 validClient = "CQ4iZ5sebOfhGRwUn3IV0r1YFMNrMTIx" 206 validOrganization = "dc6a6159-3cd5-41a2-b391-553b1351cd98" 207 ) 208 tests := []struct { 209 name string 210 config *Credentials 211 valid bool 212 }{ 213 { 214 name: "valid credentials", 215 config: &Credentials{Client: validClient, Secret: validSecret, Organization: validOrganization}, 216 valid: true, 217 }, 218 { 219 name: "valid credentials, organization is optional", 220 config: &Credentials{Client: validClient, Secret: validSecret, Organization: ""}, 221 valid: true, 222 }, 223 { 224 name: "invalid client id", 225 config: &Credentials{Client: "", Secret: validSecret}, 226 valid: false, 227 }, 228 { 229 name: "invalid client secret", 230 config: &Credentials{Client: validClient, Secret: ""}, 231 valid: false, 232 }, 233 } 234 235 for _, tt := range tests { 236 t.Run(tt.name, func(t *testing.T) { 237 err := tt.config.Validate() 238 if tt.valid && err != nil { 239 t.Errorf( 240 "Wrong validation, the credentials were correct but an error was received: \ncredentials: %v\nerr: %v", 241 tt.config, 242 err, 243 ) 244 } 245 if !tt.valid && err == nil { 246 t.Errorf( 247 "Wrong validation, the credentials were invalid but no error was received: \ncredentials: %v", 248 tt.config, 249 ) 250 } 251 }) 252 } 253 } 254 255 func TestIsEmpty(t *testing.T) { 256 var ( 257 validSecret = "qaRZGEbnQNNvmaeTLqy8Bxs22wLZ6H7obIiNSveTLPdoQuylANnuy6WBOw16XoqH" 258 validClient = "CQ4iZ5sebOfhGRwUn3IV0r1YFMNrMTIx" 259 validOrganization = "dc6a6159-3cd5-41a2-b391-553b1351cd98" 260 ) 261 tests := []struct { 262 name string 263 config *Credentials 264 want bool 265 }{ 266 { 267 name: "empty credentials", 268 config: &Credentials{Client: "", Secret: "", Organization: ""}, 269 want: true, 270 }, 271 { 272 name: "empty mandatory credentials - optionals given", 273 config: &Credentials{Client: "", Secret: "", Organization: validOrganization}, 274 want: true, 275 }, 276 { 277 name: "credentials without id", 278 config: &Credentials{Client: "", Secret: validSecret}, 279 want: false, 280 }, 281 { 282 name: "credentials without secret", 283 config: &Credentials{Client: validClient, Secret: ""}, 284 want: false, 285 }, 286 { 287 name: "credentials with all mandatory params set", 288 config: &Credentials{Client: validClient, Secret: validSecret}, 289 want: false, 290 }, 291 } 292 293 for _, tt := range tests { 294 t.Run(tt.name, func(t *testing.T) { 295 got := tt.config.IsEmpty() 296 if got != tt.want { 297 t.Errorf("Expected %v but got %v, with credentials: %v", tt.want, got, tt.config) 298 } 299 }) 300 } 301 }