Merge pull request #1780 from ywk253100/170322_refactor_adminserver_test

Refactor uts of adminserver
This commit is contained in:
Daniel Jiang 2017-03-27 16:23:03 +08:00 committed by GitHub
commit 8cfdd1f5cc
8 changed files with 562 additions and 412 deletions

View File

@ -20,13 +20,13 @@ import (
"io/ioutil"
"net/http"
cfg "github.com/vmware/harbor/src/adminserver/systemcfg"
"github.com/vmware/harbor/src/adminserver/systemcfg"
"github.com/vmware/harbor/src/common/utils/log"
)
// ListCfgs lists configurations
func ListCfgs(w http.ResponseWriter, r *http.Request) {
cfg, err := cfg.GetSystemCfg()
cfg, err := systemcfg.CfgStore.Read()
if err != nil {
log.Errorf("failed to get system configurations: %v", err)
handleInternalServerError(w)
@ -54,7 +54,7 @@ func UpdateCfgs(w http.ResponseWriter, r *http.Request) {
return
}
if err = cfg.UpdateSystemCfg(m); err != nil {
if err = systemcfg.CfgStore.Write(m); err != nil {
log.Errorf("failed to update system configurations: %v", err)
handleInternalServerError(w)
return
@ -63,9 +63,16 @@ func UpdateCfgs(w http.ResponseWriter, r *http.Request) {
// ResetCfgs resets configurations from environment variables
func ResetCfgs(w http.ResponseWriter, r *http.Request) {
if err := cfg.Reset(); err != nil {
cfgs := map[string]interface{}{}
if err := systemcfg.LoadFromEnv(cfgs, true); err != nil {
log.Errorf("failed to reset system configurations: %v", err)
handleInternalServerError(w)
return
}
if err := systemcfg.CfgStore.Write(cfgs); err != nil {
log.Errorf("failed to write system configurations to storage: %v", err)
handleInternalServerError(w)
return
}
}

View File

@ -18,6 +18,8 @@ package api
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
@ -25,189 +27,132 @@ import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/src/adminserver/systemcfg"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/utils/test"
)
func TestConfigAPI(t *testing.T) {
configPath := "/tmp/config.json"
secretKeyPath := "/tmp/secretkey"
type fakeCfgStore struct {
cfgs map[string]interface{}
err error
}
_, err := test.GenerateKey(secretKeyPath)
if err != nil {
t.Errorf("failed to generate secret key: %v", err)
return
func (f *fakeCfgStore) Name() string {
return "fake"
}
func (f *fakeCfgStore) Read() (map[string]interface{}, error) {
return f.cfgs, f.err
}
func (f *fakeCfgStore) Write(cfgs map[string]interface{}) error {
f.cfgs = cfgs
return f.err
}
func TestListCfgs(t *testing.T) {
// 500
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: errors.New("error"),
}
defer os.Remove(secretKeyPath)
secret := "secret"
envs := map[string]string{
"AUTH_MODE": common.DBAuth,
"JSON_CFG_STORE_PATH": configPath,
"KEY_PATH": secretKeyPath,
"UI_SECRET": secret,
"MYSQL_PORT": "3306",
"TOKEN_EXPIRATION": "30",
"CFG_EXPIRATION": "5",
"MAX_JOB_WORKERS": "3",
"LDAP_SCOPE": "3",
"LDAP_TIMEOUT": "30",
"EMAIL_PORT": "25",
"MYSQL_PWD": "",
"LDAP_SEARCH_PWD": "",
"EMAIL_PWD": "",
"HARBOR_ADMIN_PASSWORD": "",
}
for k, v := range envs {
if err := os.Setenv(k, v); err != nil {
t.Errorf("failed to set env %s: %v", k, err)
return
}
}
defer os.Remove(configPath)
if err := systemcfg.Init(); err != nil {
t.Errorf("failed to initialize system configurations: %v", err)
return
}
r, err := http.NewRequest("GET", "", nil)
if err != nil {
t.Errorf("failed to create request: %v", err)
return
}
r.AddCookie(&http.Cookie{
Name: "secret",
Value: secret,
})
w := httptest.NewRecorder()
ListCfgs(w, r)
if w.Code != http.StatusOK {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK)
return
}
ListCfgs(w, nil)
assert.Equal(t, http.StatusInternalServerError, w.Code)
m, err := parse(w.Body)
if err != nil {
t.Errorf("failed to parse response body: %v", err)
return
// 200
key := "key"
value := "value"
cfgs := map[string]interface{}{
key: value,
}
scope := int(m[common.LDAPScope].(float64))
if scope != 3 {
t.Errorf("unexpected ldap scope: %d != %d", scope, 3)
return
systemcfg.CfgStore = &fakeCfgStore{
cfgs: cfgs,
err: nil,
}
// modify configurations
c := map[string]interface{}{
common.AUTHMode: common.LDAPAuth,
}
b, err := json.Marshal(c)
if err != nil {
t.Errorf("failed to marshal configuartions: %v", err)
return
}
w = httptest.NewRecorder()
r, err = http.NewRequest("GET", "", bytes.NewReader(b))
ListCfgs(w, nil)
assert.Equal(t, http.StatusOK, w.Code)
result, err := parse(w.Body)
if err != nil {
t.Errorf("failed to create request: %v", err)
return
t.Fatalf("failed to parse response body: %v", err)
}
assert.Equal(t, value, result[key])
}
func TestUpdateCfgs(t *testing.T) {
// 400
w := httptest.NewRecorder()
r, err := http.NewRequest("", "", bytes.NewReader([]byte{'a'}))
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
r.AddCookie(&http.Cookie{
Name: "secret",
Value: secret,
})
UpdateCfgs(w, r)
assert.Equal(t, http.StatusBadRequest, w.Code)
if w.Code != http.StatusOK {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK)
return
// 500
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: errors.New("error"),
}
// confirm the modification is done
r, err = http.NewRequest("GET", "", nil)
if err != nil {
t.Errorf("failed to create request: %v", err)
return
}
r.AddCookie(&http.Cookie{
Name: "secret",
Value: secret,
})
w = httptest.NewRecorder()
ListCfgs(w, r)
if w.Code != http.StatusOK {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK)
return
}
m, err = parse(w.Body)
r, err = http.NewRequest("", "", bytes.NewBufferString("{}"))
if err != nil {
t.Errorf("failed to parse response body: %v", err)
return
t.Fatalf("failed to create request: %v", err)
}
mode := m[common.AUTHMode].(string)
if mode != common.LDAPAuth {
t.Errorf("unexpected auth mode: %s != %s", mode, common.LDAPAuth)
return
}
UpdateCfgs(w, r)
assert.Equal(t, http.StatusInternalServerError, w.Code)
// reset configurations
// 200
key := "key"
value := "value"
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: nil,
}
w = httptest.NewRecorder()
r, err = http.NewRequest("POST", "", nil)
r, err = http.NewRequest("", "",
bytes.NewBufferString(fmt.Sprintf(`{"%s":"%s"}`, key, value)))
if err != nil {
t.Errorf("failed to create request: %v", err)
return
}
r.AddCookie(&http.Cookie{
Name: "secret",
Value: secret,
})
ResetCfgs(w, r)
if w.Code != http.StatusOK {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK)
return
t.Fatalf("failed to create request: %v", err)
}
// confirm the reset
r, err = http.NewRequest("GET", "", nil)
if err != nil {
t.Errorf("failed to create request: %v", err)
return
UpdateCfgs(w, r)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestResetCfgs(t *testing.T) {
// 500
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: errors.New("error"),
}
r.AddCookie(&http.Cookie{
Name: "secret",
Value: secret,
})
w := httptest.NewRecorder()
ResetCfgs(w, nil)
assert.Equal(t, http.StatusInternalServerError, w.Code)
// 200
os.Clearenv()
key := "LDAP_URL"
value := "ldap://ldap.com"
if err := os.Setenv(key, value); err != nil {
t.Fatalf("failed to set env: %v", err)
}
store := &fakeCfgStore{
cfgs: nil,
err: nil,
}
systemcfg.CfgStore = store
w = httptest.NewRecorder()
ListCfgs(w, r)
if w.Code != http.StatusOK {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK)
return
}
m, err = parse(w.Body)
if err != nil {
t.Errorf("failed to parse response body: %v", err)
return
}
mode = m[common.AUTHMode].(string)
if mode != common.DBAuth {
t.Errorf("unexpected auth mode: %s != %s", mode, common.LDAPAuth)
return
}
ResetCfgs(w, nil)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, value, store.cfgs[common.LDAPURL])
}
func parse(reader io.Reader) (map[string]interface{}, error) {

View File

@ -0,0 +1,61 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package encrypt
import (
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/utils"
)
// Encryptor encrypts or decrypts a strings
type Encryptor interface {
// Encrypt encrypts plaintext
Encrypt(string) (string, error)
// Decrypt decrypts ciphertext
Decrypt(string) (string, error)
}
// AESEncryptor uses AES to encrypt or decrypt string
type AESEncryptor struct {
keyProvider comcfg.KeyProvider
keyParams map[string]interface{}
}
// NewAESEncryptor returns an instance of an AESEncryptor
func NewAESEncryptor(keyProvider comcfg.KeyProvider,
keyParams map[string]interface{}) Encryptor {
return &AESEncryptor{
keyProvider: keyProvider,
}
}
// Encrypt ...
func (a *AESEncryptor) Encrypt(plaintext string) (string, error) {
key, err := a.keyProvider.Get(a.keyParams)
if err != nil {
return "", err
}
return utils.ReversibleEncrypt(plaintext, key)
}
// Decrypt ...
func (a *AESEncryptor) Decrypt(ciphertext string) (string, error) {
key, err := a.keyProvider.Get(a.keyParams)
if err != nil {
return "", err
}
return utils.ReversibleDecrypt(ciphertext, key)
}

View File

@ -0,0 +1,93 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package encrypt
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
comcfg "github.com/vmware/harbor/src/common/config"
)
type fakeKeyProvider struct {
key string
err error
}
func (f *fakeKeyProvider) Get(params map[string]interface{}) (
string, error) {
return f.key, f.err
}
func TestEncrypt(t *testing.T) {
cases := []struct {
plaintext string
keyProvider comcfg.KeyProvider
err bool
}{
{"", &fakeKeyProvider{"", errors.New("error")}, true},
{"text", &fakeKeyProvider{"1234567890123456", nil}, false},
}
for _, c := range cases {
encrptor := NewAESEncryptor(c.keyProvider, nil)
ciphertext, err := encrptor.Encrypt(c.plaintext)
if c.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
str, err := encrptor.Decrypt(ciphertext)
assert.Nil(t, err)
assert.Equal(t, c.plaintext, str)
}
}
}
func TestDecrypt(t *testing.T) {
plaintext := "text"
key := "1234567890123456"
encrptor := NewAESEncryptor(&fakeKeyProvider{
key: key,
err: nil,
}, nil)
ciphertext, err := encrptor.Encrypt(plaintext)
if err != nil {
t.Fatalf("failed to encrpt %s: %v", plaintext, err)
}
cases := []struct {
ciphertext string
keyProvider comcfg.KeyProvider
err bool
}{
{"", &fakeKeyProvider{"", errors.New("error")}, true},
{ciphertext, &fakeKeyProvider{key, nil}, false},
}
for _, c := range cases {
encrptor := NewAESEncryptor(c.keyProvider, nil)
str, err := encrptor.Decrypt(c.ciphertext)
if c.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, plaintext, str)
}
}
}

View File

@ -0,0 +1,98 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package encrypt
import (
"github.com/vmware/harbor/src/adminserver/systemcfg/encrypt"
"github.com/vmware/harbor/src/adminserver/systemcfg/store"
"github.com/vmware/harbor/src/common/utils/log"
)
const (
name = "encrypt"
)
// cfgStore wraps a store.Driver with an encryptor
type cfgStore struct {
// attrs need to be encrypted and decrypted
keys []string
encryptor encrypt.Encryptor
store store.Driver
}
// NewCfgStore returns an instance of cfgStore
// keys are the attrs need to be encrypted or decrypted
func NewCfgStore(encryptor encrypt.Encryptor,
keys []string, store store.Driver) store.Driver {
return &cfgStore{
keys: keys,
encryptor: encryptor,
store: store,
}
}
func (c *cfgStore) Name() string {
return name
}
func (c *cfgStore) Read() (map[string]interface{}, error) {
m, err := c.store.Read()
if err != nil {
return nil, err
}
for _, key := range c.keys {
v, ok := m[key]
if !ok {
continue
}
str, ok := v.(string)
if !ok {
log.Warningf("%v is not string, skip decrypt", v)
continue
}
text, err := c.encryptor.Decrypt(str)
if err != nil {
return nil, err
}
m[key] = text
}
return m, nil
}
func (c *cfgStore) Write(m map[string]interface{}) error {
for _, key := range c.keys {
v, ok := m[key]
if !ok {
continue
}
str, ok := v.(string)
if !ok {
log.Warningf("%v is not string, skip encrypt", v)
continue
}
ciphertext, err := c.encryptor.Encrypt(str)
if err != nil {
return err
}
m[key] = ciphertext
}
return c.store.Write(m)
}

View File

@ -0,0 +1,82 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package encrypt
import (
"testing"
"github.com/stretchr/testify/assert"
)
type fakeCfgStore struct {
cfgs map[string]interface{}
}
func (f *fakeCfgStore) Name() string {
return "fake"
}
func (f *fakeCfgStore) Read() (map[string]interface{}, error) {
return f.cfgs, nil
}
func (f *fakeCfgStore) Write(cfgs map[string]interface{}) error {
f.cfgs = cfgs
return nil
}
type fakeEncryptor struct {
}
func (f *fakeEncryptor) Encrypt(plaintext string) (string, error) {
return "encrypted" + plaintext, nil
}
func (f *fakeEncryptor) Decrypt(ciphertext string) (string, error) {
return "decrypted" + ciphertext, nil
}
func TestName(t *testing.T) {
driver := NewCfgStore(nil, nil, nil)
assert.Equal(t, name, driver.Name())
}
func TestRead(t *testing.T) {
keys := []string{"key"}
driver := NewCfgStore(&fakeEncryptor{}, keys, &fakeCfgStore{
cfgs: map[string]interface{}{"key": "value"},
})
cfgs, err := driver.Read()
assert.Nil(t, err)
assert.Equal(t, "decryptedvalue", cfgs["key"])
}
func TestWrite(t *testing.T) {
keys := []string{"key"}
store := &fakeCfgStore{
cfgs: map[string]interface{}{},
}
driver := NewCfgStore(&fakeEncryptor{}, keys, store)
cfgs := map[string]interface{}{
"key": "value",
}
err := driver.Write(cfgs)
assert.Nil(t, err)
assert.Equal(t, "encryptedvalue", store.cfgs["key"])
}

View File

@ -21,23 +21,24 @@ import (
"strconv"
"strings"
enpt "github.com/vmware/harbor/src/adminserver/systemcfg/encrypt"
"github.com/vmware/harbor/src/adminserver/systemcfg/store"
"github.com/vmware/harbor/src/adminserver/systemcfg/store/encrypt"
"github.com/vmware/harbor/src/adminserver/systemcfg/store/json"
"github.com/vmware/harbor/src/common"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/utils"
"github.com/vmware/harbor/src/common/utils/log"
)
const (
defaultCfgStoreDriver string = "json"
defaultJSONCfgStorePath string = "/etc/adminserver/config.json"
defaultKeyPath string = "/etc/adminserver/key"
)
var (
cfgStore store.Driver
keyProvider comcfg.KeyProvider
// CfgStore is a storage driver that configurations
// can be read from and wrote to
CfgStore store.Driver
// attrs need to be encrypted or decrypted
attrs = []string{
@ -157,6 +158,9 @@ type parser struct {
}
func parseStringToInt(str string) (interface{}, error) {
if len(str) == 0 {
return 0, nil
}
return strconv.Atoi(str)
}
@ -165,80 +169,65 @@ func parseStringToBool(str string) (interface{}, error) {
strings.ToLower(str) == "on", nil
}
// Init system configurations. Read from config store first,
// if null read from env
// Init system configurations. If env RESET is set or configurations
// read from storage driver is null, load all configurations from env
func Init() (err error) {
//init configuation store
if err = initCfgStore(); err != nil {
return err
}
//init key provider
initKeyProvider()
loadAll := false
cfgs := map[string]interface{}{}
if os.Getenv("RESET") == "true" {
log.Info("RESET is set, resetting system configurations...")
return Reset()
log.Info("RESET is set, will load all configurations from environment variables")
loadAll = true
}
cfg, err := GetSystemCfg()
if err != nil {
if !loadAll {
cfgs, err = CfgStore.Read()
if cfgs == nil {
log.Info("configurations read from storage driver are null, will load them from environment variables")
loadAll = true
cfgs = map[string]interface{}{}
}
}
if err = LoadFromEnv(cfgs, loadAll); err != nil {
return err
}
if cfg != nil {
if err = loadFromEnv(cfg, false); err != nil {
return err
}
} else {
log.Info("configurations read from store driver are null, initializing system from environment variables...")
cfg = make(map[string]interface{})
if err = loadFromEnv(cfg, true); err != nil {
return err
}
}
//sync configurations into cfg store
log.Info("updating system configurations...")
return UpdateSystemCfg(cfg)
return CfgStore.Write(cfgs)
}
func initCfgStore() (err error) {
t := os.Getenv("CFG_STORE_DRIVER")
if len(t) == 0 {
t = defaultCfgStoreDriver
}
log.Infof("configuration store driver: %s", t)
switch t {
case "json":
path := os.Getenv("JSON_CFG_STORE_PATH")
if len(path) == 0 {
path = defaultJSONCfgStorePath
}
log.Infof("json configuration store path: %s", path)
cfgStore, err = json.NewCfgStore(path)
default:
err = fmt.Errorf("unsupported configuration store driver %s", t)
}
return err
}
func initKeyProvider() {
path := os.Getenv("KEY_PATH")
path := os.Getenv("JSON_CFG_STORE_PATH")
if len(path) == 0 {
path = defaultKeyPath
path = defaultJSONCfgStorePath
}
log.Infof("key path: %s", path)
log.Infof("the path of json configuration storage: %s", path)
keyProvider = comcfg.NewFileKeyProvider(path)
CfgStore, err = json.NewCfgStore(path)
if err != nil {
return
}
kp := os.Getenv("KEY_PATH")
if len(kp) == 0 {
kp = defaultKeyPath
}
log.Infof("the path of key used by key provider: %s", kp)
encryptor := enpt.NewAESEncryptor(
comcfg.NewFileKeyProvider(kp), nil)
CfgStore = encrypt.NewCfgStore(encryptor, attrs, CfgStore)
return nil
}
// load the configurations from allEnvs, if all is false, it just loads
// LoadFromEnv loads the configurations from allEnvs, if all is false, it just loads
// the repeatLoadEnvs
func loadFromEnv(cfg map[string]interface{}, all bool) error {
func LoadFromEnv(cfgs map[string]interface{}, all bool) error {
envs := repeatLoadEnvs
if all {
envs = allEnvs
@ -246,7 +235,7 @@ func loadFromEnv(cfg map[string]interface{}, all bool) error {
for k, v := range envs {
if str, ok := v.(string); ok {
cfg[k] = os.Getenv(str)
cfgs[k] = os.Getenv(str)
continue
}
@ -255,7 +244,7 @@ func loadFromEnv(cfg map[string]interface{}, all bool) error {
if err != nil {
return err
}
cfg[k] = i
cfgs[k] = i
continue
}
@ -264,90 +253,3 @@ func loadFromEnv(cfg map[string]interface{}, all bool) error {
return nil
}
// GetSystemCfg returns the system configurations
func GetSystemCfg() (map[string]interface{}, error) {
m, err := cfgStore.Read()
if err != nil {
return nil, err
}
key, err := keyProvider.Get(nil)
if err != nil {
return nil, fmt.Errorf("failed to get key: %v", err)
}
if err = decrypt(m, attrs, key); err != nil {
return nil, err
}
return m, nil
}
// UpdateSystemCfg updates the system configurations
func UpdateSystemCfg(cfg map[string]interface{}) error {
key, err := keyProvider.Get(nil)
if err != nil {
return fmt.Errorf("failed to get key: %v", err)
}
if err := encrypt(cfg, attrs, key); err != nil {
return err
}
return cfgStore.Write(cfg)
}
func encrypt(m map[string]interface{}, keys []string, secretKey string) error {
for _, key := range keys {
v, ok := m[key]
if !ok {
continue
}
if len(v.(string)) == 0 {
continue
}
cipherText, err := utils.ReversibleEncrypt(v.(string), secretKey)
if err != nil {
return err
}
m[key] = cipherText
}
return nil
}
func decrypt(m map[string]interface{}, keys []string, secretKey string) error {
for _, key := range keys {
v, ok := m[key]
if !ok {
continue
}
if len(v.(string)) == 0 {
continue
}
text, err := utils.ReversibleDecrypt(v.(string), secretKey)
if err != nil {
return err
}
m[key] = text
}
return nil
}
// Reset clears old system configurations and reloads them
// from environment variables
func Reset() error {
cfg := map[string]interface{}{}
if err := loadFromEnv(cfg, true); err != nil {
return err
}
//sync configurations into cfg store
log.Info("updating system configurations...")
return UpdateSystemCfg(cfg)
}

View File

@ -19,119 +19,81 @@ import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/utils/test"
)
// test functions in adminserver/systemcfg/systemcfg.go
func TestSystemcfg(t *testing.T) {
configPath := "/tmp/config.json"
if _, err := os.Stat(configPath); err == nil {
if err := os.Remove(configPath); err != nil {
t.Errorf("failed to remove %s: %v", configPath, err)
return
}
} else if !os.IsNotExist(err) {
t.Errorf("failed to check the existence of %s: %v", configPath, err)
return
func TestParseStringToInt(t *testing.T) {
cases := []struct {
input string
result int
}{
{"1", 1},
{"-1", -1},
{"0", 0},
{"", 0},
}
if err := os.Setenv("JSON_CFG_STORE_PATH", configPath); err != nil {
t.Errorf("failed to set env: %v", err)
return
}
keyPath := "/tmp/secretkey"
if _, err := test.GenerateKey(keyPath); err != nil {
t.Errorf("failed to generate key: %v", err)
return
}
defer os.Remove(keyPath)
if err := os.Setenv("KEY_PATH", keyPath); err != nil {
t.Errorf("failed to set env: %v", err)
return
}
m := map[string]string{
"AUTH_MODE": common.DBAuth,
"LDAP_SCOPE": "1",
"LDAP_TIMEOUT": "30",
"MYSQL_PORT": "3306",
"MAX_JOB_WORKERS": "3",
"TOKEN_EXPIRATION": "30",
"CFG_EXPIRATION": "5",
"EMAIL_PORT": "25",
"MYSQL_PWD": "",
"LDAP_SEARCH_PWD": "",
"EMAIL_PWD": "",
"HARBOR_ADMIN_PASSWORD": "",
}
for k, v := range m {
if err := os.Setenv(k, v); err != nil {
t.Fatalf("failed to set env %s: %v", k, err)
}
}
if err := Init(); err != nil {
t.Errorf("failed to initialize system configurations: %v", err)
return
}
defer os.Remove(configPath)
// run Init again to make sure it works well when the configuration file
// already exists
if err := Init(); err != nil {
t.Errorf("failed to initialize system configurations: %v", err)
return
}
cfg, err := GetSystemCfg()
if err != nil {
t.Errorf("failed to get system configurations: %v", err)
return
}
if cfg[common.AUTHMode] != common.DBAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[common.AUTHMode], common.DBAuth)
return
}
cfg[common.AUTHMode] = common.LDAPAuth
if err = UpdateSystemCfg(cfg); err != nil {
t.Errorf("failed to update system configurations: %v", err)
return
}
cfg, err = GetSystemCfg()
if err != nil {
t.Errorf("failed to get system configurations: %v", err)
return
}
if cfg[common.AUTHMode] != common.LDAPAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[common.AUTHMode], common.DBAuth)
return
}
if err = Reset(); err != nil {
t.Errorf("failed to reset system configurations: %v", err)
return
}
cfg, err = GetSystemCfg()
if err != nil {
t.Errorf("failed to get system configurations: %v", err)
return
}
if cfg[common.AUTHMode] != common.DBAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[common.AUTHMode], common.DBAuth)
return
for _, c := range cases {
i, err := parseStringToInt(c.input)
assert.Nil(t, err)
assert.Equal(t, c.result, i)
}
}
func TestParseStringToBool(t *testing.T) {
cases := []struct {
input string
result bool
}{
{"true", true},
{"on", true},
{"TRUE", true},
{"ON", true},
{"other", false},
{"", false},
}
for _, c := range cases {
b, _ := parseStringToBool(c.input)
assert.Equal(t, c.result, b)
}
}
func TestInitCfgStore(t *testing.T) {
os.Clearenv()
path := "/tmp/config.json"
if err := os.Setenv("JSON_CFG_STORE_PATH", path); err != nil {
t.Fatalf("failed to set env: %v", err)
}
defer os.RemoveAll(path)
err := initCfgStore()
assert.Nil(t, err)
}
func TestLoadFromEnv(t *testing.T) {
os.Clearenv()
ldapURL := "ldap://ldap.com"
extEndpoint := "http://harbor.com"
if err := os.Setenv("LDAP_URL", ldapURL); err != nil {
t.Fatalf("failed to set env: %v", err)
}
cfgs := map[string]interface{}{}
err := LoadFromEnv(cfgs, true)
assert.Nil(t, err)
assert.Equal(t, ldapURL, cfgs[common.LDAPURL])
os.Clearenv()
if err := os.Setenv("LDAP_URL", ldapURL); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("EXT_ENDPOINT", extEndpoint); err != nil {
t.Fatalf("failed to set env: %v", err)
}
cfgs = map[string]interface{}{}
err = LoadFromEnv(cfgs, false)
assert.Nil(t, err)
assert.Equal(t, extEndpoint, cfgs[common.ExtEndpoint])
assert.Equal(t, nil, cfgs[common.LDAPURL])
}