github.com/kayoticsully/syncthing@v0.8.9-0.20140724133906-c45a2fdc03f8/model/model_test.go (about)

     1  // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
     2  // All rights reserved. Use of this source code is governed by an MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package model
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"os"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/calmh/syncthing/config"
    15  	"github.com/calmh/syncthing/protocol"
    16  	"github.com/syndtr/goleveldb/leveldb"
    17  	"github.com/syndtr/goleveldb/leveldb/storage"
    18  )
    19  
    20  var node1, node2 protocol.NodeID
    21  
    22  func init() {
    23  	node1, _ = protocol.NodeIDFromString("AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR")
    24  	node2, _ = protocol.NodeIDFromString("GYRZZQB-IRNPV4Z-T7TC52W-EQYJ3TT-FDQW6MW-DFLMU42-SSSU6EM-FBK2VAY")
    25  }
    26  
    27  var testDataExpected = map[string]protocol.FileInfo{
    28  	"foo": protocol.FileInfo{
    29  		Name:     "foo",
    30  		Flags:    0,
    31  		Modified: 0,
    32  		Blocks:   []protocol.BlockInfo{{Offset: 0x0, Size: 0x7, Hash: []uint8{0xae, 0xc0, 0x70, 0x64, 0x5f, 0xe5, 0x3e, 0xe3, 0xb3, 0x76, 0x30, 0x59, 0x37, 0x61, 0x34, 0xf0, 0x58, 0xcc, 0x33, 0x72, 0x47, 0xc9, 0x78, 0xad, 0xd1, 0x78, 0xb6, 0xcc, 0xdf, 0xb0, 0x1, 0x9f}}},
    33  	},
    34  	"empty": protocol.FileInfo{
    35  		Name:     "empty",
    36  		Flags:    0,
    37  		Modified: 0,
    38  		Blocks:   []protocol.BlockInfo{{Offset: 0x0, Size: 0x0, Hash: []uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}},
    39  	},
    40  	"bar": protocol.FileInfo{
    41  		Name:     "bar",
    42  		Flags:    0,
    43  		Modified: 0,
    44  		Blocks:   []protocol.BlockInfo{{Offset: 0x0, Size: 0xa, Hash: []uint8{0x2f, 0x72, 0xcc, 0x11, 0xa6, 0xfc, 0xd0, 0x27, 0x1e, 0xce, 0xf8, 0xc6, 0x10, 0x56, 0xee, 0x1e, 0xb1, 0x24, 0x3b, 0xe3, 0x80, 0x5b, 0xf9, 0xa9, 0xdf, 0x98, 0xf9, 0x2f, 0x76, 0x36, 0xb0, 0x5c}}},
    45  	},
    46  }
    47  
    48  func init() {
    49  	// Fix expected test data to match reality
    50  	for n, f := range testDataExpected {
    51  		fi, _ := os.Stat("testdata/" + n)
    52  		f.Flags = uint32(fi.Mode())
    53  		f.Modified = fi.ModTime().Unix()
    54  		testDataExpected[n] = f
    55  	}
    56  }
    57  
    58  func TestRequest(t *testing.T) {
    59  	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
    60  	m := NewModel("/tmp", &config.Configuration{}, "syncthing", "dev", db)
    61  	m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
    62  	m.ScanRepo("default")
    63  
    64  	bs, err := m.Request(node1, "default", "foo", 0, 6)
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  	if bytes.Compare(bs, []byte("foobar")) != 0 {
    69  		t.Errorf("Incorrect data from request: %q", string(bs))
    70  	}
    71  
    72  	bs, err = m.Request(node1, "default", "../walk.go", 0, 6)
    73  	if err == nil {
    74  		t.Error("Unexpected nil error on insecure file read")
    75  	}
    76  	if bs != nil {
    77  		t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
    78  	}
    79  }
    80  
    81  func genFiles(n int) []protocol.FileInfo {
    82  	files := make([]protocol.FileInfo, n)
    83  	t := time.Now().Unix()
    84  	for i := 0; i < n; i++ {
    85  		files[i] = protocol.FileInfo{
    86  			Name:     fmt.Sprintf("file%d", i),
    87  			Modified: t,
    88  			Blocks:   []protocol.BlockInfo{{0, 100, []byte("some hash bytes")}},
    89  		}
    90  	}
    91  
    92  	return files
    93  }
    94  
    95  func BenchmarkIndex10000(b *testing.B) {
    96  	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
    97  	m := NewModel("/tmp", nil, "syncthing", "dev", db)
    98  	m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
    99  	m.ScanRepo("default")
   100  	files := genFiles(10000)
   101  
   102  	b.ResetTimer()
   103  	for i := 0; i < b.N; i++ {
   104  		m.Index(node1, "default", files)
   105  	}
   106  }
   107  
   108  func BenchmarkIndex00100(b *testing.B) {
   109  	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
   110  	m := NewModel("/tmp", nil, "syncthing", "dev", db)
   111  	m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
   112  	m.ScanRepo("default")
   113  	files := genFiles(100)
   114  
   115  	b.ResetTimer()
   116  	for i := 0; i < b.N; i++ {
   117  		m.Index(node1, "default", files)
   118  	}
   119  }
   120  
   121  func BenchmarkIndexUpdate10000f10000(b *testing.B) {
   122  	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
   123  	m := NewModel("/tmp", nil, "syncthing", "dev", db)
   124  	m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
   125  	m.ScanRepo("default")
   126  	files := genFiles(10000)
   127  	m.Index(node1, "default", files)
   128  
   129  	b.ResetTimer()
   130  	for i := 0; i < b.N; i++ {
   131  		m.IndexUpdate(node1, "default", files)
   132  	}
   133  }
   134  
   135  func BenchmarkIndexUpdate10000f00100(b *testing.B) {
   136  	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
   137  	m := NewModel("/tmp", nil, "syncthing", "dev", db)
   138  	m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
   139  	m.ScanRepo("default")
   140  	files := genFiles(10000)
   141  	m.Index(node1, "default", files)
   142  
   143  	ufiles := genFiles(100)
   144  	b.ResetTimer()
   145  	for i := 0; i < b.N; i++ {
   146  		m.IndexUpdate(node1, "default", ufiles)
   147  	}
   148  }
   149  
   150  func BenchmarkIndexUpdate10000f00001(b *testing.B) {
   151  	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
   152  	m := NewModel("/tmp", nil, "syncthing", "dev", db)
   153  	m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
   154  	m.ScanRepo("default")
   155  	files := genFiles(10000)
   156  	m.Index(node1, "default", files)
   157  
   158  	ufiles := genFiles(1)
   159  	b.ResetTimer()
   160  	for i := 0; i < b.N; i++ {
   161  		m.IndexUpdate(node1, "default", ufiles)
   162  	}
   163  }
   164  
   165  type FakeConnection struct {
   166  	id          protocol.NodeID
   167  	requestData []byte
   168  }
   169  
   170  func (FakeConnection) Close() error {
   171  	return nil
   172  }
   173  
   174  func (f FakeConnection) ID() protocol.NodeID {
   175  	return f.id
   176  }
   177  
   178  func (f FakeConnection) Name() string {
   179  	return ""
   180  }
   181  
   182  func (f FakeConnection) Option(string) string {
   183  	return ""
   184  }
   185  
   186  func (FakeConnection) Index(string, []protocol.FileInfo) error {
   187  	return nil
   188  }
   189  
   190  func (FakeConnection) IndexUpdate(string, []protocol.FileInfo) error {
   191  	return nil
   192  }
   193  
   194  func (f FakeConnection) Request(repo, name string, offset int64, size int) ([]byte, error) {
   195  	return f.requestData, nil
   196  }
   197  
   198  func (FakeConnection) ClusterConfig(protocol.ClusterConfigMessage) {}
   199  
   200  func (FakeConnection) Ping() bool {
   201  	return true
   202  }
   203  
   204  func (FakeConnection) Statistics() protocol.Statistics {
   205  	return protocol.Statistics{}
   206  }
   207  
   208  func BenchmarkRequest(b *testing.B) {
   209  	db, _ := leveldb.Open(storage.NewMemStorage(), nil)
   210  	m := NewModel("/tmp", nil, "syncthing", "dev", db)
   211  	m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"})
   212  	m.ScanRepo("default")
   213  
   214  	const n = 1000
   215  	files := make([]protocol.FileInfo, n)
   216  	t := time.Now().Unix()
   217  	for i := 0; i < n; i++ {
   218  		files[i] = protocol.FileInfo{
   219  			Name:     fmt.Sprintf("file%d", i),
   220  			Modified: t,
   221  			Blocks:   []protocol.BlockInfo{{0, 100, []byte("some hash bytes")}},
   222  		}
   223  	}
   224  
   225  	fc := FakeConnection{
   226  		id:          node1,
   227  		requestData: []byte("some data to return"),
   228  	}
   229  	m.AddConnection(fc, fc)
   230  	m.Index(node1, "default", files)
   231  
   232  	b.ResetTimer()
   233  	for i := 0; i < b.N; i++ {
   234  		data, err := m.requestGlobal(node1, "default", files[i%n].Name, 0, 32, nil)
   235  		if err != nil {
   236  			b.Error(err)
   237  		}
   238  		if data == nil {
   239  			b.Error("nil data")
   240  		}
   241  	}
   242  }
   243  
   244  func TestActivityMap(t *testing.T) {
   245  	isValid := func(protocol.NodeID) bool {
   246  		return true
   247  	}
   248  	m := make(activityMap)
   249  	if node := m.leastBusyNode([]protocol.NodeID{node1}, isValid); node != node1 {
   250  		t.Errorf("Incorrect least busy node %q", node)
   251  	}
   252  	if node := m.leastBusyNode([]protocol.NodeID{node2}, isValid); node != node2 {
   253  		t.Errorf("Incorrect least busy node %q", node)
   254  	}
   255  	if node := m.leastBusyNode([]protocol.NodeID{node1, node2}, isValid); node != node1 {
   256  		t.Errorf("Incorrect least busy node %q", node)
   257  	}
   258  	if node := m.leastBusyNode([]protocol.NodeID{node1, node2}, isValid); node != node2 {
   259  		t.Errorf("Incorrect least busy node %q", node)
   260  	}
   261  }