| // Copyright 2015 The etcd Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package backend |
| |
| import ( |
| "reflect" |
| "testing" |
| "time" |
| |
| bolt "github.com/coreos/bbolt" |
| ) |
| |
| func TestBatchTxPut(t *testing.T) { |
| b, tmpPath := NewTmpBackend(time.Hour, 10000) |
| defer cleanup(b, tmpPath) |
| |
| tx := b.batchTx |
| tx.Lock() |
| defer tx.Unlock() |
| |
| // create bucket |
| tx.UnsafeCreateBucket([]byte("test")) |
| |
| // put |
| v := []byte("bar") |
| tx.UnsafePut([]byte("test"), []byte("foo"), v) |
| |
| // check put result before and after tx is committed |
| for k := 0; k < 2; k++ { |
| _, gv := tx.UnsafeRange([]byte("test"), []byte("foo"), nil, 0) |
| if !reflect.DeepEqual(gv[0], v) { |
| t.Errorf("v = %s, want %s", string(gv[0]), string(v)) |
| } |
| tx.commit(false) |
| } |
| } |
| |
| func TestBatchTxRange(t *testing.T) { |
| b, tmpPath := NewTmpBackend(time.Hour, 10000) |
| defer cleanup(b, tmpPath) |
| |
| tx := b.batchTx |
| tx.Lock() |
| defer tx.Unlock() |
| |
| tx.UnsafeCreateBucket([]byte("test")) |
| // put keys |
| allKeys := [][]byte{[]byte("foo"), []byte("foo1"), []byte("foo2")} |
| allVals := [][]byte{[]byte("bar"), []byte("bar1"), []byte("bar2")} |
| for i := range allKeys { |
| tx.UnsafePut([]byte("test"), allKeys[i], allVals[i]) |
| } |
| |
| tests := []struct { |
| key []byte |
| endKey []byte |
| limit int64 |
| |
| wkeys [][]byte |
| wvals [][]byte |
| }{ |
| // single key |
| { |
| []byte("foo"), nil, 0, |
| allKeys[:1], allVals[:1], |
| }, |
| // single key, bad |
| { |
| []byte("doo"), nil, 0, |
| nil, nil, |
| }, |
| // key range |
| { |
| []byte("foo"), []byte("foo1"), 0, |
| allKeys[:1], allVals[:1], |
| }, |
| // key range, get all keys |
| { |
| []byte("foo"), []byte("foo3"), 0, |
| allKeys, allVals, |
| }, |
| // key range, bad |
| { |
| []byte("goo"), []byte("goo3"), 0, |
| nil, nil, |
| }, |
| // key range with effective limit |
| { |
| []byte("foo"), []byte("foo3"), 1, |
| allKeys[:1], allVals[:1], |
| }, |
| // key range with limit |
| { |
| []byte("foo"), []byte("foo3"), 4, |
| allKeys, allVals, |
| }, |
| } |
| for i, tt := range tests { |
| keys, vals := tx.UnsafeRange([]byte("test"), tt.key, tt.endKey, tt.limit) |
| if !reflect.DeepEqual(keys, tt.wkeys) { |
| t.Errorf("#%d: keys = %+v, want %+v", i, keys, tt.wkeys) |
| } |
| if !reflect.DeepEqual(vals, tt.wvals) { |
| t.Errorf("#%d: vals = %+v, want %+v", i, vals, tt.wvals) |
| } |
| } |
| } |
| |
| func TestBatchTxDelete(t *testing.T) { |
| b, tmpPath := NewTmpBackend(time.Hour, 10000) |
| defer cleanup(b, tmpPath) |
| |
| tx := b.batchTx |
| tx.Lock() |
| defer tx.Unlock() |
| |
| tx.UnsafeCreateBucket([]byte("test")) |
| tx.UnsafePut([]byte("test"), []byte("foo"), []byte("bar")) |
| |
| tx.UnsafeDelete([]byte("test"), []byte("foo")) |
| |
| // check put result before and after tx is committed |
| for k := 0; k < 2; k++ { |
| ks, _ := tx.UnsafeRange([]byte("test"), []byte("foo"), nil, 0) |
| if len(ks) != 0 { |
| t.Errorf("keys on foo = %v, want nil", ks) |
| } |
| tx.commit(false) |
| } |
| } |
| |
| func TestBatchTxCommit(t *testing.T) { |
| b, tmpPath := NewTmpBackend(time.Hour, 10000) |
| defer cleanup(b, tmpPath) |
| |
| tx := b.batchTx |
| tx.Lock() |
| tx.UnsafeCreateBucket([]byte("test")) |
| tx.UnsafePut([]byte("test"), []byte("foo"), []byte("bar")) |
| tx.Unlock() |
| |
| tx.Commit() |
| |
| // check whether put happens via db view |
| b.db.View(func(tx *bolt.Tx) error { |
| bucket := tx.Bucket([]byte("test")) |
| if bucket == nil { |
| t.Errorf("bucket test does not exit") |
| return nil |
| } |
| v := bucket.Get([]byte("foo")) |
| if v == nil { |
| t.Errorf("foo key failed to written in backend") |
| } |
| return nil |
| }) |
| } |
| |
| func TestBatchTxBatchLimitCommit(t *testing.T) { |
| // start backend with batch limit 1 so one write can |
| // trigger a commit |
| b, tmpPath := NewTmpBackend(time.Hour, 1) |
| defer cleanup(b, tmpPath) |
| |
| tx := b.batchTx |
| tx.Lock() |
| tx.UnsafeCreateBucket([]byte("test")) |
| tx.UnsafePut([]byte("test"), []byte("foo"), []byte("bar")) |
| tx.Unlock() |
| |
| // batch limit commit should have been triggered |
| // check whether put happens via db view |
| b.db.View(func(tx *bolt.Tx) error { |
| bucket := tx.Bucket([]byte("test")) |
| if bucket == nil { |
| t.Errorf("bucket test does not exit") |
| return nil |
| } |
| v := bucket.Get([]byte("foo")) |
| if v == nil { |
| t.Errorf("foo key failed to written in backend") |
| } |
| return nil |
| }) |
| } |