diff --git a/rados/write_op_test.go b/rados/write_op_test.go new file mode 100644 index 0000000..3a58a58 --- /dev/null +++ b/rados/write_op_test.go @@ -0,0 +1,247 @@ +package rados + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// timeStamp generates a dummy Timespec value. +func timeStamp() Timespec { + // Future TODO (maybe?) - vary the value? + return Timespec{342334800, 0} +} + +func (suite *RadosTestSuite) TestWriteOpCreate() { + suite.SetupConnection() + + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + err := op.Operate(suite.ioctx, "TestWriteOpCreate", OperationNoFlag) + assert.NoError(suite.T(), err) + + op2 := CreateWriteOp() + defer op2.Release() + op2.Create(CreateExclusive) + err = op2.Operate(suite.ioctx, "TestWriteOpCreate", OperationNoFlag) + assert.Error(suite.T(), err) + + // ensure a nil ioctx triggers a panic + assert.Panics(suite.T(), func() { + op := CreateWriteOp() + defer op.Release() + op.Operate(nil, "foo", OperationNoFlag) + }) +} + +func (suite *RadosTestSuite) TestWriteOpCreateWithTimestamp() { + suite.SetupConnection() + + oid := "TestWriteOpCreateWithTimestamp" + gts := timeStamp() + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + err := op.OperateWithMtime(suite.ioctx, oid, gts, OperationNoFlag) + assert.NoError(suite.T(), err) + + s, err := suite.ioctx.Stat(oid) + assert.NoError(suite.T(), err) + statTime := s.ModTime.Unix() + assert.Equal(suite.T(), gts.Sec, statTime) +} + +func (suite *RadosTestSuite) TestWriteOpSetOmap() { + suite.SetupConnection() + ta := assert.New(suite.T()) + + oid := "TestWriteOpSetOmap" + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + op.SetOmap(map[string][]byte{ + "alice": []byte("car"), + "boss": []byte("office"), + "catbert": []byte("dungeon"), + }) + err := op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + // the 2nd set of omap values should not be applied because + // the Create will fail to exclusively make the object + op2 := CreateWriteOp() + defer op2.Release() + op.Create(CreateExclusive) + op.SetOmap(map[string][]byte{ + "alice": []byte("home"), + "boss": []byte("golf course"), + "catbert": []byte("dungeon"), + }) + err = op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.Error(err) + + fetched, err := suite.ioctx.GetOmapValues(oid, "", "", 10) + ta.NoError(err) + ta.Equal("car", string(fetched["alice"])) + ta.Equal("office", string(fetched["boss"])) +} + +func (suite *RadosTestSuite) TestWriteOpRmOmapKeys() { + suite.SetupConnection() + ta := assert.New(suite.T()) + + oid := "TestWriteOpRmOmapKeys" + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + op.SetOmap(map[string][]byte{ + "alice": []byte("car"), + "boss": []byte("office"), + "catbert": []byte("dungeon"), + }) + err := op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + op2 := CreateWriteOp() + defer op2.Release() + op2.Create(CreateIdempotent) + op2.SetOmap(map[string][]byte{ + "dogbert": []byte("lab"), + }) + op2.RmOmapKeys([]string{"catbert"}) + err = op2.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + fetched, err := suite.ioctx.GetOmapValues(oid, "", "", 10) + ta.NoError(err) + ta.Len(fetched, 3) + ta.Equal("car", string(fetched["alice"])) + ta.Equal("office", string(fetched["boss"])) + ta.Equal("lab", string(fetched["dogbert"])) + ta.NotContains(fetched, "catbert") +} + +func (suite *RadosTestSuite) TestWriteOpCleanOmap() { + suite.SetupConnection() + ta := assert.New(suite.T()) + + oid := "TestWriteOpCleanOmap" + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + op.SetOmap(map[string][]byte{ + "alice": []byte("car"), + "boss": []byte("office"), + "catbert": []byte("dungeon"), + }) + err := op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + // this test simulates wanting to start a fresh new set of + // omap keys, atomically clearing and setting a new key & value. + op2 := CreateWriteOp() + defer op2.Release() + op2.Create(CreateIdempotent) + op2.CleanOmap() + op2.SetOmap(map[string][]byte{ + "dogbert": []byte("lab"), + }) + op2.RmOmapKeys([]string{"catbert"}) + err = op2.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + fetched, err := suite.ioctx.GetOmapValues(oid, "", "", 10) + ta.NoError(err) + ta.Len(fetched, 1) + ta.Equal("lab", string(fetched["dogbert"])) +} + +func (suite *RadosTestSuite) TestWriteOpAssertExists() { + suite.SetupConnection() + ta := assert.New(suite.T()) + + oid := "TestWriteOpRmOmapKeys" + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + err := op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + op2 := CreateWriteOp() + defer op2.Release() + op2.AssertExists() + op2.CleanOmap() + err = op2.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + op3 := CreateWriteOp() + defer op3.Release() + op3.AssertExists() + op3.CleanOmap() + err = op3.Operate(suite.ioctx, oid+"dne", OperationNoFlag) + ta.Error(err) +} + +func (suite *RadosTestSuite) TestWriteOpWrite() { + suite.SetupConnection() + ta := assert.New(suite.T()) + + oid := "TestWriteOpWrite" + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + op.Write([]byte("go-go-gadget"), 0) + op.Write([]byte("ceph project!"), 6) + err := op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + d := make([]byte, 32) + l, err := suite.ioctx.Read(oid, d, 0) + ta.NoError(err) + ta.Equal("go-go-ceph project!", string(d[:l])) +} + +func (suite *RadosTestSuite) TestWriteOpWriteFull() { + suite.SetupConnection() + ta := assert.New(suite.T()) + + oid := "TestWriteOpWriteFull" + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + op.WriteFull([]byte("one, two")) + op.WriteFull([]byte("buckle my shoe")) + err := op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + d := make([]byte, 32) + l, err := suite.ioctx.Read(oid, d, 0) + ta.NoError(err) + ta.Equal("buckle my shoe", string(d[:l])) +} + +func (suite *RadosTestSuite) TestWriteOpWriteSame() { + suite.SetupConnection() + ta := assert.New(suite.T()) + + oid := "TestWriteOpWriteSame" + op := CreateWriteOp() + defer op.Release() + op.Create(CreateIdempotent) + op.WriteSame([]byte("repetition "), 44, 0) + op.Write([]byte("is fun"), 44) + err := op.Operate(suite.ioctx, oid, OperationNoFlag) + ta.NoError(err) + + d := make([]byte, 64) + l, err := suite.ioctx.Read(oid, d, 0) + ta.NoError(err) + ta.Equal("repetition repetition repetition repetition is fun", string(d[:l])) +} + +func TestWriteOpInvalid(t *testing.T) { + r := &WriteOp{} + err := r.Operate(&IOContext{}, "foo", 0) + assert.Error(t, err) +}