github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/index/corpus_test.go (about)

     1  /*
     2  Copyright 2013 The Camlistore Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package index_test
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	"camlistore.org/pkg/blob"
    25  	"camlistore.org/pkg/context"
    26  	"camlistore.org/pkg/index"
    27  	"camlistore.org/pkg/index/indextest"
    28  	"camlistore.org/pkg/types"
    29  	"camlistore.org/pkg/types/camtypes"
    30  )
    31  
    32  func TestCorpusAppendPermanodeAttrValues(t *testing.T) {
    33  	c := index.ExpNewCorpus()
    34  	pn := blob.MustParse("abc-123")
    35  	tm := time.Unix(99, 0)
    36  	claim := func(verb, attr, val string) *camtypes.Claim {
    37  		tm = tm.Add(time.Second)
    38  		return &camtypes.Claim{
    39  			Type:  verb + "-attribute",
    40  			Attr:  attr,
    41  			Value: val,
    42  			Date:  tm,
    43  		}
    44  	}
    45  	s := func(s ...string) []string { return s }
    46  
    47  	c.SetClaims(pn, &index.PermanodeMeta{
    48  		Claims: []*camtypes.Claim{
    49  			claim("set", "foo", "foov"), // time 100
    50  
    51  			claim("add", "tag", "a"), // time 101
    52  			claim("add", "tag", "b"), // time 102
    53  			claim("del", "tag", ""),
    54  			claim("add", "tag", "c"),
    55  			claim("add", "tag", "d"),
    56  			claim("add", "tag", "e"),
    57  			claim("del", "tag", "d"),
    58  
    59  			claim("add", "DelAll", "a"),
    60  			claim("add", "DelAll", "b"),
    61  			claim("add", "DelAll", "c"),
    62  			claim("del", "DelAll", ""),
    63  
    64  			claim("add", "DelOne", "a"),
    65  			claim("add", "DelOne", "b"),
    66  			claim("add", "DelOne", "c"),
    67  			claim("add", "DelOne", "d"),
    68  			claim("del", "DelOne", "d"),
    69  			claim("del", "DelOne", "a"),
    70  
    71  			claim("add", "SetAfterAdd", "a"),
    72  			claim("add", "SetAfterAdd", "b"),
    73  			claim("set", "SetAfterAdd", "setv"),
    74  		},
    75  	})
    76  
    77  	tests := []struct {
    78  		attr string
    79  		want []string
    80  		t    time.Time
    81  	}{
    82  		{attr: "not-exist", want: s()},
    83  		{attr: "DelAll", want: s()},
    84  		{attr: "DelOne", want: s("b", "c")},
    85  		{attr: "foo", want: s("foov")},
    86  		{attr: "tag", want: s("c", "e")},
    87  		{attr: "tag", want: s("a", "b"), t: time.Unix(102, 0)},
    88  		{attr: "SetAfterAdd", want: s("setv")},
    89  	}
    90  	for i, tt := range tests {
    91  		got := c.AppendPermanodeAttrValues(nil, pn, tt.attr, tt.t, blob.Ref{})
    92  		if len(got) == 0 && len(tt.want) == 0 {
    93  			continue
    94  		}
    95  		if !reflect.DeepEqual(got, tt.want) {
    96  			t.Errorf("%d. attr %q = %q; want %q",
    97  				i, tt.attr, got, tt.want)
    98  		}
    99  	}
   100  
   101  }
   102  
   103  func TestKVClaimAllocs(t *testing.T) {
   104  	n := testing.AllocsPerRun(20, func() {
   105  		index.ExpKvClaim("claim|sha1-b380b3080f9c71faa5c1d82bbd4d583a473bc77d|2931A67C26F5ABDA|2011-11-28T01:32:37.000123456Z|sha1-b3d93daee62e40d36237ff444022f42d7d0e43f2",
   106  			"set-attribute|tag|foo1|sha1-ad87ca5c78bd0ce1195c46f7c98e6025abbaf007",
   107  			blob.Parse)
   108  	})
   109  	t.Logf("%v allocations", n)
   110  }
   111  
   112  func TestKVClaim(t *testing.T) {
   113  	tests := []struct {
   114  		k, v string
   115  		ok   bool
   116  		want camtypes.Claim
   117  	}{
   118  		{
   119  			k:  "claim|sha1-b380b3080f9c71faa5c1d82bbd4d583a473bc77d|2931A67C26F5ABDA|2011-11-28T01:32:37.000123456Z|sha1-b3d93daee62e40d36237ff444022f42d7d0e43f2",
   120  			v:  "set-attribute|tag|foo1|sha1-ad87ca5c78bd0ce1195c46f7c98e6025abbaf007",
   121  			ok: true,
   122  			want: camtypes.Claim{
   123  				BlobRef:   blob.MustParse("sha1-b3d93daee62e40d36237ff444022f42d7d0e43f2"),
   124  				Signer:    blob.MustParse("sha1-ad87ca5c78bd0ce1195c46f7c98e6025abbaf007"),
   125  				Permanode: blob.MustParse("sha1-b380b3080f9c71faa5c1d82bbd4d583a473bc77d"),
   126  				Type:      "set-attribute",
   127  				Attr:      "tag",
   128  				Value:     "foo1",
   129  				Date:      time.Time(types.ParseTime3339OrZero("2011-11-28T01:32:37.000123456Z")),
   130  			},
   131  		},
   132  	}
   133  	for _, tt := range tests {
   134  		got, ok := index.ExpKvClaim(tt.k, tt.v, blob.Parse)
   135  		if ok != tt.ok {
   136  			t.Errorf("kvClaim(%q, %q) = ok %v; want %v", tt.k, tt.v, ok, tt.ok)
   137  			continue
   138  		}
   139  		if got != tt.want {
   140  			t.Errorf("kvClaim(%q, %q) = %+v; want %+v", tt.k, tt.v, got, tt.want)
   141  			continue
   142  		}
   143  	}
   144  }
   145  
   146  func TestDeletePermanode_Modtime(t *testing.T) {
   147  	testDeletePermanodes(t,
   148  		func(c *index.Corpus, ctx *context.Context, ch chan<- camtypes.BlobMeta) error {
   149  			return c.EnumeratePermanodesLastModifiedLocked(ctx, ch)
   150  		},
   151  	)
   152  }
   153  
   154  func TestDeletePermanode_CreateTime(t *testing.T) {
   155  	testDeletePermanodes(t,
   156  		func(c *index.Corpus, ctx *context.Context, ch chan<- camtypes.BlobMeta) error {
   157  			return c.EnumeratePermanodesCreatedLocked(ctx, ch, true)
   158  		},
   159  	)
   160  }
   161  
   162  func testDeletePermanodes(t *testing.T,
   163  	enumFunc func(*index.Corpus, *context.Context, chan<- camtypes.BlobMeta) error) {
   164  	idx := index.NewMemoryIndex()
   165  	idxd := indextest.NewIndexDeps(idx)
   166  
   167  	foopn := idxd.NewPlannedPermanode("foo")
   168  	idxd.SetAttribute(foopn, "tag", "foo")
   169  	barpn := idxd.NewPlannedPermanode("bar")
   170  	idxd.SetAttribute(barpn, "tag", "bar")
   171  	bazpn := idxd.NewPlannedPermanode("baz")
   172  	idxd.SetAttribute(bazpn, "tag", "baz")
   173  	idxd.Delete(barpn)
   174  	c, err := idxd.Index.KeepInMemory()
   175  	if err != nil {
   176  		t.Fatalf("error slurping index to memory: %v", err)
   177  	}
   178  
   179  	// check that we initially only find permanodes foo and baz,
   180  	// because bar is already marked as deleted.
   181  	want := []blob.Ref{foopn, bazpn}
   182  	ch := make(chan camtypes.BlobMeta, 10)
   183  	var got []camtypes.BlobMeta
   184  	errc := make(chan error, 1)
   185  	c.RLock()
   186  	go func() { errc <- enumFunc(c, context.TODO(), ch) }()
   187  	for blobMeta := range ch {
   188  		got = append(got, blobMeta)
   189  	}
   190  	err = <-errc
   191  	c.RUnlock()
   192  	if err != nil {
   193  		t.Fatalf("Could not enumerate permanodes: %v", err)
   194  	}
   195  	if len(got) != len(want) {
   196  		t.Fatalf("Saw %d permanodes in corpus; want %d", len(got), len(want))
   197  	}
   198  	for _, bm := range got {
   199  		found := false
   200  		for _, perm := range want {
   201  			if bm.Ref == perm {
   202  				found = true
   203  				break
   204  			}
   205  		}
   206  		if !found {
   207  			t.Fatalf("permanode %v was not found in corpus", bm.Ref)
   208  		}
   209  	}
   210  
   211  	// now add a delete claim for permanode baz, and check that we're only left with foo permanode
   212  	delbaz := idxd.Delete(bazpn)
   213  	want = []blob.Ref{foopn}
   214  	got = got[:0]
   215  	ch = make(chan camtypes.BlobMeta, 10)
   216  	c.RLock()
   217  	go func() { errc <- enumFunc(c, context.TODO(), ch) }()
   218  	for blobMeta := range ch {
   219  		got = append(got, blobMeta)
   220  	}
   221  	err = <-errc
   222  	c.RUnlock()
   223  	if err != nil {
   224  		t.Fatalf("Could not enumerate permanodes: %v", err)
   225  	}
   226  	if len(got) != len(want) {
   227  		t.Fatalf("Saw %d permanodes in corpus; want %d", len(got), len(want))
   228  	}
   229  	if got[0].Ref != foopn {
   230  		t.Fatalf("Wrong permanode found in corpus. Wanted %v, got %v", foopn, got[0].Ref)
   231  	}
   232  
   233  	// baz undeletion. delete delbaz.
   234  	idxd.Delete(delbaz)
   235  	want = []blob.Ref{foopn, bazpn}
   236  	got = got[:0]
   237  	ch = make(chan camtypes.BlobMeta, 10)
   238  	c.RLock()
   239  	go func() { errc <- enumFunc(c, context.TODO(), ch) }()
   240  	for blobMeta := range ch {
   241  		got = append(got, blobMeta)
   242  	}
   243  	err = <-errc
   244  	c.RUnlock()
   245  	if err != nil {
   246  		t.Fatalf("Could not enumerate permanodes: %v", err)
   247  	}
   248  	if len(got) != len(want) {
   249  		t.Fatalf("Saw %d permanodes in corpus; want %d", len(got), len(want))
   250  	}
   251  	for _, bm := range got {
   252  		found := false
   253  		for _, perm := range want {
   254  			if bm.Ref == perm {
   255  				found = true
   256  				break
   257  			}
   258  		}
   259  		if !found {
   260  			t.Fatalf("permanode %v was not found in corpus", bm.Ref)
   261  		}
   262  	}
   263  }
   264  
   265  func TestEnumerateOrder_Modtime(t *testing.T) {
   266  	testEnumerateOrder(t,
   267  		func(c *index.Corpus, ctx *context.Context, ch chan<- camtypes.BlobMeta) error {
   268  			return c.EnumeratePermanodesLastModifiedLocked(ctx, ch)
   269  		},
   270  		modtimeOrder,
   271  	)
   272  }
   273  
   274  func TestEnumerateOrder_CreateTime(t *testing.T) {
   275  	testEnumerateOrder(t,
   276  		func(c *index.Corpus, ctx *context.Context, ch chan<- camtypes.BlobMeta) error {
   277  			return c.EnumeratePermanodesCreatedLocked(ctx, ch, true)
   278  		},
   279  		createOrder,
   280  	)
   281  }
   282  
   283  const (
   284  	modtimeOrder = iota
   285  	createOrder
   286  )
   287  
   288  func testEnumerateOrder(t *testing.T,
   289  	enumFunc func(*index.Corpus, *context.Context, chan<- camtypes.BlobMeta) error,
   290  	order int) {
   291  	idx := index.NewMemoryIndex()
   292  	idxd := indextest.NewIndexDeps(idx)
   293  
   294  	// permanode with no contents
   295  	foopn := idxd.NewPlannedPermanode("foo")
   296  	idxd.SetAttribute(foopn, "tag", "foo")
   297  	// permanode with file contents
   298  	// we set the time of the contents 1 second older than the modtime of foopn
   299  	fooModTime := idxd.LastTime()
   300  	fileTime := fooModTime.Add(-1 * time.Second)
   301  	fileRef, _ := idxd.UploadFile("foo.html", "<html>I am an html file.</html>", fileTime)
   302  	barpn := idxd.NewPlannedPermanode("bar")
   303  	idxd.SetAttribute(barpn, "camliContent", fileRef.String())
   304  
   305  	c, err := idxd.Index.KeepInMemory()
   306  	if err != nil {
   307  		t.Fatalf("error slurping index to memory: %v", err)
   308  	}
   309  
   310  	// check that we get a different order whether with enumerate according to
   311  	// contents time, or to permanode modtime.
   312  	var want []blob.Ref
   313  	if order == modtimeOrder {
   314  		// modtime.
   315  		want = []blob.Ref{barpn, foopn}
   316  	} else {
   317  		// creation time.
   318  		want = []blob.Ref{foopn, barpn}
   319  	}
   320  	ch := make(chan camtypes.BlobMeta, 10)
   321  	var got []camtypes.BlobMeta
   322  	errc := make(chan error, 1)
   323  	c.RLock()
   324  	go func() { errc <- enumFunc(c, context.TODO(), ch) }()
   325  	for blobMeta := range ch {
   326  		got = append(got, blobMeta)
   327  	}
   328  	err = <-errc
   329  	c.RUnlock()
   330  	if err != nil {
   331  		t.Fatalf("Could not enumerate permanodes: %v", err)
   332  	}
   333  	if len(got) != len(want) {
   334  		t.Fatalf("Saw %d permanodes in corpus; want %d", len(got), len(want))
   335  	}
   336  	for k, v := range got {
   337  		if v.Ref != want[k] {
   338  			t.Fatalf("Wrong result from enumeration. Got %v, wanted %v.", v.Ref, want[k])
   339  		}
   340  	}
   341  }