github.com/go-kivik/kivik/v4@v4.3.2/pouchdb/test/test.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 //go:build js 14 15 // Package test provides PouchDB integration tests. 16 package test 17 18 import ( 19 "net/http" 20 "net/url" 21 "os" 22 "runtime" 23 "strings" 24 "testing" 25 26 "github.com/gopherjs/gopherjs/js" 27 28 kivik "github.com/go-kivik/kivik/v4" 29 "github.com/go-kivik/kivik/v4/kiviktest" 30 "github.com/go-kivik/kivik/v4/kiviktest/kt" 31 ) 32 33 func init() { 34 if pouchDB := js.Global.Get("PouchDB"); pouchDB != js.Undefined { 35 memPouch := js.Global.Get("PouchDB").Call("defaults", map[string]interface{}{ 36 "db": js.Global.Call("require", "memdown"), 37 }) 38 js.Global.Set("PouchDB", memPouch) 39 } 40 } 41 42 // RegisterPouchDBSuites registers the PouchDB test suites. 43 func RegisterPouchDBSuites() { 44 kiviktest.RegisterSuite(kiviktest.SuitePouchLocal, kt.SuiteConfig{ 45 "PreCleanup.skip": true, 46 47 // Features which are not supported by PouchDB 48 "Log.skip": true, 49 "Flush.skip": true, 50 "Security.skip": true, // FIXME: Perhaps implement later with a plugin? 51 "SetSecurity.skip": true, // FIXME: Perhaps implement later with a plugin? 52 "DBUpdates.skip": true, 53 54 "AllDBs.skip": true, // FIXME: Find a way to test with the plugin 55 "CreateDB.skip": true, // FIXME: No way to validate if this works unless/until allDbs works 56 "DBExists.skip": true, // FIXME: Maybe fix this if/when allDBs works? 57 58 "AllDocs/Admin.databases": []string{}, 59 "AllDocs/RW/group/Admin/WithDocs/UpdateSeq.skip": true, 60 61 "Find/Admin.databases": []string{}, 62 // TODO: Fix this and uncomment https://github.com/go-kivik/kivik/issues/588 63 // "Find/RW/group/Admin/Warning.warning": indexWarning, 64 65 "Explain.databases": []string{}, 66 "Explain.plan": &kivik.QueryPlan{ 67 Index: map[string]interface{}{ 68 "ddoc": nil, 69 "name": "_all_docs", 70 "type": "special", 71 "def": map[string]interface{}{"fields": []interface{}{map[string]string{"_id": "asc"}}}, 72 }, 73 Selector: map[string]interface{}{"_id": map[string]interface{}{"$gt": nil}}, 74 Options: map[string]interface{}{ 75 "bookmark": "nil", 76 "conflicts": false, 77 "r": []int{49}, 78 "sort": map[string]interface{}{}, 79 "use_index": []interface{}{}, 80 }, 81 Fields: func() []interface{} { 82 if ver := runtime.Version(); strings.HasPrefix(ver, "go1.16") { 83 return []interface{}{} 84 } 85 // From GopherJS 17 on, null arrays are properly converted to nil 86 return nil 87 }(), 88 Range: map[string]interface{}{ 89 "start_key": nil, 90 }, 91 }, 92 93 "Query/RW/group/Admin/WithDocs/UpdateSeq.skip": true, 94 95 "Version.version": `^[789]\.\d\.\d$`, 96 "Version.vendor": `^PouchDB$`, 97 "Version.vendor_version": `^[789]\.\d\.\d$`, 98 99 "Get/RW/group/Admin/bogus.status": http.StatusNotFound, 100 "Get/RW/group/NoAuth/bogus.status": http.StatusNotFound, 101 102 "GetRev/RW/group/Admin/bogus.status": http.StatusNotFound, 103 "GetRev/RW/group/NoAuth/bogus.status": http.StatusNotFound, 104 105 "Delete/RW/Admin/group/MissingDoc.status": http.StatusNotFound, 106 "Delete/RW/Admin/group/InvalidRevFormat.status": http.StatusBadRequest, 107 "Delete/RW/Admin/group/WrongRev.status": http.StatusConflict, 108 109 "Stats/Admin.skip": true, // No predefined DBs for Local PouchDB 110 111 "BulkDocs/RW/Admin/group/Mix/Conflict.status": http.StatusConflict, 112 113 "GetAttachment/RW/group/Admin/foo/NotFound.status": http.StatusNotFound, 114 115 "GetAttachmentMeta/RW/group/Admin/foo/NotFound.status": http.StatusNotFound, 116 117 "PutAttachment/RW/group/Admin/Conflict.status": http.StatusConflict, 118 119 // "DeleteAttachment/RW/group/Admin/NotFound.status": http.StatusNotFound, // https://github.com/pouchdb/pouchdb/issues/6409 120 "DeleteAttachment/RW/group/Admin/NoDoc.status": http.StatusNotFound, 121 122 "Put/RW/Admin/group/LeadingUnderscoreInID.status": http.StatusBadRequest, 123 "Put/RW/Admin/group/Conflict.status": http.StatusConflict, 124 125 "CreateIndex/RW/Admin/group/EmptyIndex.status": http.StatusInternalServerError, 126 "CreateIndex/RW/Admin/group/BlankIndex.status": http.StatusBadRequest, 127 "CreateIndex/RW/Admin/group/InvalidIndex.status": http.StatusInternalServerError, 128 "CreateIndex/RW/Admin/group/NilIndex.status": http.StatusInternalServerError, 129 "CreateIndex/RW/Admin/group/InvalidJSON.status": http.StatusBadRequest, 130 131 "GetIndexes.databases": []string{}, 132 133 "DeleteIndex/RW/Admin/group/NotFoundDdoc.status": http.StatusNotFound, 134 "DeleteIndex/RW/Admin/group/NotFoundName.status": http.StatusNotFound, 135 136 "Replicate.skip": true, // No need to do this for both Local and Remote 137 138 "Query/RW/group/Admin/WithoutDocs/ScanDoc.status": http.StatusBadRequest, 139 140 "Changes/Continuous.options": kivik.Params(map[string]interface{}{ 141 "live": true, 142 "timeout": false, 143 }), 144 }) 145 kiviktest.RegisterSuite(kiviktest.SuitePouchRemote, kt.SuiteConfig{ 146 // Features which are not supported by PouchDB 147 "Log.skip": true, 148 "Flush.skip": true, 149 "Session.skip": true, 150 "Security.skip": true, // FIXME: Perhaps implement later with a plugin? 151 "SetSecurity.skip": true, // FIXME: Perhaps implement later with a plugin? 152 "DBUpdates.skip": true, 153 154 "PreCleanup.skip": true, 155 156 "AllDBs.skip": true, // FIXME: Perhaps a workaround can be found? 157 158 "CreateDB/RW/NoAuth.status": http.StatusUnauthorized, 159 "CreateDB/RW/Admin/Recreate.status": http.StatusPreconditionFailed, 160 161 "DBExists.databases": []string{"_users", "chicken"}, 162 "DBExists/Admin/_users.exists": true, 163 "DBExists/Admin/chicken.exists": false, 164 "DBExists/NoAuth/_users.exists": true, 165 "DBExists/NoAuth/chicken.exists": false, 166 "DBExists/RW/group/Admin.exists": true, 167 "DBExists/RW/group/NoAuth.exists": true, 168 169 "DestroyDB/RW/NoAuth/NonExistantDB.status": http.StatusNotFound, 170 "DestroyDB/RW/Admin/NonExistantDB.status": http.StatusNotFound, 171 "DestroyDB/RW/NoAuth/ExistingDB.status": http.StatusUnauthorized, 172 173 "AllDocs.databases": []string{"_replicator", "_users", "chicken"}, 174 "AllDocs/Admin/_replicator.expected": []string{"_design/_replicator"}, 175 "AllDocs/Admin/_replicator.offset": 0, 176 "AllDocs/Admin/_users.expected": []string{"_design/_auth"}, 177 "AllDocs/Admin/chicken.status": http.StatusNotFound, 178 "AllDocs/NoAuth/_replicator.status": http.StatusUnauthorized, 179 "AllDocs/NoAuth/_users.status": http.StatusUnauthorized, 180 "AllDocs/NoAuth/chicken.status": http.StatusNotFound, 181 "AllDocs/Admin/_replicator/WithDocs/UpdateSeq.skip": true, 182 "AllDocs/Admin/_users/WithDocs/UpdateSeq.skip": true, 183 "AllDocs/RW/group/Admin/WithDocs/UpdateSeq.skip": true, 184 "AllDocs/RW/group/Admin/WithoutDocs/UpdateSeq.skip": true, 185 "AllDocs/RW/group/NoAuth/WithDocs/UpdateSeq.skip": true, 186 "AllDocs/RW/group/NoAuth/WithoutDocs/UpdateSeq.skip": true, 187 188 "Find.databases": []string{"chicken", "_duck"}, 189 "Find/Admin/chicken.status": http.StatusNotFound, 190 "Find/Admin/_duck.status": http.StatusNotFound, 191 "Find/NoAuth/chicken.status": http.StatusNotFound, 192 "Find/NoAuth/_duck.status": http.StatusUnauthorized, 193 // TODO: Fix this and uncomment https://github.com/go-kivik/kivik/issues/588 194 // "Find/RW/group/Admin/Warning.warning": "No matching index found, create an index to optimize query time", 195 "Find/RW/group/NoAuth/Warning.warning": "No matching index found, create an index to optimize query time", 196 197 "Explain.databases": []string{"chicken", "_duck"}, 198 "Explain/Admin/chicken.status": http.StatusNotFound, 199 "Explain/Admin/_duck.status": http.StatusNotFound, 200 "Explain/NoAuth/chicken.status": http.StatusNotFound, 201 "Explain/NoAuth/_duck.status": http.StatusUnauthorized, 202 "Explain.plan": &kivik.QueryPlan{ 203 Index: map[string]interface{}{ 204 "ddoc": nil, 205 "name": "_all_docs", 206 "type": "special", 207 "def": map[string]interface{}{"fields": []interface{}{map[string]string{"_id": "asc"}}}, 208 }, 209 Selector: map[string]interface{}{"_id": map[string]interface{}{"$gt": nil}}, 210 Options: map[string]interface{}{ 211 "bookmark": "nil", 212 "conflicts": false, 213 "execution_stats": false, 214 "r": []int{49}, 215 "sort": map[string]interface{}{}, 216 "use_index": []interface{}{}, 217 "stable": false, 218 "stale": false, 219 "update": true, 220 "skip": 0, 221 "limit": 25, //nolint:gomnd 222 "fields": "all_fields", 223 }, 224 Fields: func() []interface{} { 225 if ver := runtime.Version(); strings.HasPrefix(ver, "go1.16") { 226 return []interface{}{} 227 } 228 // From GopherJS 17 on, null arrays are properly converted to nil 229 return nil 230 }(), 231 Range: nil, 232 Limit: 25, //nolint:gomnd 233 }, 234 235 "CreateIndex/RW/Admin/group/EmptyIndex.status": http.StatusBadRequest, 236 "CreateIndex/RW/Admin/group/BlankIndex.status": http.StatusBadRequest, 237 "CreateIndex/RW/Admin/group/InvalidIndex.status": http.StatusBadRequest, 238 "CreateIndex/RW/Admin/group/NilIndex.status": http.StatusBadRequest, 239 "CreateIndex/RW/Admin/group/InvalidJSON.status": http.StatusBadRequest, 240 "CreateIndex/RW/NoAuth/group/EmptyIndex.status": http.StatusBadRequest, 241 "CreateIndex/RW/NoAuth/group/BlankIndex.status": http.StatusBadRequest, 242 "CreateIndex/RW/NoAuth/group/InvalidIndex.status": http.StatusBadRequest, 243 "CreateIndex/RW/NoAuth/group/NilIndex.status": http.StatusBadRequest, 244 "CreateIndex/RW/NoAuth/group/InvalidJSON.status": http.StatusBadRequest, 245 "CreateIndex/RW/NoAuth/group/Valid.status": http.StatusInternalServerError, // COUCHDB-3374 246 247 "GetIndexes.databases": []string{"_replicator", "_users", "_global_changes"}, 248 "GetIndexes/Admin/_replicator.indexes": []kivik.Index{kt.AllDocsIndex}, 249 "GetIndexes/Admin/_users.indexes": []kivik.Index{kt.AllDocsIndex}, 250 "GetIndexes/Admin/_global_changes.indexes": []kivik.Index{kt.AllDocsIndex}, 251 "GetIndexes/NoAuth/_replicator.indexes": []kivik.Index{kt.AllDocsIndex}, 252 "GetIndexes/NoAuth/_users.indexes": []kivik.Index{kt.AllDocsIndex}, 253 "GetIndexes/NoAuth/_global_changes.skip": true, // Pouch connects to the DB before searching the Index, so this test fails 254 "GetIndexes/NoAuth/_global_changes.status": http.StatusUnauthorized, 255 "GetIndexes/RW.indexes": []kivik.Index{ 256 kt.AllDocsIndex, 257 { 258 DesignDoc: "_design/foo", 259 Name: "bar", 260 Type: "json", 261 Definition: map[string]interface{}{ 262 "fields": []map[string]string{ 263 {"foo": "asc"}, 264 }, 265 "partial_filter_selector": map[string]string{}, 266 }, 267 }, 268 }, 269 270 "DeleteIndex/RW/Admin/group/NotFoundDdoc.status": http.StatusNotFound, 271 "DeleteIndex/RW/Admin/group/NotFoundName.status": http.StatusNotFound, 272 "DeleteIndex/RW/NoAuth/group/NotFoundDdoc.status": http.StatusNotFound, 273 "DeleteIndex/RW/NoAuth/group/NotFoundName.status": http.StatusNotFound, 274 275 "Query/RW/group/Admin/WithDocs/UpdateSeq.skip": true, 276 "Query/RW/group/NoAuth/WithDocs/UpdateSeq.skip": true, 277 278 "Version.version": `^[789]\.\d\.\d$`, 279 "Version.vendor": `^PouchDB$`, 280 "Version.vendor_version": `^[789]\.\d\.\d$`, 281 282 "Get/RW/group/Admin/bogus.status": http.StatusNotFound, 283 "Get/RW/group/NoAuth/bogus.status": http.StatusNotFound, 284 285 "GetRev/RW/group/Admin/bogus.status": http.StatusNotFound, 286 "GetRev/RW/group/NoAuth/bogus.status": http.StatusNotFound, 287 288 "Delete/RW/Admin/group/MissingDoc.status": http.StatusNotFound, 289 "Delete/RW/Admin/group/InvalidRevFormat.status": http.StatusBadRequest, 290 "Delete/RW/Admin/group/WrongRev.status": http.StatusConflict, 291 "Delete/RW/NoAuth/group/MissingDoc.status": http.StatusNotFound, 292 "Delete/RW/NoAuth/group/InvalidRevFormat.status": http.StatusBadRequest, 293 "Delete/RW/NoAuth/group/WrongRev.status": http.StatusConflict, 294 "Delete/RW/NoAuth/group/DesignDoc.status": http.StatusUnauthorized, 295 296 "Stats.databases": []string{"_users", "chicken"}, 297 "Stats/Admin/chicken.status": http.StatusNotFound, 298 "Stats/NoAuth/chicken.status": http.StatusNotFound, 299 300 "BulkDocs/RW/NoAuth/group/Mix/Conflict.status": http.StatusConflict, 301 "BulkDocs/RW/Admin/group/Mix/Conflict.status": http.StatusConflict, 302 303 "GetAttachment/RW/group/Admin/foo/NotFound.status": http.StatusNotFound, 304 "GetAttachment/RW/group/NoAuth/foo/NotFound.status": http.StatusNotFound, 305 306 "GetAttachmentMeta/RW/group/Admin/foo/NotFound.status": http.StatusNotFound, 307 "GetAttachmentMeta/RW/group/NoAuth/foo/NotFound.status": http.StatusNotFound, 308 309 "PutAttachment/RW/group/Admin/Conflict.status": http.StatusConflict, 310 "PutAttachment/RW/group/NoAuth/Conflict.status": http.StatusConflict, 311 "PutAttachment/RW/group/NoAuth/UpdateDesignDoc.status": http.StatusUnauthorized, 312 "PutAttachment/RW/group/NoAuth/CreateDesignDoc.status": http.StatusUnauthorized, 313 314 // "DeleteAttachment/RW/group/Admin/NotFound.status": http.StatusNotFound, // COUCHDB-3362 315 // "DeleteAttachment/RW/group/NoAuth/NotFound.status": http.StatusNotFound, // COUCHDB-3362 316 "DeleteAttachment/RW/group/Admin/NoDoc.status": http.StatusConflict, 317 "DeleteAttachment/RW/group/NoAuth/NoDoc.status": http.StatusConflict, 318 "DeleteAttachment/RW/group/NoAuth/DesignDoc.status": http.StatusUnauthorized, 319 320 "Put/RW/Admin/group/LeadingUnderscoreInID.status": http.StatusBadRequest, 321 "Put/RW/Admin/group/Conflict.status": http.StatusConflict, 322 "Put/RW/NoAuth/group/DesignDoc.status": http.StatusUnauthorized, 323 "Put/RW/NoAuth/group/LeadingUnderscoreInID.status": http.StatusBadRequest, 324 "Put/RW/NoAuth/group/Conflict.status": http.StatusConflict, 325 326 "Replicate.NotFoundDB": func() string { 327 var dsn string 328 for _, env := range []string{ 329 "KIVIK_TESt_DSN_COUCH22", "KIVIK_TEST_DSN_COUCH21", 330 "KIVIK_TEST_DSN_COUCH20", "KIVIK_TEST_DSN_COUCH16", 331 "KIVIK_TEST_DSN_CLOUDANT", 332 } { 333 dsn = os.Getenv(env) 334 if dsn != "" { 335 break 336 } 337 } 338 parsed, _ := url.Parse(dsn) 339 parsed.User = nil 340 return strings.TrimSuffix(parsed.String(), "/") + "/doesntexist" 341 }(), 342 "Replicate.prefix": "none", 343 "Replicate.timeoutSeconds": 5, //nolint:gomnd 344 "Replicate.mode": "pouchdb", 345 "Replicate/RW/Admin/group/MissingSource/Results.status": http.StatusUnauthorized, 346 "Replicate/RW/Admin/group/MissingTarget/Results.status": http.StatusUnauthorized, 347 "Replicate/RW/NoAuth/group/MissingSource/Results.status": http.StatusUnauthorized, 348 "Replicate/RW/NoAuth/group/MissingTarget/Results.status": http.StatusUnauthorized, 349 350 "Query/RW/group/Admin/WithoutDocs/ScanDoc.status": http.StatusBadRequest, 351 "Query/RW/group/NoAuth/WithoutDocs/ScanDoc.status": http.StatusBadRequest, 352 353 // "ViewCleanup/RW/NoAuth.status": http.StatusUnauthorized, # FIXME: #14 354 355 "Changes/Continuous.options": kivik.Params(map[string]interface{}{ 356 "live": true, 357 "timeout": false, 358 }), 359 }) 360 } 361 362 // PouchLocalTest runs the PouchDB tests against a local database. 363 func PouchLocalTest(t *testing.T) { 364 client, err := kivik.New("pouch", "") 365 if err != nil { 366 t.Errorf("Failed to connect to PouchDB driver: %s", err) 367 return 368 } 369 clients := &kt.Context{ 370 RW: true, 371 Admin: client, 372 T: t, 373 } 374 kiviktest.RunTestsInternal(clients, kiviktest.SuitePouchLocal) 375 } 376 377 // PouchRemoteTest runs the PouchDB tests against a remote CouchDB database. 378 func PouchRemoteTest(t *testing.T) { 379 kiviktest.DoTest(t, kiviktest.SuitePouchRemote, "KIVIK_TEST_DSN_COUCH22") 380 }