func createPodWorkers() (*podWorkers, map[types.UID][]syncPodRecord) {
	lock := sync.Mutex{}
	processed := make(map[types.UID][]syncPodRecord)
	fakeRecorder := &record.FakeRecorder{}
	fakeRuntime := &containertest.FakeRuntime{}
	fakeCache := containertest.NewFakeCache(fakeRuntime)
	podWorkers := newPodWorkers(
		func(options syncPodOptions) error {
			func() {
				lock.Lock()
				defer lock.Unlock()
				pod := options.pod
				processed[pod.UID] = append(processed[pod.UID], syncPodRecord{
					name:       pod.Name,
					updateType: options.updateType,
				})
			}()
			return nil
		},
		fakeRecorder,
		queue.NewBasicWorkQueue(&util.RealClock{}),
		time.Second,
		time.Second,
		fakeCache,
	)
	return podWorkers, processed
}
func createPodWorkers() (*podWorkers, map[types.UID][]string) {
	lock := sync.Mutex{}
	processed := make(map[types.UID][]string)
	fakeRecorder := &record.FakeRecorder{}
	fakeRuntimeCache := createFakeRuntimeCache(fakeRecorder)
	podWorkers := newPodWorkers(
		fakeRuntimeCache,
		func(pod *api.Pod, mirrorPod *api.Pod, runningPod kubecontainer.Pod, updateType kubetypes.SyncPodType) error {
			func() {
				lock.Lock()
				defer lock.Unlock()
				processed[pod.UID] = append(processed[pod.UID], pod.Name)
			}()
			return nil
		},
		fakeRecorder,
		queue.NewBasicWorkQueue(),
		time.Second,
		time.Second,
	)
	return podWorkers, processed
}
// TestFakePodWorkers verifies that the fakePodWorkers behaves the same way as the real podWorkers
// for their invocation of the syncPodFn.
func TestFakePodWorkers(t *testing.T) {
	fakeRecorder := &record.FakeRecorder{}
	fakeRuntime := &containertest.FakeRuntime{}
	fakeCache := containertest.NewFakeCache(fakeRuntime)

	kubeletForRealWorkers := &simpleFakeKubelet{}
	kubeletForFakeWorkers := &simpleFakeKubelet{}

	realPodWorkers := newPodWorkers(kubeletForRealWorkers.syncPodWithWaitGroup, fakeRecorder, queue.NewBasicWorkQueue(&util.RealClock{}), time.Second, time.Second, fakeCache)
	fakePodWorkers := &fakePodWorkers{kubeletForFakeWorkers.syncPod, fakeCache, t}

	tests := []struct {
		pod       *api.Pod
		mirrorPod *api.Pod
	}{
		{
			&api.Pod{},
			&api.Pod{},
		},
		{
			podWithUidNameNs("12345678", "foo", "new"),
			podWithUidNameNs("12345678", "fooMirror", "new"),
		},
		{
			podWithUidNameNs("98765", "bar", "new"),
			podWithUidNameNs("98765", "barMirror", "new"),
		},
	}

	for i, tt := range tests {
		kubeletForRealWorkers.wg.Add(1)
		realPodWorkers.UpdatePod(&UpdatePodOptions{
			Pod:        tt.pod,
			MirrorPod:  tt.mirrorPod,
			UpdateType: kubetypes.SyncPodUpdate,
		})
		fakePodWorkers.UpdatePod(&UpdatePodOptions{
			Pod:        tt.pod,
			MirrorPod:  tt.mirrorPod,
			UpdateType: kubetypes.SyncPodUpdate,
		})

		kubeletForRealWorkers.wg.Wait()

		if !reflect.DeepEqual(kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod)
		}

		if !reflect.DeepEqual(kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod)
		}

		if !reflect.DeepEqual(kubeletForRealWorkers.podStatus, kubeletForFakeWorkers.podStatus) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.podStatus, kubeletForFakeWorkers.podStatus)
		}
	}
}
// TestFakePodWorkers verifies that the fakePodWorkers behaves the same way as the real podWorkers
// for their invocation of the syncPodFn.
func TestFakePodWorkers(t *testing.T) {
	fakeRecorder := &record.FakeRecorder{}
	fakeRuntime := &kubecontainer.FakeRuntime{}
	fakeRuntimeCache := kubecontainer.NewFakeRuntimeCache(fakeRuntime)

	kubeletForRealWorkers := &simpleFakeKubelet{}
	kubeletForFakeWorkers := &simpleFakeKubelet{}

	realPodWorkers := newPodWorkers(fakeRuntimeCache, kubeletForRealWorkers.syncPodWithWaitGroup, fakeRecorder, queue.NewBasicWorkQueue(), time.Second, time.Second)
	fakePodWorkers := &fakePodWorkers{kubeletForFakeWorkers.syncPod, fakeRuntimeCache, t}

	tests := []struct {
		pod                    *api.Pod
		mirrorPod              *api.Pod
		podList                []*kubecontainer.Pod
		containersInRunningPod int
	}{
		{
			&api.Pod{},
			&api.Pod{},
			[]*kubecontainer.Pod{},
			0,
		},
		{
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "12345678",
					Name:      "foo",
					Namespace: "new",
				},
			},
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "12345678",
					Name:      "fooMirror",
					Namespace: "new",
				},
			},
			[]*kubecontainer.Pod{
				{
					ID:        "12345678",
					Name:      "foo",
					Namespace: "new",
					Containers: []*kubecontainer.Container{
						{
							Name: "fooContainer",
						},
					},
				},
				{
					ID:        "12345678",
					Name:      "fooMirror",
					Namespace: "new",
					Containers: []*kubecontainer.Container{
						{
							Name: "fooContainerMirror",
						},
					},
				},
			},
			1,
		},
		{
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "bar",
					Namespace: "new",
				},
			},
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "barMirror",
					Namespace: "new",
				},
			},
			[]*kubecontainer.Pod{
				{
					ID:        "98765",
					Name:      "bar",
					Namespace: "new",
					Containers: []*kubecontainer.Container{
						{
							Name: "barContainer0",
						},
						{
							Name: "barContainer1",
						},
					},
				},
				{
					ID:        "98765",
					Name:      "barMirror",
					Namespace: "new",
					Containers: []*kubecontainer.Container{
						{
							Name: "barContainerMirror0",
						},
						{
							Name: "barContainerMirror1",
						},
					},
				},
			},
			2,
		},
	}

	for i, tt := range tests {
		kubeletForRealWorkers.wg.Add(1)

		fakeRuntime.PodList = tt.podList
		realPodWorkers.UpdatePod(tt.pod, tt.mirrorPod, kubetypes.SyncPodUpdate, func() {})
		fakePodWorkers.UpdatePod(tt.pod, tt.mirrorPod, kubetypes.SyncPodUpdate, func() {})

		kubeletForRealWorkers.wg.Wait()

		if !reflect.DeepEqual(kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod)
		}

		if !reflect.DeepEqual(kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod)
		}

		if tt.containersInRunningPod != len(kubeletForFakeWorkers.runningPod.Containers) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, tt.containersInRunningPod, len(kubeletForFakeWorkers.runningPod.Containers))
		}

		sort.Sort(byContainerName(kubeletForRealWorkers.runningPod))
		sort.Sort(byContainerName(kubeletForFakeWorkers.runningPod))
		if !reflect.DeepEqual(kubeletForRealWorkers.runningPod, kubeletForFakeWorkers.runningPod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.runningPod, kubeletForFakeWorkers.runningPod)
		}
	}
}
// TestFakePodWorkers verifies that the fakePodWorkers behaves the same way as the real podWorkers
// for their invocation of the syncPodFn.
func TestFakePodWorkers(t *testing.T) {
	fakeRecorder := &record.FakeRecorder{}
	fakeRuntime := &kubecontainer.FakeRuntime{}
	fakeCache := kubecontainer.NewFakeCache(fakeRuntime)

	kubeletForRealWorkers := &simpleFakeKubelet{}
	kubeletForFakeWorkers := &simpleFakeKubelet{}

	realPodWorkers := newPodWorkers(kubeletForRealWorkers.syncPodWithWaitGroup, fakeRecorder, queue.NewBasicWorkQueue(), time.Second, time.Second, fakeCache)
	fakePodWorkers := &fakePodWorkers{kubeletForFakeWorkers.syncPod, fakeCache, t}

	tests := []struct {
		pod       *api.Pod
		mirrorPod *api.Pod
	}{
		{
			&api.Pod{},
			&api.Pod{},
		},
		{
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "12345678",
					Name:      "foo",
					Namespace: "new",
				},
			},
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "12345678",
					Name:      "fooMirror",
					Namespace: "new",
				},
			},
		},
		{
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "bar",
					Namespace: "new",
				},
			},
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "barMirror",
					Namespace: "new",
				},
			},
		},
	}

	for i, tt := range tests {
		kubeletForRealWorkers.wg.Add(1)
		realPodWorkers.UpdatePod(tt.pod, tt.mirrorPod, kubetypes.SyncPodUpdate, func() {})
		fakePodWorkers.UpdatePod(tt.pod, tt.mirrorPod, kubetypes.SyncPodUpdate, func() {})

		kubeletForRealWorkers.wg.Wait()

		if !reflect.DeepEqual(kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod)
		}

		if !reflect.DeepEqual(kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod)
		}

		if !reflect.DeepEqual(kubeletForRealWorkers.podStatus, kubeletForFakeWorkers.podStatus) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.podStatus, kubeletForFakeWorkers.podStatus)
		}
	}
}
// TestFakePodWorkers verifies that the fakePodWorkers behaves the same way as the real podWorkers
// for their invocation of the syncPodFn.
func TestFakePodWorkers(t *testing.T) {
	// Create components for pod workers.
	fakeDocker := &dockertools.FakeDockerClient{}
	fakeRecorder := &record.FakeRecorder{}
	np, _ := network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))
	dockerManager := dockertools.NewFakeDockerManager(fakeDocker, fakeRecorder, nil, nil, &cadvisorapi.MachineInfo{}, dockertools.PodInfraContainerImage, 0, 0, "", kubecontainer.FakeOS{}, np, nil, nil, nil)
	fakeRuntimeCache := kubecontainer.NewFakeRuntimeCache(dockerManager)

	kubeletForRealWorkers := &simpleFakeKubelet{}
	kubeletForFakeWorkers := &simpleFakeKubelet{}

	realPodWorkers := newPodWorkers(fakeRuntimeCache, kubeletForRealWorkers.syncPodWithWaitGroup, fakeRecorder, queue.NewBasicWorkQueue(), time.Second, time.Second)
	fakePodWorkers := &fakePodWorkers{kubeletForFakeWorkers.syncPod, fakeRuntimeCache, t}

	tests := []struct {
		pod                    *api.Pod
		mirrorPod              *api.Pod
		containerList          []docker.APIContainers
		containersInRunningPod int
	}{
		{
			&api.Pod{},
			&api.Pod{},
			[]docker.APIContainers{},
			0,
		},

		{
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "12345678",
					Name:      "foo",
					Namespace: "new",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name: "fooContainer",
						},
					},
				},
			},
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "12345678",
					Name:      "fooMirror",
					Namespace: "new",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name: "fooContainerMirror",
						},
					},
				},
			},
			[]docker.APIContainers{
				{
					// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>_<random>
					Names: []string{"/k8s_bar.hash123_foo_new_12345678_0"},
					ID:    "1234",
				},
				{
					// pod infra container
					Names: []string{"/k8s_POD.hash123_foo_new_12345678_0"},
					ID:    "9876",
				},
			},
			2,
		},

		{
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "bar",
					Namespace: "new",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name: "fooContainer",
						},
					},
				},
			},
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "fooMirror",
					Namespace: "new",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name: "fooContainerMirror",
						},
					},
				},
			},
			[]docker.APIContainers{
				{
					// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>_<random>
					Names: []string{"/k8s_bar.hash123_bar_new_98765_0"},
					ID:    "1234",
				},
				{
					// pod infra container
					Names: []string{"/k8s_POD.hash123_foo_new_12345678_0"},
					ID:    "9876",
				},
			},
			1,
		},

		// Empty running pod.
		{
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "baz",
					Namespace: "new",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name: "bazContainer",
						},
					},
				},
			},
			&api.Pod{
				ObjectMeta: api.ObjectMeta{
					UID:       "98765",
					Name:      "bazMirror",
					Namespace: "new",
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{
							Name: "bazContainerMirror",
						},
					},
				},
			},
			[]docker.APIContainers{
				{
					// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>_<random>
					Names: []string{"/k8s_bar.hash123_bar_new_12345678_0"},
					ID:    "1234",
				},
				{
					// pod infra container
					Names: []string{"/k8s_POD.hash123_foo_new_12345678_0"},
					ID:    "9876",
				},
			},
			0,
		},
	}

	for i, tt := range tests {
		kubeletForRealWorkers.wg.Add(1)

		fakeDocker.ContainerList = tt.containerList
		realPodWorkers.UpdatePod(tt.pod, tt.mirrorPod, kubetypes.SyncPodUpdate, func() {})
		fakePodWorkers.UpdatePod(tt.pod, tt.mirrorPod, kubetypes.SyncPodUpdate, func() {})

		kubeletForRealWorkers.wg.Wait()

		if !reflect.DeepEqual(kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod)
		}

		if !reflect.DeepEqual(kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod)
		}

		if tt.containersInRunningPod != len(kubeletForFakeWorkers.runningPod.Containers) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, tt.containersInRunningPod, len(kubeletForFakeWorkers.runningPod.Containers))
		}

		sort.Sort(byContainerName(kubeletForRealWorkers.runningPod))
		sort.Sort(byContainerName(kubeletForFakeWorkers.runningPod))
		if !reflect.DeepEqual(kubeletForRealWorkers.runningPod, kubeletForFakeWorkers.runningPod) {
			t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.runningPod, kubeletForFakeWorkers.runningPod)
		}
	}
}