diff --git a/rados/operation_test.go b/rados/operation_test.go new file mode 100644 index 0000000..67c6cc8 --- /dev/null +++ b/rados/operation_test.go @@ -0,0 +1,119 @@ +package rados + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestOperationError(t *testing.T) { + oe := OperationError{ + kind: readOp, + OpError: fmt.Errorf("bad mojo %v", 77), + StepErrors: map[int]error{ + 1: fmt.Errorf("limit exceeded"), + 3: fmt.Errorf("weirdness"), + }, + } + assert.Error(t, oe) + estr := oe.Error() + assert.Contains(t, estr, "read operation error") + assert.Contains(t, estr, "op=bad mojo 77") + assert.Contains(t, estr, "Step#1=limit exceeded") + assert.Contains(t, estr, "Step#3=weirdness") + + oe = OperationError{ + kind: writeOp, + StepErrors: map[int]error{ + 0: fmt.Errorf("unlucky"), + }, + } + assert.Error(t, oe) + estr = oe.Error() + assert.Contains(t, estr, "write operation error") + assert.NotContains(t, estr, "op=") + assert.Contains(t, estr, "Step#0=unlucky") +} + +type fooStep struct { + updateCount int + freeCount int + failMe error +} + +func (fs *fooStep) update() error { + fs.updateCount++ + return fs.failMe +} + +func (fs *fooStep) free() { + fs.freeCount++ +} + +func TestOpStepFinalizer(t *testing.T) { + // this confirms that given a valid op step the finalizer helper + // function calls the free method of the interface + fs := &fooStep{} + opStepFinalizer(fs) + opStepFinalizer(fs) + assert.Equal(t, 2, fs.freeCount) + + // this should not panic + opStepFinalizer(nil) +} + +func TestOperationType(t *testing.T) { + t.Run("stepErrors", func(t *testing.T) { + o := &operation{} + o.steps = append(o.steps, &fooStep{}) + o.steps = append(o.steps, &fooStep{failMe: fmt.Errorf("yow")}) + o.steps = append(o.steps, &fooStep{}) + o.steps = append(o.steps, &fooStep{}) + o.steps = append(o.steps, &fooStep{failMe: fmt.Errorf("ouch")}) + + err := o.update(readOp, 0) + if assert.Error(t, err) { + oe := err.(OperationError) + assert.NoError(t, oe.OpError) + assert.Len(t, oe.StepErrors, 2) + assert.Contains(t, oe.StepErrors, 1) + assert.Contains(t, oe.StepErrors, 4) + } + }) + + t.Run("opError", func(t *testing.T) { + o := &operation{} + o.steps = append(o.steps, &fooStep{}) + o.steps = append(o.steps, &fooStep{}) + o.steps = append(o.steps, &fooStep{}) + o.steps = append(o.steps, &fooStep{}) + + err := o.update(readOp, 5) + if assert.Error(t, err) { + oe := err.(OperationError) + assert.Error(t, oe.OpError) + assert.Len(t, oe.StepErrors, 0) + } + }) + + t.Run("noErrors", func(t *testing.T) { + o := &operation{} + o.steps = append(o.steps, &fooStep{}) + o.steps = append(o.steps, &fooStep{}) + err := o.update(readOp, 0) + assert.NoError(t, err) + x := 0 + for i := range o.steps { + x += o.steps[i].(*fooStep).updateCount + } + assert.Equal(t, 2, x) + + o.free() + x = 0 + for i := range o.steps { + x += o.steps[i].(*fooStep).updateCount + } + assert.Equal(t, 2, x) + }) +}