Files
core/resources/resources_test.go
2024-10-29 14:55:55 +01:00

856 lines
14 KiB
Go

package resources
import (
"slices"
"sync"
"testing"
"time"
"github.com/datarhei/core/v16/internal/mock/psutil"
"github.com/stretchr/testify/require"
)
func TestConfigNoLimits(t *testing.T) {
_, err := New(Config{
PSUtil: psutil.New(0),
})
require.NoError(t, err)
}
func TestConfigWrongLimits(t *testing.T) {
_, err := New(Config{
MaxCPU: 102,
MaxMemory: 573,
PSUtil: psutil.New(0),
})
require.Error(t, err)
_, err = New(Config{
MaxCPU: 0,
MaxMemory: 0,
MaxGPU: 101,
MaxGPUMemory: 103,
PSUtil: psutil.New(0),
})
require.NoError(t, err)
_, err = New(Config{
MaxCPU: 0,
MaxMemory: 0,
MaxGPU: 101,
MaxGPUMemory: 103,
PSUtil: psutil.New(1),
})
require.Error(t, err)
}
func TestMemoryLimit(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 150. / 200. * 100,
PSUtil: psutil.New(0),
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := false
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, limit, _ = r.ShouldLimit()
if limit {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.True(t, limit)
_, err = r.Request(Request{CPU: 5, Memory: 10})
require.Error(t, err)
r.Cancel()
}
func TestMemoryUnlimit(t *testing.T) {
util := psutil.New(0)
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 150. / 200. * 100,
PSUtil: util,
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := false
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, limit, _ = r.ShouldLimit()
if limit {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.True(t, limit)
_, limit, _ = r.ShouldLimit()
require.True(t, limit)
util.Lock.Lock()
util.MemInfo.Used = 140
util.Lock.Unlock()
wg.Add(1)
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, limit, _ = r.ShouldLimit()
if !limit {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.False(t, limit)
r.Cancel()
}
func TestCPULimit(t *testing.T) {
r, err := New(Config{
MaxCPU: 50.,
MaxMemory: 100,
PSUtil: psutil.New(0),
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := false
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
limit, _, _ = r.ShouldLimit()
if limit {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.True(t, limit)
_, err = r.Request(Request{CPU: 5, Memory: 10})
require.Error(t, err)
r.Cancel()
}
func TestCPUUnlimit(t *testing.T) {
util := psutil.New(0)
r, err := New(Config{
MaxCPU: 50.,
MaxMemory: 100,
PSUtil: util,
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := false
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
limit, _, _ = r.ShouldLimit()
if limit {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.True(t, limit)
limit, _, _ = r.ShouldLimit()
require.True(t, limit)
util.Lock.Lock()
util.CPUInfo.User = 20
util.Lock.Unlock()
wg.Add(1)
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
limit, _, _ = r.ShouldLimit()
if !limit {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.False(t, limit)
r.Cancel()
}
func TestGPULimitMemory(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
MaxGPU: 100,
MaxGPUMemory: 20,
PSUtil: psutil.New(2),
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := []bool{}
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, _, limit = r.ShouldLimit()
if slices.Contains(limit, true) {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.Contains(t, limit, true)
_, err = r.Request(Request{CPU: 5, Memory: 10, GPUUsage: 10, GPUMemory: 10})
require.Error(t, err)
r.Cancel()
}
func TestGPUUnlimitMemory(t *testing.T) {
util := psutil.New(2)
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
MaxGPU: 100,
MaxGPUMemory: 20,
PSUtil: util,
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := []bool{}
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, _, limit = r.ShouldLimit()
if slices.Contains(limit, true) {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.Contains(t, limit, true)
util.Lock.Lock()
util.GPUInfo[0].MemoryUsed = 10
util.GPUInfo[1].MemoryUsed = 10
util.Lock.Unlock()
wg.Add(1)
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, _, limit = r.ShouldLimit()
if !slices.Contains(limit, true) {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.NotContains(t, limit, true)
r.Cancel()
}
func TestGPULimitMemorySome(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
MaxGPU: 100,
MaxGPUMemory: 14. / 24. * 100.,
PSUtil: psutil.New(4),
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := []bool{}
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, _, limit = r.ShouldLimit()
if slices.Contains(limit, true) {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.Equal(t, []bool{false, false, true, true}, limit)
_, err = r.Request(Request{CPU: 5, Memory: 10, GPUUsage: 10, GPUMemory: 10})
require.NoError(t, err)
r.Cancel()
}
func TestGPULimitUsage(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
MaxGPU: 40,
MaxGPUMemory: 100,
PSUtil: psutil.New(3),
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := []bool{}
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, _, limit = r.ShouldLimit()
if slices.Contains(limit, true) {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.Equal(t, []bool{true, false, false}, limit)
_, err = r.Request(Request{CPU: 5, Memory: 10, GPUUsage: 10, GPUMemory: 10})
require.Error(t, err)
_, err = r.Request(Request{CPU: 5, Memory: 10, GPUEncoder: 10, GPUMemory: 10})
require.NoError(t, err)
r.Cancel()
}
func TestGPUUnlimitUsage(t *testing.T) {
util := psutil.New(3)
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
MaxGPU: 40,
MaxGPUMemory: 100,
PSUtil: util,
Logger: nil,
})
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(1)
limit := []bool{}
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, _, limit = r.ShouldLimit()
if slices.Contains(limit, true) {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.Equal(t, []bool{true, false, false}, limit)
util.Lock.Lock()
util.GPUInfo[0].Usage = 30
util.GPUInfo[0].Encoder = 30
util.GPUInfo[0].Decoder = 30
util.Lock.Unlock()
wg.Add(1)
go func() {
defer func() {
wg.Done()
}()
timer := time.NewTimer(10 * time.Second)
defer timer.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, _, limit = r.ShouldLimit()
if !slices.Contains(limit, true) {
return
}
case <-timer.C:
return
}
}
}()
wg.Wait()
require.Equal(t, []bool{false, false, false}, limit)
r.Cancel()
}
func TestRequestCPU(t *testing.T) {
r, err := New(Config{
MaxCPU: 70.,
PSUtil: psutil.New(0),
})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 0, Memory: 0})
require.Error(t, err)
_, err = r.Request(Request{CPU: 5, Memory: 10})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 30, Memory: 10})
require.Error(t, err)
}
func TestRequestMemory(t *testing.T) {
r, err := New(Config{
MaxMemory: 170. / 200. * 100,
PSUtil: psutil.New(0),
})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 5, Memory: 0})
require.Error(t, err)
_, err = r.Request(Request{CPU: 5, Memory: 10})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 50, Memory: 20})
require.Error(t, err)
}
func TestRequestNoGPU(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
PSUtil: psutil.New(0),
})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUEncoder: 30, GPUMemory: 10})
require.Error(t, err)
}
func TestRequestInvalidGPURequest(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
PSUtil: psutil.New(1),
})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUEncoder: 30, GPUMemory: 0})
require.Error(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUUsage: -1, GPUEncoder: 30, GPUMemory: 0})
require.Error(t, err)
}
func TestRequestGPULimitsOneGPU(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
MaxGPU: 50,
MaxGPUMemory: 60,
PSUtil: psutil.New(1),
})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUUsage: 50, GPUMemory: 10})
require.Error(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUEncoder: 50, GPUMemory: 10})
require.Error(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUDecoder: 50, GPUMemory: 10})
require.Error(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUEncoder: 10, GPUMemory: 5 * 1024 * 1024 * 1024})
require.Error(t, err)
res, err := r.Request(Request{CPU: 10, Memory: 10, GPUEncoder: 10, GPUMemory: 10})
require.NoError(t, err)
require.Equal(t, 0, res.GPU)
}
func TestRequestGPULimitsMoreGPU(t *testing.T) {
r, err := New(Config{
MaxCPU: 100,
MaxMemory: 100,
MaxGPU: 60,
MaxGPUMemory: 60,
PSUtil: psutil.New(2),
})
require.NoError(t, err)
_, err = r.Request(Request{CPU: 10, Memory: 10, GPUEncoder: 50, GPUMemory: 10})
require.Error(t, err)
res, err := r.Request(Request{CPU: 10, Memory: 10, GPUEncoder: 30, GPUMemory: 10})
require.NoError(t, err)
require.Equal(t, 1, res.GPU)
}
func TestHasLimits(t *testing.T) {
r, err := New(Config{
MaxCPU: 70.,
MaxMemory: 170. / 200. * 100,
PSUtil: psutil.New(0),
Logger: nil,
})
require.NoError(t, err)
require.True(t, r.HasLimits())
r, err = New(Config{
MaxCPU: 100,
MaxMemory: 100,
PSUtil: psutil.New(0),
Logger: nil,
})
require.NoError(t, err)
require.True(t, r.HasLimits())
r, err = New(Config{
MaxCPU: 0,
MaxMemory: 0,
PSUtil: psutil.New(0),
Logger: nil,
})
require.NoError(t, err)
require.False(t, r.HasLimits())
r, err = New(Config{
MaxCPU: 0,
MaxMemory: 0,
MaxGPU: 10,
PSUtil: psutil.New(1),
Logger: nil,
})
require.NoError(t, err)
require.True(t, r.HasLimits())
r, err = New(Config{
MaxCPU: 0,
MaxMemory: 0,
MaxGPU: 10,
PSUtil: psutil.New(0),
Logger: nil,
})
require.NoError(t, err)
require.False(t, r.HasLimits())
}
func TestInfo(t *testing.T) {
r, err := New(Config{
MaxCPU: 90,
MaxMemory: 90,
MaxGPU: 11,
MaxGPUMemory: 50,
PSUtil: psutil.New(2),
})
require.NoError(t, err)
info := r.Info()
require.Equal(t, Info{
Mem: MemoryInfo{
Total: 200,
Available: 40,
Used: 160,
Limit: 180,
Core: 42,
Throttling: false,
Error: nil,
},
CPU: CPUInfo{
NCPU: 2,
System: 10,
User: 50,
Idle: 35,
Other: 5,
Limit: 90,
Core: 6,
Throttling: false,
Error: nil,
},
GPU: GPUInfo{
NGPU: 2,
GPU: []GPUInfoStat{{
Index: 0,
Name: "L4",
MemoryTotal: 24 * 1024 * 1024 * 1024,
MemoryUsed: 12 * 1024 * 1024 * 1024,
MemoryAvailable: 12 * 1024 * 1024 * 1024,
MemoryLimit: 12 * 1024 * 1024 * 1024,
Usage: 45,
Encoder: 40,
Decoder: 47,
UsageLimit: 11,
}, {
Index: 1,
Name: "L4",
MemoryTotal: 24 * 1024 * 1024 * 1024,
MemoryUsed: 13 * 1024 * 1024 * 1024,
MemoryAvailable: 11 * 1024 * 1024 * 1024,
MemoryLimit: 12 * 1024 * 1024 * 1024,
Usage: 40,
Encoder: 30,
Decoder: 44,
UsageLimit: 11,
}},
Error: nil,
},
}, info)
}