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 }