Я пытаюсь написать тесты для этой функции в Go:
type LinuxBackend struct {
fs afero.Fs
}
func (b *LinuxBackend) GetSSHUser(name string) users.SSHUser {
// Get the user from the system
usr, err := user.Lookup(name)
if err != nil {
panic(err)
}
return users.SSHUser{ User: usr }
}
Мне бы хотелось иметь подделку /etc/passwd
, чтобы мои тесты могли создавать в этом файле необходимых пользователей, а не полагаться на реальный системный файл.
Для других частей моего кода я абстрагировал базовую файловую систему, используя Afero для создания файловой системы в памяти, создавая необходимые файлы (включая /etc/passwd
), чтобы можно было запускать тесты. Вот для чего нужно поле fs
в LinuxBackend
.
Например, вот еще одна функция из того же пакета:
func (b *LinuxBackend) GetMinMaxUid() (int, int) {
content, err := afero.ReadFile(b.fs, LoginDefsPath)
// more code here...
return min, max
}
Затем я могу проверить это, не касаясь реальной файловой системы:
func createLoginDefs(afs afero.Fs) {
afs.MkdirAll("/etc", os.FileMode(os.ModeDir))
f, _ := afs.OpenFile(LoginDefsPath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
defer f.Close()
f.WriteString("UID_MIN " + strconv.Itoa(uidMin) + "\n")
f.WriteString("UID_MAX " + strconv.Itoa(uidMax) + "\n")
}
func TestLinuxBackend_GetMinMaxUid(t *testing.T) {
afs := afero.NewMemMapFs() // <-- This is the trick.
createLoginDefs(afs)
backend := LinuxBackend{afs}
min, max := backend.GetMinMaxUid()
// rest of the test...
}
Я не могу сделать это для user.Lookup()
, однако это означает, что он попытается получить несуществующих тестовых пользователей из реальной файловой системы.
user.Lookup
вызывает user.lookupUser
, который имеет две конкретные реализации: pure Go one и cgo one . Я полагаю, что последнее совершенно невозможно заставить использовать виртуальную файловую систему, поскольку она использует служебные функции libc pw*
для извлечения пользователей. Первый из них начинается с Open
, используя дескриптор файла, а затем передает его в функцию findUsername
, которая принимает io.Reader
в качестве аргумента, но эта функция не экспортируется из модуля, поэтому я не могу использовать ее напрямую для передать в него ридер из файловой системы Afero.
Можно ли как-нибудь заставить Go использовать файловую систему в памяти для user.Lookup
и user.lookupUser
, или написать код или выполнить тестирование каким-либо другим способом, чтобы user.Lookup
не использовал настоящий файл система
Я всегда мог скопировать user.lookupUser
, но я бы предпочел этого избежать.