From eb6ef5214405d9452e445f0be0d48a192926d9e3 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Fri, 22 Apr 2016 11:39:32 +0200 Subject: [PATCH] functional: add TestReplaceSerialization test to assert serialization of 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. --- .../fixtures/units/replace-sync.service | 5 ++ functional/unit_action_test.go | 76 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 functional/fixtures/units/replace-sync.service diff --git a/functional/fixtures/units/replace-sync.service b/functional/fixtures/units/replace-sync.service new file mode 100644 index 000000000..b81c42683 --- /dev/null +++ b/functional/fixtures/units/replace-sync.service @@ -0,0 +1,5 @@ +[Service] +ExecStartPre=/bin/bash -c "echo 'sync'" +ExecStart=/bin/bash -c "while true; do echo Hello, World!; sleep 1; done" +ExecStop=/bin/bash -c "echo 'stopping'" +ExecStopPost=/bin/bash -c "sleep 3; touch /tmp/fleetSyncFile" diff --git a/functional/unit_action_test.go b/functional/unit_action_test.go index f0bf99d21..7cf91fdab 100644 --- a/functional/unit_action_test.go +++ b/functional/unit_action_test.go @@ -717,3 +717,79 @@ func replaceUnitMultiple(cmd string, n int) error { return nil } + +// TestReplaceSerialization tests if the ExecStartPre of the new version +// of the unit when it replaces the old one is excuted after +// ExecStopPost of the old version. +// This test is to make sure that two versions of the same unit will not +// conflict with each other, that the directives are always serialized, +// and it tries its best to avoid the following scenarios: +// https://github.com/coreos/fleet/issues/1000 +// https://github.com/systemd/systemd/issues/518 +// Now we can't guarantee that that behaviour will not be triggered by +// another external operation, but at least from the Unit replace +// feature context we try to avoid it. +func TestReplaceSerialization(t *testing.T) { + cluster, err := platform.NewNspawnCluster("smoke") + if err != nil { + t.Fatal(err) + } + defer cluster.Destroy() + + m, err := cluster.CreateMember() + if err != nil { + t.Fatal(err) + } + + _, err = cluster.WaitForNMachines(m, 1) + if err != nil { + t.Fatal(err) + } + + tmpSyncFile := "/tmp/fleetSyncReplaceFile" + syncOld := "echo 'sync'" + syncNew := fmt.Sprintf("test -f %s", tmpSyncFile) + tmpSyncService := "/tmp/replace-sync.service" + syncService := "fixtures/units/replace-sync.service" + + stdout, stderr, err := cluster.Fleetctl(m, "start", syncService) + if err != nil { + t.Fatalf("Unable to start fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err) + } + + _, err = cluster.WaitForNActiveUnits(m, 1) + if err != nil { + t.Fatal(err) + } + + // replace the unit content, make sure that: + // It shows up and it did 'stat /tmp/fleetSyncFile' correctly + err = util.GenNewFleetService(tmpSyncService, syncService, syncNew, syncOld) + if err != nil { + t.Fatalf("Failed to generate a temp fleet service: %v", err) + } + + stdout, stderr, err = cluster.Fleetctl(m, "start", "--replace", tmpSyncService) + if err != nil { + t.Fatalf("Failed to replace fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err) + } + + _, err = cluster.WaitForNActiveUnits(m, 1) + if err != nil { + t.Fatalf("Did not find 1 unit in cluster, unit replace failed: %v", err) + } + + tmpService := path.Base(tmpSyncService) + stdout, _ = cluster.MemberCommand(m, "systemctl", "show", "--property=ActiveState", tmpService) + if strings.TrimSpace(stdout) != "ActiveState=active" { + t.Fatalf("Fleet unit not reported as active: %s", stdout) + } + + stdout, _ = cluster.MemberCommand(m, "systemctl", "show", "--property=Result", tmpService) + if strings.TrimSpace(stdout) != "Result=success" { + t.Fatalf("Result for fleet unit not reported as success: %s", stdout) + } + + os.Remove(tmpSyncFile) + os.Remove(tmpSyncService) +}