mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-03 23:40:03 +00:00 
			
		
		
		
	Merge pull request #77 from brendandburns/kublet
Expand unit tests, coverage now to 56.9%
This commit is contained in:
		@@ -21,10 +21,12 @@ import (
 | 
				
			|||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -237,18 +239,15 @@ func dockerNameToManifestAndContainer(name string) (manifestId, containerName st
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (kl *Kubelet) RunContainer(manifest *api.ContainerManifest, container *api.Container) (name string, err error) {
 | 
					func makeEnvironmentVariables(container *api.Container) []string {
 | 
				
			||||||
	err = kl.pullImage(container.Image)
 | 
						var result []string
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	name = manifestAndContainerToDockerName(manifest, container)
 | 
					 | 
				
			||||||
	envVariables := []string{}
 | 
					 | 
				
			||||||
	for _, value := range container.Env {
 | 
						for _, value := range container.Env {
 | 
				
			||||||
		envVariables = append(envVariables, fmt.Sprintf("%s=%s", value.Name, value.Value))
 | 
							result = append(result, fmt.Sprintf("%s=%s", value.Name, value.Value))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func makeVolumesAndBinds(container *api.Container) (map[string]struct{}, []string) {
 | 
				
			||||||
	volumes := map[string]struct{}{}
 | 
						volumes := map[string]struct{}{}
 | 
				
			||||||
	binds := []string{}
 | 
						binds := []string{}
 | 
				
			||||||
	for _, volume := range container.VolumeMounts {
 | 
						for _, volume := range container.VolumeMounts {
 | 
				
			||||||
@@ -259,7 +258,10 @@ func (kl *Kubelet) RunContainer(manifest *api.ContainerManifest, container *api.
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		binds = append(binds, basePath)
 | 
							binds = append(binds, basePath)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return volumes, binds
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func makePortsAndBindings(container *api.Container) (map[docker.Port]struct{}, map[docker.Port][]docker.PortBinding) {
 | 
				
			||||||
	exposedPorts := map[docker.Port]struct{}{}
 | 
						exposedPorts := map[docker.Port]struct{}{}
 | 
				
			||||||
	portBindings := map[docker.Port][]docker.PortBinding{}
 | 
						portBindings := map[docker.Port][]docker.PortBinding{}
 | 
				
			||||||
	for _, port := range container.Ports {
 | 
						for _, port := range container.Ports {
 | 
				
			||||||
@@ -275,10 +277,24 @@ func (kl *Kubelet) RunContainer(manifest *api.ContainerManifest, container *api.
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return exposedPorts, portBindings
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func makeCommandLine(container *api.Container) []string {
 | 
				
			||||||
	var cmdList []string
 | 
						var cmdList []string
 | 
				
			||||||
	if len(container.Command) > 0 {
 | 
						if len(container.Command) > 0 {
 | 
				
			||||||
		cmdList = strings.Split(container.Command, " ")
 | 
							cmdList = strings.Split(container.Command, " ")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return cmdList
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (kl *Kubelet) RunContainer(manifest *api.ContainerManifest, container *api.Container) (name string, err error) {
 | 
				
			||||||
 | 
						name = manifestAndContainerToDockerName(manifest, container)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						envVariables := makeEnvironmentVariables(container)
 | 
				
			||||||
 | 
						volumes, binds := makeVolumesAndBinds(container)
 | 
				
			||||||
 | 
						exposedPorts, portBindings := makePortsAndBindings(container)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts := docker.CreateContainerOptions{
 | 
						opts := docker.CreateContainerOptions{
 | 
				
			||||||
		Name: name,
 | 
							Name: name,
 | 
				
			||||||
		Config: &docker.Config{
 | 
							Config: &docker.Config{
 | 
				
			||||||
@@ -287,7 +303,7 @@ func (kl *Kubelet) RunContainer(manifest *api.ContainerManifest, container *api.
 | 
				
			|||||||
			Env:          envVariables,
 | 
								Env:          envVariables,
 | 
				
			||||||
			Volumes:      volumes,
 | 
								Volumes:      volumes,
 | 
				
			||||||
			WorkingDir:   container.WorkingDir,
 | 
								WorkingDir:   container.WorkingDir,
 | 
				
			||||||
			Cmd:          cmdList,
 | 
								Cmd:          makeCommandLine(container),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	dockerContainer, err := kl.DockerClient.CreateContainer(opts)
 | 
						dockerContainer, err := kl.DockerClient.CreateContainer(opts)
 | 
				
			||||||
@@ -320,76 +336,78 @@ func (kl *Kubelet) KillContainer(name string) error {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (kl *Kubelet) extractFromFile(lastData []byte, name string, changeChannel chan<- api.ContainerManifest) ([]byte, error) {
 | 
				
			||||||
 | 
						var file *os.File
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						if file, err = os.Open(name); err != nil {
 | 
				
			||||||
 | 
							return lastData, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return kl.extractFromReader(lastData, file, changeChannel)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (kl *Kubelet) extractFromReader(lastData []byte, reader io.Reader, changeChannel chan<- api.ContainerManifest) ([]byte, error) {
 | 
				
			||||||
 | 
						var manifest api.ContainerManifest
 | 
				
			||||||
 | 
						data, err := ioutil.ReadAll(reader)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Couldn't read file: %v", err)
 | 
				
			||||||
 | 
							return lastData, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err = kl.ExtractYAMLData(data, &manifest); err != nil {
 | 
				
			||||||
 | 
							return lastData, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !bytes.Equal(lastData, data) {
 | 
				
			||||||
 | 
							lastData = data
 | 
				
			||||||
 | 
							// Ok, we have a valid configuration, send to channel for
 | 
				
			||||||
 | 
							// rejiggering.
 | 
				
			||||||
 | 
							changeChannel <- manifest
 | 
				
			||||||
 | 
							return data, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return lastData, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Watch a file for changes to the set of pods that should run on this Kubelet
 | 
					// Watch a file for changes to the set of pods that should run on this Kubelet
 | 
				
			||||||
// This function loops forever and is intended to be run as a goroutine
 | 
					// This function loops forever and is intended to be run as a goroutine
 | 
				
			||||||
func (kl *Kubelet) WatchFile(file string, changeChannel chan<- api.ContainerManifest) {
 | 
					func (kl *Kubelet) WatchFile(file string, changeChannel chan<- api.ContainerManifest) {
 | 
				
			||||||
	var lastData []byte
 | 
						var lastData []byte
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
		time.Sleep(kl.FileCheckFrequency)
 | 
							time.Sleep(kl.FileCheckFrequency)
 | 
				
			||||||
		var manifest api.ContainerManifest
 | 
							lastData, err = kl.extractFromFile(lastData, file, changeChannel)
 | 
				
			||||||
		data, err := ioutil.ReadFile(file)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Printf("Couldn't read file: %s : %v", file, err)
 | 
								log.Printf("Error polling file: %#v", err)
 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err = kl.ExtractYAMLData(data, &manifest); err != nil {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !bytes.Equal(lastData, data) {
 | 
					 | 
				
			||||||
			lastData = data
 | 
					 | 
				
			||||||
			// Ok, we have a valid configuration, send to channel for
 | 
					 | 
				
			||||||
			// rejiggering.
 | 
					 | 
				
			||||||
			changeChannel <- manifest
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (kl *Kubelet) extractFromHTTP(lastData []byte, url string, changeChannel chan<- api.ContainerManifest) ([]byte, error) {
 | 
				
			||||||
 | 
						client := &http.Client{}
 | 
				
			||||||
 | 
						request, err := http.NewRequest("GET", url, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return lastData, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						response, err := client.Do(request)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return lastData, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer response.Body.Close()
 | 
				
			||||||
 | 
						return kl.extractFromReader(lastData, response.Body, changeChannel)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Watch an HTTP endpoint for changes to the set of pods that should run on this Kubelet
 | 
					// Watch an HTTP endpoint for changes to the set of pods that should run on this Kubelet
 | 
				
			||||||
// This function runs forever and is intended to be run as a goroutine
 | 
					// This function runs forever and is intended to be run as a goroutine
 | 
				
			||||||
func (kl *Kubelet) WatchHTTP(url string, changeChannel chan<- api.ContainerManifest) {
 | 
					func (kl *Kubelet) WatchHTTP(url string, changeChannel chan<- api.ContainerManifest) {
 | 
				
			||||||
	var lastData []byte
 | 
						var lastData []byte
 | 
				
			||||||
	client := &http.Client{}
 | 
					 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
		time.Sleep(kl.HTTPCheckFrequency)
 | 
							time.Sleep(kl.HTTPCheckFrequency)
 | 
				
			||||||
		var config api.ContainerManifest
 | 
							lastData, err = kl.extractFromHTTP(lastData, url, changeChannel)
 | 
				
			||||||
		data, err := kl.SyncHTTP(client, url, &config)
 | 
					 | 
				
			||||||
		log.Printf("Containers: %#v", config)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Printf("Error syncing HTTP: %#v", err)
 | 
								log.Printf("Error syncing http: %#v", err)
 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !bytes.Equal(lastData, data) {
 | 
					 | 
				
			||||||
			lastData = data
 | 
					 | 
				
			||||||
			changeChannel <- config
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SyncHTTP reads from url a yaml manifest and populates config. Returns the
 | 
					 | 
				
			||||||
// raw bytes, if something was read. Returns an error if something goes wrong.
 | 
					 | 
				
			||||||
// 'client' is used to execute the request, to allow caching of clients.
 | 
					 | 
				
			||||||
func (kl *Kubelet) SyncHTTP(client *http.Client, url string, config *api.ContainerManifest) ([]byte, error) {
 | 
					 | 
				
			||||||
	request, err := http.NewRequest("GET", url, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	response, err := client.Do(request)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer response.Body.Close()
 | 
					 | 
				
			||||||
	body, err := ioutil.ReadAll(response.Body)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err = kl.ExtractYAMLData(body, &config); err != nil {
 | 
					 | 
				
			||||||
		return body, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return body, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Take an etcd Response object, and turn it into a structured list of containers
 | 
					// Take an etcd Response object, and turn it into a structured list of containers
 | 
				
			||||||
// Return a list of containers, or an error if one occurs.
 | 
					// Return a list of containers, or an error if one occurs.
 | 
				
			||||||
func (kl *Kubelet) ResponseToManifests(response *etcd.Response) ([]api.ContainerManifest, error) {
 | 
					func (kl *Kubelet) ResponseToManifests(response *etcd.Response) ([]api.ContainerManifest, error) {
 | 
				
			||||||
@@ -473,30 +491,32 @@ func (kl *Kubelet) ExtractYAMLData(buf []byte, output interface{}) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (kl *Kubelet) extractFromEtcd(response *etcd.Response) ([]api.ContainerManifest, error) {
 | 
				
			||||||
 | 
						var manifests []api.ContainerManifest
 | 
				
			||||||
 | 
						if response.Node == nil || len(response.Node.Value) == 0 {
 | 
				
			||||||
 | 
							return manifests, fmt.Errorf("No nodes field: %#v", response)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := kl.ExtractYAMLData([]byte(response.Node.Value), &manifests)
 | 
				
			||||||
 | 
						return manifests, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Watch etcd for changes, receives config objects from the etcd client watch.
 | 
					// Watch etcd for changes, receives config objects from the etcd client watch.
 | 
				
			||||||
// This function loops forever and is intended to be run as a goroutine.
 | 
					// This function loops until the watchChannel is closed, and is intended to be run as a goroutine.
 | 
				
			||||||
func (kl *Kubelet) WatchEtcd(watchChannel <-chan *etcd.Response, changeChannel chan<- []api.ContainerManifest) {
 | 
					func (kl *Kubelet) WatchEtcd(watchChannel <-chan *etcd.Response, changeChannel chan<- []api.ContainerManifest) {
 | 
				
			||||||
	defer util.HandleCrash()
 | 
						defer util.HandleCrash()
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		watchResponse := <-watchChannel
 | 
							watchResponse := <-watchChannel
 | 
				
			||||||
		log.Printf("Got change: %#v", watchResponse)
 | 
							log.Printf("Got change: %#v", watchResponse)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		// This means the channel has been closed.
 | 
							// This means the channel has been closed.
 | 
				
			||||||
		if watchResponse == nil {
 | 
							if watchResponse == nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							manifests, err := kl.extractFromEtcd(watchResponse)
 | 
				
			||||||
		if watchResponse.Node == nil || len(watchResponse.Node.Value) == 0 {
 | 
							if err != nil {
 | 
				
			||||||
			log.Printf("No nodes field: %#v", watchResponse)
 | 
								log.Printf("Error handling response from etcd: %#v", err)
 | 
				
			||||||
			if watchResponse.Node != nil {
 | 
					 | 
				
			||||||
				log.Printf("Node: %#v", watchResponse.Node)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		log.Printf("Got data: %v", watchResponse.Node.Value)
 | 
					 | 
				
			||||||
		var manifests []api.ContainerManifest
 | 
					 | 
				
			||||||
		if err := kl.ExtractYAMLData([]byte(watchResponse.Node.Value), &manifests); err != nil {
 | 
					 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							log.Printf("manifests: %#v", manifests)
 | 
				
			||||||
		// Ok, we have a valid configuration, send to channel for
 | 
							// Ok, we have a valid configuration, send to channel for
 | 
				
			||||||
		// rejiggering.
 | 
							// rejiggering.
 | 
				
			||||||
		changeChannel <- manifests
 | 
							changeChannel <- manifests
 | 
				
			||||||
@@ -518,6 +538,11 @@ func (kl *Kubelet) SyncManifests(config []api.ContainerManifest) error {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			if !exists {
 | 
								if !exists {
 | 
				
			||||||
				log.Printf("%#v doesn't exist, creating", element)
 | 
									log.Printf("%#v doesn't exist, creating", element)
 | 
				
			||||||
 | 
									err = kl.pullImage(element.Image)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										log.Printf("Error pulling container: %#v", err)
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				actualName, err = kl.RunContainer(&manifest, &element)
 | 
									actualName, err = kl.RunContainer(&manifest, &element)
 | 
				
			||||||
				// For some reason, list gives back names that start with '/'
 | 
									// For some reason, list gives back names that start with '/'
 | 
				
			||||||
				actualName = "/" + actualName
 | 
									actualName = "/" + actualName
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,13 @@ limitations under the License.
 | 
				
			|||||||
package kubelet
 | 
					package kubelet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -191,6 +194,14 @@ func TestContainerExists(t *testing.T) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Errorf("Unexpected error: %#v", err)
 | 
							t.Errorf("Unexpected error: %#v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fakeDocker.clearCalls()
 | 
				
			||||||
 | 
						missingManifest := api.ContainerManifest{Id: "foobar"}
 | 
				
			||||||
 | 
						exists, _, err = kubelet.ContainerExists(&missingManifest, &container)
 | 
				
			||||||
 | 
						verifyCalls(t, fakeDocker, []string{"list"})
 | 
				
			||||||
 | 
						if exists {
 | 
				
			||||||
 | 
							t.Errorf("Failed to not find container %#v, missingManifest")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetContainerID(t *testing.T) {
 | 
					func TestGetContainerID(t *testing.T) {
 | 
				
			||||||
@@ -322,42 +333,6 @@ func TestKillContainer(t *testing.T) {
 | 
				
			|||||||
	verifyCalls(t, fakeDocker, []string{"list", "stop"})
 | 
						verifyCalls(t, fakeDocker, []string{"list", "stop"})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSyncHTTP(t *testing.T) {
 | 
					 | 
				
			||||||
	containers := api.ContainerManifest{
 | 
					 | 
				
			||||||
		Containers: []api.Container{
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Name:  "foo",
 | 
					 | 
				
			||||||
				Image: "dockerfile/foo",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				Name:  "bar",
 | 
					 | 
				
			||||||
				Image: "dockerfile/bar",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	data, _ := json.Marshal(containers)
 | 
					 | 
				
			||||||
	fakeHandler := util.FakeHandler{
 | 
					 | 
				
			||||||
		StatusCode:   200,
 | 
					 | 
				
			||||||
		ResponseBody: string(data),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	testServer := httptest.NewServer(&fakeHandler)
 | 
					 | 
				
			||||||
	kubelet := Kubelet{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var containersOut api.ContainerManifest
 | 
					 | 
				
			||||||
	data, err := kubelet.SyncHTTP(&http.Client{}, testServer.URL, &containersOut)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Unexpected error: %#v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(containers.Containers) != len(containersOut.Containers) {
 | 
					 | 
				
			||||||
		t.Errorf("Container sizes don't match.  Expected: %d Received %d, %#v", len(containers.Containers), len(containersOut.Containers), containersOut)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	expectedData, _ := json.Marshal(containers)
 | 
					 | 
				
			||||||
	actualData, _ := json.Marshal(containersOut)
 | 
					 | 
				
			||||||
	if string(expectedData) != string(actualData) {
 | 
					 | 
				
			||||||
		t.Errorf("Container data doesn't match.  Expected: %s Received %s", string(expectedData), string(actualData))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestResponseToContainersNil(t *testing.T) {
 | 
					func TestResponseToContainersNil(t *testing.T) {
 | 
				
			||||||
	kubelet := Kubelet{}
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
	list, err := kubelet.ResponseToManifests(&etcd.Response{Node: nil})
 | 
						list, err := kubelet.ResponseToManifests(&etcd.Response{Node: nil})
 | 
				
			||||||
@@ -560,3 +535,331 @@ func TestSyncManifestsDeletes(t *testing.T) {
 | 
				
			|||||||
		t.Errorf("Unexpected call sequence: %#v", fakeDocker.called)
 | 
							t.Errorf("Unexpected call sequence: %#v", fakeDocker.called)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEventWriting(t *testing.T) {
 | 
				
			||||||
 | 
						fakeEtcd := registry.MakeFakeEtcdClient(t)
 | 
				
			||||||
 | 
						kubelet := &Kubelet{
 | 
				
			||||||
 | 
							Client: fakeEtcd,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						expectedEvent := api.Event{
 | 
				
			||||||
 | 
							Event: "test",
 | 
				
			||||||
 | 
							Container: &api.Container{
 | 
				
			||||||
 | 
								Name: "foo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := kubelet.LogEvent(&expectedEvent)
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						if fakeEtcd.Ix != 1 {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected number of children added: %d, expected 1", fakeEtcd.Ix)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						response, err := fakeEtcd.Get("/events/foo/1", false, false)
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						var event api.Event
 | 
				
			||||||
 | 
						err = json.Unmarshal([]byte(response.Node.Value), &event)
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						if event.Event != expectedEvent.Event ||
 | 
				
			||||||
 | 
							event.Container.Name != expectedEvent.Container.Name {
 | 
				
			||||||
 | 
							t.Errorf("Event's don't match.  Expected: %#v Saw: %#v", expectedEvent, event)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestEventWritingError(t *testing.T) {
 | 
				
			||||||
 | 
						fakeEtcd := registry.MakeFakeEtcdClient(t)
 | 
				
			||||||
 | 
						kubelet := &Kubelet{
 | 
				
			||||||
 | 
							Client: fakeEtcd,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fakeEtcd.Err = fmt.Errorf("Test error")
 | 
				
			||||||
 | 
						err := kubelet.LogEvent(&api.Event{
 | 
				
			||||||
 | 
							Event: "test",
 | 
				
			||||||
 | 
							Container: &api.Container{
 | 
				
			||||||
 | 
								Name: "foo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected non-error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMakeCommandLine(t *testing.T) {
 | 
				
			||||||
 | 
						expected := []string{"echo", "hello", "world"}
 | 
				
			||||||
 | 
						container := api.Container{
 | 
				
			||||||
 | 
							Command: strings.Join(expected, " "),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cmdLine := makeCommandLine(&container)
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(expected, cmdLine) {
 | 
				
			||||||
 | 
							t.Error("Unexpected command line.  Expected %#v, got %#v", expected, cmdLine)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMakeEnvVariables(t *testing.T) {
 | 
				
			||||||
 | 
						container := api.Container{
 | 
				
			||||||
 | 
							Env: []api.EnvVar{
 | 
				
			||||||
 | 
								api.EnvVar{
 | 
				
			||||||
 | 
									Name:  "foo",
 | 
				
			||||||
 | 
									Value: "bar",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								api.EnvVar{
 | 
				
			||||||
 | 
									Name:  "baz",
 | 
				
			||||||
 | 
									Value: "blah",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						vars := makeEnvironmentVariables(&container)
 | 
				
			||||||
 | 
						if len(vars) != len(container.Env) {
 | 
				
			||||||
 | 
							t.Errorf("Vars don't match.  Expected: %#v Found: %#v", container.Env, vars)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for ix, env := range container.Env {
 | 
				
			||||||
 | 
							value := fmt.Sprintf("%s=%s", env.Name, env.Value)
 | 
				
			||||||
 | 
							if value != vars[ix] {
 | 
				
			||||||
 | 
								t.Errorf("Unexpected value: %s.  Expected: %s", vars[ix], value)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMakeVolumesAndBinds(t *testing.T) {
 | 
				
			||||||
 | 
						container := api.Container{
 | 
				
			||||||
 | 
							VolumeMounts: []api.VolumeMount{
 | 
				
			||||||
 | 
								api.VolumeMount{
 | 
				
			||||||
 | 
									MountPath: "/mnt/path",
 | 
				
			||||||
 | 
									Name:      "disk",
 | 
				
			||||||
 | 
									ReadOnly:  false,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								api.VolumeMount{
 | 
				
			||||||
 | 
									MountPath: "/mnt/path2",
 | 
				
			||||||
 | 
									Name:      "disk2",
 | 
				
			||||||
 | 
									ReadOnly:  true,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						volumes, binds := makeVolumesAndBinds(&container)
 | 
				
			||||||
 | 
						if len(volumes) != len(container.VolumeMounts) ||
 | 
				
			||||||
 | 
							len(binds) != len(container.VolumeMounts) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected volumes and binds: %#v %#v.  Container was: %#v", volumes, binds, container)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for ix, volume := range container.VolumeMounts {
 | 
				
			||||||
 | 
							expectedBind := "/exports/" + volume.Name + ":" + volume.MountPath
 | 
				
			||||||
 | 
							if volume.ReadOnly {
 | 
				
			||||||
 | 
								expectedBind = expectedBind + ":ro"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if binds[ix] != expectedBind {
 | 
				
			||||||
 | 
								t.Errorf("Unexpected bind.  Expected %s.  Found %s", expectedBind, binds[ix])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, ok := volumes[volume.MountPath]; !ok {
 | 
				
			||||||
 | 
								t.Errorf("Map is missing key: %s. %#v", volume.MountPath, volumes)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMakePortsAndBindings(t *testing.T) {
 | 
				
			||||||
 | 
						container := api.Container{
 | 
				
			||||||
 | 
							Ports: []api.Port{
 | 
				
			||||||
 | 
								api.Port{
 | 
				
			||||||
 | 
									ContainerPort: 80,
 | 
				
			||||||
 | 
									HostPort:      8080,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								api.Port{
 | 
				
			||||||
 | 
									ContainerPort: 443,
 | 
				
			||||||
 | 
									HostPort:      443,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						exposedPorts, bindings := makePortsAndBindings(&container)
 | 
				
			||||||
 | 
						if len(container.Ports) != len(exposedPorts) ||
 | 
				
			||||||
 | 
							len(container.Ports) != len(bindings) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected ports and bindings, %#v %#v %#v", container, exposedPorts, bindings)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExtractFromNonExistentFile(t *testing.T) {
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						changeChannel := make(chan api.ContainerManifest)
 | 
				
			||||||
 | 
						lastData := []byte{1, 2, 3}
 | 
				
			||||||
 | 
						data, err := kubelet.extractFromFile(lastData, "/some/fake/file", changeChannel)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Error("Unexpected non-error.")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !bytes.Equal(data, lastData) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected data response.  Expected %#v, found %#v", lastData, data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExtractFromBadDataFile(t *testing.T) {
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						changeChannel := make(chan api.ContainerManifest)
 | 
				
			||||||
 | 
						lastData := []byte{1, 2, 3}
 | 
				
			||||||
 | 
						file, err := ioutil.TempFile("", "foo")
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						name := file.Name()
 | 
				
			||||||
 | 
						file.Close()
 | 
				
			||||||
 | 
						ioutil.WriteFile(name, lastData, 0755)
 | 
				
			||||||
 | 
						data, err := kubelet.extractFromFile(lastData, name, changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Error("Unexpected non-error.")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !bytes.Equal(data, lastData) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected data response.  Expected %#v, found %#v", lastData, data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExtractFromSameDataFile(t *testing.T) {
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						changeChannel := make(chan api.ContainerManifest)
 | 
				
			||||||
 | 
						manifest := api.ContainerManifest{
 | 
				
			||||||
 | 
							Id: "foo",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lastData, err := json.Marshal(manifest)
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						file, err := ioutil.TempFile("", "foo")
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						name := file.Name()
 | 
				
			||||||
 | 
						expectNoError(t, file.Close())
 | 
				
			||||||
 | 
						ioutil.WriteFile(name, lastData, 0755)
 | 
				
			||||||
 | 
						data, err := kubelet.extractFromFile(lastData, name, changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						if !bytes.Equal(data, lastData) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected data response.  Expected %#v, found %#v", lastData, data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExtractFromChangedDataFile(t *testing.T) {
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						changeChannel := make(chan api.ContainerManifest)
 | 
				
			||||||
 | 
						reader := startReadingSingle(changeChannel)
 | 
				
			||||||
 | 
						oldManifest := api.ContainerManifest{
 | 
				
			||||||
 | 
							Id: "foo",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						newManifest := api.ContainerManifest{
 | 
				
			||||||
 | 
							Id: "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lastData, err := json.Marshal(oldManifest)
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						newData, err := json.Marshal(newManifest)
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						file, err := ioutil.TempFile("", "foo")
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						name := file.Name()
 | 
				
			||||||
 | 
						expectNoError(t, file.Close())
 | 
				
			||||||
 | 
						ioutil.WriteFile(name, newData, 0755)
 | 
				
			||||||
 | 
						data, err := kubelet.extractFromFile(lastData, name, changeChannel)
 | 
				
			||||||
 | 
						close(changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
						if !bytes.Equal(data, newData) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected data response.  Expected %#v, found %#v", lastData, data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						read := reader.GetList()
 | 
				
			||||||
 | 
						if len(read) != 1 {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected channel traffic: %#v", read)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(read[0], newManifest) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected difference.  Expected %#v, got %#v", newManifest, read[0])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExtractFromHttpBadness(t *testing.T) {
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						lastData := []byte{1, 2, 3}
 | 
				
			||||||
 | 
						changeChannel := make(chan api.ContainerManifest)
 | 
				
			||||||
 | 
						data, err := kubelet.extractFromHTTP(lastData, "http://localhost:12345", changeChannel)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Error("Unexpected non-error.")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !bytes.Equal(lastData, data) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected difference.  Expected: %#v, Saw: %#v", lastData, data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExtractFromHttpNoChange(t *testing.T) {
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						changeChannel := make(chan api.ContainerManifest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						manifest := api.ContainerManifest{
 | 
				
			||||||
 | 
							Id: "foo",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lastData, err := json.Marshal(manifest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fakeHandler := util.FakeHandler{
 | 
				
			||||||
 | 
							StatusCode:   200,
 | 
				
			||||||
 | 
							ResponseBody: string(lastData),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						testServer := httptest.NewServer(&fakeHandler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data, err := kubelet.extractFromHTTP(lastData, testServer.URL, changeChannel)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected error: %#v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !bytes.Equal(lastData, data) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected difference.  Expected: %#v, Saw: %#v", lastData, data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExtractFromHttpChanges(t *testing.T) {
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						changeChannel := make(chan api.ContainerManifest)
 | 
				
			||||||
 | 
						reader := startReadingSingle(changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						manifest := api.ContainerManifest{
 | 
				
			||||||
 | 
							Id: "foo",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						newManifest := api.ContainerManifest{
 | 
				
			||||||
 | 
							Id: "bar",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lastData, _ := json.Marshal(manifest)
 | 
				
			||||||
 | 
						newData, _ := json.Marshal(newManifest)
 | 
				
			||||||
 | 
						fakeHandler := util.FakeHandler{
 | 
				
			||||||
 | 
							StatusCode:   200,
 | 
				
			||||||
 | 
							ResponseBody: string(newData),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						testServer := httptest.NewServer(&fakeHandler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data, err := kubelet.extractFromHTTP(lastData, testServer.URL, changeChannel)
 | 
				
			||||||
 | 
						close(changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						read := reader.GetList()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected error: %#v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(read) != 1 {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected list: %#v", read)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !bytes.Equal(newData, data) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected difference.  Expected: %#v, Saw: %#v", lastData, data)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(newManifest, read[0]) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected difference.  Expected: %#v, Saw: %#v", newManifest, read[0])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestWatchEtcd(t *testing.T) {
 | 
				
			||||||
 | 
						watchChannel := make(chan *etcd.Response)
 | 
				
			||||||
 | 
						changeChannel := make(chan []api.ContainerManifest)
 | 
				
			||||||
 | 
						kubelet := Kubelet{}
 | 
				
			||||||
 | 
						reader := startReading(changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						manifest := []api.ContainerManifest{
 | 
				
			||||||
 | 
							api.ContainerManifest{
 | 
				
			||||||
 | 
								Id: "foo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						data, err := json.Marshal(manifest)
 | 
				
			||||||
 | 
						expectNoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go kubelet.WatchEtcd(watchChannel, changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						watchChannel <- &etcd.Response{
 | 
				
			||||||
 | 
							Node: &etcd.Node{
 | 
				
			||||||
 | 
								Value: string(data),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						close(watchChannel)
 | 
				
			||||||
 | 
						close(changeChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						read := reader.GetList()
 | 
				
			||||||
 | 
						if len(read) != 1 ||
 | 
				
			||||||
 | 
							!reflect.DeepEqual(read[0], manifest) {
 | 
				
			||||||
 | 
							t.Errorf("Unexpected manifest(s) %#v %#v", read[0], manifest)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,8 +30,9 @@ type EtcdResponseWithError struct {
 | 
				
			|||||||
type FakeEtcdClient struct {
 | 
					type FakeEtcdClient struct {
 | 
				
			||||||
	Data        map[string]EtcdResponseWithError
 | 
						Data        map[string]EtcdResponseWithError
 | 
				
			||||||
	deletedKeys []string
 | 
						deletedKeys []string
 | 
				
			||||||
	err         error
 | 
						Err         error
 | 
				
			||||||
	t           *testing.T
 | 
						t           *testing.T
 | 
				
			||||||
 | 
						Ix			int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func MakeFakeEtcdClient(t *testing.T) *FakeEtcdClient {
 | 
					func MakeFakeEtcdClient(t *testing.T) *FakeEtcdClient {
 | 
				
			||||||
@@ -42,7 +43,8 @@ func MakeFakeEtcdClient(t *testing.T) *FakeEtcdClient {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *FakeEtcdClient) AddChild(key, data string, ttl uint64) (*etcd.Response, error) {
 | 
					func (f *FakeEtcdClient) AddChild(key, data string, ttl uint64) (*etcd.Response, error) {
 | 
				
			||||||
	return f.Set(key, data, ttl)
 | 
						f.Ix = f.Ix + 1
 | 
				
			||||||
 | 
						return f.Set(fmt.Sprintf("%s/%d", key, f.Ix), data, ttl)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *FakeEtcdClient) Get(key string, sort, recursive bool) (*etcd.Response, error) {
 | 
					func (f *FakeEtcdClient) Get(key string, sort, recursive bool) (*etcd.Response, error) {
 | 
				
			||||||
@@ -63,14 +65,14 @@ func (f *FakeEtcdClient) Set(key, value string, ttl uint64) (*etcd.Response, err
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	f.Data[key] = result
 | 
						f.Data[key] = result
 | 
				
			||||||
	return result.R, f.err
 | 
						return result.R, f.Err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (f *FakeEtcdClient) Create(key, value string, ttl uint64) (*etcd.Response, error) {
 | 
					func (f *FakeEtcdClient) Create(key, value string, ttl uint64) (*etcd.Response, error) {
 | 
				
			||||||
	return f.Set(key, value, ttl)
 | 
						return f.Set(key, value, ttl)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (f *FakeEtcdClient) Delete(key string, recursive bool) (*etcd.Response, error) {
 | 
					func (f *FakeEtcdClient) Delete(key string, recursive bool) (*etcd.Response, error) {
 | 
				
			||||||
	f.deletedKeys = append(f.deletedKeys, key)
 | 
						f.deletedKeys = append(f.deletedKeys, key)
 | 
				
			||||||
	return &etcd.Response{}, f.err
 | 
						return &etcd.Response{}, f.Err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *FakeEtcdClient) Watch(prefix string, waitIndex uint64, recursive bool, receiver chan *etcd.Response, stop chan bool) (*etcd.Response, error) {
 | 
					func (f *FakeEtcdClient) Watch(prefix string, waitIndex uint64, recursive bool, receiver chan *etcd.Response, stop chan bool) (*etcd.Response, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user