Add fileleak task
This commit is contained in:
parent
b6f50e3aba
commit
fc2e047ed1
3 changed files with 114 additions and 0 deletions
23
fileleak/README.md
Normal file
23
fileleak/README.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# fileleak
|
||||||
|
|
||||||
|
Реализуйте библиотеку для поиска утечек файлов в тестах.
|
||||||
|
|
||||||
|
Библиотека содержит единственную функцию - `VerifyNone`. Пользователь должен вызвать эту функцию в начале своего теста.
|
||||||
|
|
||||||
|
Библиотека смотрит на все открытые файлы процесса в начале и в конце теста. Если в конце теста будут находятся открытые файлы,
|
||||||
|
которые не были открыты на момент старта теста, то библиотека фейлит весь тест.
|
||||||
|
|
||||||
|
Эта задача будет корректно работать только на `linux`. Чтобы узнать открытые файлы процесса, нужно прочитать директорию
|
||||||
|
`/proc/self/fd`. Эта директория содержит символические ссылки. Именем ссылки является номер файлового дескриптора, а значением
|
||||||
|
ссылки является какое-то текстовое описание открытого файла. Значение ссылки можно прочитать, используя `os.Readlink`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
prime@bee ~/C/shad-go> ls -lah /proc/self/fd
|
||||||
|
total 0
|
||||||
|
dr-x------ 2 prime prime 0 мар 12 19:44 ./
|
||||||
|
dr-xr-xr-x 9 prime prime 0 мар 12 19:44 ../
|
||||||
|
lrwx------ 1 prime prime 64 мар 12 19:44 0 -> /dev/pts/7
|
||||||
|
lrwx------ 1 prime prime 64 мар 12 19:44 1 -> /dev/pts/7
|
||||||
|
lrwx------ 1 prime prime 64 мар 12 19:44 2 -> /dev/pts/7
|
||||||
|
lr-x------ 1 prime prime 64 мар 12 19:44 3 -> /proc/871308/fd/
|
||||||
|
```
|
12
fileleak/fileleak.go
Normal file
12
fileleak/fileleak.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// +build !solution
|
||||||
|
|
||||||
|
package fileleak
|
||||||
|
|
||||||
|
type testingT interface {
|
||||||
|
Errorf(msg string, args ...interface{})
|
||||||
|
Cleanup(func())
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyNone(t testingT) {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
79
fileleak/fileleak_test.go
Normal file
79
fileleak/fileleak_test.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package fileleak_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"gitlab.com/slon/shad-go/fileleak"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeT struct {
|
||||||
|
failed bool
|
||||||
|
buffer bytes.Buffer
|
||||||
|
cleanup []func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeT) Errorf(msg string, args ...interface{}) {
|
||||||
|
f.failed = true
|
||||||
|
fmt.Fprintf(&f.buffer, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeT) Cleanup(cb func()) {
|
||||||
|
f.cleanup = append([]func(){cb}, f.cleanup...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkLeak(t *testing.T, shouldDetect bool, leaker func()) {
|
||||||
|
var fake fakeT
|
||||||
|
fileleak.VerifyNone(&fake)
|
||||||
|
leaker()
|
||||||
|
for _, cb := range fake.cleanup {
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case shouldDetect && !fake.failed:
|
||||||
|
t.Errorf("fileleak didn't detect a leak")
|
||||||
|
case !shouldDetect && fake.failed:
|
||||||
|
t.Errorf("fileleak detected a leak when there is none:\n%s", fake.buffer.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileLeak_OpenFile(t *testing.T) {
|
||||||
|
var f *os.File
|
||||||
|
checkLeak(t, true, func() {
|
||||||
|
var err error
|
||||||
|
f, err = os.Open("/proc/self/exe")
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
if f != nil {
|
||||||
|
_ = f.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileLeak_AlwaysOpenFile(t *testing.T) {
|
||||||
|
f, err := os.Open("/proc/self/exe")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
checkLeak(t, false, func() {})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileLeak_ReopenFile(t *testing.T) {
|
||||||
|
f, err := os.Open("/proc/self/exe")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
checkLeak(t, true, func() {
|
||||||
|
_ = f.Close()
|
||||||
|
|
||||||
|
ff, err := ioutil.TempFile("", "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
f = ff
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue