github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/pkg/schema/schema_test.go (about)

     1  /*
     2  Copyright 2011 Google Inc.
     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 schema
    18  
    19  import (
    20  	"encoding/json"
    21  	"os"
    22  	"path/filepath"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"camlistore.org/pkg/blob"
    28  	. "camlistore.org/pkg/test/asserts"
    29  )
    30  
    31  const kExpectedHeader = `{"camliVersion"`
    32  
    33  func TestJSON(t *testing.T) {
    34  	fileName := "schema_test.go"
    35  	fi, _ := os.Lstat(fileName)
    36  	m := NewCommonFileMap(fileName, fi)
    37  	json, err := m.JSON()
    38  	if err != nil {
    39  		t.Fatalf("Unexpected error: %v", err)
    40  	}
    41  	t.Logf("Got json: [%s]\n", json)
    42  	// TODO: test it parses back
    43  
    44  	if !strings.HasPrefix(json, kExpectedHeader) {
    45  		t.Errorf("JSON does't start with expected header.")
    46  	}
    47  
    48  }
    49  
    50  func TestRegularFile(t *testing.T) {
    51  	fileName := "schema_test.go"
    52  	fi, err := os.Lstat(fileName)
    53  	AssertNil(t, err, "schema_test.go stat")
    54  	m := NewCommonFileMap("schema_test.go", fi)
    55  	json, err := m.JSON()
    56  	if err != nil {
    57  		t.Fatalf("Unexpected error: %v", err)
    58  	}
    59  	t.Logf("Got json for regular file: [%s]\n", json)
    60  }
    61  
    62  func TestSymlink(t *testing.T) {
    63  	// We create the symlink now because make.go does not mirror
    64  	// symlinks properly, and it is less intrusive to do that here.
    65  	defer os.RemoveAll("testdata")
    66  	err := os.Mkdir("testdata", 0755)
    67  	AssertNil(t, err, "Mkdir")
    68  	err = os.Chdir("testdata")
    69  	AssertNil(t, err, "Chdir")
    70  	err = os.Symlink("test-target", "test-symlink")
    71  	AssertNil(t, err, "creating test-symlink")
    72  	err = os.Chdir("..")
    73  	AssertNil(t, err, "Chdir")
    74  	fileName := filepath.Join("testdata", "test-symlink")
    75  	fi, err := os.Lstat(fileName)
    76  	AssertNil(t, err, "test-symlink stat")
    77  	m := NewCommonFileMap(fileName, fi)
    78  	json, err := m.JSON()
    79  	if err != nil {
    80  		t.Fatalf("Unexpected error: %v", err)
    81  	}
    82  	t.Logf("Got json for symlink file: [%s]\n", json)
    83  }
    84  
    85  type mixPartsTest struct {
    86  	json, expected string
    87  }
    88  
    89  func TestStringFromMixedArray(t *testing.T) {
    90  	tests := []mixPartsTest{
    91  		{`["brad"]`, "brad"},
    92  		{`["brad", 32, 70]`, "brad F"},
    93  		{`["brad", "fitz"]`, "bradfitz"},
    94  		{`["Am", 233, "lie.jpg"]`, "Am\xe9lie.jpg"},
    95  	}
    96  	for idx, test := range tests {
    97  		var v []interface{}
    98  		if err := json.Unmarshal([]byte(test.json), &v); err != nil {
    99  			t.Fatalf("invalid JSON in test %d", idx)
   100  		}
   101  		got := stringFromMixedArray(v)
   102  		if got != test.expected {
   103  			t.Errorf("test %d got %q; expected %q", idx, got, test.expected)
   104  		}
   105  	}
   106  }
   107  
   108  func TestRFC3339(t *testing.T) {
   109  	tests := []string{
   110  		"2012-05-13T15:02:47Z",
   111  		"2012-05-13T15:02:47.1234Z",
   112  		"2012-05-13T15:02:47.123456789Z",
   113  	}
   114  	for _, in := range tests {
   115  		tm, err := time.Parse(time.RFC3339, in)
   116  		if err != nil {
   117  			t.Errorf("error parsing %q", in)
   118  			continue
   119  		}
   120  		if out := RFC3339FromTime(tm); in != out {
   121  			t.Errorf("RFC3339FromTime(%q) = %q; want %q", in, out, in)
   122  		}
   123  	}
   124  }
   125  
   126  func TestBlobFromReader(t *testing.T) {
   127  	br := blob.MustParse("sha1-f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
   128  	blob, err := BlobFromReader(br, strings.NewReader(`{"camliVersion": 1, "camliType": "foo"}  `))
   129  	if err != nil {
   130  		t.Error(err)
   131  	} else if blob.Type() != "foo" {
   132  		t.Errorf("got type %q; want foo", blob.Type())
   133  	}
   134  
   135  	blob, err = BlobFromReader(br, strings.NewReader(`{"camliVersion": 1, "camliType": "foo"}  X  `))
   136  	if err == nil {
   137  		// TODO(bradfitz): fix this somehow. Currently encoding/json's
   138  		// decoder over-reads.
   139  		// See: https://code.google.com/p/go/issues/detail?id=1955 ,
   140  		// which was "fixed", but not really.
   141  		t.Logf("TODO(bradfitz): make sure bogus non-whitespace after the JSON object causes an error.")
   142  	}
   143  }
   144  
   145  func TestAttribute(t *testing.T) {
   146  	tm := time.Unix(123, 456)
   147  	br := blob.MustParse("xxx-1234")
   148  	tests := []struct {
   149  		bb   *Builder
   150  		want string
   151  	}{
   152  		{
   153  			bb: NewSetAttributeClaim(br, "attr1", "val1"),
   154  			want: `{"camliVersion": 1,
   155    "attribute": "attr1",
   156    "camliType": "claim",
   157    "claimDate": "1970-01-01T00:02:03.000000456Z",
   158    "claimType": "set-attribute",
   159    "permaNode": "xxx-1234",
   160    "value": "val1"
   161  }`,
   162  		},
   163  		{
   164  			bb: NewAddAttributeClaim(br, "tag", "funny"),
   165  			want: `{"camliVersion": 1,
   166    "attribute": "tag",
   167    "camliType": "claim",
   168    "claimDate": "1970-01-01T00:02:03.000000456Z",
   169    "claimType": "add-attribute",
   170    "permaNode": "xxx-1234",
   171    "value": "funny"
   172  }`,
   173  		},
   174  		{
   175  			bb: NewDelAttributeClaim(br, "attr1", "val1"),
   176  			want: `{"camliVersion": 1,
   177    "attribute": "attr1",
   178    "camliType": "claim",
   179    "claimDate": "1970-01-01T00:02:03.000000456Z",
   180    "claimType": "del-attribute",
   181    "permaNode": "xxx-1234",
   182    "value": "val1"
   183  }`,
   184  		},
   185  		{
   186  			bb: NewDelAttributeClaim(br, "attr2", ""),
   187  			want: `{"camliVersion": 1,
   188    "attribute": "attr2",
   189    "camliType": "claim",
   190    "claimDate": "1970-01-01T00:02:03.000000456Z",
   191    "claimType": "del-attribute",
   192    "permaNode": "xxx-1234"
   193  }`,
   194  		},
   195  		{
   196  			bb: NewClaim(&claimParam{
   197  				permanode: br,
   198  				claimType: SetAttributeClaim,
   199  				attribute: "foo",
   200  				value:     "bar",
   201  			}, &claimParam{
   202  				permanode: br,
   203  				claimType: DelAttributeClaim,
   204  				attribute: "foo",
   205  				value:     "specific-del",
   206  			}, &claimParam{
   207  				permanode: br,
   208  				claimType: DelAttributeClaim,
   209  				attribute: "foo",
   210  			}),
   211  			want: `{"camliVersion": 1,
   212    "camliType": "claim",
   213    "claimDate": "1970-01-01T00:02:03.000000456Z",
   214    "claimType": "multi",
   215    "claims": [
   216      {
   217        "attribute": "foo",
   218        "claimType": "set-attribute",
   219        "permaNode": "xxx-1234",
   220        "value": "bar"
   221      },
   222      {
   223        "attribute": "foo",
   224        "claimType": "del-attribute",
   225        "permaNode": "xxx-1234",
   226        "value": "specific-del"
   227      },
   228      {
   229        "attribute": "foo",
   230        "claimType": "del-attribute",
   231        "permaNode": "xxx-1234"
   232      }
   233    ]
   234  }`,
   235  		},
   236  	}
   237  	for i, tt := range tests {
   238  		tt.bb.SetClaimDate(tm)
   239  		got, err := tt.bb.JSON()
   240  		if err != nil {
   241  			t.Errorf("%d. JSON error = %v", i, err)
   242  			continue
   243  		}
   244  		if got != tt.want {
   245  			t.Errorf("%d.\t got:\n%s\n\twant:q\n%s", i, got, tt.want)
   246  		}
   247  	}
   248  }
   249  
   250  func TestDeleteClaim(t *testing.T) {
   251  	tm := time.Unix(123, 456)
   252  	br := blob.MustParse("xxx-1234")
   253  	delTest := struct {
   254  		bb   *Builder
   255  		want string
   256  	}{
   257  		bb: NewDeleteClaim(br),
   258  		want: `{"camliVersion": 1,
   259    "camliType": "claim",
   260    "claimDate": "1970-01-01T00:02:03.000000456Z",
   261    "claimType": "delete",
   262    "target": "xxx-1234"
   263  }`,
   264  	}
   265  	delTest.bb.SetClaimDate(tm)
   266  	got, err := delTest.bb.JSON()
   267  	if err != nil {
   268  		t.Fatalf("JSON error = %v", err)
   269  	}
   270  	if got != delTest.want {
   271  		t.Fatalf("got:\n%s\n\twant:q\n%s", got, delTest.want)
   272  	}
   273  }
   274  
   275  func TestAsClaimAndAsShare(t *testing.T) {
   276  	br := blob.MustParse("xxx-1234")
   277  	signer := blob.MustParse("yyy-5678")
   278  
   279  	bb := NewSetAttributeClaim(br, "title", "Test Title")
   280  	bb = bb.SetSigner(signer)
   281  	bb = bb.SetClaimDate(time.Now())
   282  	c1 := bb.Blob()
   283  	c1.ss.Sig = "non-null-sig" // required by AsShare
   284  
   285  	bb = NewShareRef(ShareHaveRef, br, true)
   286  	bb = bb.SetSigner(signer)
   287  	bb = bb.SetClaimDate(time.Now())
   288  	c2 := bb.Blob()
   289  	c2.ss.Sig = "non-null-sig" // required by AsShare
   290  
   291  	if !br.Valid() {
   292  		t.Error("Blobref not valid")
   293  	}
   294  
   295  	_, ok := c1.AsClaim()
   296  	if !ok {
   297  		t.Error("Claim 1 not returned as claim")
   298  	}
   299  
   300  	_, ok = c2.AsClaim()
   301  	if !ok {
   302  		t.Error("Claim 2 not returned as claim")
   303  	}
   304  
   305  	s, ok := c1.AsShare()
   306  	if ok {
   307  		t.Error("Title claim returned share", s)
   308  	}
   309  
   310  	s, ok = c2.AsShare()
   311  	if !ok {
   312  		t.Error("Share claim failed to return share")
   313  	}
   314  }
   315  
   316  func TestShareExpiration(t *testing.T) {
   317  	defer func() { clockNow = time.Now }()
   318  	b, err := BlobFromReader(
   319  		blob.MustParse("sha1-64ffa72fa9bcb2f825e7ed40b9451e5cadca4c2c"),
   320  		strings.NewReader(`{"camliVersion": 1,
   321    "authType": "haveref",
   322    "camliSigner": "sha1-f2b0b7da718b97ce8c31591d8ed4645c777f3ef4",
   323    "camliType": "claim",
   324    "claimDate": "2013-09-08T23:58:53.656549677Z",
   325    "claimType": "share",
   326    "expires": "2013-09-09T23:58:53.65658012Z",
   327    "target": "sha1-f1d2d2f924e986ac86fdf7b36c94bcdf32beec15",
   328    "transitive": false
   329  ,"camliSig":"wsBcBAABCAAQBQJSLQ89CRApMaZ8JvWr2gAAcuEIABRQolhn+yKksfaBx6oLo18NWvWQ+aYweF+5Gu0TH0Ixur7t1o5HFtFSSfFISyggSZDJSjsxoxaawhWrvCe9dZuU2s/zgRpgUtd2xmBt82tLOn9JidnUavsNGFXbfCwdUBSkzN0vDYLmgXW0VtiybB354uIKfOInZor2j8Mq0p6pkWzK3qq9W0dku7iE96YFaTb4W7eOikqoSC6VpjC1/4MQWOYRHLcPcIEY6xJ8es2sYMMSNXuVaR9nMupz8ZcTygP4jh+lPR1OH61q/FSjpRp7GKt4wZ1PknYjMbnpIzVjiSz0MkYd65bpZwuPOwZh/h2kHW7wvHNQZfWUJHEsOAI==J2ID"}`),
   330  	)
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  	s, ok := b.AsShare()
   335  	if !ok {
   336  		t.Fatal("expected share")
   337  	}
   338  	clockNow = func() time.Time { return time.Unix(100, 0) }
   339  	if s.IsExpired() {
   340  		t.Error("expected not expired")
   341  	}
   342  	clockNow = func() time.Time { return time.Unix(1378687181+2*86400, 0) }
   343  	if !s.IsExpired() {
   344  		t.Error("expected expired")
   345  	}
   346  
   347  	// And without an expiration time:
   348  	b, err = BlobFromReader(
   349  		blob.MustParse("sha1-931875ec6b8d917b7aae9f672f4f92de1ffaeeb1"),
   350  		strings.NewReader(`{"camliVersion": 1,
   351    "authType": "haveref",
   352    "camliSigner": "sha1-f2b0b7da718b97ce8c31591d8ed4645c777f3ef4",
   353    "camliType": "claim",
   354    "claimDate": "2013-09-09T01:01:09.907842963Z",
   355    "claimType": "share",
   356    "target": "sha1-64ffa72fa9bcb2f825e7ed40b9451e5cadca4c2c",
   357    "transitive": false
   358  ,"camliSig":"wsBcBAABCAAQBQJSLR3VCRApMaZ8JvWr2gAA14kIAKmi5rCI5JTBvHbBuAu7wPVA87BLXm/BaD6zjqOENB4U8B+6KxyuT6KXe9P591IDXdZmJTP5tesbLtKw0iAWiRf2ea0Y7Ms3K77nLnSZM5QIOzb4aQKd1668p/5KqU3VfNayoHt69YkXyKBkqyEPjHINzC03QuLz5NIEBMYJaNqKKtEtSgh4gG8BBYq5qQzdKFg/Hx7VhkhW1y/1wwGSFJjaiPFMIJsF4d/gaO01Ip7XLro63ccyCy81tqKHnVjv0uULmZdbpgd3RHGGSnW3c9BfqkGvc3Wl11UQKzqc9OT+WTAWp8TXg6bLES9sQNzerx2wUfjKB9J4Yrk14iBfjl8==AynO"}`),
   359  	)
   360  	if err != nil {
   361  		t.Fatal(err)
   362  	}
   363  	s, ok = b.AsShare()
   364  	if !ok {
   365  		t.Fatal("expected share")
   366  	}
   367  	clockNow = func() time.Time { return time.Unix(100, 0) }
   368  	if s.IsExpired() {
   369  		t.Error("expected not expired")
   370  	}
   371  	clockNow = func() time.Time { return time.Unix(1378687181+2*86400, 0) }
   372  	if s.IsExpired() {
   373  		t.Error("expected not expired")
   374  	}
   375  }
   376  
   377  // camlistore.org/issue/305
   378  func TestIssue305(t *testing.T) {
   379  	var in = `{"camliVersion": 1,
   380    "camliType": "file",
   381    "fileName": "2012-03-10 15.03.18.m4v",
   382    "parts": [
   383      {
   384        "bytesRef": "sha1-c76d8b17b887c207875e61a77b7eccc60289e61c",
   385        "size": 20032564
   386      }
   387    ]
   388  }`
   389  	var ss superset
   390  	if err := json.NewDecoder(strings.NewReader(in)).Decode(&ss); err != nil {
   391  		t.Fatal(err)
   392  	}
   393  	inref := blob.SHA1FromString(in)
   394  	blob, err := BlobFromReader(inref, strings.NewReader(in))
   395  	if err != nil {
   396  		t.Fatal(err)
   397  	}
   398  	if blob.BlobRef() != inref {
   399  		t.Error("original ref = %s; want %s", blob.BlobRef(), inref)
   400  	}
   401  	bb := blob.Builder()
   402  	jback, err := bb.JSON()
   403  	if err != nil {
   404  		t.Fatal(err)
   405  	}
   406  	if jback != in {
   407  		t.Errorf("JSON doesn't match:\n got: %q\nwant: %q\n", jback, in)
   408  	}
   409  	out := bb.Blob()
   410  	if got := out.BlobRef(); got != inref {
   411  		t.Errorf("cloned ref = %v; want %v", got, inref)
   412  	}
   413  }