Как я могу протестировать код Golang, который вызывает users.Lookup с виртуальной файловой системой, такой как Afero in-memory FS? - PullRequest
0 голосов
/ 04 ноября 2018

Я пытаюсь написать тесты для этой функции в 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, но я бы предпочел этого избежать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...