Skip to content

Commit

Permalink
Merge pull request firecracker-microvm#637 from austinvazquez/integ-t…
Browse files Browse the repository at this point in the history
…est-ref

refactor: integ test common code into internal package
  • Loading branch information
kzys authored May 21, 2022
2 parents 8892911 + 82d8478 commit 956c44a
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 153 deletions.
71 changes: 71 additions & 0 deletions internal/integtest/containerd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package integtest

import (
"bytes"
"context"

"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
)

// CommandResult encapsulates the stdout, stderr, and exit code returned
// from a task.
type CommandResult struct {
Stdout string
Stderr string
ExitCode uint32
}

// RunTask is a utility function for running a task and returning the result.
func RunTask(ctx context.Context, c containerd.Container) (*CommandResult, error) {
var stdout bytes.Buffer
var stderr bytes.Buffer

task, err := c.NewTask(ctx, cio.NewCreator(cio.WithStreams(nil, &stdout, &stderr)))
if err != nil {
return nil, err
}

exitCh, err := task.Wait(ctx)
if err != nil {
return nil, err
}

err = task.Start(ctx)
if err != nil {
return nil, err
}

select {
case exitStatus := <-exitCh:
if err := exitStatus.Error(); err != nil {
return nil, err
}

_, err := task.Delete(ctx)
if err != nil {
return nil, err
}

return &CommandResult{
Stdout: stdout.String(),
Stderr: stderr.String(),
ExitCode: exitStatus.ExitCode(),
}, nil
case <-ctx.Done():
return nil, ctx.Err()
}
}
21 changes: 21 additions & 0 deletions internal/integtest/firecracker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package integtest

import "github.com/firecracker-microvm/firecracker-containerd/firecracker-control/client"

// NewFCControlClient returns a Firecracker control client for the given socket.
func NewFCControlClient(socket string) (*client.Client, error) {
return client.New(socket + ".ttrpc")
}
34 changes: 34 additions & 0 deletions internal/integtest/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package integtest

import (
"github.com/firecracker-microvm/firecracker-containerd/config"
"github.com/firecracker-microvm/firecracker-containerd/proto"
)

// WithDefaultNetwork is an option to use the default network configuration
// in the runtime configuration for integration testing
func WithDefaultNetwork() func(c *config.Config) {
return func(c *config.Config) {
c.DefaultNetworkInterfaces = []proto.FirecrackerNetworkInterface{
{
CNIConfig: &proto.CNIConfiguration{
NetworkName: "fcnet",
InterfaceName: "veth0",
},
},
}
}
}
36 changes: 36 additions & 0 deletions internal/integtest/runtime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package integtest

import (
"os"
)

const (
// FirecrackerRuntime is the Firecracker-containerd runtime
FirecrackerRuntime = "aws.firecracker"

containerdSockPathEnvVar = "CONTAINERD_SOCKET"
)

var (
// ContainerdSockPath is the default Firecracker-containerd socket path
ContainerdSockPath = "/run/firecracker-containerd/containerd.sock"
)

func init() {
if v := os.Getenv(containerdSockPathEnvVar); v != "" {
ContainerdSockPath = v
}
}
6 changes: 3 additions & 3 deletions runtime/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ func createAndStopVM(
}

func benchmarkCreateAndStopVM(t *testing.T, vcpuCount uint32, kernelArgs string) {
client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
client, err := containerd.New(integtest.ContainerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", integtest.ContainerdSockPath)
defer client.Close()

ctx := namespaces.WithNamespace(context.Background(), "default")

fcClient, err := newFCControlClient(containerdSockPath)
fcClient, err := integtest.NewFCControlClient(integtest.ContainerdSockPath)
require.NoError(t, err, "failed to create fccontrol client")

request := proto.CreateVMRequest{
Expand Down
32 changes: 9 additions & 23 deletions runtime/cni_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/firecracker-microvm/firecracker-containerd/config"
"github.com/firecracker-microvm/firecracker-containerd/internal"
"github.com/firecracker-microvm/firecracker-containerd/internal/integtest"
"github.com/firecracker-microvm/firecracker-containerd/proto"
Expand All @@ -45,11 +44,11 @@ func TestCNISupport_Isolated(t *testing.T) {
ctx, cancel := context.WithTimeout(namespaces.WithNamespace(context.Background(), defaultNamespace), testTimeout)
defer cancel()

client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
client, err := containerd.New(integtest.ContainerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", integtest.ContainerdSockPath)
defer client.Close()

fcClient, err := newFCControlClient(containerdSockPath)
fcClient, err := integtest.NewFCControlClient(integtest.ContainerdSockPath)
require.NoError(t, err, "failed to create fccontrol client")

image, err := alpineImage(ctx, client, defaultSnapshotterName)
Expand Down Expand Up @@ -148,14 +147,14 @@ func TestCNISupport_Isolated(t *testing.T) {
}

func TestAutomaticCNISupport_Isolated(t *testing.T) {
integtest.Prepare(t, withDefaultNetwork())
integtest.Prepare(t, integtest.WithDefaultNetwork())

testTimeout := 120 * time.Second
ctx, cancel := context.WithTimeout(namespaces.WithNamespace(context.Background(), defaultNamespace), testTimeout)
defer cancel()

client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
client, err := containerd.New(integtest.ContainerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", integtest.ContainerdSockPath)
defer client.Close()

image, err := alpineImage(ctx, client, defaultSnapshotterName)
Expand Down Expand Up @@ -226,11 +225,11 @@ func TestCNIPlugin_Performance(t *testing.T) {
ctx, cancel := context.WithTimeout(namespaces.WithNamespace(context.Background(), defaultNamespace), testTimeout)
defer cancel()

client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
client, err := containerd.New(integtest.ContainerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(t, err, "unable to create client to containerd service at %s, is containerd running?", integtest.ContainerdSockPath)
defer client.Close()

fcClient, err := newFCControlClient(containerdSockPath)
fcClient, err := integtest.NewFCControlClient(integtest.ContainerdSockPath)
require.NoError(t, err, "failed to create ttrpc client")

image, err := iperf3Image(ctx, client, defaultSnapshotterName)
Expand Down Expand Up @@ -362,19 +361,6 @@ func writeCNIConf(path, chainedPluginName, networkName, nameserver string) error
}`, networkName, nameserver, chainedPluginName)), 0644)
}

func withDefaultNetwork() func(c *config.Config) {
return func(c *config.Config) {
c.DefaultNetworkInterfaces = []proto.FirecrackerNetworkInterface{
{
CNIConfig: &proto.CNIConfiguration{
NetworkName: "fcnet",
InterfaceName: "veth0",
},
},
}
}
}

func runCommand(ctx context.Context, t *testing.T, name string, args ...string) {
t.Helper()
output, err := exec.CommandContext(ctx, name, args...).CombinedOutput()
Expand Down
57 changes: 0 additions & 57 deletions runtime/integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,8 @@
package main

import (
"bytes"
"context"
"strings"

"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
"github.com/pkg/errors"

"github.com/firecracker-microvm/firecracker-containerd/firecracker-control/client"
"github.com/firecracker-microvm/firecracker-containerd/internal"
"github.com/firecracker-microvm/firecracker-containerd/internal/integtest"
)
Expand All @@ -45,53 +38,3 @@ var testNameToVMIDReplacer = strings.NewReplacer("/", "-", "_", "-")
func testNameToVMID(s string) string {
return testNameToVMIDReplacer.Replace(s)
}

type commandResult struct {
stdout string
stderr string
exitCode uint32
}

func runTask(ctx context.Context, c containerd.Container) (*commandResult, error) {
var stdout bytes.Buffer
var stderr bytes.Buffer

task, err := c.NewTask(ctx, cio.NewCreator(cio.WithStreams(nil, &stdout, &stderr)))
if err != nil {
return nil, err
}

exitCh, err := task.Wait(ctx)
if err != nil {
return nil, err
}

err = task.Start(ctx)
if err != nil {
return nil, err
}

select {
case exitStatus := <-exitCh:
if err := exitStatus.Error(); err != nil {
return nil, err
}

_, err := task.Delete(ctx)
if err != nil {
return nil, err
}

return &commandResult{
stdout: stdout.String(),
stderr: stderr.String(),
exitCode: exitStatus.ExitCode(),
}, nil
case <-ctx.Done():
return nil, errors.New("context cancelled")
}
}

func newFCControlClient(socket string) (*client.Client, error) {
return client.New(socket + ".ttrpc")
}
12 changes: 6 additions & 6 deletions runtime/jailer_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ func fsSafeTestName(tb testing.TB) string {
func testJailer(t *testing.T, jailerConfig *proto.JailerConfig) {
require := require.New(t)

client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
client, err := containerd.New(integtest.ContainerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(err, "unable to create client to containerd service at %s, is containerd running?", integtest.ContainerdSockPath)
defer client.Close()

ctx := namespaces.WithNamespace(context.Background(), "default")
Expand Down Expand Up @@ -140,7 +140,7 @@ func testJailer(t *testing.T, jailerConfig *proto.JailerConfig) {
require.NoError(err, "failed to chown %q", additionalDrive)
}

fcClient, err := newFCControlClient(containerdSockPath)
fcClient, err := integtest.NewFCControlClient(integtest.ContainerdSockPath)
require.NoError(err)

_, err = fcClient.CreateVM(ctx, &request)
Expand Down Expand Up @@ -202,16 +202,16 @@ func TestJailerCPUSet_Isolated(t *testing.T) {

func testAttachBlockDevice(t *testing.T, jailerConfig *proto.JailerConfig) {
require := require.New(t)
client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
client, err := containerd.New(integtest.ContainerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(err, "unable to create client to containerd service at %s, is containerd running?", integtest.ContainerdSockPath)
defer client.Close()

ctx := namespaces.WithNamespace(context.Background(), "default")

image, err := alpineImage(ctx, client, defaultSnapshotterName)
require.NoError(err, "failed to get alpine image")

fcClient, err := newFCControlClient(containerdSockPath)
fcClient, err := integtest.NewFCControlClient(integtest.ContainerdSockPath)
require.NoError(err)

vmID := testNameToVMID(t.Name())
Expand Down
10 changes: 5 additions & 5 deletions runtime/limits_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ func TestDiskLimit_Isolated(t *testing.T) {

ctx := namespaces.WithNamespace(context.Background(), "default")

client, err := containerd.New(containerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(err, "unable to create client to containerd service at %s, is containerd running?", containerdSockPath)
client, err := containerd.New(integtest.ContainerdSockPath, containerd.WithDefaultRuntime(firecrackerRuntime))
require.NoError(err, "unable to create client to containerd service at %s, is containerd running?", integtest.ContainerdSockPath)
defer client.Close()

image, err := alpineImage(ctx, client, defaultSnapshotterName)
Expand All @@ -57,11 +57,11 @@ func TestDiskLimit_Isolated(t *testing.T) {
require.NoError(err, "failed to delete a container")
}()

result, err := runTask(ctx, container)
result, err := integtest.RunTask(ctx, container)
require.NoError(err, "failed to create a container")

assert.Equal(uint32(1), result.exitCode, "writing 2GB must fail")
assert.Equal(uint32(1), result.ExitCode, "writing 2GB must fail")
assert.Equal(`952+0 records in
951+0 records out
`, result.stderr, "but it must be able to write ~1024MB")
`, result.Stderr, "but it must be able to write ~1024MB")
}
Loading

0 comments on commit 956c44a

Please sign in to comment.