...

Source file src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_test.go

Documentation: github.com/syndtr/goleveldb/leveldb/storage

     1  // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
     2  // All rights reserved.
     3  //
     4  // Use of this source code is governed by a BSD-style license that can be
     5  // found in the LICENSE file.
     6  
     7  package storage
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"math/rand"
    13  	"os"
    14  	"path/filepath"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  var cases = []struct {
    20  	oldName []string
    21  	name    string
    22  	ftype   FileType
    23  	num     int64
    24  }{
    25  	{nil, "000100.log", TypeJournal, 100},
    26  	{nil, "000000.log", TypeJournal, 0},
    27  	{[]string{"000000.sst"}, "000000.ldb", TypeTable, 0},
    28  	{nil, "MANIFEST-000002", TypeManifest, 2},
    29  	{nil, "MANIFEST-000007", TypeManifest, 7},
    30  	{nil, "9223372036854775807.log", TypeJournal, 9223372036854775807},
    31  	{nil, "000100.tmp", TypeTemp, 100},
    32  }
    33  
    34  var invalidCases = []string{
    35  	"",
    36  	"foo",
    37  	"foo-dx-100.log",
    38  	".log",
    39  	"",
    40  	"manifest",
    41  	"CURREN",
    42  	"CURRENTX",
    43  	"MANIFES",
    44  	"MANIFEST",
    45  	"MANIFEST-",
    46  	"XMANIFEST-3",
    47  	"MANIFEST-3x",
    48  	"LOC",
    49  	"LOCKx",
    50  	"LO",
    51  	"LOGx",
    52  	"18446744073709551616.log",
    53  	"184467440737095516150.log",
    54  	"100",
    55  	"100.",
    56  	"100.lop",
    57  }
    58  
    59  func tempDir(t *testing.T) string {
    60  	dir, err := ioutil.TempDir("", "goleveldb-")
    61  	if err != nil {
    62  		t.Fatal(t)
    63  	}
    64  	t.Log("Using temp-dir:", dir)
    65  	return dir
    66  }
    67  
    68  func TestFileStorage_CreateFileName(t *testing.T) {
    69  	for _, c := range cases {
    70  		if name := fsGenName(FileDesc{c.ftype, c.num}); name != c.name {
    71  			t.Errorf("invalid filename got '%s', want '%s'", name, c.name)
    72  		}
    73  	}
    74  }
    75  
    76  func TestFileStorage_MetaSetGet(t *testing.T) {
    77  	temp := tempDir(t)
    78  	fs, err := OpenFile(temp, false)
    79  	if err != nil {
    80  		t.Fatal("OpenFile: got error: ", err)
    81  	}
    82  
    83  	for i := 0; i < 10; i++ {
    84  		num := rand.Int63()
    85  		fd := FileDesc{Type: TypeManifest, Num: num}
    86  		w, err := fs.Create(fd)
    87  		if err != nil {
    88  			t.Fatalf("Create(%d): got error: %v", i, err)
    89  		}
    90  		if _, err := w.Write([]byte("TEST")); err != nil {
    91  			t.Fatalf("Write(%d): got error: %v", i, err)
    92  		}
    93  		w.Close()
    94  		if err := fs.SetMeta(fd); err != nil {
    95  			t.Fatalf("SetMeta(%d): got error: %v", i, err)
    96  		}
    97  		rfd, err := fs.GetMeta()
    98  		if err != nil {
    99  			t.Fatalf("GetMeta(%d): got error: %v", i, err)
   100  		}
   101  		if fd != rfd {
   102  			t.Fatalf("Invalid meta (%d): got '%s', want '%s'", i, rfd, fd)
   103  		}
   104  	}
   105  	os.RemoveAll(temp)
   106  }
   107  
   108  func TestFileStorage_Meta(t *testing.T) {
   109  	type current struct {
   110  		num      int64
   111  		backup   bool
   112  		current  bool
   113  		manifest bool
   114  		corrupt  bool
   115  	}
   116  	type testCase struct {
   117  		currents []current
   118  		notExist bool
   119  		corrupt  bool
   120  		expect   int64
   121  	}
   122  	cases := []testCase{
   123  		{
   124  			currents: []current{
   125  				{num: 2, backup: true, manifest: true},
   126  				{num: 1, current: true},
   127  			},
   128  			expect: 2,
   129  		},
   130  		{
   131  			currents: []current{
   132  				{num: 2, backup: true, manifest: true},
   133  				{num: 1, current: true, manifest: true},
   134  			},
   135  			expect: 1,
   136  		},
   137  		{
   138  			currents: []current{
   139  				{num: 2, manifest: true},
   140  				{num: 3, manifest: true},
   141  				{num: 4, current: true, manifest: true},
   142  			},
   143  			expect: 4,
   144  		},
   145  		{
   146  			currents: []current{
   147  				{num: 2, manifest: true},
   148  				{num: 3, manifest: true},
   149  				{num: 4, current: true, manifest: true, corrupt: true},
   150  			},
   151  			expect: 3,
   152  		},
   153  		{
   154  			currents: []current{
   155  				{num: 2, manifest: true},
   156  				{num: 3, manifest: true},
   157  				{num: 5, current: true, manifest: true, corrupt: true},
   158  				{num: 4, backup: true, manifest: true},
   159  			},
   160  			expect: 4,
   161  		},
   162  		{
   163  			currents: []current{
   164  				{num: 4, manifest: true},
   165  				{num: 3, manifest: true},
   166  				{num: 2, current: true, manifest: true},
   167  			},
   168  			expect: 4,
   169  		},
   170  		{
   171  			currents: []current{
   172  				{num: 4, manifest: true, corrupt: true},
   173  				{num: 3, manifest: true},
   174  				{num: 2, current: true, manifest: true},
   175  			},
   176  			expect: 3,
   177  		},
   178  		{
   179  			currents: []current{
   180  				{num: 4, manifest: true, corrupt: true},
   181  				{num: 3, manifest: true, corrupt: true},
   182  				{num: 2, current: true, manifest: true},
   183  			},
   184  			expect: 2,
   185  		},
   186  		{
   187  			currents: []current{
   188  				{num: 4},
   189  				{num: 3, manifest: true},
   190  				{num: 2, current: true, manifest: true},
   191  			},
   192  			expect: 3,
   193  		},
   194  		{
   195  			currents: []current{
   196  				{num: 4},
   197  				{num: 3, manifest: true},
   198  				{num: 6, current: true},
   199  				{num: 5, backup: true, manifest: true},
   200  			},
   201  			expect: 5,
   202  		},
   203  		{
   204  			currents: []current{
   205  				{num: 4},
   206  				{num: 3},
   207  				{num: 6, current: true},
   208  				{num: 5, backup: true},
   209  			},
   210  			notExist: true,
   211  		},
   212  		{
   213  			currents: []current{
   214  				{num: 4, corrupt: true},
   215  				{num: 3},
   216  				{num: 6, current: true},
   217  				{num: 5, backup: true},
   218  			},
   219  			corrupt: true,
   220  		},
   221  	}
   222  	for i, tc := range cases {
   223  		t.Logf("Test-%d", i)
   224  		temp := tempDir(t)
   225  		fs, err := OpenFile(temp, false)
   226  		if err != nil {
   227  			t.Fatal("OpenFile: got error: ", err)
   228  		}
   229  		for _, cur := range tc.currents {
   230  			var curName string
   231  			switch {
   232  			case cur.current:
   233  				curName = "CURRENT"
   234  			case cur.backup:
   235  				curName = "CURRENT.bak"
   236  			default:
   237  				curName = fmt.Sprintf("CURRENT.%d", cur.num)
   238  			}
   239  			fd := FileDesc{Type: TypeManifest, Num: cur.num}
   240  			content := fmt.Sprintf("%s\n", fsGenName(fd))
   241  			if cur.corrupt {
   242  				content = content[:len(content)-1-rand.Intn(3)]
   243  			}
   244  			if err := ioutil.WriteFile(filepath.Join(temp, curName), []byte(content), 0644); err != nil {
   245  				t.Fatal(err)
   246  			}
   247  			if cur.manifest {
   248  				w, err := fs.Create(fd)
   249  				if err != nil {
   250  					t.Fatal(err)
   251  				}
   252  				if _, err := w.Write([]byte("TEST")); err != nil {
   253  					t.Fatal(err)
   254  				}
   255  				w.Close()
   256  			}
   257  		}
   258  		ret, err := fs.GetMeta()
   259  		if tc.notExist {
   260  			if err != os.ErrNotExist {
   261  				t.Fatalf("expect ErrNotExist, got: %v", err)
   262  			}
   263  		} else if tc.corrupt {
   264  			if !isCorrupted(err) {
   265  				t.Fatalf("expect ErrCorrupted, got: %v", err)
   266  			}
   267  		} else {
   268  			if err != nil {
   269  				t.Fatal(err)
   270  			}
   271  			if ret.Type != TypeManifest {
   272  				t.Fatalf("expecting manifest, got: %s", ret.Type)
   273  			}
   274  			if ret.Num != tc.expect {
   275  				t.Fatalf("invalid num, expect=%d got=%d", tc.expect, ret.Num)
   276  			}
   277  			fis, err := ioutil.ReadDir(temp)
   278  			if err != nil {
   279  				t.Fatal(err)
   280  			}
   281  			for _, fi := range fis {
   282  				if strings.HasPrefix(fi.Name(), "CURRENT") {
   283  					switch fi.Name() {
   284  					case "CURRENT", "CURRENT.bak":
   285  					default:
   286  						t.Fatalf("found rouge CURRENT file: %s", fi.Name())
   287  					}
   288  				}
   289  				t.Logf("-> %s", fi.Name())
   290  			}
   291  		}
   292  		os.RemoveAll(temp)
   293  	}
   294  }
   295  
   296  func TestFileStorage_ParseFileName(t *testing.T) {
   297  	for _, c := range cases {
   298  		for _, name := range append([]string{c.name}, c.oldName...) {
   299  			fd, ok := fsParseName(name)
   300  			if !ok {
   301  				t.Errorf("cannot parse filename '%s'", name)
   302  				continue
   303  			}
   304  			if fd.Type != c.ftype {
   305  				t.Errorf("filename '%s' invalid type got '%d', want '%d'", name, fd.Type, c.ftype)
   306  			}
   307  			if fd.Num != c.num {
   308  				t.Errorf("filename '%s' invalid number got '%d', want '%d'", name, fd.Num, c.num)
   309  			}
   310  		}
   311  	}
   312  }
   313  
   314  func TestFileStorage_InvalidFileName(t *testing.T) {
   315  	for _, name := range invalidCases {
   316  		if fsParseNamePtr(name, nil) {
   317  			t.Errorf("filename '%s' should be invalid", name)
   318  		}
   319  	}
   320  }
   321  
   322  func TestFileStorage_Locking(t *testing.T) {
   323  	temp := tempDir(t)
   324  	defer os.RemoveAll(temp)
   325  
   326  	p1, err := OpenFile(temp, false)
   327  	if err != nil {
   328  		t.Fatal("OpenFile(1): got error: ", err)
   329  	}
   330  
   331  	p2, err := OpenFile(temp, false)
   332  	if err != nil {
   333  		t.Logf("OpenFile(2): got error: %s (expected)", err)
   334  	} else {
   335  		p2.Close()
   336  		p1.Close()
   337  		t.Fatal("OpenFile(2): expect error")
   338  	}
   339  
   340  	p1.Close()
   341  
   342  	p3, err := OpenFile(temp, false)
   343  	if err != nil {
   344  		t.Fatal("OpenFile(3): got error: ", err)
   345  	}
   346  	defer p3.Close()
   347  
   348  	l, err := p3.Lock()
   349  	if err != nil {
   350  		t.Fatal("storage lock failed(1): ", err)
   351  	}
   352  	_, err = p3.Lock()
   353  	if err == nil {
   354  		t.Fatal("expect error for second storage lock attempt")
   355  	} else {
   356  		t.Logf("storage lock got error: %s (expected)", err)
   357  	}
   358  	l.Unlock()
   359  	_, err = p3.Lock()
   360  	if err != nil {
   361  		t.Fatal("storage lock failed(2): ", err)
   362  	}
   363  }
   364  
   365  func TestFileStorage_ReadOnlyLocking(t *testing.T) {
   366  	temp := tempDir(t)
   367  	defer os.RemoveAll(temp)
   368  
   369  	p1, err := OpenFile(temp, false)
   370  	if err != nil {
   371  		t.Fatal("OpenFile(1): got error: ", err)
   372  	}
   373  
   374  	_, err = OpenFile(temp, true)
   375  	if err != nil {
   376  		t.Logf("OpenFile(2): got error: %s (expected)", err)
   377  	} else {
   378  		t.Fatal("OpenFile(2): expect error")
   379  	}
   380  
   381  	p1.Close()
   382  
   383  	p3, err := OpenFile(temp, true)
   384  	if err != nil {
   385  		t.Fatal("OpenFile(3): got error: ", err)
   386  	}
   387  
   388  	p4, err := OpenFile(temp, true)
   389  	if err != nil {
   390  		t.Fatal("OpenFile(4): got error: ", err)
   391  	}
   392  
   393  	_, err = OpenFile(temp, false)
   394  	if err != nil {
   395  		t.Logf("OpenFile(5): got error: %s (expected)", err)
   396  	} else {
   397  		t.Fatal("OpenFile(2): expect error")
   398  	}
   399  
   400  	p3.Close()
   401  	p4.Close()
   402  }
   403  

View as plain text