Example #1
0
// getContainerStatus creates the api.containerStatus of a container from the podInfo.
// TODO(yifan): Get more detailed info such as Image, ImageID, etc.
func (p *podInfo) getContainerStatus(container *kubecontainer.Container) api.ContainerStatus {
	var status api.ContainerStatus
	status.Name = container.Name
	status.Image = container.Image
	containerID, _ := parseContainerID(string(container.ID))
	status.ImageID = containerID.imageID

	switch p.state {
	case Running:
		// TODO(yifan): Get StartedAt.
		status.State = api.ContainerState{
			Running: &api.ContainerStateRunning{
				StartedAt: util.Unix(container.Created, 0),
			},
		}
	case Embryo, Preparing, Prepared:
		status.State = api.ContainerState{Waiting: &api.ContainerStateWaiting{}}
	case AbortedPrepare, Deleting, Exited, Garbage:
		exitCode, ok := p.exitCodes[status.ImageID]
		if !ok {
			glog.Warningf("rkt: Cannot get exit code for container %v", container)
		}
		exitCode = -1
		status.State = api.ContainerState{
			Terminated: &api.ContainerStateTerminated{
				ExitCode:  exitCode,
				StartedAt: util.Unix(container.Created, 0),
			},
		}
	default:
		glog.Warningf("rkt: Unknown pod state: %q", p.state)
	}
	return status
}
Example #2
0
func TestStoreEventsMultipleEventsInput(t *testing.T) {
	// Arrange
	fakeSink := NewFakeSink(false /* avoidColumns */)
	event1Time := kube_time.Unix(12345, 0)
	event2Time := kube_time.Unix(12366, 0)
	event1SourceHostname := "event1HostName"
	event2SourceHostname := "event2HostName"
	event1Reason := "event1"
	event2Reason := "event2"
	events := []kube_api.Event{
		kube_api.Event{
			Reason:        event1Reason,
			LastTimestamp: event1Time,
			Source: kube_api.EventSource{
				Host: event1SourceHostname,
			},
		},
		kube_api.Event{
			Reason:        event2Reason,
			LastTimestamp: event2Time,
			Source: kube_api.EventSource{
				Host: event2SourceHostname,
			},
		},
	}

	// Act
	err := fakeSink.StoreEvents(events)

	// Assert
	assert.NoError(t, err)
	assert.Equal(t, 1 /* expected */, len(fakeSink.fakeClient.capturedWriteCalls) /* actual */)
	assert.Equal(t, influxdb.Millisecond /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].timePrecision /* actual */)
	assert.Equal(t, 1 /* expected */, len(fakeSink.fakeClient.capturedWriteCalls[0].series) /* actual */)
	assert.Equal(t, eventsSeriesName /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Name /* actual */)
	assert.Equal(t, 6 /* expected */, len(fakeSink.fakeClient.capturedWriteCalls[0].series[0].Columns) /* actual */)
	assert.Equal(t, 2 /* expected */, len(fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points) /* actual */)
	assert.Equal(t, event1Time.Unix() /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[0][0] /* actual */)          // Column 0 - time
	assert.Equal(t, uint64(0xcbf29ce484222325) /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[0][1] /* actual */) // Column 1 - sequence_number
	assert.Equal(t, "" /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[0][2] /* actual */)                         // Column 2 - pod_id
	assert.Equal(t, "" /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[0][3] /* actual */)                         // Column 3 - pod_id
	assert.Equal(t, event1SourceHostname /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[0][4] /* actual */)       // Column 4 - pod_id
	assert.Contains(t, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[0][5], event1Reason)                                        // Column 5 - value
	assert.Equal(t, event2Time.Unix() /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[1][0] /* actual */)          // Column 0 - time
	assert.Equal(t, uint64(0xcbf29ce484222325) /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[1][1] /* actual */) // Column 1 - sequence_number
	assert.Equal(t, "" /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[1][2] /* actual */)                         // Column 2 - pod_id
	assert.Equal(t, "" /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[1][3] /* actual */)                         // Column 3 - pod_id
	assert.Equal(t, event2SourceHostname /* expected */, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[1][4] /* actual */)       // Column 4 - pod_id
	assert.Contains(t, fakeSink.fakeClient.capturedWriteCalls[0].series[0].Points[1][5], event2Reason)                                        // Column 5 - value

}
Example #3
0
func TestStoreEventsSingleEventInput(t *testing.T) {
	// Arrange
	fakeSink := NewFakeSink()
	eventTime := kube_time.Unix(12345, 0)
	events := []kube_api.Event{
		kube_api.Event{
			Reason:         "event1",
			FirstTimestamp: eventTime,
			LastTimestamp:  eventTime,
			Source: kube_api.EventSource{
				Host: "event1HostName",
			},
		},
	}

	// Act
	err := fakeSink.StoreEvents(events)

	// Assert
	assert.NoError(t, err)
	assert.Equal(t, 1 /* expected */, len(fakeSink.fakeHttpClient.capturedSendRequests) /* actual */)
	assert.Equal(t, "POST" /* expected */, fakeSink.fakeHttpClient.capturedSendRequests[0].Method /* actual */)
	assert.Equal(t, "https" /* expected */, fakeSink.fakeHttpClient.capturedSendRequests[0].URL.Scheme /* actual */)
	assert.Equal(t, "logging.googleapis.com" /* expected */, fakeSink.fakeHttpClient.capturedSendRequests[0].URL.Host /* actual */)
	assert.Equal(t, "/v1beta3/projects/fakeProjectId/logs/kubernetes.io%2Fevents/entries:write" /* expected */, fakeSink.fakeHttpClient.capturedSendRequests[0].URL.Opaque /* actual */)
	assert.Equal(t, 2 /* expected */, len(fakeSink.fakeHttpClient.capturedSendRequests[0].Header) /* actual */)
	assert.Equal(t, 1 /* expected */, len(fakeSink.fakeHttpClient.capturedSendRequests[0].Header["Content-Type"]) /* actual */)
	assert.Equal(t, "application/json" /* expected */, fakeSink.fakeHttpClient.capturedSendRequests[0].Header["Content-Type"][0] /* actual */)
	assert.Equal(t, 1 /* expected */, len(fakeSink.fakeHttpClient.capturedSendRequests[0].Header["Authorization"]) /* actual */)
	assert.Equal(t, "Bearer fakeToken" /* expected */, fakeSink.fakeHttpClient.capturedSendRequests[0].Header["Authorization"][0] /* actual */)
	reqBodyBytes, err := ioutil.ReadAll(fakeSink.fakeHttpClient.capturedSendRequests[0].Body)
	assert.NoError(t, err)
	expectedJson := "{\"entries\":[{\"metadata\":{\"timestamp\":\"1970-01-01T03:25:45Z\",\"severity\":\"NOTICE\",\"projectId\":\"fakeProjectId\",\"serviceName\":\"custom.googleapis.com\"},\"structPayload\":{\"metadata\":{\"creationTimestamp\":null},\"involvedObject\":{},\"reason\":\"event1\",\"source\":{\"host\":\"event1HostName\"},\"firstTimestamp\":\"1970-01-01T03:25:45Z\",\"lastTimestamp\":\"1970-01-01T03:25:45Z\"}}]}"
	assert.Equal(t, expectedJson /* expected */, string(reqBodyBytes) /* actual */)
}
func TestAddOrUpdateEventExisting(t *testing.T) {
	// Arrange
	event1Time := util.Unix(2324, 2342)
	event2Time := util.Now()
	event1 := api.Event{
		Reason:  "something happened",
		Message: "can you believe it?",
		ObjectMeta: api.ObjectMeta{
			ResourceVersion: "rs1",
		},
		InvolvedObject: api.ObjectReference{
			Kind:       "Scheduler",
			Name:       "anOkName",
			Namespace:  "someNamespace",
			UID:        "C934D3234CD0242",
			APIVersion: "version",
		},
		Source: api.EventSource{
			Component: "kubelet",
			Host:      "kublet.node2",
		},
		Count:          1,
		FirstTimestamp: event1Time,
		LastTimestamp:  event1Time,
	}
	event2 := api.Event{
		Reason:  "something happened",
		Message: "can you believe it?",
		ObjectMeta: api.ObjectMeta{
			ResourceVersion: "rs2",
		},
		InvolvedObject: api.ObjectReference{
			Kind:       "Scheduler",
			Name:       "anOkName",
			Namespace:  "someNamespace",
			UID:        "C934D3234CD0242",
			APIVersion: "version",
		},
		Source: api.EventSource{
			Component: "kubelet",
			Host:      "kublet.node2",
		},
		Count:          3,
		FirstTimestamp: event1Time,
		LastTimestamp:  event2Time,
	}

	// Act
	addOrUpdateEvent(&event1)
	result1 := addOrUpdateEvent(&event2)
	result2 := getEvent(&event1)

	// Assert
	compareEventWithHistoryEntry(&event2, &result1, t)
	compareEventWithHistoryEntry(&event2, &result2, t)
}
Example #5
0
// FuzzerFor can randomly populate api objects that are destined for version.
func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
	f := fuzz.New().NilChance(.5).NumElements(1, 1)
	if src != nil {
		f.RandSource(src)
	}
	f.Funcs(
		func(j *runtime.PluginBase, c fuzz.Continue) {
			// Do nothing; this struct has only a Kind field and it must stay blank in memory.
		},
		func(j *runtime.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.ObjectMeta, c fuzz.Continue) {
			j.Name = c.RandString()
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()
			j.UID = types.UID(c.RandString())
			j.GenerateName = c.RandString()

			var sec, nsec int64
			c.Fuzz(&sec)
			c.Fuzz(&nsec)
			j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
		},
		func(j *api.ObjectReference, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = c.RandString()
			j.Kind = c.RandString()
			j.Namespace = c.RandString()
			j.Name = c.RandString()
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.FieldPath = c.RandString()
		},
		func(j *api.ListMeta, c fuzz.Continue) {
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()
		},
		func(j *api.ListOptions, c fuzz.Continue) {
			// TODO: add some parsing
			j.LabelSelector, _ = labels.Parse("a=b")
			j.FieldSelector, _ = fields.ParseSelector("a=b")
		},
		func(j *api.PodPhase, c fuzz.Continue) {
			statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
			*j = statuses[c.Rand.Intn(len(statuses))]
		},
		func(j *api.PodTemplateSpec, c fuzz.Continue) {
			// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
			// conversion compare converted object to nil via DeepEqual
			j.ObjectMeta = api.ObjectMeta{}
			c.Fuzz(&j.ObjectMeta)
			j.ObjectMeta = api.ObjectMeta{Labels: j.ObjectMeta.Labels}
			j.Spec = api.PodSpec{}
			c.Fuzz(&j.Spec)
		},
		func(j *api.Binding, c fuzz.Continue) {
			c.Fuzz(&j.ObjectMeta)
			j.Target.Name = c.RandString()
		},
		func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			//j.TemplateRef = nil // this is required for round trip
		},
		func(j *api.ReplicationControllerStatus, c fuzz.Continue) {
			// only replicas round trips
			j.Replicas = int(c.RandUint64())
		},
		func(j *api.List, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			// TODO: uncomment when round trip starts from a versioned object
			if false { //j.Items == nil {
				j.Items = []runtime.Object{}
			}
		},
		func(j *runtime.Object, c fuzz.Continue) {
			// TODO: uncomment when round trip starts from a versioned object
			if true { //c.RandBool() {
				*j = &runtime.Unknown{
					TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"},
					RawJSON:  []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`),
				}
			} else {
				types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
				t := types[c.Rand.Intn(len(types))]
				c.Fuzz(t)
				*j = t
			}
		},
		func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pb[docker.Port(c.RandString())] = []docker.PortBinding{
				{c.RandString(), c.RandString()},
				{c.RandString(), c.RandString()},
			}
		},
		func(pm map[string]docker.PortMapping, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pm[c.RandString()] = docker.PortMapping{
				c.RandString(): c.RandString(),
			}
		},
		func(q *resource.Quantity, c fuzz.Continue) {
			// Real Quantity fuzz testing is done elsewhere;
			// this limited subset of functionality survives
			// round-tripping to v1beta1/2.
			q.Amount = &inf.Dec{}
			q.Format = resource.DecimalExponent
			//q.Amount.SetScale(inf.Scale(-c.Intn(12)))
			q.Amount.SetUnscaled(c.Int63n(1000))
		},
		func(p *api.PullPolicy, c fuzz.Continue) {
			policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent}
			*p = policies[c.Rand.Intn(len(policies))]
		},
		func(rp *api.RestartPolicy, c fuzz.Continue) {
			policies := []api.RestartPolicy{api.RestartPolicyAlways, api.RestartPolicyNever, api.RestartPolicyOnFailure}
			*rp = policies[c.Rand.Intn(len(policies))]
		},
		func(vs *api.VolumeSource, c fuzz.Continue) {
			// Exactly one of the fields must be set.
			v := reflect.ValueOf(vs).Elem()
			i := int(c.RandUint64() % uint64(v.NumField()))
			v = v.Field(i).Addr()
			// Use a new fuzzer which cannot populate nil to ensure one field will be set.
			fuzz.New().NilChance(0).NumElements(1, 1).Fuzz(v.Interface())
		},
		func(d *api.DNSPolicy, c fuzz.Continue) {
			policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
			*d = policies[c.Rand.Intn(len(policies))]
		},
		func(p *api.Protocol, c fuzz.Continue) {
			protocols := []api.Protocol{api.ProtocolTCP, api.ProtocolUDP}
			*p = protocols[c.Rand.Intn(len(protocols))]
		},
		func(p *api.ServiceAffinity, c fuzz.Continue) {
			types := []api.ServiceAffinity{api.ServiceAffinityClientIP, api.ServiceAffinityNone}
			*p = types[c.Rand.Intn(len(types))]
		},
		func(p *api.ServiceType, c fuzz.Continue) {
			types := []api.ServiceType{api.ServiceTypeClusterIP, api.ServiceTypeNodePort, api.ServiceTypeLoadBalancer}
			*p = types[c.Rand.Intn(len(types))]
		},
		func(ct *api.Container, c fuzz.Continue) {
			c.FuzzNoCustom(ct)                                          // fuzz self without calling this function again
			ct.TerminationMessagePath = "/" + ct.TerminationMessagePath // Must be non-empty
		},
		func(ev *api.EnvVar, c fuzz.Continue) {
			ev.Name = c.RandString()
			if c.RandBool() {
				ev.Value = c.RandString()
			} else {
				ev.ValueFrom = &api.EnvVarSource{}
				ev.ValueFrom.FieldRef = &api.ObjectFieldSelector{}

				versions := []string{"v1beta1", "v1beta2", "v1beta3"}

				ev.ValueFrom.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))]
				ev.ValueFrom.FieldRef.FieldPath = c.RandString()
			}
		},
		func(sc *api.SecurityContext, c fuzz.Continue) {
			c.FuzzNoCustom(sc) // fuzz self without calling this function again
			priv := c.RandBool()
			sc.Privileged = &priv
			sc.Capabilities = &api.Capabilities{
				Add:  make([]api.Capability, 0),
				Drop: make([]api.Capability, 0),
			}
			c.Fuzz(&sc.Capabilities.Add)
			c.Fuzz(&sc.Capabilities.Drop)
		},
		func(e *api.Event, c fuzz.Continue) {
			c.FuzzNoCustom(e) // fuzz self without calling this function again
			// Fix event count to 1, otherwise, if a v1beta1 or v1beta2 event has a count set arbitrarily, it's count is ignored
			if e.FirstTimestamp.IsZero() {
				e.Count = 1
			} else {
				c.Fuzz(&e.Count)
			}
		},
		func(s *api.Secret, c fuzz.Continue) {
			c.FuzzNoCustom(s) // fuzz self without calling this function again
			s.Type = api.SecretTypeOpaque
		},
		func(pv *api.PersistentVolume, c fuzz.Continue) {
			c.FuzzNoCustom(pv) // fuzz self without calling this function again
			types := []api.PersistentVolumePhase{api.VolumeAvailable, api.VolumePending, api.VolumeBound, api.VolumeReleased, api.VolumeFailed}
			pv.Status.Phase = types[c.Rand.Intn(len(types))]
			pv.Status.Message = c.RandString()
			reclamationPolicies := []api.PersistentVolumeReclaimPolicy{api.PersistentVolumeReclaimRecycle, api.PersistentVolumeReclaimRetain}
			pv.Spec.PersistentVolumeReclaimPolicy = reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))]
		},
		func(pvc *api.PersistentVolumeClaim, c fuzz.Continue) {
			c.FuzzNoCustom(pvc) // fuzz self without calling this function again
			types := []api.PersistentVolumeClaimPhase{api.ClaimBound, api.ClaimPending}
			pvc.Status.Phase = types[c.Rand.Intn(len(types))]
		},
		func(s *api.NamespaceSpec, c fuzz.Continue) {
			s.Finalizers = []api.FinalizerName{api.FinalizerKubernetes}
		},
		func(s *api.NamespaceStatus, c fuzz.Continue) {
			s.Phase = api.NamespaceActive
		},
		func(http *api.HTTPGetAction, c fuzz.Continue) {
			c.FuzzNoCustom(http)            // fuzz self without calling this function again
			http.Path = "/" + http.Path     // can't be blank
			http.Scheme = "x" + http.Scheme // can't be blank
		},
		func(ss *api.ServiceSpec, c fuzz.Continue) {
			c.FuzzNoCustom(ss) // fuzz self without calling this function again
			if len(ss.Ports) == 0 {
				// There must be at least 1 port.
				ss.Ports = append(ss.Ports, api.ServicePort{})
				c.Fuzz(&ss.Ports[0])
			}
			for i := range ss.Ports {
				switch ss.Ports[i].TargetPort.Kind {
				case util.IntstrInt:
					ss.Ports[i].TargetPort.IntVal = 1 + ss.Ports[i].TargetPort.IntVal%65535 // non-zero
				case util.IntstrString:
					ss.Ports[i].TargetPort.StrVal = "x" + ss.Ports[i].TargetPort.StrVal // non-empty
				}
			}
		},
		func(n *api.Node, c fuzz.Continue) {
			c.FuzzNoCustom(n)
			n.Spec.ExternalID = "external"
		},
	)
	return f
}
	},
	func(j *api.TypeMeta, c fuzz.Continue) {
		// We have to customize the randomization of TypeMetas because their
		// APIVersion and Kind must remain blank in memory.
		j.APIVersion = ""
		j.Kind = ""
	},
	func(j *api.ObjectMeta, c fuzz.Continue) {
		j.Name = c.RandString()
		j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
		j.SelfLink = c.RandString()

		var sec, nsec int64
		c.Fuzz(&sec)
		c.Fuzz(&nsec)
		j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
	},
	func(j *api.ListMeta, c fuzz.Continue) {
		j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
		j.SelfLink = c.RandString()
	},
	func(j *api.PodPhase, c fuzz.Continue) {
		statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
		*j = statuses[c.Rand.Intn(len(statuses))]
	},
	func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
		// TemplateRef must be nil for round trip
		c.Fuzz(&j.Template)
		if j.Template == nil {
			// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
			// conversion compare converted object to nil via DeepEqual
// fuzzerFor can randomly populate api objects that are destined for version.
func fuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
	f := fuzz.New().NilChance(.5).NumElements(1, 1)
	if src != nil {
		f.RandSource(src)
	}
	f.Funcs(
		func(j *runtime.PluginBase, c fuzz.Continue) {
			// Do nothing; this struct has only a Kind field and it must stay blank in memory.
		},
		func(j *runtime.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.ObjectMeta, c fuzz.Continue) {
			j.Name = c.RandString()
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()

			var sec, nsec int64
			c.Fuzz(&sec)
			c.Fuzz(&nsec)
			j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
		},
		func(j *api.ListMeta, c fuzz.Continue) {
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()
		},
		func(j *api.PodPhase, c fuzz.Continue) {
			statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
			*j = statuses[c.Rand.Intn(len(statuses))]
		},
		func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
			// TemplateRef must be nil for round trip
			c.Fuzz(&j.Template)
			if j.Template == nil {
				// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
				// conversion compare converted object to nil via DeepEqual
				j.Template = &api.PodTemplateSpec{}
			}
			j.Template.ObjectMeta = api.ObjectMeta{Labels: j.Template.ObjectMeta.Labels}
			j.Template.Spec.NodeSelector = nil
			c.Fuzz(&j.Selector)
			j.Replicas = int(c.RandUint64())
		},
		func(j *api.ReplicationControllerStatus, c fuzz.Continue) {
			// only replicas round trips
			j.Replicas = int(c.RandUint64())
		},
		func(j *api.List, c fuzz.Continue) {
			c.Fuzz(&j.ListMeta)
			c.Fuzz(&j.Items)
			if j.Items == nil {
				j.Items = []runtime.Object{}
			}
		},
		func(j *runtime.Object, c fuzz.Continue) {
			if c.RandBool() {
				*j = &runtime.Unknown{
					TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"},
					RawJSON:  []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`),
				}
			} else {
				types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
				t := types[c.Rand.Intn(len(types))]
				c.Fuzz(t)
				*j = t
			}
		},
		func(intstr *util.IntOrString, c fuzz.Continue) {
			// util.IntOrString will panic if its kind is set wrong.
			if c.RandBool() {
				intstr.Kind = util.IntstrInt
				intstr.IntVal = int(c.RandUint64())
				intstr.StrVal = ""
			} else {
				intstr.Kind = util.IntstrString
				intstr.IntVal = 0
				intstr.StrVal = c.RandString()
			}
		},
		func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pb[docker.Port(c.RandString())] = []docker.PortBinding{
				{c.RandString(), c.RandString()},
				{c.RandString(), c.RandString()},
			}
		},
		func(pm map[string]docker.PortMapping, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pm[c.RandString()] = docker.PortMapping{
				c.RandString(): c.RandString(),
			}
		},

		func(q *resource.Quantity, c fuzz.Continue) {
			// Real Quantity fuzz testing is done elsewhere;
			// this limited subset of functionality survives
			// round-tripping to v1beta1/2.
			q.Amount = &inf.Dec{}
			q.Format = resource.DecimalExponent
			//q.Amount.SetScale(inf.Scale(-c.Intn(12)))
			q.Amount.SetUnscaled(c.Int63n(1000))
		},
	)
	return f
}
func TestDescribeBuildDuration(t *testing.T) {
	type testBuild struct {
		build  *buildapi.Build
		output string
	}

	creation := kutil.Date(2015, time.April, 9, 6, 0, 0, 0, time.Local)
	// now a minute ago
	minuteAgo := kutil.Unix(kutil.Now().Rfc3339Copy().Time.Unix()-60, 0)
	start := kutil.Date(2015, time.April, 9, 6, 1, 0, 0, time.Local)
	completion := kutil.Date(2015, time.April, 9, 6, 2, 0, 0, time.Local)
	duration := completion.Rfc3339Copy().Time.Sub(start.Rfc3339Copy().Time)
	zeroDuration := time.Duration(0)

	tests := []testBuild{
		{ // 0 - build new
			&buildapi.Build{
				ObjectMeta: kapi.ObjectMeta{CreationTimestamp: minuteAgo},
				Status:     buildapi.BuildStatusNew,
				Duration:   zeroDuration,
			},
			"waiting for 1m0s",
		},
		{ // 1 - build pending
			&buildapi.Build{
				ObjectMeta: kapi.ObjectMeta{CreationTimestamp: minuteAgo},
				Status:     buildapi.BuildStatusPending,
				Duration:   zeroDuration,
			},
			"waiting for 1m0s",
		},
		{ // 2 - build running
			&buildapi.Build{
				ObjectMeta:     kapi.ObjectMeta{CreationTimestamp: creation},
				StartTimestamp: &start,
				Status:         buildapi.BuildStatusRunning,
				Duration:       duration,
			},
			"running for 1m0s",
		},
		{ // 3 - build completed
			&buildapi.Build{
				ObjectMeta:          kapi.ObjectMeta{CreationTimestamp: creation},
				StartTimestamp:      &start,
				CompletionTimestamp: &completion,
				Status:              buildapi.BuildStatusComplete,
				Duration:            duration,
			},
			"1m0s",
		},
		{ // 4 - build failed
			&buildapi.Build{
				ObjectMeta:          kapi.ObjectMeta{CreationTimestamp: creation},
				StartTimestamp:      &start,
				CompletionTimestamp: &completion,
				Status:              buildapi.BuildStatusFailed,
				Duration:            duration,
			},
			"1m0s",
		},
		{ // 5 - build error
			&buildapi.Build{
				ObjectMeta:          kapi.ObjectMeta{CreationTimestamp: creation},
				StartTimestamp:      &start,
				CompletionTimestamp: &completion,
				Status:              buildapi.BuildStatusError,
				Duration:            duration,
			},
			"1m0s",
		},
		{ // 6 - build cancelled before running, start time wasn't set yet
			&buildapi.Build{
				ObjectMeta:          kapi.ObjectMeta{CreationTimestamp: creation},
				CompletionTimestamp: &completion,
				Status:              buildapi.BuildStatusCancelled,
				Duration:            duration,
			},
			"waited for 2m0s",
		},
		{ // 7 - build cancelled while running, start time is set already
			&buildapi.Build{
				ObjectMeta:          kapi.ObjectMeta{CreationTimestamp: creation},
				StartTimestamp:      &start,
				CompletionTimestamp: &completion,
				Status:              buildapi.BuildStatusCancelled,
				Duration:            duration,
			},
			"1m0s",
		},
		{ // 8 - build failed before running, start time wasn't set yet
			&buildapi.Build{
				ObjectMeta:          kapi.ObjectMeta{CreationTimestamp: creation},
				CompletionTimestamp: &completion,
				Status:              buildapi.BuildStatusFailed,
				Duration:            duration,
			},
			"waited for 2m0s",
		},
		{ // 9 - build error before running, start time wasn't set yet
			&buildapi.Build{
				ObjectMeta:          kapi.ObjectMeta{CreationTimestamp: creation},
				CompletionTimestamp: &completion,
				Status:              buildapi.BuildStatusError,
				Duration:            duration,
			},
			"waited for 2m0s",
		},
	}

	for i, tc := range tests {
		if actual, expected := describeBuildDuration(tc.build), tc.output; actual != expected {
			t.Errorf("(%d) expected duration output %s, got %s", i, expected, actual)
		}
	}
}
Example #9
0
// FuzzerFor can randomly populate api objects that are destined for version.
func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
	f := fuzz.New().NilChance(.5).NumElements(1, 1)
	if src != nil {
		f.RandSource(src)
	}
	f.Funcs(
		func(j *runtime.PluginBase, c fuzz.Continue) {
			// Do nothing; this struct has only a Kind field and it must stay blank in memory.
		},
		func(j *runtime.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.ObjectMeta, c fuzz.Continue) {
			j.Name = c.RandString()
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()
			j.UID = types.UID(c.RandString())
			j.GenerateName = c.RandString()

			var sec, nsec int64
			c.Fuzz(&sec)
			c.Fuzz(&nsec)
			j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
		},
		func(j *api.ObjectReference, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = c.RandString()
			j.Kind = c.RandString()
			j.Namespace = c.RandString()
			j.Name = c.RandString()
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.FieldPath = c.RandString()
		},
		func(j *api.ListMeta, c fuzz.Continue) {
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()
		},
		func(j *api.PodPhase, c fuzz.Continue) {
			statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
			*j = statuses[c.Rand.Intn(len(statuses))]
		},
		func(j *api.PodTemplateSpec, c fuzz.Continue) {
			// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
			// conversion compare converted object to nil via DeepEqual
			j.ObjectMeta = api.ObjectMeta{}
			c.Fuzz(&j.ObjectMeta)
			j.ObjectMeta = api.ObjectMeta{Labels: j.ObjectMeta.Labels}
			j.Spec = api.PodSpec{}
			c.Fuzz(&j.Spec)
		},
		func(j *api.Binding, c fuzz.Continue) {
			c.Fuzz(&j.ObjectMeta)
			j.Target.Name = c.RandString()
		},
		func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
			c.FuzzNoCustom(j)   // fuzz self without calling this function again
			j.TemplateRef = nil // this is required for round trip
		},
		func(j *api.ReplicationControllerStatus, c fuzz.Continue) {
			// only replicas round trips
			j.Replicas = int(c.RandUint64())
		},
		func(j *api.List, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			if j.Items == nil {
				j.Items = []runtime.Object{}
			}
		},
		func(j *runtime.Object, c fuzz.Continue) {
			if c.RandBool() {
				*j = &runtime.Unknown{
					TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"},
					RawJSON:  []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`),
				}
			} else {
				types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
				t := types[c.Rand.Intn(len(types))]
				c.Fuzz(t)
				*j = t
			}
		},
		func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pb[docker.Port(c.RandString())] = []docker.PortBinding{
				{c.RandString(), c.RandString()},
				{c.RandString(), c.RandString()},
			}
		},
		func(pm map[string]docker.PortMapping, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pm[c.RandString()] = docker.PortMapping{
				c.RandString(): c.RandString(),
			}
		},
		func(q *resource.Quantity, c fuzz.Continue) {
			// Real Quantity fuzz testing is done elsewhere;
			// this limited subset of functionality survives
			// round-tripping to v1beta1/2.
			q.Amount = &inf.Dec{}
			q.Format = resource.DecimalExponent
			//q.Amount.SetScale(inf.Scale(-c.Intn(12)))
			q.Amount.SetUnscaled(c.Int63n(1000))
		},
		func(p *api.PullPolicy, c fuzz.Continue) {
			policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent}
			*p = policies[c.Rand.Intn(len(policies))]
		},
		func(rp *api.RestartPolicy, c fuzz.Continue) {
			policies := []api.RestartPolicy{api.RestartPolicyAlways, api.RestartPolicyNever, api.RestartPolicyOnFailure}
			*rp = policies[c.Rand.Intn(len(policies))]
		},
		func(vs *api.VolumeSource, c fuzz.Continue) {
			// Exactly one of the fields should be set.
			//FIXME: the fuzz can still end up nil.  What if fuzz allowed me to say that?
			fuzzOneOf(c, &vs.HostPath, &vs.EmptyDir, &vs.GCEPersistentDisk, &vs.GitRepo, &vs.Secret, &vs.NFS)
		},
		func(d *api.DNSPolicy, c fuzz.Continue) {
			policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
			*d = policies[c.Rand.Intn(len(policies))]
		},
		func(p *api.Protocol, c fuzz.Continue) {
			protocols := []api.Protocol{api.ProtocolTCP, api.ProtocolUDP}
			*p = protocols[c.Rand.Intn(len(protocols))]
		},
		func(p *api.AffinityType, c fuzz.Continue) {
			types := []api.AffinityType{api.AffinityTypeClientIP, api.AffinityTypeNone}
			*p = types[c.Rand.Intn(len(types))]
		},
		func(ct *api.Container, c fuzz.Continue) {
			c.FuzzNoCustom(ct)                                          // fuzz self without calling this function again
			ct.TerminationMessagePath = "/" + ct.TerminationMessagePath // Must be non-empty
		},
		func(e *api.Event, c fuzz.Continue) {
			c.FuzzNoCustom(e) // fuzz self without calling this function again
			// Fix event count to 1, otherwise, if a v1beta1 or v1beta2 event has a count set arbitrarily, it's count is ignored
			if e.FirstTimestamp.IsZero() {
				e.Count = 1
			} else {
				c.Fuzz(&e.Count)
			}
		},
		func(s *api.Secret, c fuzz.Continue) {
			c.FuzzNoCustom(s) // fuzz self without calling this function again
			s.Type = api.SecretTypeOpaque
		},
		func(s *api.NamespaceStatus, c fuzz.Continue) {
			s.Phase = api.NamespaceActive
		},
		func(ep *api.Endpoint, c fuzz.Continue) {
			// TODO: If our API used a particular type for IP fields we could just catch that here.
			ep.IP = fmt.Sprintf("%d.%d.%d.%d", c.Rand.Intn(256), c.Rand.Intn(256), c.Rand.Intn(256), c.Rand.Intn(256))
			ep.Port = c.Rand.Intn(65536)
		},
		func(http *api.HTTPGetAction, c fuzz.Continue) {
			c.FuzzNoCustom(http)        // fuzz self without calling this function again
			http.Path = "/" + http.Path // can't be blank
		},
		func(ss *api.ServiceSpec, c fuzz.Continue) {
			c.FuzzNoCustom(ss) // fuzz self without calling this function again
			switch ss.TargetPort.Kind {
			case util.IntstrInt:
				ss.TargetPort.IntVal = 1 + ss.TargetPort.IntVal%65535 // non-zero
			case util.IntstrString:
				ss.TargetPort.StrVal = "x" + ss.TargetPort.StrVal // non-empty
			}
		},
	)
	return f
}
// FuzzerFor can randomly populate api objects that are destined for version.
func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
	f := fuzz.New().NilChance(.5).NumElements(1, 1)
	if src != nil {
		f.RandSource(src)
	}
	f.Funcs(
		func(j *runtime.PluginBase, c fuzz.Continue) {
			// Do nothing; this struct has only a Kind field and it must stay blank in memory.
		},
		func(j *runtime.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.TypeMeta, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = ""
			j.Kind = ""
		},
		func(j *api.ObjectMeta, c fuzz.Continue) {
			j.Name = c.RandString()
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()
			j.UID = types.UID(c.RandString())
			j.GenerateName = c.RandString()

			var sec, nsec int64
			c.Fuzz(&sec)
			c.Fuzz(&nsec)
			j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
		},
		func(j *api.ObjectReference, c fuzz.Continue) {
			// We have to customize the randomization of TypeMetas because their
			// APIVersion and Kind must remain blank in memory.
			j.APIVersion = c.RandString()
			j.Kind = c.RandString()
			j.Namespace = c.RandString()
			j.Name = c.RandString()
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.FieldPath = c.RandString()
		},
		func(j *api.ListMeta, c fuzz.Continue) {
			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
			j.SelfLink = c.RandString()
		},
		func(j *api.PodPhase, c fuzz.Continue) {
			statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
			*j = statuses[c.Rand.Intn(len(statuses))]
		},
		func(j *api.PodTemplateSpec, c fuzz.Continue) {
			// TODO: v1beta1/2 can't round trip a nil template correctly, fix by having v1beta1/2
			// conversion compare converted object to nil via DeepEqual
			j.ObjectMeta = api.ObjectMeta{}
			c.Fuzz(&j.ObjectMeta)
			j.ObjectMeta = api.ObjectMeta{Labels: j.ObjectMeta.Labels}
			j.Spec = api.PodSpec{}
			c.Fuzz(&j.Spec)
		},
		func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
			// TemplateRef is set to nil by omission; this is required for round trip
			c.Fuzz(&j.Template)
			c.Fuzz(&j.Selector)
			j.Replicas = int(c.RandUint64())
		},
		func(j *api.ReplicationControllerStatus, c fuzz.Continue) {
			// only replicas round trips
			j.Replicas = int(c.RandUint64())
		},
		func(j *api.List, c fuzz.Continue) {
			c.Fuzz(&j.ListMeta)
			c.Fuzz(&j.Items)
			if j.Items == nil {
				j.Items = []runtime.Object{}
			}
		},
		func(j *runtime.Object, c fuzz.Continue) {
			if c.RandBool() {
				*j = &runtime.Unknown{
					TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"},
					RawJSON:  []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`),
				}
			} else {
				types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
				t := types[c.Rand.Intn(len(types))]
				c.Fuzz(t)
				*j = t
			}
		},
		func(intstr *util.IntOrString, c fuzz.Continue) {
			// util.IntOrString will panic if its kind is set wrong.
			if c.RandBool() {
				intstr.Kind = util.IntstrInt
				intstr.IntVal = int(c.RandUint64())
				intstr.StrVal = ""
			} else {
				intstr.Kind = util.IntstrString
				intstr.IntVal = 0
				intstr.StrVal = c.RandString()
			}
		},
		func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pb[docker.Port(c.RandString())] = []docker.PortBinding{
				{c.RandString(), c.RandString()},
				{c.RandString(), c.RandString()},
			}
		},
		func(pm map[string]docker.PortMapping, c fuzz.Continue) {
			// This is necessary because keys with nil values get omitted.
			// TODO: Is this a bug?
			pm[c.RandString()] = docker.PortMapping{
				c.RandString(): c.RandString(),
			}
		},
		func(q *resource.Quantity, c fuzz.Continue) {
			// Real Quantity fuzz testing is done elsewhere;
			// this limited subset of functionality survives
			// round-tripping to v1beta1/2.
			q.Amount = &inf.Dec{}
			q.Format = resource.DecimalExponent
			//q.Amount.SetScale(inf.Scale(-c.Intn(12)))
			q.Amount.SetUnscaled(c.Int63n(1000))
		},
		func(p *api.PullPolicy, c fuzz.Continue) {
			policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent}
			*p = policies[c.Rand.Intn(len(policies))]
		},
		func(rp *api.RestartPolicy, c fuzz.Continue) {
			// Exactly one of the fields should be set.
			fuzzOneOf(c, &rp.Always, &rp.OnFailure, &rp.Never)
		},
		func(vs *api.VolumeSource, c fuzz.Continue) {
			// Exactly one of the fields should be set.
			//FIXME: the fuzz can still end up nil.  What if fuzz allowed me to say that?
			fuzzOneOf(c, &vs.HostPath, &vs.EmptyDir, &vs.GCEPersistentDisk, &vs.GitRepo, &vs.Secret)
		},
		func(d *api.DNSPolicy, c fuzz.Continue) {
			policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
			*d = policies[c.Rand.Intn(len(policies))]
		},
		func(p *api.Protocol, c fuzz.Continue) {
			protocols := []api.Protocol{api.ProtocolTCP, api.ProtocolUDP}
			*p = protocols[c.Rand.Intn(len(protocols))]
		},
		func(p *api.AffinityType, c fuzz.Continue) {
			types := []api.AffinityType{api.AffinityTypeClientIP, api.AffinityTypeNone}
			*p = types[c.Rand.Intn(len(types))]
		},
		func(ct *api.Container, c fuzz.Continue) {
			// This function exists soley to set TerminationMessagePath to a
			// non-empty string. TODO: consider making TerminationMessagePath a
			// new type to simplify fuzzing.
			ct.TerminationMessagePath = api.TerminationMessagePathDefault
			// Let fuzzer handle the rest of the fileds.
			c.Fuzz(&ct.Name)
			c.Fuzz(&ct.Image)
			c.Fuzz(&ct.Command)
			c.Fuzz(&ct.Ports)
			c.Fuzz(&ct.WorkingDir)
			c.Fuzz(&ct.Env)
			c.Fuzz(&ct.VolumeMounts)
			c.Fuzz(&ct.LivenessProbe)
			c.Fuzz(&ct.Lifecycle)
			c.Fuzz(&ct.ImagePullPolicy)
			c.Fuzz(&ct.Privileged)
			c.Fuzz(&ct.Capabilities)
		},
		func(e *api.Event, c fuzz.Continue) {
			// Fix event count to 1, otherwise, if a v1beta1 or v1beta2 event has a count set arbitrarily, it's count is ignored
			c.Fuzz(&e.TypeMeta)
			c.Fuzz(&e.ObjectMeta)
			c.Fuzz(&e.InvolvedObject)
			c.Fuzz(&e.Reason)
			c.Fuzz(&e.Message)
			c.Fuzz(&e.Source)
			c.Fuzz(&e.FirstTimestamp)
			c.Fuzz(&e.LastTimestamp)
			if e.FirstTimestamp.IsZero() {
				e.Count = 1
			} else {
				c.Fuzz(&e.Count)
			}
		},
		func(s *api.Secret, c fuzz.Continue) {
			c.Fuzz(&s.TypeMeta)
			c.Fuzz(&s.ObjectMeta)

			s.Type = api.SecretTypeOpaque
			c.Fuzz(&s.Data)
		},
		func(ep *api.Endpoint, c fuzz.Continue) {
			// TODO: If our API used a particular type for IP fields we could just catch that here.
			ep.IP = fmt.Sprintf("%d.%d.%d.%d", c.Rand.Intn(256), c.Rand.Intn(256), c.Rand.Intn(256), c.Rand.Intn(256))
			ep.Port = c.Rand.Intn(65536)
		},
	)
	return f
}