2
Copyright 2013 The Go Authors
4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
8
http://www.apache.org/licenses/LICENSE-2.0
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
32
func TestLock(t *testing.T) {
36
func TestLockPortable(t *testing.T) {
40
func TestLockInChild(t *testing.T) {
41
f := os.Getenv("TEST_LOCK_FILE")
47
if v, _ := strconv.ParseBool(os.Getenv("TEST_LOCK_PORTABLE")); v {
52
for scan := bufio.NewScanner(os.Stdin); scan.Scan(); {
61
// Simulate a crash, or at least not unlocking the lock.
64
err = fmt.Errorf("unexpected child command %q", scan.Text())
74
func testLock(t *testing.T, portable bool) {
79
t.Logf("test lock, portable %v", portable)
81
td, err := ioutil.TempDir("", "")
85
defer os.RemoveAll(td)
87
path := filepath.Join(td, "foo.lock")
89
proc := newChildProc(t, path, portable)
92
t.Logf("First lock in child")
93
if err := proc.do("lock"); err != nil {
94
t.Fatalf("first lock in child process: %v", err)
98
if err := proc.do("exit"); err != nil {
99
t.Fatalf("crash in child process: %v", err)
102
proc = newChildProc(t, path, portable)
105
t.Logf("Locking+unlocking in child...")
106
if err := proc.do("lock"); err != nil {
107
t.Fatalf("lock in child process after crashing child: %v", err)
109
if err := proc.do("unlock"); err != nil {
110
t.Fatalf("lock in child process after crashing child: %v", err)
113
t.Logf("Locking in parent...")
114
lk1, err := lock(path)
119
t.Logf("Again in parent...")
122
t.Fatal("expected second lock to fail")
125
t.Logf("Locking in child...")
126
if err := proc.do("lock"); err == nil {
127
t.Fatalf("expected lock in child process to fail")
130
t.Logf("Unlocking lock in parent")
131
if err := lk1.Close(); err != nil {
135
t.Logf("Trying lock again in child...")
136
if err := proc.do("lock"); err != nil {
139
if err := proc.do("unlock"); err != nil {
143
lk3, err := lock(path)
150
type childLockCmd struct {
155
type childProc struct {
160
func (c *childProc) kill() {
164
func (c *childProc) do(op string) error {
165
reply := make(chan error)
173
func newChildProc(t *testing.T, path string, portable bool) *childProc {
174
cmd := exec.Command(os.Args[0], "-test.run=LockInChild$")
175
cmd.Env = []string{"TEST_LOCK_FILE=" + path}
176
toChild, err := cmd.StdinPipe()
178
t.Fatalf("cannot make pipe: %v", err)
180
fromChild, err := cmd.StdoutPipe()
182
t.Fatalf("cannot make pipe: %v", err)
184
cmd.Stderr = os.Stderr
186
cmd.Env = append(cmd.Env, "TEST_LOCK_PORTABLE=1")
188
if err := cmd.Start(); err != nil {
189
t.Fatalf("cannot start child: %v", err)
191
cmdChan := make(chan childLockCmd)
193
defer fromChild.Close()
194
defer toChild.Close()
195
inScan := bufio.NewScanner(fromChild)
196
for c := range cmdChan {
197
fmt.Fprintln(toChild, c.op)
201
c.reply <- errors.New("child did not exit")
209
panic("child exited early")
211
if errText := inScan.Text(); errText != "" {
212
c.reply <- errors.New(errText)