github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/repo/refstore_test.go (about) 1 package repo 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/qri-io/qfs" 9 "github.com/qri-io/qfs/muxfs" 10 "github.com/qri-io/qri/dsref" 11 "github.com/qri-io/qri/event" 12 "github.com/qri-io/qri/profile" 13 reporef "github.com/qri-io/qri/repo/ref" 14 ) 15 16 var cases = []struct { 17 ref reporef.DatasetRef 18 String string 19 Absolute string 20 AliasString string 21 }{ 22 {reporef.DatasetRef{ 23 Peername: "peername", 24 }, "peername", "peername", "peername"}, 25 {reporef.DatasetRef{ 26 Peername: "peername", 27 Name: "datasetname", 28 }, "peername/datasetname", "peername/datasetname", "peername/datasetname"}, 29 30 {reporef.DatasetRef{ 31 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 32 }, "", "@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", ""}, 33 {reporef.DatasetRef{ 34 Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", 35 }, "@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", ""}, 36 37 {reporef.DatasetRef{ 38 Peername: "peername", 39 Name: "datasetname", 40 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 41 }, "peername/datasetname", "peername/datasetname@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", "peername/datasetname"}, 42 {reporef.DatasetRef{ 43 Peername: "peername", 44 Name: "datasetname", 45 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 46 Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", 47 }, "peername/datasetname@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "peername/datasetname@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "peername/datasetname"}, 48 49 {reporef.DatasetRef{ 50 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 51 Peername: "lucille", 52 }, "lucille", "lucille@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", "lucille"}, 53 {reporef.DatasetRef{ 54 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 55 Peername: "lucille", 56 Name: "ball", 57 Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", 58 }, "lucille/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "lucille/ball@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "lucille/ball"}, 59 60 {reporef.DatasetRef{ 61 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 62 Peername: "bad_name", 63 }, "bad_name", "bad_name@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", "bad_name"}, 64 // TODO - this used to be me@badId, which isn't very useful, but at least provided coding parity 65 // might be worth revisiting 66 {reporef.DatasetRef{ 67 ProfileID: profile.IDRawByteString("badID"), 68 Peername: "me", 69 }, "me", "me@C6mUq3y", "me"}, 70 } 71 72 func TestDatasetString(t *testing.T) { 73 for i, c := range cases { 74 if c.ref.String() != c.String { 75 t.Errorf("case %d:\n%s\n%s", i, c.ref.String(), c.String) 76 continue 77 } 78 } 79 } 80 81 func TestDatasetAbsolute(t *testing.T) { 82 for i, c := range cases { 83 if c.ref.Absolute() != c.Absolute { 84 t.Errorf("case %d:\n%s\n%s", i, c.ref.Absolute(), c.Absolute) 85 continue 86 } 87 } 88 } 89 90 func TestDatasetAliasString(t *testing.T) { 91 for i, c := range cases { 92 if c.ref.AliasString() != c.AliasString { 93 t.Errorf("case %d:\n%s\n%s", i, c.ref.AliasString(), c.AliasString) 94 continue 95 } 96 } 97 } 98 99 func TestParseDatasetRef(t *testing.T) { 100 peernameDatasetRef := reporef.DatasetRef{ 101 Peername: "peername", 102 } 103 104 nameDatasetRef := reporef.DatasetRef{ 105 Peername: "peername", 106 Name: "datasetname", 107 } 108 109 peerIDDatasetRef := reporef.DatasetRef{ 110 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 111 } 112 113 idNameDatasetRef := reporef.DatasetRef{ 114 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 115 Name: "datasetname", 116 } 117 118 idFullDatasetRef := reporef.DatasetRef{ 119 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 120 Name: "datasetname", 121 Path: "/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", 122 } 123 124 idFullIPFSDatasetRef := reporef.DatasetRef{ 125 Name: "datasetname", 126 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 127 Path: "/ipfs/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", 128 } 129 130 fullDatasetRef := reporef.DatasetRef{ 131 Peername: "peername", 132 Name: "datasetname", 133 Path: "/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", 134 } 135 136 fullIPFSDatasetRef := reporef.DatasetRef{ 137 Peername: "peername", 138 Name: "datasetname", 139 Path: "/ipfs/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", 140 } 141 142 pathOnlyDatasetRef := reporef.DatasetRef{ 143 Path: "/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", 144 } 145 146 ipfsOnlyDatasetRef := reporef.DatasetRef{ 147 Path: "/ipfs/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", 148 } 149 150 mapDatasetRef := reporef.DatasetRef{ 151 Path: "/map/QmcQsi93yUryyWvw6mPyDNoKRb7FcBx8QGBAeJ25kXQjnC", 152 } 153 154 cases := []struct { 155 input string 156 expect reporef.DatasetRef 157 err string 158 }{ 159 {"", reporef.DatasetRef{}, "repo: empty dataset reference"}, 160 {"peername/", peernameDatasetRef, ""}, 161 {"peername", peernameDatasetRef, ""}, 162 163 {"QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/", peerIDDatasetRef, ""}, 164 {"/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", peerIDDatasetRef, ""}, 165 166 {"peername/datasetname/", nameDatasetRef, ""}, 167 {"peername/datasetname", nameDatasetRef, ""}, 168 {"peername/datasetname/@", nameDatasetRef, ""}, 169 {"peername/datasetname@", nameDatasetRef, ""}, 170 171 {"/datasetname@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", idNameDatasetRef, ""}, 172 {"/datasetname@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/", idNameDatasetRef, ""}, 173 {"/datasetname/@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", idNameDatasetRef, ""}, 174 175 {"peername/datasetname/@/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", fullDatasetRef, ""}, 176 {"peername/datasetname@/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", fullDatasetRef, ""}, 177 178 {"/datasetname@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", idFullDatasetRef, ""}, 179 {"/datasetname@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", idFullDatasetRef, ""}, // 15 180 {"/datasetname/@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/ipfs/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", idFullIPFSDatasetRef, ""}, 181 {"/datasetname@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", idFullDatasetRef, ""}, 182 183 {"@/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", pathOnlyDatasetRef, ""}, 184 {"@/ipfs/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", ipfsOnlyDatasetRef, ""}, 185 {"@/map/QmcQsi93yUryyWvw6mPyDNoKRb7FcBx8QGBAeJ25kXQjnC", mapDatasetRef, ""}, 186 187 {"peername/datasetname/@/network/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/junk/junk/...", fullDatasetRef, ""}, 188 {"peername/datasetname/@/ipfs/QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/junk/junk/...", fullIPFSDatasetRef, ""}, 189 } 190 191 for i, c := range cases { 192 got, err := ParseDatasetRef(c.input) 193 if !(err == nil && c.err == "" || err != nil && err.Error() == c.err) { 194 t.Errorf("case %d error mismatch. expected: '%s', got: '%s'", i, c.err, err) 195 continue 196 } 197 198 if err := CompareDatasetRef(got, c.expect); err != nil { 199 t.Errorf("case %d: %s", i, err.Error()) 200 } 201 } 202 } 203 204 func TestMatch(t *testing.T) { 205 cases := []struct { 206 a, b string 207 match bool 208 }{ 209 {"a/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "a/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", true}, 210 {"a/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "a/b@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", true}, 211 {"QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/b@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", true}, 212 213 {"a/different_name@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", "a/b@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", true}, 214 {"different_peername/b@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", "a/b@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", true}, 215 {"different_peername/b@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", "QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/b@/b/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", true}, 216 } 217 218 for i, c := range cases { 219 a, err := ParseDatasetRef(c.a) 220 if err != nil { 221 t.Errorf("case %d error parsing dataset ref a: %s", i, err.Error()) 222 continue 223 } 224 b, err := ParseDatasetRef(c.b) 225 if err != nil { 226 t.Errorf("case %d error parsing dataset ref b: %s", i, err.Error()) 227 continue 228 } 229 230 gotA := a.Match(b) 231 if gotA != c.match { 232 t.Errorf("case %d a.Match", i) 233 continue 234 } 235 236 gotB := b.Match(a) 237 if gotB != c.match { 238 t.Errorf("case %d b.Match", i) 239 continue 240 } 241 } 242 } 243 244 func TestEqual(t *testing.T) { 245 cases := []struct { 246 a, b string 247 equal bool 248 }{ 249 {"a/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "a/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", true}, 250 {"a/b@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "a/b@/ipfs/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", false}, 251 252 {"QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1/b@/b/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", true}, 253 {"QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1/b@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1/b@/ipfs/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", false}, 254 255 {"a/different_name@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "a/b@/ipfs/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", false}, 256 {"different_peername/b@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "a/b@/ipfs/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", false}, 257 258 {"QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL/different_name@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL/b@/ipfs/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", false}, 259 {"QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL/b@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "a/b@/ipfs/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", false}, 260 {"QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL/b@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1/b@/ipfs/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL", false}, 261 } 262 263 for i, c := range cases { 264 a, err := ParseDatasetRef(c.a) 265 if err != nil { 266 t.Errorf("case %d error parsing dataset ref a: %s", i, err.Error()) 267 continue 268 } 269 b, err := ParseDatasetRef(c.b) 270 if err != nil { 271 t.Errorf("case %d error parsing dataset ref b: %s", i, err.Error()) 272 continue 273 } 274 275 gotA := a.Equal(b) 276 if gotA != c.equal { 277 t.Errorf("case %d a.Equal", i) 278 continue 279 } 280 281 gotB := b.Equal(a) 282 if gotB != c.equal { 283 t.Errorf("case %d b.Equal", i) 284 continue 285 } 286 } 287 } 288 289 func TestIsEmpty(t *testing.T) { 290 cases := []struct { 291 ref reporef.DatasetRef 292 empty bool 293 }{ 294 {reporef.DatasetRef{}, true}, 295 {reporef.DatasetRef{Peername: "a"}, false}, 296 {reporef.DatasetRef{Name: "a"}, false}, 297 {reporef.DatasetRef{Path: "a"}, false}, 298 {reporef.DatasetRef{ProfileID: profile.IDRawByteString("a")}, false}, 299 } 300 301 for i, c := range cases { 302 got := c.ref.IsEmpty() 303 if got != c.empty { 304 t.Errorf("case %d: %s", i, c.ref) 305 continue 306 } 307 } 308 } 309 310 func TestCompareDatasets(t *testing.T) { 311 cases := []struct { 312 a, b reporef.DatasetRef 313 err string 314 }{ 315 {reporef.DatasetRef{}, reporef.DatasetRef{}, ""}, 316 {reporef.DatasetRef{Name: "a"}, reporef.DatasetRef{}, "Name mismatch. a != "}, 317 {reporef.DatasetRef{Peername: "a"}, reporef.DatasetRef{}, "Peername mismatch. a != "}, 318 {reporef.DatasetRef{Path: "a"}, reporef.DatasetRef{}, "Path mismatch. a != "}, 319 {reporef.DatasetRef{ProfileID: profile.IDB58MustDecode("QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1")}, reporef.DatasetRef{}, "PeerID mismatch. QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1 != "}, 320 } 321 322 for i, c := range cases { 323 err := CompareDatasetRef(c.a, c.b) 324 if !(err == nil && c.err == "" || err != nil && err.Error() == c.err) { 325 t.Errorf("case %d error mistmatch. expected: '%s', got: '%s'", i, c.err, err) 326 continue 327 } 328 } 329 } 330 331 func TestCanonicalizeDatasetRef(t *testing.T) { 332 ctx := context.Background() 333 lucille := &profile.Profile{ID: profile.IDRawByteString("a"), Peername: "lucille", PrivKey: privKey} 334 carla := &profile.Profile{ID: profile.IDRawByteString("b"), Peername: "carla"} 335 336 fs, err := muxfs.New(ctx, []qfs.Config{ 337 {Type: "mem"}, 338 }) 339 340 if err != nil { 341 t.Fatal(err) 342 } 343 344 memRepo, err := NewMemRepoWithProfile(ctx, lucille, fs, event.NilBus) 345 if err != nil { 346 t.Errorf("error allocating mem repo: %s", err.Error()) 347 return 348 } 349 rs := memRepo.MemRefstore 350 for _, r := range []reporef.DatasetRef{ 351 {ProfileID: lucille.ID, Peername: "lucille", Name: "foo", Path: "/ipfs/QmTest"}, 352 {ProfileID: carla.ID, Peername: carla.Peername, Name: "hockey_stats", Path: "/ipfs/QmTest2"}, 353 {ProfileID: lucille.ID, Peername: "lucille", Name: "ball", Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1"}, 354 } { 355 if err := rs.PutRef(r); err != nil { 356 t.Fatal(err) 357 } 358 } 359 360 // TODO - this points to a problem in our thinking. placing a reference in the refstore doesn't automatically 361 // add it to the profile store. This can lead to bugs higher up the stack, but points to an architectural challenge: 362 // the profile store is supposed to be the source of truth for profiles, and that isn't being enforced here. 363 // Moreover, what's the correct thing to do when adding a ref to the refstore who's profile information is not in the profile 364 // store, or worse, doesn't match the profile store? 365 // There's an implied hierarchy of profile store > refstore that isn't being enforced in code, and should be. 366 if err := memRepo.Profiles().PutProfile(ctx, carla); err != nil { 367 t.Fatal(err.Error()) 368 } 369 370 cases := []struct { 371 input string 372 expect string 373 err string 374 }{ 375 {"me/foo", "lucille/foo@/ipfs/QmTest", ""}, 376 {"carla/hockey_stats", "carla/hockey_stats@/ipfs/QmTest2", ""}, 377 {"lucille/ball", "lucille/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", ""}, 378 {"me/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "lucille/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", ""}, 379 {"@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "lucille/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", ""}, 380 {"renamed/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", "lucille/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", ""}, 381 } 382 383 for i, c := range cases { 384 ref, err := ParseDatasetRef(c.input) 385 if err != nil { 386 t.Errorf("case %d unexpected dataset ref parse error: %s", i, err.Error()) 387 continue 388 } 389 got := &ref 390 391 err = canonicalizeDatasetRef(ctx, memRepo, got) 392 if !(err == nil && c.err == "" || err != nil && err.Error() == c.err) { 393 t.Errorf("case %d error mismatch. expected: '%s', got: '%s'", i, c.err, err) 394 continue 395 } 396 397 if got.String() != c.expect { 398 t.Errorf("case %d expected: %s, got: %s", i, c.expect, got) 399 continue 400 } 401 } 402 } 403 404 func TestCanonicalizeDatasetRefFSI(t *testing.T) { 405 ctx, cancel := context.WithCancel(context.Background()) 406 defer cancel() 407 408 peer := "lucille" 409 prof := &profile.Profile{ID: profile.IDRawByteString("a"), Peername: peer, PrivKey: privKey} 410 fs, err := muxfs.New(ctx, []qfs.Config{ 411 {Type: "mem"}, 412 }) 413 if err != nil { 414 t.Fatal(err) 415 } 416 417 memRepo, err := NewMemRepoWithProfile(ctx, prof, fs, event.NilBus) 418 if err != nil { 419 t.Fatal(err) 420 } 421 id := prof.ID 422 423 rs := memRepo.MemRefstore 424 rs.PutRef(reporef.DatasetRef{ProfileID: id, Peername: peer, Name: "apple", Path: "/ipfs/QmTest1"}) 425 rs.PutRef(reporef.DatasetRef{ProfileID: id, Peername: peer, Name: "banana", Path: "/ipfs/QmTest2", FSIPath: "/path/to/dataset"}) 426 427 goodCases := []struct { 428 input string 429 expectPath string 430 expectFSI string 431 }{ 432 {"me/apple", "/ipfs/QmTest1", ""}, 433 {"me/apple@/ipfs/QmTest1", "/ipfs/QmTest1", ""}, 434 {"me/apple@/ipfs/QmTest1Prev", "/ipfs/QmTest1Prev", ""}, 435 {"me/banana", "/ipfs/QmTest2", "/path/to/dataset"}, 436 {"me/banana@/ipfs/QmTest2", "/ipfs/QmTest2", "/path/to/dataset"}, 437 {"me/banana@/ipfs/QmTest2Prev", "/ipfs/QmTest2Prev", "/path/to/dataset"}, 438 } 439 440 for i, c := range goodCases { 441 ref, err := ParseDatasetRef(c.input) 442 if err != nil { 443 t.Errorf("case %d unexpected dataset ref parse error: %s", i, err) 444 continue 445 } 446 got := &ref 447 448 err = canonicalizeDatasetRef(ctx, memRepo, got) 449 if err != nil { 450 t.Errorf("case %d got error: %s", i, err) 451 continue 452 } 453 454 if got.Path != c.expectPath { 455 t.Errorf("case %d expected path: %s, got: %s", i, c.expectPath, got.Path) 456 continue 457 } 458 if got.FSIPath != c.expectFSI { 459 t.Errorf("case %d expected FSI path: %s, got: %s", i, c.expectFSI, got.FSIPath) 460 continue 461 } 462 } 463 } 464 465 func TestCanonicalizeProfile(t *testing.T) { 466 ctx, cancel := context.WithCancel(context.Background()) 467 defer cancel() 468 469 prof := &profile.Profile{Peername: "lucille", ID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), PrivKey: privKey} 470 fs, err := muxfs.New(ctx, []qfs.Config{ 471 {Type: "mem"}, 472 }) 473 if err != nil { 474 t.Fatal(err) 475 } 476 477 repo, err := NewMemRepoWithProfile(ctx, prof, fs, event.NilBus) 478 if err != nil { 479 t.Errorf("error allocating mem repo: %s", err.Error()) 480 return 481 } 482 483 lucille := reporef.DatasetRef{ 484 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 485 Peername: "lucille", 486 } 487 488 ball := reporef.DatasetRef{ 489 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 490 Peername: "lucille", 491 Name: "ball", 492 Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", 493 } 494 495 ballPeer := reporef.DatasetRef{ 496 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 497 Peername: "lucille", 498 Name: "ball", 499 } 500 501 renamePeerName := reporef.DatasetRef{ 502 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 503 Peername: "lucy", 504 Name: "ball", 505 Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", 506 } 507 508 badProfileIDGoodName := reporef.DatasetRef{ 509 ProfileID: profile.IDRawByteString("badID"), 510 Peername: "me", 511 } 512 513 cases := []struct { 514 input string 515 inputDataset reporef.DatasetRef 516 expect reporef.DatasetRef 517 err string 518 }{ 519 {"me", reporef.DatasetRef{}, lucille, ""}, 520 {"lucille", reporef.DatasetRef{}, lucille, ""}, 521 {"QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", reporef.DatasetRef{}, lucille, ""}, 522 {"me/ball@/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", reporef.DatasetRef{}, ball, ""}, 523 {"/ball@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", reporef.DatasetRef{}, ball, ""}, 524 {"/ball@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", reporef.DatasetRef{}, ballPeer, ""}, 525 {"me/ball", reporef.DatasetRef{}, ballPeer, ""}, 526 {"", badProfileIDGoodName, lucille, ""}, 527 {"/ball@QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", renamePeerName, ball, ""}, 528 {"", reporef.DatasetRef{}, reporef.DatasetRef{}, ""}, 529 } 530 531 for i, c := range cases { 532 var ( 533 ref reporef.DatasetRef 534 err error 535 ) 536 if c.input != "" { 537 ref, err = ParseDatasetRef(c.input) 538 if err != nil { 539 t.Errorf("case %d unexpected dataset ref parse error: %s", i, err.Error()) 540 continue 541 } 542 } else { 543 ref = c.inputDataset 544 } 545 got := &ref 546 547 err = canonicalizeProfile(ctx, repo, got) 548 if !(err == nil && c.err == "" || err != nil && err.Error() == c.err) { 549 t.Errorf("case %d error mismatch. expected: '%s', got: '%s'", i, c.err, err) 550 continue 551 } 552 553 if c.err == "" { 554 if got.ProfileID != c.expect.ProfileID { 555 t.Errorf("case %d ProfileID mismatch. expected: '%s', got: '%s'", i, c.expect.ProfileID, got.ProfileID) 556 } 557 if got.Peername != c.expect.Peername { 558 t.Errorf("case %d Peername mismatch. expected: '%s', got: '%s'", i, c.expect.Peername, got.Peername) 559 } 560 if got.Name != c.expect.Name { 561 t.Errorf("case %d Name mismatch. expected: '%s', got: '%s'", i, c.expect.Name, got.Name) 562 } 563 if got.Path != c.expect.Path { 564 t.Errorf("case %d Path mismatch. expected: '%s', got: '%s'", i, c.expect.Path, got.Path) 565 } 566 } 567 } 568 } 569 570 func TestConvertToDsref(t *testing.T) { 571 ref := reporef.DatasetRef{ 572 ProfileID: profile.IDB58MustDecode("QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y"), 573 Peername: "lucy", 574 Name: "ball", 575 Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", 576 } 577 expect := dsref.Ref{ 578 Username: "lucy", 579 Name: "ball", 580 ProfileID: "QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", 581 Path: "/ipfs/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1", 582 } 583 got := reporef.ConvertToDsref(ref) 584 585 if diff := cmp.Diff(expect, got); diff != "" { 586 t.Errorf("result mismatch (-want +got):\n%s", diff) 587 } 588 }