Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Commit b4ee8d5

Browse files
author
Djalal Harouni
committed
functional: add TestReplaceSerialization test to assert serialization of systemd directives
This tests asserts that systemd directives are serialized when we transit from the old version of the unit to the new one. Make sure that ExecStartPre of the new one are executed after ExecStopPost of the previous one.
1 parent 9dfa2ef commit b4ee8d5

2 files changed

Lines changed: 115 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[Service]
2+
ExecStartPre=/bin/bash -c "echo 'sync'"
3+
ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done"
4+
ExecStop=/bin/bash -c "echo 'stopping'"
5+
ExecStopPost=/bin/bash -c "sleep 3; touch /tmp/fleetSyncReplaceFile"

functional/unit_action_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,3 +717,113 @@ func replaceUnitMultiple(cmd string, n int) error {
717717

718718
return nil
719719
}
720+
721+
// TestReplaceSerialization tests if the ExecStartPre of the new version
722+
// of the unit when it replaces the old one is excuted after
723+
// ExecStopPost of the old version.
724+
// This test is to make sure that two versions of the same unit will not
725+
// conflict with each other, that the directives are always serialized,
726+
// and it tries its best to avoid the following scenarios:
727+
// https://github.com/coreos/fleet/issues/1000
728+
// https://github.com/systemd/systemd/issues/518
729+
// Now we can't guarantee that that behaviour will not be triggered by
730+
// another external operation, but at least from the Unit replace
731+
// feature context we try to avoid it.
732+
func TestReplaceSerialization(t *testing.T) {
733+
cluster, err := platform.NewNspawnCluster("smoke")
734+
if err != nil {
735+
t.Fatal(err)
736+
}
737+
defer cluster.Destroy()
738+
739+
m, err := cluster.CreateMember()
740+
if err != nil {
741+
t.Fatal(err)
742+
}
743+
744+
_, err = cluster.WaitForNMachines(m, 1)
745+
if err != nil {
746+
t.Fatal(err)
747+
}
748+
749+
tmpSyncFile := "/tmp/fleetSyncReplaceFile"
750+
syncOld := "echo 'sync'"
751+
syncNew := fmt.Sprintf("test -f %s", tmpSyncFile)
752+
tmpSyncService := "/tmp/replace-sync.service"
753+
syncService := "fixtures/units/replace-sync.service"
754+
755+
stdout, stderr, err := cluster.Fleetctl(m, "start", syncService)
756+
if err != nil {
757+
t.Fatalf("Unable to start unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
758+
}
759+
760+
_, err = cluster.WaitForNActiveUnits(m, 1)
761+
if err != nil {
762+
t.Fatal(err)
763+
}
764+
765+
// replace the unit content, make sure that:
766+
// It shows up and it did 'test -f /tmp/fleetSyncReplaceFile' correctly
767+
err = util.GenNewFleetService(tmpSyncService, syncService, syncNew, syncOld)
768+
if err != nil {
769+
t.Fatalf("Failed to generate a temp fleet service: %v", err)
770+
}
771+
772+
stdout, stderr, err = cluster.Fleetctl(m, "start", "--replace", tmpSyncService)
773+
if err != nil {
774+
t.Fatalf("Failed to replace unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
775+
}
776+
777+
_, err = cluster.WaitForNActiveUnits(m, 1)
778+
if err != nil {
779+
t.Fatalf("Did not find 1 unit in cluster, unit replace failed: %v", err)
780+
}
781+
782+
// Wait for the sync file, if the sync file is not created then
783+
// the previous unit failed, if it's created we continue. Here
784+
// the new version of the unit is probably already running and
785+
// the ExecStartPre is running at the same time, if it failed
786+
// then we probably will catch it later when we check its status
787+
tmpService := path.Base(tmpSyncService)
788+
timeout, err := util.WaitForState(
789+
func() bool {
790+
_, err = cluster.MemberCommand(m, syncNew)
791+
if err != nil {
792+
return false
793+
}
794+
return true
795+
},
796+
)
797+
if err != nil {
798+
t.Fatalf("Failed to check if file %s exists within %v", tmpSyncFile, timeout)
799+
}
800+
801+
timeout, err = util.WaitForState(
802+
func() bool {
803+
stdout, _ = cluster.MemberCommand(m, "systemctl", "show", "--property=ActiveState", tmpService)
804+
if strings.TrimSpace(stdout) != "ActiveState=active" {
805+
return false
806+
}
807+
return true
808+
},
809+
)
810+
if err != nil {
811+
t.Fatalf("%s unit not reported as active within %v", tmpService, timeout)
812+
}
813+
814+
timeout, err = util.WaitForState(
815+
func() bool {
816+
stdout, _ = cluster.MemberCommand(m, "systemctl", "show", "--property=Result", tmpService)
817+
if strings.TrimSpace(stdout) != "Result=success" {
818+
return false
819+
}
820+
return true
821+
},
822+
)
823+
if err != nil {
824+
t.Fatalf("Result for %s unit not reported as success withing %v", tmpService, timeout)
825+
}
826+
827+
os.Remove(tmpSyncFile)
828+
os.Remove(tmpSyncService)
829+
}

0 commit comments

Comments
 (0)