 len(a.changes), 1)
}

func TestResourceUpdatedUpdatingADeploymentReferencingSameConfigsDoesNotIntroduceAChange(t *testing.T) {
	a := agent()
	d := deploymentA()

	a.Start(nil)
	a.ResourceUpdated(d)
	d.VersionValue = deploymentAUpdated().Version()
	a.ResourceUpdated(d)
	a.Stop()

	equals(t, len(a.changes), 1)
	equals(t, a.changes[d.FullName()].Observations, 1)
}

func TestResourceDeletedCleansUpConfigs(t *testing.T) {
	a := agent()
	c := configA()

	a.Start(nil)
	a.ResourceUpdated(c)
	a.ResourceDeleted(c)
	a.Stop()

	equals(t, len(a.configs), 0)
	equals(t, len(a.changes), 0)
}

func TestResourceDeletedCleansUpDeploymentsAndUnusedConfigs(t *testing.T) {
	a := agent()
	d := deploymentA()

	a.Start(nil)
	a.ResourceUpdated(d)
	a.ResourceDeleted(d)
	a.Stop()

	equals(t, len(a.deployments), 0)
	equals(t, len(a.configs), 0)
	equals(t, len(a.changes), 0)
}

func TestResourceDeletedCleansUpDeploymentConfigs(t *testing.T) {
	a := agent()
	c := configA()
	d := deploymentA()

	a.Start(nil)
	a.ResourceUpdated(c)
	a.ResourceUpdated(d)
	a.ResourceDeleted(c)
	a.Stop()

	equals(t, len(a.configs), 1)
	equals(t, len(a.changes), 1)
	deployment := a.deployments[d.FullName()]
	equals(t, deployment!= nil, true)
	equals(t, len(deployment.Configs), 1)
}

func TestConfigChangesGetProcessedInGracePeriod(t *testing.T) {
	a := agent()
	c := configA()
	d := deploymentA()

	a.Start(nil)
	a.ResourceUpdated(c)
	a.ResourceUpdated(d)
	time.Sleep(150 * time.Millisecond)
	a.Stop()

	equals(t, len(a.changes), 0)
	equals(t, d.UpdatedChecksums, map[string]string(nil))
}

func TestConfigChangesOrphanedResourceChangesGetCleanedUp(t *testing.T) {
	a := agent()

	a.changes["non-existent"] = NewChange()
	a.Start(nil)
	time.Sleep(150 * time.Millisecond)
	a.Stop()

	equals(t, len(a.changes), 0)
}

func TestConfigChangesNewDeploymentsGetChecksumUpdatesWithoutRestarts(t *testing.T) {
	a := agent()
	c := configAUpdated()
	d := deploymentA()
	delete(d.AppliedChecksumsValue, c.FullName())

	a.Start(nil)
	a.ResourceUpdated(c)
	a.ResourceUpdated(d)
	time.Sleep(150 * time.Millisecond)
	a.Stop()

	expectedChecksums := map[string]string{
		c.FullName():         c.Checksum(),
		configB().FullName(): configB().Checksum(),
	}

	equals(t, len(a.changes), 0)
	equals(t, d.UpdatedChecksums, expectedChecksums)
	equals(t, d.UpdatedRestart, false)
}

func TestConfigChangesConfigChangeGetDeploymentChecksumsUpdatedWithRestart(t *testing.T) {
	a := agent()
	c := configAUpdated()
	d := deploymentA()

	a.Start(nil)
	a.ResourceUpdated(c)
	a.ResourceUpdated(d)
	time.Sleep(150 * time.Millisecond)
	a.Stop()

	expectedChecksums := map[string]string{
		c.FullName():         c.Checksum(),
		configB().FullName(): configB().Checksum(),
	}

	equals(t, len(a.changes), 0)
	equals(t, d.UpdatedChecksums, expectedChecksums)
	equals(t, d.UpdatedRestart, true)
}

func TestConfigChangesConfigChangeCleansUpDeploymentChange(t *testing.T) {
	a := agent()
	c := configAUpdated()
	d1 := deploymentA()
	d2 := deploymentAUpdated()
	d2.AppliedChecksumsValue = map[string]string{}

	a.Start(nil)
	a.ResourceUpdated(c)
	a.ResourceUpdated(d1)
	a.ResourceUpdated(d2)
	time.Sleep(150 * time.Millisecond)
	a.Stop()

	expectedChecksums := map[string]string{
		c.FullName(): c.Checksum(),
	}

	equals(t, len(a.changes), 0)
	equals(t, d2.UpdatedChecksums, expectedChecksums)
	equals(t, d2.UpdatedRestart, false)
}

func TestConfigChangesMissingDeploymentAnnotaionsGetRestored(t *testing.T) {
	a := agent()
	c := configA()
	d1 := deploymentA()
	d2 := deploymentAUpdated()
	delete(d2.AppliedChecksumsValue, c.FullName())

	a.Start(nil)
	a.ResourceUpdated(c)
	a.ResourceUpdated(d1)
	a.ResourceUpdated(d2)
	time.Sleep(150 * time.Millisecond)
	a.Stop()

	expectedChecksums := map[string]string{
		c.FullName():         c.Checksum(),
		configB().FullName(): configB().Checksum(),
	}

	equals(t, len(a.changes), 0)
	equals(t, d2.UpdatedChecksums, expectedChecksums)
	equals(t, d2.UpdatedRestart, false)
}

func TestConfigChangesUnsavedImportantChangesGetAppliedWhenStopped(t *testing.T) {
	a := agent()
	d := deploymentA()
	c1 := configA()
	c2 := configAUpdated()
	delete(d.AppliedChecksumsValue, c1.FullName())

	a.Start(nil)
	a.ResourceUpdated(d)
	a.ResourceUpdated(c1)
	a.ResourceUpdated(c2)
	a.Stop()

	time.Sleep(150 * time.Millisecond)

	expectedChecksums := map[string]string{
		c2.FullName():        c2.Checksum(),
		configB().FullName(): configB().Checksum(),
	}

	equals(t, len(a.changes), 0)
	equals(t, d.UpdatedChecksums, expectedChecksums)
	equals(t, d.UpdatedRestart, true)
}

func TestConfigChangesProcessStopsOnError(t *testing.T) {
	a := agent()
	c := configAUpdated()
	d := deploymentA()
	d.UpdateError = errors.New("Dummy error")

	controllerStopCh := make(chan struct{})
	a.Start(controllerStopCh)
	a.ResourceUpdated(c)
	a.ResourceUpdated(d)
	time.Sleep(150 * time.Millisecond)
	<-controllerStopCh

	expectedChecksums := map[string]string{
		c.FullName():         c.Checksum(),
		configB().FullName(): configB().Checksum(),
	}

	equals(t, d.UpdatedChecksums, expectedChecksums)
	equals(t, d.UpdatedRestart, true)
}

func configA() *test.DummyMetaConfig {
	return test.NewMetaConfigWithParams("configmap/test/test", "12345", "abc")
}

func configAUpdated() *test.DummyMetaConfig {
	return test.NewMetaConfigWithParams("configmap/test/test", "23456", "bcd")
}

func configB() *test.DummyMetaConfig {
	