diff --git a/util/sync.go b/util/sync.go index 12d1113e..e21aae37 100644 --- a/util/sync.go +++ b/util/sync.go @@ -21,6 +21,28 @@ import ( "sync" ) +// EasyAck is a wrapper to build ack functionality into a simple interface. +type EasyAck struct { + done chan struct{} +} + +// NewEasyAck builds the object. This must be called before use. +func NewEasyAck() *EasyAck { + return &EasyAck{ + done: make(chan struct{}), + } +} + +// Ack sends the acknowledgment message. This can only be called once. +func (obj *EasyAck) Ack() { + close(obj.done) +} + +// Wait returns a channel that you can wait on for the ack message. +func (obj *EasyAck) Wait() <-chan struct{} { + return obj.done +} + // EasyOnce is a wrapper for the sync.Once functionality which lets you define // and register the associated `run once` function at declaration time. It may // be copied at any time. diff --git a/util/sync_test.go b/util/sync_test.go new file mode 100644 index 00000000..89ec2e2e --- /dev/null +++ b/util/sync_test.go @@ -0,0 +1,63 @@ +// Mgmt +// Copyright (C) 2013-2018+ James Shubin and the project contributors +// Written by James Shubin and the project contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// +build !root + +package util + +import ( + "testing" + "time" +) + +func TestEasyAck1(t *testing.T) { + ea := NewEasyAck() + ea.Ack() // send the ack + select { + case <-ea.Wait(): // we got it! + case <-time.After(time.Duration(60) * time.Second): + t.Errorf("the Ack did not arrive in time") + } +} + +func TestEasyAck2(t *testing.T) { + ea := NewEasyAck() + // never send an ack + select { + case <-ea.Wait(): // we got it! + t.Errorf("the Ack arrived unexpectedly") + default: + } +} + +func TestEasyAck3(t *testing.T) { + ea := NewEasyAck() + ea.Ack() // send the ack + select { + case <-ea.Wait(): // we got it! + case <-time.After(time.Duration(60) * time.Second): + t.Errorf("the Ack did not arrive in time") + } + + ea = NewEasyAck() // build a new one + ea.Ack() // send the ack + select { + case <-ea.Wait(): // we got it! + case <-time.After(time.Duration(60) * time.Second): + t.Errorf("the second Ack did not arrive in time") + } +}