8000 vic/cmd/vic-init/tether_test.go at lookup · hmahmood/vic · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
283 lines (225 loc) · 7.41 KB

tether_test.go

File metadata and controls

283 lines (225 loc) · 7.41 KB
// Copyright 2016 VMware, Inc. 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.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License 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 main
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net"
"net/url"
"os"
"runtime"
"testing"
log "github.com/Sirupsen/logrus"
"golang.org/x/crypto/ssh"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/vic/lib/config/executor"
"github.com/vmware/vic/lib/system"
"github.com/vmware/vic/lib/tether"
"github.com/vmware/vic/pkg/dio"
"github.com/vmware/vic/pkg/trace"
"github.com/vmware/vic/pkg/vsphere/extraconfig"
)
var Mocked Mocker
type Mocker struct {
Base tether.BaseOperations
// allow tests to tell when the tether has finished setup
Started chan bool
// allow tests to tell when the tether has finished
Cleaned chan bool
// Session exit
SessionExit chan bool
// debug output gets logged here
LogBuffer bytes.Buffer
// session output gets logged here
SessionLogBuffer bytes.Buffer
// the hostname of the system
Hostname string
// the ip configuration for name index networks
IPs map[string]net.IP
// filesystem mounts, indexed by disk label
Mounts map[string]string
WindowCol uint32
WindowRow uint32
Signal ssh.Signal
}
// Start implements the extension method
func (t *Mocker) Start() error {
return nil
}
// Stop implements the extension method
func (t *Mocker) Stop() error {
close(t.Cleaned)
return nil
}
// Reload implements the extension method
func (t *Mocker) Reload(config *tether.ExecutorConfig) error {
// the tether has definitely finished it's startup by the time we hit this
defer func() {
// deal with repeated reloads
recover()
}()
close(t.Started)
return nil
}
func (t *Mocker) Setup(tether.Config) error {
return nil
}
func (t *Mocker) Cleanup() error {
return nil
}
func (t *Mocker) Log() (io.Writer, error) {
return &t.LogBuffer, nil
}
func (t *Mocker) SessionLog(session *tether.SessionConfig) (dio.DynamicMultiWriter, dio.DynamicMultiWriter, error) {
return dio.MultiWriter(&t.SessionLogBuffer), dio.MultiWriter(&t.SessionLogBuffer), nil
}
func (t *Mocker) HandleSessionExit(config *tether.ExecutorConfig, session *tether.SessionConfig) func() {
return func() {
t.SessionExit <- true
}
}
func (t *Mocker) ProcessEnv(env []string) []string {
return t.Base.ProcessEnv(env)
}
// SetHostname sets both the kernel hostname and /etc/hostname to the specified string
func (t *Mocker) SetHostname(hostname string, aliases ...string) error {
defer trace.End(trace.Begin("mocking hostname to " + hostname))
// TODO: we could mock at a much finer granularity, only extracting the syscall
// that would exercise the file modification paths, however it's much less generalizable
t.Hostname = hostname
return nil
}
func (t *Mocker) SetupFirewall(cxt context.Context, 8000 conf *tether.ExecutorConfig) error {
return nil
}
// Apply takes the network endpoint configuration and applies it to the system
func (t *Mocker) Apply(endpoint *tether.NetworkEndpoint) error {
defer trace.End(trace.Begin("mocking endpoint configuration for " + endpoint.Network.Name))
t.IPs[endpoint.Network.Name] = endpoint.Assigned.IP
return nil
}
// MountLabel performs a mount with the source treated as a disk label
// This assumes that /dev/disk/by-label is being populated, probably by udev
func (t *Mocker) MountLabel(ctx context.Context, label, target string) error {
defer trace.End(trace.Begin(fmt.Sprintf("mocking mounting %s on %s", label, target)))
if t.Mounts == nil {
t.Mounts = make(map[string]string)
}
t.Mounts[label] = target
return nil
}
// MountTarget performs a mount with the source treated as an nfs target
func (t *Mocker) MountTarget(ctx context.Context, source url.URL, target string, mountOptions string) error {
defer trace.End(trace.Begin(fmt.Sprintf("mocking mounting %s on %s", source.String(), target)))
if t.Mounts == nil {
t.Mounts = make(map[string]string)
}
t.Mounts[source.String()] = target
return nil
}
// CopyExistingContent copies the underlying files shadowed by a mount on a directory
// to the volume mounted on the directory
func (t *Mocker) CopyExistingContent(source string) error {
defer trace.End(trace.Begin(fmt.Sprintf("mocking copyExistingContent from %s", source)))
return nil
}
// Fork triggers vmfork and handles the necessary pre/post OS level operations
func (t *Mocker) Fork() error {
defer trace.End(trace.Begin("mocking fork"))
return errors.New("Fork test not implemented")
}
// LaunchUtility uses the underlying implementation for launching and tracking utility processes
func (t *Mocker) LaunchUtility(fn tether.UtilityFn) (<-chan int, error) {
return t.Base.LaunchUtility(fn)
}
func (t *Mocker) HandleUtilityExit(pid, exitCode int) bool {
return t.Base.HandleUtilityExit(pid, exitCode)
}
// TestMain simply so we have control of debugging level and somewhere to call package wide test setup
func TestMain(m *testing.M) {
log.SetLevel(log.DebugLevel)
trace.Logger = log.StandardLogger()
// replace the Sys variable with a mock
tether.Sys = system.System{
Hosts: &tether.MockHosts{},
ResolvConf: &tether.MockResolvConf{},
Syscall: &tether.MockSyscall{},
Root: os.TempDir(),
}
retCode := m.Run()
// call with result of m.Run()
os.Exit(retCode)
}
func StartTether(t *testing.T, cfg *executor.ExecutorConfig) (tether.Tether, extraconfig.DataSource) {
store := extraconfig.New()
sink := store.Put
src := store.Get
extraconfig.Encode(sink, cfg)
log.Debugf("Test configuration: %#v", sink)
tthr = tether.New(src, sink, &Mocked)
tthr.Register("mocker", &Mocked)
// run the tether to service the attach
go func() {
err := tthr.Start()
if err != nil {
t.Error(err)
}
}()
return tthr, src
}
func RunTether(t *testing.T, cfg *executor.ExecutorConfig) (tether.Tether, extraconfig.DataSource, error) {
store := extraconfig.New()
sink := store.Put
src := store.Get
extraconfig.Encode(sink, cfg)
log.Debugf("Test configuration: %#v", sink)
tthr = tether.New(src, sink, &Mocked)
tthr.Register("Mocker", &Mocked)
// run the tether to service the attach
erR := tthr.Start()
return tthr, src, erR
}
func OptionValueArrayToString(options []types.BaseOptionValue) string {
// create the key/value store from the extraconfig slice for lookups
kv := make(map[string]string)
for i := range options {
k := options[i].GetOptionValue().Key
v := options[i].GetOptionValue().Value.(string)
kv[k] = v
}
return fmt.Sprintf("%#v", kv)
}
func testSetup(t *testing.T) {
pc, _, _, _ := runtime.Caller(1)
name := runtime.FuncForPC(pc).Name()
log.Infof("Started test setup for %s", name)
// use the mock ops - fresh one each time as tests might apply different mocked calls
Mocked = Mocker{
Started: make(chan bool),
Cleaned: make(chan bool),
SessionExit: make(chan bool),
}
}
func testTeardown(t *testing.T) {
// cleanup
<-Mocked.Cleaned
os.RemoveAll(pathPrefix)
log.SetOutput(os.Stdout)
pc, _, _, _ := runtime.Caller(1)
name := runtime.FuncForPC(pc).Name()
log.Infof("Finished test teardown for %s", name)
}
0