mirror of
https://github.com/containers/podman
synced 2024-10-22 02:03:38 +00:00
1f49f555af
podman run/create have the ability to set the stop timeout flag. We need to stop it in the database. Also Allowing negative time for stop timeout makes no sense, so switching to timeout of uint, allows user to specify huge timeout values. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #158 Approved by: TomSweeneyRedHat
569 lines
14 KiB
Go
569 lines
14 KiB
Go
package libpod
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/containers/storage"
|
|
"github.com/opencontainers/runtime-tools/generate"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func getTestContainer(id, name, locksDir string) (*Container, error) {
|
|
ctr := &Container{
|
|
config: &ContainerConfig{
|
|
ID: id,
|
|
Name: name,
|
|
RootfsImageID: id,
|
|
RootfsImageName: "testimg",
|
|
UseImageConfig: true,
|
|
StaticDir: "/does/not/exist/",
|
|
Stdin: true,
|
|
Labels: make(map[string]string),
|
|
StopSignal: 0,
|
|
StopTimeout: 0,
|
|
CreatedTime: time.Now(),
|
|
},
|
|
state: &containerRuntimeInfo{
|
|
State: ContainerStateRunning,
|
|
ConfigPath: "/does/not/exist/specs/" + id,
|
|
RunDir: "/does/not/exist/tmp/",
|
|
Mounted: true,
|
|
Mountpoint: "/does/not/exist/tmp/" + id,
|
|
PID: 1234,
|
|
},
|
|
valid: true,
|
|
}
|
|
|
|
g := generate.New()
|
|
ctr.config.Spec = g.Spec()
|
|
|
|
ctr.config.Labels["test"] = "testing"
|
|
|
|
// Must make lockfile or container will error on being retrieved from DB
|
|
lockPath := filepath.Join(locksDir, id)
|
|
lock, err := storage.GetLockfile(lockPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ctr.lock = lock
|
|
|
|
return ctr, nil
|
|
}
|
|
|
|
// This horrible hack tests if containers are equal in a way that should handle
|
|
// empty arrays being dropped to nil pointers in the spec JSON
|
|
func testContainersEqual(a, b *Container) bool {
|
|
if a == nil && b == nil {
|
|
return true
|
|
} else if a == nil || b == nil {
|
|
return false
|
|
}
|
|
|
|
if a.valid != b.valid {
|
|
return false
|
|
}
|
|
|
|
aConfigJSON, err := json.Marshal(a.config)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
bConfigJSON, err := json.Marshal(b.config)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
if !reflect.DeepEqual(aConfigJSON, bConfigJSON) {
|
|
return false
|
|
}
|
|
|
|
aStateJSON, err := json.Marshal(a.state)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
bStateJSON, err := json.Marshal(b.state)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return reflect.DeepEqual(aStateJSON, bStateJSON)
|
|
}
|
|
|
|
// Get an empty state for use in tests
|
|
// An empty Runtime is provided
|
|
func getEmptyState() (s State, p string, p2 string, err error) {
|
|
tmpDir, err := ioutil.TempDir("", "libpod_state_test_")
|
|
if err != nil {
|
|
return nil, "", "", err
|
|
}
|
|
defer func() {
|
|
if err != nil {
|
|
os.RemoveAll(tmpDir)
|
|
}
|
|
}()
|
|
|
|
dbPath := filepath.Join(tmpDir, "db.sql")
|
|
specsDir := filepath.Join(tmpDir, "specs")
|
|
lockDir := filepath.Join(tmpDir, "locks")
|
|
|
|
runtime := new(Runtime)
|
|
runtime.config = new(RuntimeConfig)
|
|
runtime.config.StorageConfig = storage.StoreOptions{}
|
|
|
|
state, err := NewSQLState(dbPath, specsDir, lockDir, runtime)
|
|
if err != nil {
|
|
return nil, "", "", err
|
|
}
|
|
|
|
return state, tmpDir, lockDir, nil
|
|
}
|
|
|
|
func TestAddAndGetContainer(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
retrievedCtr, err := state.Container(testCtr.ID())
|
|
assert.NoError(t, err)
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr, retrievedCtr) {
|
|
assert.EqualValues(t, testCtr, retrievedCtr)
|
|
}
|
|
}
|
|
|
|
func TestAddAndGetContainerFromMultiple(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr1, err := getTestContainer("11111111111111111111111111111111", "test1", lockPath)
|
|
assert.NoError(t, err)
|
|
testCtr2, err := getTestContainer("22222222222222222222222222222222", "test2", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr1)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr2)
|
|
assert.NoError(t, err)
|
|
|
|
retrievedCtr, err := state.Container(testCtr1.ID())
|
|
assert.NoError(t, err)
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr1, retrievedCtr) {
|
|
assert.EqualValues(t, testCtr1, retrievedCtr)
|
|
}
|
|
}
|
|
|
|
func TestAddInvalidContainerFails(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
err = state.AddContainer(&Container{})
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestAddDuplicateIDFails(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr1, err := getTestContainer("11111111111111111111111111111111", "test1", lockPath)
|
|
assert.NoError(t, err)
|
|
testCtr2, err := getTestContainer(testCtr1.ID(), "test2", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr1)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr2)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestAddDuplicateNameFails(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr1, err := getTestContainer("11111111111111111111111111111111", "test1", lockPath)
|
|
assert.NoError(t, err)
|
|
testCtr2, err := getTestContainer("22222222222222222222222222222222", testCtr1.Name(), lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr1)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr2)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestGetNonexistantContainerFails(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
_, err = state.Container("does not exist")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestGetContainerWithEmptyIDFails(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
_, err = state.Container("")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestLookupContainerWithEmptyIDFails(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
_, err = state.LookupContainer("")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestLookupNonexistantContainerFails(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
|
|
_, err = state.LookupContainer("does not exist")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestLookupContainerByFullID(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
retrievedCtr, err := state.LookupContainer(testCtr.ID())
|
|
assert.NoError(t, err)
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr, retrievedCtr) {
|
|
assert.EqualValues(t, testCtr, retrievedCtr)
|
|
}
|
|
}
|
|
|
|
func TestLookupContainerByUniquePartialID(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
retrievedCtr, err := state.LookupContainer(testCtr.ID()[0:8])
|
|
assert.NoError(t, err)
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr, retrievedCtr) {
|
|
assert.EqualValues(t, testCtr, retrievedCtr)
|
|
}
|
|
}
|
|
|
|
func TestLookupContainerByNonUniquePartialIDFails(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr1, err := getTestContainer("00000000000000000000000000000000", "test1", lockPath)
|
|
assert.NoError(t, err)
|
|
testCtr2, err := getTestContainer("00000000000000000000000000000001", "test2", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr1)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr2)
|
|
assert.NoError(t, err)
|
|
|
|
_, err = state.LookupContainer(testCtr1.ID()[0:8])
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestLookupContainerByName(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
retrievedCtr, err := state.LookupContainer(testCtr.Name())
|
|
assert.NoError(t, err)
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr, retrievedCtr) {
|
|
assert.EqualValues(t, testCtr, retrievedCtr)
|
|
}
|
|
}
|
|
|
|
func TestHasContainerEmptyIDFails(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
_, err = state.HasContainer("")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestHasContainerNoSuchContainerReturnsFalse(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
exists, err := state.HasContainer("does not exist")
|
|
assert.NoError(t, err)
|
|
assert.False(t, exists)
|
|
}
|
|
|
|
func TestHasContainerFindsContainer(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
exists, err := state.HasContainer(testCtr.ID())
|
|
assert.NoError(t, err)
|
|
assert.True(t, exists)
|
|
}
|
|
|
|
func TestSaveAndUpdateContainer(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
retrievedCtr, err := state.Container(testCtr.ID())
|
|
assert.NoError(t, err)
|
|
|
|
retrievedCtr.state.State = ContainerStateStopped
|
|
retrievedCtr.state.ExitCode = 127
|
|
retrievedCtr.state.FinishedTime = time.Now()
|
|
|
|
err = state.SaveContainer(retrievedCtr)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.UpdateContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr, retrievedCtr) {
|
|
assert.EqualValues(t, testCtr, retrievedCtr)
|
|
}
|
|
}
|
|
|
|
func TestUpdateContainerNotInDatabaseReturnsError(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.UpdateContainer(testCtr)
|
|
assert.Error(t, err)
|
|
assert.False(t, testCtr.valid)
|
|
}
|
|
|
|
func TestUpdateInvalidContainerReturnsError(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
err = state.UpdateContainer(&Container{})
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestSaveInvalidContainerReturnsError(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
err = state.SaveContainer(&Container{})
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestSaveContainerNotInStateReturnsError(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.SaveContainer(testCtr)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestRemoveContainer(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
ctrs, err := state.AllContainers()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, len(ctrs))
|
|
|
|
err = state.RemoveContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
ctrs2, err := state.AllContainers()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 0, len(ctrs2))
|
|
}
|
|
|
|
func TestRemoveNonexistantContainerFails(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.RemoveContainer(testCtr)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestGetAllContainersOnNewStateIsEmpty(t *testing.T) {
|
|
state, path, _, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
ctrs, err := state.AllContainers()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 0, len(ctrs))
|
|
}
|
|
|
|
func TestGetAllContainersWithOneContainer(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr, err := getTestContainer("0123456789ABCDEF0123456789ABCDEF", "test", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr)
|
|
assert.NoError(t, err)
|
|
|
|
ctrs, err := state.AllContainers()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, len(ctrs))
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr, ctrs[0]) {
|
|
assert.EqualValues(t, testCtr, ctrs[0])
|
|
}
|
|
}
|
|
|
|
func TestGetAllContainersTwoContainers(t *testing.T) {
|
|
state, path, lockPath, err := getEmptyState()
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(path)
|
|
defer state.Close()
|
|
|
|
testCtr1, err := getTestContainer("11111111111111111111111111111111", "test1", lockPath)
|
|
assert.NoError(t, err)
|
|
testCtr2, err := getTestContainer("22222222222222222222222222222222", "test2", lockPath)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr1)
|
|
assert.NoError(t, err)
|
|
|
|
err = state.AddContainer(testCtr2)
|
|
assert.NoError(t, err)
|
|
|
|
ctrs, err := state.AllContainers()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, len(ctrs))
|
|
|
|
// Containers should be ordered by creation time
|
|
|
|
// Use assert.EqualValues if the test fails to pretty print diff
|
|
// between actual and expected
|
|
if !testContainersEqual(testCtr2, ctrs[0]) {
|
|
assert.EqualValues(t, testCtr2, ctrs[0])
|
|
}
|
|
if !testContainersEqual(testCtr1, ctrs[1]) {
|
|
assert.EqualValues(t, testCtr1, ctrs[1])
|
|
}
|
|
}
|