mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-02-14 06:51:56 +00:00
240 lines
13 KiB
YAML
240 lines
13 KiB
YAML
desc: Tests insertion into tables
|
|
table_variable_name: tbl
|
|
tests:
|
|
|
|
# Set up our secondary test table
|
|
- cd: r.db('test').table_create('test2')
|
|
ot: partial({'tables_created':1})
|
|
|
|
- def: tbl2 = r.db('test').table('test2')
|
|
|
|
# Single doc insert
|
|
- cd: tbl.insert({'id':0,'a':0})
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
- cd: tbl.count()
|
|
ot: 1
|
|
|
|
# Hard durability insert
|
|
- py: tbl.insert({'id':1, 'a':1}, durability='hard')
|
|
js: tbl.insert({id:1, a:1}, {durability:'hard'})
|
|
rb: tbl.insert({ :id => 1, :a => 1 }, { :durability => 'hard' })
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
- cd: tbl.count()
|
|
ot: 2
|
|
|
|
# Soft durability insert
|
|
- py: tbl.insert({'id':2, 'a':2}, durability='soft')
|
|
js: tbl.insert({id:2, a:2}, {durability:'soft'})
|
|
rb: tbl.insert({ :id => 2, :a => 2 }, { :durability => 'soft' })
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
- cd: tbl.count()
|
|
ot: 3
|
|
|
|
# Wrong durability insert
|
|
- py: tbl.insert({'id':3, 'a':3}, durability='wrong')
|
|
js: tbl.insert({id:3, a:3}, {durability:'wrong'})
|
|
rb: tbl.insert({ :id => 3, :a => 3 }, { :durability => 'wrong' })
|
|
ot: err('ReqlQueryLogicError', 'Durability option `wrong` unrecognized (options are "hard" and "soft").', [0])
|
|
- cd: tbl.count()
|
|
ot: 3
|
|
|
|
# Cleanup.
|
|
- cd: tbl.get(2).delete()
|
|
ot: {'deleted':1,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':0}
|
|
|
|
# Multi doc insert
|
|
- cd: tbl.insert([{'id':2,'a':2}, {'id':3,'a':3}])
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':2}
|
|
|
|
# Stream insert
|
|
- cd: tbl2.insert(tbl)
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':4}
|
|
|
|
# test pkey clash error
|
|
- cd: tbl.insert({'id':2,'b':20})
|
|
ot: {'first_error':"Duplicate primary key `id`:\n{\n\t\"a\":\t2,\n\t\"id\":\t2\n}\n{\n\t\"b\":\t20,\n\t\"id\":\t2\n}",'deleted':0,'replaced':0,'unchanged':0,'errors':1,'skipped':0,'inserted':0}
|
|
|
|
# test error conflict option (object exists)
|
|
- py: tbl.insert({'id':2,'b':20}, conflict='error')
|
|
js: tbl.insert({'id':2,'b':20}, {conflict:'error'})
|
|
rb: tbl.insert({:id => 2, :b => 20}, { :conflict => 'error' })
|
|
ot: {'first_error':"Duplicate primary key `id`:\n{\n\t\"a\":\t2,\n\t\"id\":\t2\n}\n{\n\t\"b\":\t20,\n\t\"id\":\t2\n}",'deleted':0,'replaced':0,'unchanged':0,'errors':1,'skipped':0,'inserted':0}
|
|
|
|
# test error conflict option (object doesn't exist)
|
|
- py: tbl.insert({'id':15,'b':20}, conflict='error')
|
|
js: tbl.insert({'id':15,'b':20}, {conflict:'error'})
|
|
rb: tbl.insert({:id => 15, :b => 20}, { :conflict => 'error' })
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
|
|
- cd: tbl.get(15)
|
|
ot: {'id':15,'b':20}
|
|
|
|
# test replace conflict option (object exists)
|
|
- py: tbl.insert({'id':2,'b':20}, conflict='replace')
|
|
js: tbl.insert({'id':2,'b':20}, {conflict:'replace'})
|
|
rb: tbl.insert({:id => 2, :b => 20}, { :conflict => 'replace' })
|
|
ot: {'deleted':0,'replaced':1,'unchanged':0,'errors':0,'skipped':0,'inserted':0}
|
|
|
|
- cd: tbl.get(2)
|
|
ot: {'id':2,'b':20}
|
|
|
|
# test replace conflict option (object doesn't exist)
|
|
- py: tbl.insert({'id':20,'b':20}, conflict='replace')
|
|
js: tbl.insert({'id':20,'b':20}, {conflict:'replace'})
|
|
rb: tbl.insert({:id => 20, :b => 20}, { :conflict => 'replace' })
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
|
|
- cd: tbl.get(20)
|
|
ot: {'id':20,'b':20}
|
|
|
|
# test update conflict option (object exists)
|
|
- py: tbl.insert({'id':2,'c':30}, conflict='update')
|
|
js: tbl.insert({'id':2,'c':30}, {conflict:'update'})
|
|
rb: tbl.insert({:id => 2, :c => 30}, { :conflict => 'update' })
|
|
ot: {'deleted':0,'replaced':1,'unchanged':0,'errors':0,'skipped':0,'inserted':0}
|
|
|
|
- cd: tbl.get(2)
|
|
ot: {'id':2, 'b':20, 'c':30}
|
|
|
|
# test update conflict option (object doesn't exist)
|
|
- py: tbl.insert({'id':30,'b':20}, conflict='update')
|
|
js: tbl.insert({'id':30,'b':20}, {conflict:'update'})
|
|
rb: tbl.insert({:id => 30, :b => 20}, { :conflict => 'update' })
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
|
|
- cd: tbl.get(30)
|
|
ot: {'id':30,'b':20}
|
|
|
|
# test incorrect conflict option
|
|
- py: tbl.insert({'id':3, 'a':3}, conflict='wrong')
|
|
js: tbl.insert({id:3, a:3}, {conflict:'wrong'})
|
|
rb: tbl.insert({ :id => 3, :a => 3 }, { :conflict => 'wrong' })
|
|
ot: err('ReqlQueryLogicError', 'Conflict option `wrong` unrecognized (options are "error", "replace" and "update").', [0])
|
|
|
|
# test auto pkey generation
|
|
- py: r.db('test').table_create('testpkey', primary_key='foo')
|
|
js: r.db('test').tableCreate('testpkey', {primaryKey:'foo'})
|
|
rb: r.db('test').table_create('testpkey', { :primary_key => 'foo' })
|
|
ot: partial({'tables_created':1})
|
|
|
|
def: tblpkey = r.db('test').table('testpkey')
|
|
|
|
- cd: tblpkey.insert({})
|
|
ot: {'deleted':0,'replaced':0,'generated_keys':arrlen(1,uuid()),'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
|
|
- cd: tblpkey
|
|
ot: [{'foo':uuid()}]
|
|
|
|
# test replace conflict pkey generation
|
|
- py: tblpkey.insert({'b':20}, conflict='replace')
|
|
js: tblpkey.insert({'b':20}, {conflict:'replace'})
|
|
rb: tblpkey.insert({:b => 20}, { :conflict => 'replace' })
|
|
ot: {'deleted':0,'replaced':0,'generated_keys':arrlen(1,uuid()),'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
|
|
# test update conflict pkey generation
|
|
- py: tblpkey.insert({'b':20}, conflict='update')
|
|
js: tblpkey.insert({'b':20}, {conflict:'update'})
|
|
rb: tblpkey.insert({:b => 20}, { :conflict => 'update' })
|
|
ot: {'deleted':0,'replaced':0,'generated_keys':arrlen(1,uuid()),'unchanged':0,'errors':0,'skipped':0,'inserted':1}
|
|
|
|
- cd: r.db('test').table_drop('testpkey')
|
|
ot: partial({'tables_dropped':1})
|
|
|
|
# Insert within for each
|
|
- py: tbl.for_each(lambda row: tbl2.insert(row.merge({'id':row['id'] + 100 })) )
|
|
js: tbl.forEach(function(row) { return tbl2.insert(row.merge({'id':row('id').add(100)})); })
|
|
rb: tbl.for_each(proc { |row| tbl2.insert(row.merge({'id'=>row['id'] + 100 })) })
|
|
ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':7}
|
|
|
|
# Insert unwritable data
|
|
- cd: tbl.insert({'value':r.minval})
|
|
rb: tbl.insert({:value => r.minval})
|
|
ot: partial({'errors':1,'first_error':'`r.minval` and `r.maxval` cannot be written to disk.'})
|
|
|
|
- cd: tbl.insert({'value':r.maxval})
|
|
rb: tbl.insert({:value => r.maxval})
|
|
ot: partial({'errors':1,'first_error':'`r.minval` and `r.maxval` cannot be written to disk.'})
|
|
|
|
# Crash 5683
|
|
- py: tbl.insert([{'id':666}, {'id':666}], return_changes="always")
|
|
ot: {'changes': [{'new_val': {'id': 666}, 'old_val': None},{'error': 'Duplicate primary key `id`:\n{\n\t"id":\t666\n}\n{\n\t"id":\t666\n}','new_val': {'id': 666},'old_val': {'id': 666}}],'deleted': 0,'errors': 1,'first_error': 'Duplicate primary key `id`:\n{\n\t"id":\t666\n}\n{\n\t"id":\t666\n}','inserted': 1,'replaced': 0,'skipped': 0,'unchanged': 0}
|
|
|
|
# Confirm inserts are ordered in return_changes always
|
|
- py: tbl.insert([{'id':100+i, 'ordered-num':i} for i in range(1,100)], return_changes="always")
|
|
ot: partial({'changes':[{'old_val': None, 'new_val': {'id': 100+i, 'ordered-num': i}} for i in range(1,100)] })
|
|
|
|
# Confirm inserts are ordered in return_changes always with complicated key
|
|
- py: tbl.insert([{'id':[1, "blah", 200+i], 'ordered-num':i} for i in range(1,100)], return_changes="always")
|
|
ot: partial({'changes':[{'old_val': None, 'new_val': {'id': [1,"blah", 200+i], 'ordered-num': i}} for i in range(1,100)] })
|
|
|
|
# Confirm inserts are ordered in return_changes always with return_changes=true
|
|
- py: tbl.insert([{'id':[1, "blah", 300+i], 'ordered-num':i} for i in range(1,100)], return_changes=true)
|
|
ot: partial({'changes':[{'old_val': None, 'new_val': {'id': [1,"blah", 300+i], 'ordered-num': i}} for i in range(1,100)] })
|
|
|
|
# Confirm errors are property returned with return_changes="always"
|
|
- py: tbl.insert([{'id':100 + i, 'ordered-num':i} for i in range(1,100)], return_changes="always")
|
|
ot: partial({'changes':[{'old_val': {'id':100+i, 'ordered-num':i}, 'new_val': {'id':100+i, 'ordered-num':i}, 'error':'Duplicate primary key `id`:\n{\n\t"id":\t'+str(100+i)+',\n\t"ordered-num":\t'+str(i)+'\n}\n{\n\t"id":\t'+str(100+i)+',\n\t"ordered-num":\t'+str(i)+'\n}'} for i in range(1,100)]})
|
|
|
|
# Trivial errors with return_changes="always", this has to be long test, testing order and message for this type
|
|
- py: tbl.insert([{'id':123}, {'id':'a'*500}, {'id':321}], return_changes="always")
|
|
ot: {'changes': [{'error': 'Duplicate primary key `id`:\n{\n\t"id":\t123,\n\t"ordered-num":\t23\n}\n{\n\t"id":\t123\n}', 'new_val': {'id': 123, 'ordered-num': 23}, 'old_val': {'id': 123, 'ordered-num': 23}}, {'error': 'Primary key too long (max 127 characters): "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"', 'new_val': None, 'old_val': None}, {'new_val': {'id': 321}, 'old_val': None}], 'deleted': 0, 'errors': 2, 'first_error': 'Primary key too long (max 127 characters): "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"', 'inserted': 1, 'replaced': 0, 'skipped': 0, 'unchanged': 0}
|
|
|
|
# No errors returned with return_changes=true
|
|
- py: tbl.insert([{'id':100 + i, 'ordered-num':i} for i in range(1,100)], return_changes=true)
|
|
ot: partial({'changes':[]})
|
|
|
|
- py: tbl.insert({'a':r.minval}, return_changes="always")
|
|
ot: partial({'changes': [{'old_val': None, 'new_val': None, 'error': '`r.minval` and `r.maxval` cannot be written to disk.'}]})
|
|
|
|
# Tests for insert conflict resolution function
|
|
|
|
# Using a conflict function
|
|
- cd: tbl.insert({'id':42, 'foo':1, 'bar':1})
|
|
ot: partial({'inserted':1})
|
|
- py: tbl.insert({'id':42, 'foo':5, 'bar':5}, conflict=lambda id, old_row, new_row: old_row.merge(new_row.pluck("bar")))
|
|
ot: partial({'replaced':1})
|
|
- py: tbl.get(42)
|
|
ot: {'id':42, 'foo':1, 'bar':5}
|
|
- rb: tbl.insert({:id=>42, :foo=>6, :bar=>6}, conflict: lambda {|id, old_row, new_row| return old_row.merge(new_row.pluck("bar"))})
|
|
ot: partial({'replaced':1})
|
|
- rb: tbl.get(42)
|
|
ot: {'id':42, 'foo':1, 'bar':6}
|
|
- js: tbl.insert({'id':42, 'foo':7, 'bar':7}, {conflict: function(id, old_row, new_row) {return old_row.merge(new_row.pluck("bar"))}})
|
|
ot: partial({'replaced':1})
|
|
- js: tbl.get(42)
|
|
ot: {'id':42, 'foo':1, 'bar':7}
|
|
|
|
# Inserting and deleting an item
|
|
- js: tbl.insert({id: "toggle"},{conflict: function(x,y,z) { return null},returnChanges: true})
|
|
ot: partial({'inserted': 1})
|
|
- js: tbl.insert({id: "toggle"},{conflict: function(x,y,z) { return null},returnChanges: true})
|
|
ot: partial({'deleted': 1})
|
|
|
|
# Returning the wrong thing from the conflict function
|
|
- py: tbl.insert({'id':42, 'foo':1, 'bar':1}, conflict=lambda a,b,c: 2)
|
|
ot: partial({'first_error': 'Inserted value must be an OBJECT (got NUMBER):\n2'})
|
|
|
|
# Incorrect Arity
|
|
- py: tbl.insert({'id':42}, conflict=lambda a,b: a)
|
|
ot: err("ReqlQueryLogicError", "The conflict function passed to `insert` should expect 3 arguments.")
|
|
|
|
# Non atomic operation
|
|
- py: tbl.insert({'id':42}, conflict=lambda a,b,c: tbl.get(42))
|
|
ot: err("ReqlQueryLogicError", "The conflict function passed to `insert` must be deterministic.")
|
|
|
|
- py: tbl.insert({'id':42}, conflict=lambda a,b,c: {'id':42, 'num':'424'})
|
|
ot: partial({'replaced': 1})
|
|
- py: tbl.get(42)
|
|
ot: {'id':42, 'num':'424'}
|
|
|
|
# Get unreturnable data
|
|
- cd: r.minval
|
|
ot: err('ReqlQueryLogicError','Cannot convert `r.minval` to JSON.')
|
|
|
|
- cd: r.maxval
|
|
ot: err('ReqlQueryLogicError','Cannot convert `r.maxval` to JSON.')
|
|
|
|
# clean up
|
|
- cd: r.db('test').table_drop('test2')
|
|
ot: partial({'tables_dropped':1})
|