Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
jio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Yaxel Perez
jio
Commits
f2943ed8
Commit
f2943ed8
authored
Dec 31, 2013
by
Tristan Cavelier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
replicaterevisionstorage upgraded + tests
parent
5a50c92f
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1173 additions
and
858 deletions
+1173
-858
src/jio.storage/replicaterevisionstorage.js
src/jio.storage/replicaterevisionstorage.js
+29
-29
test/jio.storage/replicaterevisionstorage.tests.js
test/jio.storage/replicaterevisionstorage.tests.js
+1144
-829
No files found.
src/jio.storage/replicaterevisionstorage.js
View file @
f2943ed8
...
...
@@ -22,7 +22,7 @@
module
(
jIO
);
}([
'
jio
'
],
function
(
jIO
)
{
"
use strict
"
;
jIO
.
addStorage
Type
(
'
replicaterevision
'
,
function
(
spec
)
{
jIO
.
addStorage
(
'
replicaterevision
'
,
function
(
spec
)
{
var
that
=
this
,
priv
=
{};
spec
=
spec
||
{};
...
...
@@ -217,16 +217,9 @@
command
.
success
();
}
if
(
!
param
.
_id
)
{
return
callback
({
"
status
"
:
501
});
return
callback
({
"
status
"
:
501
});
}
priv
.
check
(
command
,
param
,
option
,
callback
);
priv
.
check
(
command
,
param
,
option
,
callback
);
};
/**
...
...
@@ -264,6 +257,16 @@
callback
=
callback
||
priv
.
emptyFunction
;
option
=
option
||
{};
functions
.
begin
=
function
()
{
// // XXX make revision storage check and repair
// // to enable check/repair sub storage from this storage
// // by calling this function just below
// //functions.repairAllSubStorages();
// // else we assume that sub storages are good
// functions.getAllDocuments(functions.newParam(
// doc,
// option,
// repair
// ));
// };
// functions.repairAllSubStorages = function () {
var
i
;
...
...
@@ -315,8 +318,8 @@
// 1: [responseB, [2]]
],
"
attachments
"
:
{
// attachmentA : {_id: attachmentA, _revs_info, _
mime
type: ..}
// attachmentB : {_id: attachmentB, _revs_info, _
mime
type: ..}
// attachmentA : {_id: attachmentA, _revs_info, _
content_
type: ..}
// attachmentB : {_id: attachmentB, _revs_info, _
content_
type: ..}
}
},
"
conflicts
"
:
{
...
...
@@ -333,9 +336,9 @@
var
i
,
metadata
,
cloned_option
;
metadata
=
priv
.
clone
(
param
.
doc
);
cloned_option
=
priv
.
clone
(
param
.
option
);
option
.
conflicts
=
true
;
option
.
revs
=
true
;
option
.
revs_info
=
true
;
cloned_
option
.
conflicts
=
true
;
cloned_
option
.
revs
=
true
;
cloned_
option
.
revs_info
=
true
;
for
(
i
=
0
;
i
<
priv
.
storage_list
.
length
;
i
+=
1
)
{
// if the document is not loaded
priv
.
send
(
command
,
"
get
"
,
i
,
...
...
@@ -356,7 +359,7 @@
// get document failed, exit
param
.
deal_result_state
=
"
error
"
;
callback
({
"
status
"
:
"
conflict
"
,
"
status
"
:
409
,
"
message
"
:
"
An error occured on the sub storage
"
,
"
reason
"
:
err
.
reason
},
undefined
);
...
...
@@ -378,6 +381,7 @@
// this is now the last response
functions
.
makeResponsesStats
(
param
.
responses
);
//console.log(JSON.parse(JSON.stringify(param.responses)));
if
(
param
.
responses
.
stats_items
.
length
===
1
)
{
// the responses are equals!
response_object
.
ok
=
true
;
...
...
@@ -394,7 +398,7 @@
if
(
param
.
repair
===
false
)
{
// do not repair
callback
({
"
status
"
:
"
conflict
"
,
"
status
"
:
409
,
"
message
"
:
"
Some documents are different in the sub storages
"
,
"
reason
"
:
"
Storage contents differ
"
},
undefined
);
...
...
@@ -460,7 +464,7 @@
/*jslint unparam: true */
if
(
err
)
{
callback
({
"
status
"
:
"
conflict
"
,
"
status
"
:
409
,
"
message
"
:
"
Unable to retreive attachments
"
,
"
reason
"
:
err
.
reason
},
undefined
);
...
...
@@ -513,7 +517,7 @@
if
(
new_doc
.
_attachments
.
hasOwnProperty
(
i
))
{
attachment_to_put
.
push
({
"
_id
"
:
i
,
"
_
mime
type
"
:
new_doc
.
_attachments
[
i
].
content_type
,
"
_
content_
type
"
:
new_doc
.
_attachments
[
i
].
content_type
,
"
_revs_info
"
:
new_doc
.
_revs_info
});
}
...
...
@@ -555,9 +559,7 @@
var
i
,
attachment
;
if
(
err
)
{
return
callback
({
"
status
"
:
40
,
"
statusText
"
:
"
Check Failed
"
,
"
error
"
:
"
check_failed
"
,
"
status
"
:
409
,
"
message
"
:
"
Unable to copy attachments
"
,
"
reason
"
:
err
.
reason
},
undefined
);
...
...
@@ -566,7 +568,7 @@
attachment
=
{
"
_id
"
:
param
.
doc
.
_id
,
"
_attachment
"
:
attachment_to_put
[
i
].
_id
,
"
_
mimetype
"
:
attachment_to_put
[
i
].
_mime
type
,
"
_
content_type
"
:
attachment_to_put
[
i
].
_content_
type
,
"
_revs_info
"
:
attachment_to_put
[
i
].
_revs_info
,
// "_revs_info": param.responses.list[index]._revs_info,
"
_data
"
:
param
.
responses
.
attachments
[
attachment_to_put
[
i
].
_id
]
...
...
@@ -640,7 +642,7 @@
* @param {object} command The JIO command
*/
that
.
post
=
function
(
command
,
metadata
,
option
)
{
that
.
genericRequest
(
command
,
"
p
u
t
"
,
metadata
,
option
);
that
.
genericRequest
(
command
,
"
p
os
t
"
,
metadata
,
option
);
};
/**
...
...
@@ -649,7 +651,7 @@
* @param {object} command The JIO command
*/
that
.
put
=
function
(
command
,
metadata
,
option
)
{
that
.
genericRequest
(
command
,
"
p
os
t
"
,
metadata
,
option
);
that
.
genericRequest
(
command
,
"
p
u
t
"
,
metadata
,
option
);
};
/**
...
...
@@ -696,7 +698,5 @@
that
.
removeAttachment
=
function
(
command
,
param
,
option
)
{
that
.
genericRequest
(
command
,
"
removeAttachment
"
,
param
,
option
);
};
return
that
;
});
}));
test/jio.storage/replicaterevisionstorage.tests.js
View file @
f2943ed8
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO,
jio_tests
, hex_sha256, test, ok, deepEqual, sinon,
expect, module */
/*global define, jIO,
test_util
, hex_sha256, test, ok, deepEqual, sinon,
expect, module
, stop, start, RSVP
*/
// define([module_name], [dependencies], module);
(
function
(
dependencies
,
module
)
{
...
...
@@ -8,242 +8,288 @@
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
return
define
(
dependencies
,
module
);
}
module
(
jIO
,
jio_tests
,
{
hex_sha256
:
hex_sha256
}
);
module
(
jIO
,
test_util
,
{
hex_sha256
:
hex_sha256
},
RSVP
);
}([
'
jio
'
,
'
jio_tests
'
,
'
test_util
'
,
'
sha256
'
,
'
rsvp
'
,
'
localstorage
'
,
'
revisionstorage
'
,
'
replicaterevisionstorage
'
],
function
(
jIO
,
util
,
sha256
)
{
],
function
(
jIO
,
util
,
sha256
,
RSVP
)
{
"
use strict
"
;
//////////////////////////////////////////////////////////////////////////////
// Tools
/**
* Clones all native object in deep. Managed types: Object, Array, String,
* Number, Boolean, Function, null.
*
* @param {A} object The object to clone
* @return {A} The cloned object
*/
function
deepClone
(
object
)
{
var
i
,
cloned
;
if
(
Array
.
isArray
(
object
))
{
cloned
=
[];
for
(
i
=
0
;
i
<
object
.
length
;
i
+=
1
)
{
cloned
[
i
]
=
deepClone
(
object
[
i
]);
}
return
cloned
;
}
if
(
typeof
object
===
"
object
"
)
{
cloned
=
{};
for
(
i
in
object
)
{
if
(
object
.
hasOwnProperty
(
i
))
{
cloned
[
i
]
=
deepClone
(
object
[
i
]);
}
}
return
cloned
;
}
return
object
;
}
function
generateTools
()
{
return
{
clock
:
sinon
.
useFakeTimers
(),
spy
:
util
.
ospy
,
tick
:
util
.
otick
var
tool
=
{
"
deepClone
"
:
jIO
.
util
.
deepClone
,
"
uniqueJSONStringify
"
:
jIO
.
util
.
uniqueJSONStringify
,
"
readBlobAsBinaryString
"
:
jIO
.
util
.
readBlobAsBinaryString
};
function
reverse
(
promise
)
{
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
,
notify
)
{
promise
.
then
(
reject
,
resolve
,
notify
);
},
function
()
{
promise
.
cancel
();
});
}
function
generateRevisionHash
(
doc
,
revisions
,
deleted_flag
)
{
var
string
;
doc
=
deepClone
(
doc
);
doc
=
tool
.
deepClone
(
doc
);
delete
doc
.
_rev
;
delete
doc
.
_revs
;
delete
doc
.
_revs_info
;
string
=
JSON
.
stringify
(
doc
)
+
JSON
.
stringify
(
revisions
)
+
string
=
tool
.
uniqueJSONStringify
(
doc
)
+
tool
.
uniqueJSONStringify
(
revisions
)
+
JSON
.
stringify
(
deleted_flag
?
true
:
false
);
return
sha256
.
hex_sha256
(
string
);
}
function
unexpectedError
(
error
)
{
if
(
error
instanceof
Error
)
{
deepEqual
([
error
.
name
+
"
:
"
+
error
.
message
,
error
],
"
UNEXPECTED ERROR
"
,
"
Unexpected error
"
);
}
else
{
deepEqual
(
error
,
"
UNEXPECTED ERROR
"
,
"
Unexpected error
"
);
}
}
//////////////////////////////////////////////////////////////////////////////
// Tests
module
(
"
Replicate Revision Storage
"
);
var
testReplicateRevisionStorage
=
function
(
sinon
,
jio_description
)
{
/*jslint unparam: true */
function
testReplicateRevisionStorage
(
jio_description
)
{
var
o
=
generateTools
(),
leavesAction
,
generateLocalPath
;
var
shared
=
{},
jio
,
jio_leaves
=
[];
shared
.
workspace
=
{};
jio
=
jIO
.
createJIO
(
jio_description
,
{
"
workspace
"
:
shared
.
workspace
});
o
.
jio
=
jIO
.
newJio
(
jio_description
);
generateLocalPath
=
function
(
storage_description
)
{
return
"
jio/localstorage/
"
+
storage_description
.
username
+
"
/
"
+
storage_description
.
application_name
;
};
leavesAction
=
function
(
action
,
storage_description
,
param
)
{
function
leavesAction
(
action
,
storage_description
)
{
var
i
;
if
(
param
===
undefined
)
{
param
=
{};
}
else
{
param
=
deepClone
(
param
);
}
if
(
storage_description
.
storage_list
!==
undefined
)
{
if
(
storage_description
.
type
===
"
replicaterevision
"
)
{
// it is the replicate revision storage tree
for
(
i
=
0
;
i
<
storage_description
.
storage_list
.
length
;
i
+=
1
)
{
leavesAction
(
action
,
storage_description
.
storage_list
[
i
]
,
param
);
leavesAction
(
action
,
storage_description
.
storage_list
[
i
]);
}
}
else
if
(
storage_description
.
sub_storage
!==
undefined
)
{
}
else
if
(
storage_description
.
type
===
"
revision
"
)
{
// it is the revision storage tree
param
.
revision
=
true
;
leavesAction
(
action
,
storage_description
.
sub_storage
,
param
);
leavesAction
(
action
,
storage_description
.
sub_storage
);
}
else
{
// it is the storage tree leaf
param
[
storage_description
.
type
]
=
true
;
action
(
storage_description
,
param
);
action
(
storage_description
);
}
}
leavesAction
(
function
(
storage_description
)
{
jio_leaves
.
push
(
jIO
.
createJIO
(
storage_description
,
{
"
workspace
"
:
shared
.
workspace
}));
},
jio_description
);
jio_leaves
.
run
=
function
(
method
,
argument
)
{
var
i
,
promises
=
[];
for
(
i
=
0
;
i
<
this
.
length
;
i
+=
1
)
{
promises
[
i
]
=
this
[
i
][
method
].
apply
(
this
[
i
],
argument
);
}
return
RSVP
.
all
(
promises
);
};
o
.
leavesAction
=
function
(
action
)
{
leavesAction
(
action
,
jio_description
);
jio_leaves
.
get
=
function
()
{
return
this
.
run
(
"
get
"
,
arguments
);
};
jio_leaves
.
allDocs
=
function
()
{
return
this
.
run
(
"
allDocs
"
,
arguments
);
};
// post a new document without id
o
.
doc
=
{
"
title
"
:
"
post document without id
"
};
o
.
spy
(
o
,
"
status
"
,
undefined
,
"
Post document (without id)
"
);
o
.
jio
.
post
(
o
.
doc
,
function
(
err
,
response
)
{
o
.
f
.
apply
(
arguments
);
o
.
response_rev
=
(
err
||
response
).
rev
;
if
(
util
.
isUuid
((
err
||
response
).
id
))
{
ok
(
true
,
"
Uuid format
"
);
o
.
uuid
=
(
err
||
response
).
id
;
}
else
{
deepEqual
((
err
||
response
).
id
,
"
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
"
,
"
Uuid format
"
);
}
});
o
.
tick
(
o
);
stop
();
// check document
o
.
doc
.
_id
=
o
.
uuid
;
o
.
revisions
=
{
"
start
"
:
0
,
"
ids
"
:
[]};
o
.
rev_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
rev
=
"
1-
"
+
o
.
rev_hash
;
o
.
leavesAction
(
function
(
storage_description
,
param
)
{
var
suffix
=
""
,
doc
=
deepClone
(
o
.
doc
);
if
(
param
.
revision
)
{
deepEqual
(
o
.
response_rev
,
o
.
rev
,
"
Check revision
"
);
doc
.
_id
+=
"
.
"
+
o
.
rev
;
suffix
=
"
.
"
+
o
.
rev
;
// post a new document without id
shared
.
doc
=
{
"
title
"
:
"
post document without id
"
};
jio
.
post
(
shared
.
doc
).
then
(
function
(
answer
)
{
shared
.
revisions
=
{
"
start
"
:
0
,
"
ids
"
:
[]};
shared
.
uuid
=
answer
.
id
;
shared
.
rev
=
answer
.
rev
;
shared
.
rev_hash
=
shared
.
rev
.
slice
(
2
);
shared
.
doc
.
_id
=
shared
.
uuid
;
ok
(
util
.
isUuid
(
shared
.
uuid
),
"
Uuid should look like
"
+
"
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx :
"
+
shared
.
uuid
);
deepEqual
(
answer
,
{
"
id
"
:
shared
.
uuid
,
"
method
"
:
"
post
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
"
1-
"
+
generateRevisionHash
(
shared
.
doc
,
shared
.
revisions
),
"
status
"
:
201
,
"
statusText
"
:
"
Created
"
},
"
Post document (without id)
"
);
delete
shared
.
doc
.
_id
;
return
jio_leaves
.
get
({
"
_id
"
:
shared
.
uuid
+
"
.
"
+
shared
.
rev
});
}).
then
(
function
(
answers
)
{
var
i
;
for
(
i
=
0
;
i
<
answers
.
length
;
i
+=
1
)
{
deepEqual
(
answers
[
i
].
data
,
{
"
_id
"
:
shared
.
uuid
+
"
.
"
+
shared
.
rev
,
"
title
"
:
"
post document without id
"
},
"
Check document
"
+
(
i
+
1
));
}
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
"
/
"
+
o
.
uuid
+
suffix
),
doc
,
"
Check document
"
);
});
// get the post document without revision
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
o
.
uuid
,
"
title
"
:
"
post document without id
"
,
"
_rev
"
:
o
.
rev
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
o
.
rev
,
"
status
"
:
"
available
"
}]
},
"
Get the generated document, the winner
"
);
o
.
jio
.
get
({
"
_id
"
:
o
.
uuid
},
{
return
jio
.
get
({
"
_id
"
:
shared
.
uuid
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
{
"
_id
"
:
shared
.
uuid
,
"
_rev
"
:
shared
.
rev
,
"
_revisions
"
:
{
"
ids
"
:
[
shared
.
rev_hash
],
"
start
"
:
1
},
"
_revs_info
"
:
[{
"
rev
"
:
shared
.
rev
,
"
status
"
:
"
available
"
}],
"
title
"
:
"
post document without id
"
},
"
Get the generated document, the winner
"
);
// post a new document with id
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new doc with id
"
};
o
.
rev1_1_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
rev1_1
=
"
1-
"
+
o
.
rev1_1_hash
;
o
.
rev1_1_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_1_hash
]};
o
.
rev1_1_revs_info
=
[{
"
rev
"
:
o
.
rev1_1
,
"
status
"
:
"
available
"
}];
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev1_1
},
"
Post new document with an id
"
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new doc with id
"
};
shared
.
rev1_1_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
revisions
);
shared
.
rev1_1
=
"
1-
"
+
shared
.
rev1_1_hash
;
shared
.
rev1_1_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
shared
.
rev1_1_hash
]};
shared
.
rev1_1_revs_info
=
[{
"
rev
"
:
shared
.
rev1_1
,
"
status
"
:
"
available
"
}];
return
jio
.
post
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
post
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev1_1
,
"
status
"
:
201
,
"
statusText
"
:
"
Created
"
},
"
Post new document with an id
"
);
// /
// |
// 1-1
// check document
o
.
leavesAction
(
function
(
storage_description
,
param
)
{
var
suffix
=
""
,
doc
=
deepClone
(
o
.
doc
);
if
(
param
.
revision
)
{
doc
.
_id
+=
"
.
"
+
o
.
rev1_1
;
suffix
=
"
.
"
+
o
.
rev1_1
;
return
jio_leaves
.
get
({
"
_id
"
:
"
doc1.
"
+
shared
.
rev1_1
});
}).
then
(
function
(
answers
)
{
var
i
;
for
(
i
=
0
;
i
<
answers
.
length
;
i
+=
1
)
{
deepEqual
(
answers
[
i
].
data
,
{
"
_id
"
:
"
doc1.
"
+
shared
.
rev1_1
,
"
title
"
:
"
post new doc with id
"
},
"
Check document
"
+
(
i
+
1
));
}
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
"
/doc1
"
+
suffix
),
doc
,
"
Check document
"
);
});
// get the post document without revision
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new doc with id
"
,
"
_rev
"
:
o
.
rev1_1
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_1_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
o
.
rev1_1
,
"
status
"
:
"
available
"
}]
},
"
Get the previous document (without revision)
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
return
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
shared
.
rev1_1
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
shared
.
rev1_1_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
shared
.
rev1_1
,
"
status
"
:
"
available
"
}],
"
title
"
:
"
post new doc with id
"
},
"
Get the previous document (without revision)
"
);
// post same document without revision
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post same document without revision
"
};
o
.
rev1_2_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
rev1_2
=
"
1-
"
+
o
.
rev1_2_hash
;
o
.
rev1_2_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_2_hash
]};
o
.
rev1_2_revs_info
=
[{
"
rev
"
:
o
.
rev1_2
,
"
status
"
:
"
available
"
}];
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev1_2
},
"
Post same document (without revision)
"
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post same document without revision
"
};
shared
.
rev1_2_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
revisions
);
shared
.
rev1_2
=
"
1-
"
+
shared
.
rev1_2_hash
;
shared
.
rev1_2_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
shared
.
rev1_2_hash
]};
shared
.
rev1_2_revs_info
=
[{
"
rev
"
:
shared
.
rev1_2
,
"
status
"
:
"
available
"
}];
return
jio
.
post
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
post
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev1_2
,
"
status
"
:
201
,
"
statusText
"
:
"
Created
"
},
"
Post same document (without revision)
"
);
// /
// / \
// 1-1 1-2
// check document
o
.
leavesAction
(
function
(
storage_description
,
param
)
{
var
suffix
=
""
,
doc
=
deepClone
(
o
.
doc
);
if
(
param
.
revision
)
{
doc
.
_id
+=
"
.
"
+
o
.
rev1_2
;
suffix
=
"
.
"
+
o
.
rev1_2
;
return
jio_leaves
.
get
({
"
_id
"
:
"
doc1.
"
+
shared
.
rev1_2
});
}).
then
(
function
(
answers
)
{
var
i
;
for
(
i
=
0
;
i
<
answers
.
length
;
i
+=
1
)
{
deepEqual
(
answers
[
i
].
data
,
{
"
_id
"
:
"
doc1.
"
+
shared
.
rev1_2
,
"
title
"
:
"
post same document without revision
"
},
"
Check document
"
+
(
i
+
1
));
}
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
"
/doc1
"
+
suffix
),
doc
,
"
Check document
"
);
});
// post a new revision
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new revision
"
,
"
_rev
"
:
o
.
rev1_2
};
o
.
revisions
.
start
+=
1
;
o
.
revisions
.
ids
.
unshift
(
o
.
rev1_2_hash
);
o
.
rev2_3_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
revisions
);
o
.
rev2_3
=
"
2-
"
+
o
.
rev2_3_hash
;
o
.
rev2_3_history
=
deepClone
(
o
.
rev1_2_history
);
o
.
rev2_3_history
.
start
+=
1
;
o
.
rev2_3_history
.
ids
.
unshift
(
o
.
rev2_3_hash
);
o
.
rev2_3_revs_info
=
deepClone
(
o
.
rev1_2_revs_info
);
o
.
rev2_3_revs_info
.
unshift
({
"
rev
"
:
o
.
rev2_3
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev2_3
},
"
Post document (with revision)
"
);
o
.
jio
.
post
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post new revision
"
,
"
_rev
"
:
shared
.
rev1_2
};
shared
.
revisions
.
start
+=
1
;
shared
.
revisions
.
ids
.
unshift
(
shared
.
rev1_2_hash
);
shared
.
rev2_3_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
revisions
);
shared
.
rev2_3
=
"
2-
"
+
shared
.
rev2_3_hash
;
shared
.
rev2_3_history
=
tool
.
deepClone
(
shared
.
rev1_2_history
);
shared
.
rev2_3_history
.
start
+=
1
;
shared
.
rev2_3_history
.
ids
.
unshift
(
shared
.
rev2_3_hash
);
shared
.
rev2_3_revs_info
=
tool
.
deepClone
(
shared
.
rev1_2_revs_info
);
shared
.
rev2_3_revs_info
.
unshift
({
"
rev
"
:
shared
.
rev2_3
,
"
status
"
:
"
available
"
});
return
jio
.
post
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
post
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev2_3
,
"
status
"
:
201
,
"
statusText
"
:
"
Created
"
},
"
Post document (with revision)
"
);
// /
// / \
...
...
@@ -252,49 +298,57 @@
// 2-3
// check document
o
.
leavesAction
(
function
(
storage_description
,
param
)
{
var
suffix
=
""
,
doc
=
deepClone
(
o
.
doc
);
delete
doc
.
_rev
;
if
(
param
.
revision
)
{
doc
.
_id
+=
"
.
"
+
o
.
rev2_3
;
suffix
=
"
.
"
+
o
.
rev2_3
;
return
jio_leaves
.
get
({
"
_id
"
:
"
doc1.
"
+
shared
.
rev2_3
});
}).
then
(
function
(
answers
)
{
var
i
;
for
(
i
=
0
;
i
<
answers
.
length
;
i
+=
1
)
{
deepEqual
(
answers
[
i
].
data
,
{
"
_id
"
:
"
doc1.
"
+
shared
.
rev2_3
,
"
title
"
:
"
post new revision
"
},
"
Check document
"
+
(
i
+
1
));
}
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
generateLocalPath
(
storage_description
)
+
"
/doc1
"
+
suffix
),
doc
,
"
Check document
"
);
});
// get the post document with revision
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
post same document without revision
"
,
"
_rev
"
:
o
.
rev1_2
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_2_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
o
.
rev1_2
,
"
status
"
:
"
available
"
}],
"
_conflicts
"
:
[
o
.
rev1_1
]
},
"
Get the previous document (with revision)
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev1_2
},
{
return
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
shared
.
rev1_2
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
});
// put document without id
o
.
spy
(
o
,
"
status
"
,
20
,
"
Put document without id
"
);
o
.
jio
.
put
({},
o
.
f
);
o
.
tick
(
o
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
shared
.
rev1_2
,
"
_revisions
"
:
{
"
start
"
:
1
,
"
ids
"
:
[
shared
.
rev1_2_hash
]},
"
_revs_info
"
:
[{
"
rev
"
:
shared
.
rev1_2
,
"
status
"
:
"
available
"
}],
"
_conflicts
"
:
[
shared
.
rev1_1
],
"
title
"
:
"
post same document without revision
"
},
"
Get the previous document (with revision)
"
);
// put document without rev
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
put new document
"
};
o
.
rev1_4_hash
=
generateRevisionHash
(
o
.
doc
,
{
"
start
"
:
0
,
"
ids
"
:
[]});
o
.
rev1_4
=
"
1-
"
+
o
.
rev1_4_hash
;
o
.
rev1_4_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
o
.
rev1_4_hash
]};
o
.
rev1_4_revs_info
=
[{
"
rev
"
:
o
.
rev1_4
,
"
status
"
:
"
available
"
}];
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev1_4
},
"
Put document without rev
"
);
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
put new document
"
};
shared
.
rev1_4_hash
=
generateRevisionHash
(
shared
.
doc
,
{
"
start
"
:
0
,
"
ids
"
:
[]
});
shared
.
rev1_4
=
"
1-
"
+
shared
.
rev1_4_hash
;
shared
.
rev1_4_history
=
{
"
start
"
:
1
,
"
ids
"
:
[
shared
.
rev1_4_hash
]};
shared
.
rev1_4_revs_info
=
[{
"
rev
"
:
shared
.
rev1_4
,
"
status
"
:
"
available
"
}];
return
jio
.
put
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
put
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev1_4
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Put document without rev
"
);
// __/__
// / | \
...
...
@@ -303,16 +357,36 @@
// 2-3
// put new revision
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
put new revision
"
,
"
_rev
"
:
o
.
rev1_4
};
o
.
rev2_5_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev1_4_history
);
o
.
rev2_5
=
"
2-
"
+
o
.
rev2_5_hash
;
o
.
rev2_5_history
=
{
"
start
"
:
2
,
"
ids
"
:
[
o
.
rev2_5_hash
,
o
.
rev1_4_hash
]};
o
.
rev2_5_revs_info
=
deepClone
(
o
.
rev1_4_revs_info
);
o
.
rev2_5_revs_info
.
unshift
({
"
rev
"
:
o
.
rev2_5
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
doc1
"
,
"
ok
"
:
true
,
"
rev
"
:
o
.
rev2_5
},
"
Put new revision
"
);
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
title
"
:
"
put new revision
"
,
"
_rev
"
:
shared
.
rev1_4
};
shared
.
rev2_5_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
rev1_4_history
);
shared
.
rev2_5
=
"
2-
"
+
shared
.
rev2_5_hash
;
shared
.
rev2_5_history
=
{
"
start
"
:
2
,
"
ids
"
:
[
shared
.
rev2_5_hash
,
shared
.
rev1_4_hash
]
};
shared
.
rev2_5_revs_info
=
tool
.
deepClone
(
shared
.
rev1_4_revs_info
);
shared
.
rev2_5_revs_info
.
unshift
({
"
rev
"
:
shared
.
rev2_5
,
"
status
"
:
"
available
"
});
return
jio
.
put
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
put
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev2_5
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Put new revision
"
);
// __/__
// / | \
...
...
@@ -321,43 +395,67 @@
// 2-3 2-5
// putAttachment to inexistent document
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc2
"
,
"
_mime
type
"
:
"
text/plain
"
,
"
_content_
type
"
:
"
text/plain
"
,
"
_data
"
:
"
doc 2 - attachment 1
"
,
"
_attachment
"
:
"
attachment1
"
};
o
.
rev_hash
=
generateRevisionHash
(
o
.
doc
,
{
"
start
"
:
0
,
"
ids
"
:
[]});
o
.
rev
=
"
1-
"
+
o
.
rev_hash
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc2
"
,
"
attachment
"
:
"
attachment1
"
,
"
rev
"
:
o
.
rev
},
"
Put an attachment to an inexistent document
"
);
o
.
jio
.
putAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
rev_hash
=
generateRevisionHash
(
shared
.
doc
,
{
"
start
"
:
0
,
"
ids
"
:
[]
});
shared
.
rev
=
"
1-
"
+
shared
.
rev_hash
;
return
jio
.
putAttachment
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
attachment1
"
,
"
id
"
:
"
doc2
"
,
"
method
"
:
"
putAttachment
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Put an attachment to an inexistent document
"
);
// putAttachment
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_mime
type
"
:
"
text/plain
"
,
"
_content_
type
"
:
"
text/plain
"
,
"
_data
"
:
"
doc 1 - attachment 1
"
,
"
_attachment
"
:
"
attachment1
"
,
"
_rev
"
:
o
.
rev2_5
"
_rev
"
:
shared
.
rev2_5
};
o
.
rev3_6_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev2_5_history
);
o
.
rev3_6
=
"
3-
"
+
o
.
rev3_6_hash
;
o
.
rev3_6_history
=
deepClone
(
o
.
rev2_5_history
);
o
.
rev3_6_history
.
start
+=
1
;
o
.
rev3_6_history
.
ids
.
unshift
(
o
.
rev3_6_hash
);
o
.
rev3_6_revs_info
=
deepClone
(
o
.
rev2_5_revs_info
);
o
.
rev3_6_revs_info
.
unshift
({
"
rev
"
:
o
.
rev3_6
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
shared
.
attmt1_digest
=
"
sha256-7b6f6ec759b90a0d2aea0b2a6172544c904c6722
"
+
"
1a04fb871477825db92c42ff
"
;
shared
.
rev3_6_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
rev2_5_history
);
shared
.
rev3_6
=
"
3-
"
+
shared
.
rev3_6_hash
;
shared
.
rev3_6_history
=
tool
.
deepClone
(
shared
.
rev2_5_history
);
shared
.
rev3_6_history
.
start
+=
1
;
shared
.
rev3_6_history
.
ids
.
unshift
(
shared
.
rev3_6_hash
);
shared
.
rev3_6_revs_info
=
tool
.
deepClone
(
shared
.
rev2_5_revs_info
);
shared
.
rev3_6_revs_info
.
unshift
({
"
rev
"
:
shared
.
rev3_6
,
"
status
"
:
"
available
"
});
return
jio
.
putAttachment
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
attachment1
"
,
"
rev
"
:
o
.
rev3_6
"
id
"
:
"
doc1
"
,
"
method
"
:
"
putAttachment
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev3_6
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Put an attachment to the first document
"
);
o
.
jio
.
putAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// __/__
// / | \
...
...
@@ -368,55 +466,73 @@
// 3-6+a1
// get document
o
.
doc
=
{
return
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev3_6
,
"
_revisions
"
:
o
.
rev3_6_history
,
"
_revs_info
"
:
o
.
rev3_6_revs_info
,
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_rev
"
:
shared
.
rev3_6
,
"
_revisions
"
:
shared
.
rev3_6_history
,
"
_revs_info
"
:
shared
.
rev3_6_revs_info
,
"
_conflicts
"
:
[
shared
.
rev2_3
,
shared
.
rev1_1
],
"
_attachments
"
:
{
"
attachment1
"
:
{
"
length
"
:
"
doc 1 - attachment 1
"
.
length
,
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
md5-0505c1fb6aae02dd1695d33841726564
"
"
digest
"
:
shared
.
attmt1_digest
}
},
"
title
"
:
"
put new revision
"
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get document, the winner
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
},
"
Get document, the winner
"
);
// get
attachment
o
.
doc
=
{
// get winner
attachment
return
jio
.
getAttachment
(
{
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
};
o
.
spy
(
o
,
"
value
"
,
"
doc 1 - attachment 1
"
,
"
Get the winner's attachment
"
);
o
.
jio
.
getAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
});
}).
then
(
function
(
answer
)
{
return
tool
.
readBlobAsBinaryString
(
answer
.
data
);
}).
then
(
function
(
event
)
{
deepEqual
(
event
.
target
.
result
,
"
doc 1 - attachment 1
"
,
"
Get the winner's attachment
"
);
// put document
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev3_6
,
"
_rev
"
:
shared
.
rev3_6
,
"
title
"
:
"
Put revision, attachment must be copied
"
};
o
.
rev4_7_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev3_6_history
);
o
.
rev4_7
=
"
4-
"
+
o
.
rev4_7_hash
;
o
.
rev4_7_history
=
deepClone
(
o
.
rev3_6_history
);
o
.
rev4_7_history
.
start
+=
1
;
o
.
rev4_7_history
.
ids
.
unshift
(
o
.
rev4_7_hash
);
o
.
rev4_7_revs_info
=
deepClone
(
o
.
rev3_6_revs_info
);
o
.
rev4_7_revs_info
.
unshift
({
"
rev
"
:
o
.
rev4_7
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev4_7
},
"
Update document, attachment should be copied
"
);
o
.
jio
.
put
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
rev4_7_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
rev3_6_history
);
shared
.
rev4_7
=
"
4-
"
+
shared
.
rev4_7_hash
;
shared
.
rev4_7_history
=
tool
.
deepClone
(
shared
.
rev3_6_history
);
shared
.
rev4_7_history
.
start
+=
1
;
shared
.
rev4_7_history
.
ids
.
unshift
(
shared
.
rev4_7_hash
);
shared
.
rev4_7_revs_info
=
tool
.
deepClone
(
shared
.
rev3_6_revs_info
);
shared
.
rev4_7_revs_info
.
unshift
({
"
rev
"
:
shared
.
rev4_7
,
"
status
"
:
"
available
"
});
return
jio
.
put
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
put
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev4_7
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Update document, attachment should be copied
"
);
// __/__
// / | \
...
...
@@ -429,62 +545,77 @@
// 4-7+a1
// get document, attachment must be copied
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev4_7
,
"
title
"
:
o
.
doc
.
title
,
"
_rev
"
:
shared
.
rev4_7
,
"
title
"
:
shared
.
doc
.
title
,
"
_attachments
"
:
{
"
attachment1
"
:
{
"
length
"
:
"
doc 1 - attachment 1
"
.
length
,
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
md5-0505c1fb6aae02dd1695d33841726564
"
"
digest
"
:
shared
.
attmt1_digest
}
},
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_revisions
"
:
o
.
rev4_7_history
,
"
_revs_info
"
:
o
.
rev4_7_revs_info
"
_conflicts
"
:
[
shared
.
rev2_3
,
shared
.
rev1_1
],
"
_revisions
"
:
shared
.
rev4_7_history
,
"
_revs_info
"
:
shared
.
rev4_7_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document and its attachment metadata
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
return
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
});
// get attachment
o
.
doc
=
{
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
shared
.
doc
,
"
Get the new winner document and its attachment metadata
"
);
// get winner attachment
return
jio
.
getAttachment
({
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
};
o
.
spy
(
o
,
"
value
"
,
"
doc 1 - attachment 1
"
,
});
}).
then
(
function
(
answer
)
{
return
tool
.
readBlobAsBinaryString
(
answer
.
data
);
}).
then
(
function
(
event
)
{
deepEqual
(
event
.
target
.
result
,
"
doc 1 - attachment 1
"
,
"
Get the winner's attachment again
"
);
o
.
jio
.
getAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// remove attachment
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
,
"
_rev
"
:
o
.
rev4_7
"
_rev
"
:
shared
.
rev4_7
};
o
.
rev5_8_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev4_7_history
);
o
.
rev5_8
=
"
5-
"
+
o
.
rev5_8_hash
;
o
.
rev5_8_history
=
deepClone
(
o
.
rev4_7_history
);
o
.
rev5_8_history
.
start
+=
1
;
o
.
rev5_8_history
.
ids
.
unshift
(
o
.
rev5_8_hash
);
o
.
rev5_8_revs_info
=
deepClone
(
o
.
rev4_7_revs_info
);
o
.
rev5_8_revs_info
.
unshift
({
"
rev
"
:
o
.
rev5_8
,
"
status
"
:
"
available
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
shared
.
rev5_8_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
rev4_7_history
);
shared
.
rev5_8
=
"
5-
"
+
shared
.
rev5_8_hash
;
shared
.
rev5_8_history
=
tool
.
deepClone
(
shared
.
rev4_7_history
);
shared
.
rev5_8_history
.
start
+=
1
;
shared
.
rev5_8_history
.
ids
.
unshift
(
shared
.
rev5_8_hash
);
shared
.
rev5_8_revs_info
=
tool
.
deepClone
(
shared
.
rev4_7_revs_info
);
shared
.
rev5_8_revs_info
.
unshift
({
"
rev
"
:
shared
.
rev5_8
,
"
status
"
:
"
available
"
});
return
jio
.
removeAttachment
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
attachment1
"
,
"
rev
"
:
o
.
rev5_8
"
id
"
:
"
doc1
"
,
"
method
"
:
"
removeAttachment
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev5_8
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove attachment
"
);
o
.
jio
.
removeAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
// __/__
// / | \
...
...
@@ -499,78 +630,116 @@
// 5-8
// get document to check attachment existence
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev5_8
,
"
_rev
"
:
shared
.
rev5_8
,
"
title
"
:
"
Put revision, attachment must be copied
"
,
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_revisions
"
:
o
.
rev5_8_history
,
"
_revs_info
"
:
o
.
rev5_8_revs_info
"
_conflicts
"
:
[
shared
.
rev2_3
,
shared
.
rev1_1
],
"
_revisions
"
:
shared
.
rev5_8_history
,
"
_revs_info
"
:
shared
.
rev5_8_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document, no attachment must be provided
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
return
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
shared
.
doc
,
"
Get the new winner document, no attachment must be provided
"
);
// get specific document
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev4_7
,
"
title
"
:
o
.
doc
.
title
,
"
_rev
"
:
shared
.
rev4_7
,
"
title
"
:
shared
.
doc
.
title
,
"
_attachments
"
:
{
"
attachment1
"
:
{
"
length
"
:
"
doc 1 - attachment 1
"
.
length
,
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
md5-0505c1fb6aae02dd1695d33841726564
"
"
digest
"
:
shared
.
attmt1_digest
}
},
"
_conflicts
"
:
[
o
.
rev2_3
,
o
.
rev1_1
],
"
_revisions
"
:
o
.
rev4_7_history
,
"
_revs_info
"
:
o
.
rev4_7_revs_info
"
_conflicts
"
:
[
shared
.
rev2_3
,
shared
.
rev1_1
],
"
_revisions
"
:
shared
.
rev4_7_history
,
"
_revs_info
"
:
shared
.
rev4_7_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document and its attachment metadata
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev4_7
},
{
return
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
shared
.
rev4_7
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
shared
.
doc
,
"
Get specific revision and its attachment metadata
"
);
// get inexistent attachment
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent winner attachment
"
+
"
-> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1/attachment1
"
},
o
.
f
);
o
.
tick
(
o
);
return
reverse
(
jio
.
getAttachment
({
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
}));
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
attachment1
"
,
"
error
"
:
"
not_found
"
,
"
id
"
:
"
doc1
"
,
"
message
"
:
"
Unable to get an inexistent attachment
"
,
"
method
"
:
"
getAttachment
"
,
"
reason
"
:
"
missing
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Get inexistent winner attachment -> 404 Not Found
"
);
// get specific attachment
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_attachment
"
:
"
attachment1
"
,
"
_rev
"
:
o
.
rev3_6
"
_rev
"
:
shared
.
rev3_6
};
o
.
spy
(
o
,
"
value
"
,
"
doc 1 - attachment 1
"
,
"
Get a specific attachment
"
);
o
.
jio
.
getAttachment
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
return
jio
.
getAttachment
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
return
tool
.
readBlobAsBinaryString
(
answer
.
data
);
}).
then
(
function
(
event
)
{
deepEqual
(
event
.
target
.
result
,
"
doc 1 - attachment 1
"
,
"
Get a specific attachment
"
);
// remove specific document and conflict
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev1_1
};
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
shared
.
rev1_1
};
// generate with deleted_flag
o
.
rev2_9_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev1_1_history
,
true
);
o
.
rev2_9
=
"
2-
"
+
o
.
rev2_9_hash
;
o
.
rev2_9_history
=
deepClone
(
o
.
rev1_1_history
);
o
.
rev2_9_history
.
start
+=
1
;
o
.
rev2_9_history
.
ids
.
unshift
(
o
.
rev2_9_hash
);
o
.
rev2_9_revs_info
=
deepClone
(
o
.
rev1_1_revs_info
);
o
.
rev2_9_revs_info
.
unshift
({
"
rev
"
:
o
.
rev2_9
,
"
status
"
:
"
deleted
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev2_9
},
"
Remove specific document, and one conflict
"
);
o
.
jio
.
remove
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
rev2_9_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
rev1_1_history
,
true
);
shared
.
rev2_9
=
"
2-
"
+
shared
.
rev2_9_hash
;
shared
.
rev2_9_history
=
tool
.
deepClone
(
shared
.
rev1_1_history
);
shared
.
rev2_9_history
.
start
+=
1
;
shared
.
rev2_9_history
.
ids
.
unshift
(
shared
.
rev2_9_hash
);
shared
.
rev2_9_revs_info
=
tool
.
deepClone
(
shared
.
rev1_1_revs_info
);
shared
.
rev2_9_revs_info
.
unshift
({
"
rev
"
:
shared
.
rev2_9
,
"
status
"
:
"
deleted
"
});
return
jio
.
remove
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
remove
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev2_9
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove specific document, and one conflict
"
);
// __/___
// / | \
...
...
@@ -585,18 +754,31 @@
// 5-8
// remove specific document and conflict
o
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev2_3
};
o
.
rev3_10_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev2_3_history
,
true
);
o
.
rev3_10
=
"
3-
"
+
o
.
rev3_10_hash
;
o
.
rev3_10_history
=
deepClone
(
o
.
rev2_3_history
);
o
.
rev3_10_history
.
start
+=
1
;
o
.
rev3_10_history
.
ids
.
unshift
(
o
.
rev3_10_hash
);
o
.
rev3_10_revs_info
=
deepClone
(
o
.
rev2_3_revs_info
);
o
.
rev3_10_revs_info
.
unshift
({
"
rev
"
:
o
.
rev3_10
,
"
status
"
:
"
deleted
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev3_10
},
"
Remove specific document, and one conflict
"
);
o
.
jio
.
remove
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
shared
.
rev2_3
};
shared
.
rev3_10_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
rev2_3_history
,
true
);
shared
.
rev3_10
=
"
3-
"
+
shared
.
rev3_10_hash
;
shared
.
rev3_10_history
=
tool
.
deepClone
(
shared
.
rev2_3_history
);
shared
.
rev3_10_history
.
start
+=
1
;
shared
.
rev3_10_history
.
ids
.
unshift
(
shared
.
rev3_10_hash
);
shared
.
rev3_10_revs_info
=
tool
.
deepClone
(
shared
.
rev2_3_revs_info
);
shared
.
rev3_10_revs_info
.
unshift
({
"
rev
"
:
shared
.
rev3_10
,
"
status
"
:
"
deleted
"
});
return
jio
.
remove
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
remove
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev3_10
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove anther specific document, and one conflict
"
);
// ___/____
// / | \
...
...
@@ -611,33 +793,46 @@
// 5-8
// get document no more conflict
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev5_8
,
"
_rev
"
:
shared
.
rev5_8
,
"
title
"
:
"
Put revision, attachment must be copied
"
,
"
_revisions
"
:
o
.
rev5_8_history
,
"
_revs_info
"
:
o
.
rev5_8_revs_info
"
_revisions
"
:
shared
.
rev5_8_history
,
"
_revs_info
"
:
shared
.
rev5_8_revs_info
};
o
.
spy
(
o
,
"
value
"
,
o
.
doc
,
"
Get the new winner document, no more conflicts
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
return
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
shared
.
doc
,
"
Get the new winner document, no more conflicts
"
);
// remove document
o
.
doc
=
{
shared
.
doc
=
{
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
o
.
rev5_8
"
_rev
"
:
shared
.
rev5_8
};
o
.
rev6_11_hash
=
generateRevisionHash
(
o
.
doc
,
o
.
rev5_8_history
,
true
);
o
.
rev6_11
=
"
6-
"
+
o
.
rev6_11_hash
;
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev6_11
},
"
Remove the last document
"
);
o
.
jio
.
remove
(
o
.
doc
,
o
.
f
);
o
.
tick
(
o
);
shared
.
rev6_11_hash
=
generateRevisionHash
(
shared
.
doc
,
shared
.
rev5_8_history
,
true
);
shared
.
rev6_11
=
"
6-
"
+
shared
.
rev6_11_hash
;
return
jio
.
remove
(
shared
.
doc
);
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
remove
"
,
"
result
"
:
"
success
"
,
"
rev
"
:
shared
.
rev6_11
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove the last document
"
);
// ___/____
// / | \
...
...
@@ -654,51 +849,84 @@
// D6-11
// get inexistent document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent document -> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc3
"
},
{
return
reverse
(
jio
.
get
({
"
_id
"
:
"
doc3
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revisions
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
}));
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
error
"
:
"
not_found
"
,
"
id
"
:
"
doc3
"
,
"
message
"
:
"
Document not found
"
,
"
method
"
:
"
get
"
,
"
reason
"
:
"
missing
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Get inexistent document -> 404 Not Found
"
);
// get specific deleted document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get deleted document -> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
rev
"
:
o
.
rev3_10
},
{
return
reverse
(
jio
.
get
({
"
_id
"
:
"
doc1
"
,
"
rev
"
:
shared
.
rev3_10
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
}));
// get specific deleted document
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get deleted document -> 404 Not Found
"
);
o
.
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
error
"
:
"
not_found
"
,
"
id
"
:
"
doc1
"
,
"
message
"
:
"
Document not found
"
,
"
method
"
:
"
get
"
,
"
reason
"
:
"
deleted
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Get specific deleted document -> 404 Not Found
"
);
// get deleted document
return
reverse
(
jio
.
get
({
"
_id
"
:
"
doc1
"
},
{
"
conflicts
"
:
true
,
"
revs
"
:
true
,
"
revs_info
"
:
true
},
o
.
f
);
o
.
tick
(
o
);
}));
util
.
closeAndcleanUpJio
(
o
.
jio
);
}).
then
(
function
(
answer
)
{
};
deepEqual
(
answer
,
{
"
error
"
:
"
not_found
"
,
"
id
"
:
"
doc1
"
,
"
message
"
:
"
Document not found
"
,
"
method
"
:
"
get
"
,
"
reason
"
:
"
deleted
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Get deleted document -> 404 Not Found
"
);
}).
fail
(
unexpectedError
).
always
(
start
);
}
test
(
"
[Revision + Local Storage] Scenario
"
,
function
()
{
testReplicateRevisionStorage
(
this
,
{
testReplicateRevisionStorage
({
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
ureprevloc
"
,
"
application_name
"
:
"
areprevloc
"
"
mode
"
:
"
memory
"
}
}]
});
});
test
(
"
[Replicate Revision + Revision + Local Storage] Scenario
"
,
function
()
{
testReplicateRevisionStorage
(
this
,
{
testReplicateRevisionStorage
({
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
replicaterevision
"
,
...
...
@@ -707,34 +935,34 @@
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
urepreprevloc
"
,
"
application_name
"
:
"
arepreprevloc
"
"
mode
"
:
"
memory
"
}
}]
}]
});
});
test
(
"
2x [Revision + Local Storage] Scenario
"
,
function
()
{
testReplicateRevisionStorage
(
this
,
{
testReplicateRevisionStorage
({
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
ureprevlocloc1
"
,
"
application_name
"
:
"
areprevlocloc1
"
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
ureprevlocloc2
"
,
"
application_name
"
:
"
areprevlocloc2
"
"
mode
"
:
"
memory
"
}
}]
});
});
test
(
"
2x [Replicate Rev + 2x [Rev + Local]] Scenario
"
,
function
()
{
testReplicateRevisionStorage
(
this
,
{
testReplicateRevisionStorage
({
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
replicaterevision
"
,
...
...
@@ -743,14 +971,14 @@
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
urepreprevloc1
"
,
"
application_name
"
:
"
arepreprevloc1
"
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
urepreprevloc2
"
,
"
application_name
"
:
"
arepreprevloc2
"
"
mode
"
:
"
memory
"
}
}]
},
{
...
...
@@ -760,253 +988,336 @@
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
urepreprevloc3
"
,
"
application_name
"
:
"
arepreprevloc3
"
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
urepreprevloc4
"
,
"
application_name
"
:
"
arepreprevloc4
"
"
mode
"
:
"
memory
"
}
}]
}]
});
});
function
replicateStorageSynchronisationGenerator
(
that
,
description
,
index
)
{
/*jslint unparam: true */
var
o
=
generateTools
();
function
replicateStorageSynchronisationGenerator
(
jio_description
)
{
o
.
jio
=
jIO
.
newJio
(
description
);
o
.
localpath1
=
"
jio/localstorage/usyncreprevlocloc1/
"
+
index
;
o
.
localpath2
=
"
jio/localstorage/usyncreprevlocloc2/
"
+
index
;
o
.
localpath3
=
"
jio/localstorage/usyncreprevlocloc3/
"
+
index
;
o
.
localpath4
=
"
jio/localstorage/usyncreprevlocloc4/
"
+
index
;
var
shared
=
{},
jio
,
jio_leaves
=
[];
shared
.
workspace
=
{};
jio
=
jIO
.
createJIO
(
jio_description
,
{
"
workspace
"
:
shared
.
workspace
});
function
leavesAction
(
action
,
storage_description
)
{
var
i
;
if
(
storage_description
.
type
===
"
replicaterevision
"
)
{
// it is the replicate revision storage tree
for
(
i
=
0
;
i
<
storage_description
.
storage_list
.
length
;
i
+=
1
)
{
leavesAction
(
action
,
storage_description
.
storage_list
[
i
]);
}
}
else
if
(
storage_description
.
type
===
"
revision
"
)
{
// it is the revision storage tree
leavesAction
(
action
,
storage_description
.
sub_storage
);
}
else
{
// it is the storage tree leaf
action
(
storage_description
);
}
}
leavesAction
(
function
(
storage_description
)
{
jio_leaves
.
push
(
jIO
.
createJIO
(
storage_description
,
{
"
workspace
"
:
shared
.
workspace
}));
},
jio_description
);
if
(
jio_leaves
.
length
!==
4
)
{
// please make a jio description with 4 localstorage
ok
(
false
,
"
More or less then 4 localstorage were provided
"
);
return
;
}
jio_leaves
.
run
=
function
(
method
,
argument
)
{
var
i
,
promises
=
[];
for
(
i
=
0
;
i
<
this
.
length
;
i
+=
1
)
{
promises
[
i
]
=
this
[
i
][
method
].
apply
(
this
[
i
],
argument
);
}
return
RSVP
.
all
(
promises
);
};
jio_leaves
.
get
=
function
()
{
return
this
.
run
(
"
get
"
,
arguments
);
};
jio_leaves
.
put
=
function
()
{
return
this
.
run
(
"
put
"
,
arguments
);
};
jio_leaves
.
allDocs
=
function
()
{
return
this
.
run
(
"
allDocs
"
,
arguments
);
};
stop
();
// add documents to localstorage
o
.
doctree1_1
=
{
shared
.
doctree1_1
=
{
"
_id
"
:
"
doc1.revision_tree.json
"
,
"
children
"
:
[{
"
children
"
:
JSON
.
stringify
(
[{
"
rev
"
:
"
1-111
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
}]
}]
)
};
o
.
doc1_1
=
{
"
_id
"
:
"
doc1.1-111
"
,
"
title
"
:
"
A
"
};
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree1_1
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
,
o
.
doctree1_1
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath3
+
"
/doc1.revision_tree.json
"
,
o
.
doctree1_1
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath4
+
"
/doc1.revision_tree.json
"
,
o
.
doctree1_1
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath2
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath3
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath4
+
"
/
"
+
o
.
doc1_1
.
_id
,
o
.
doc1_1
);
shared
.
doc1_1
=
{
"
_id
"
:
"
doc1.1-111
"
,
"
title
"
:
"
A
"
};
jio_leaves
.
put
(
shared
.
doctree1_1
).
then
(
function
()
{
return
jio_leaves
.
put
(
shared
.
doc1_1
);
}).
then
(
function
()
{
// no synchronisation
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Check document
"
);
o
.
jio
.
check
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
);
return
jio
.
check
({
"
_id
"
:
"
doc1
"
});
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
,
"
rev
"
:
"
1-111
"
},
"
Check document with revision
"
);
o
.
jio
.
check
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-111
"
},
o
.
f
);
o
.
tick
(
o
);
}).
then
(
function
(
answer
)
{
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Repair document
"
);
o
.
jio
.
repair
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
);
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
check
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Check document
"
);
return
jio
.
check
({
"
_id
"
:
"
doc1
"
,
"
_rev
"
:
"
1-111
"
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
check
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Check document with revision
"
);
return
jio
.
repair
({
"
_id
"
:
"
doc1
"
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
repair
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Repair document
"
);
// check documents from localstorage
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 1, no synchro done
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 2, no synchro done
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 3, no synchro done
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath4
+
"
/doc1.revision_tree.json
"
),
o
.
doctree1_1
,
"
Check revision tree 4, no synchro done
"
);
return
jio_leaves
.
get
({
"
_id
"
:
"
doc1.revision_tree.json
"
});
}).
then
(
function
(
answers
)
{
var
i
;
for
(
i
=
0
;
i
<
answers
.
length
;
i
+=
1
)
{
deepEqual
(
answers
[
i
].
data
,
shared
.
doctree1_1
,
"
Check revision tree
"
+
i
+
"
, no syncho done
"
);
}
// add documents to localstorage
o
.
doctree2_2
=
deepClone
(
o
.
doctree1_1
);
o
.
doctree2_2
.
children
[
0
].
children
.
push
({
shared
.
doctree2_2
=
tool
.
deepClone
(
shared
.
doctree1_1
);
shared
.
doctree2_2
.
children
=
JSON
.
parse
(
shared
.
doctree2_2
.
children
);
shared
.
doctree2_2
.
children
[
0
].
children
.
push
({
"
rev
"
:
"
2-222
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
});
o
.
doc2_2
=
{
shared
.
doctree2_2
.
children
=
JSON
.
stringify
(
shared
.
doctree2_2
.
children
);
shared
.
doc2_2
=
{
"
_id
"
:
"
doc1.2-222
"
,
"
title
"
:
"
B
"
,
"
_attachments
"
:
{
"
haha
"
:
{
"
length
"
:
3
,
"
digest
"
:
"
md5-900150983cd24fb0d6963f7d28e17f72
"
,
"
digest
"
:
"
sha256-ba7816bf8f01cfea414140de5dae2223b00361a3
"
+
"
96177a9cb410ff61f20015ad
"
,
"
content_type
"
:
"
text/plain
"
}
}
};
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree2_2
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_2
.
_id
,
o
.
doc2_2
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_2
.
_id
+
"
/haha
"
,
"
abc
"
);
return
jio_leaves
[
0
].
put
(
shared
.
doctree2_2
);
}).
then
(
function
()
{
return
jio_leaves
[
0
].
put
(
shared
.
doc2_2
);
}).
then
(
function
()
{
return
jio_leaves
[
0
].
putAttachment
({
"
_id
"
:
shared
.
doc2_2
.
_id
,
"
_attachment
"
:
"
haha
"
,
"
_data
"
:
"
abc
"
,
"
_content_type
"
:
"
text/plain
"
});
}).
then
(
function
()
{
// document synchronisation without conflict
o
.
spy
(
o
,
"
status
"
,
41
,
"
Check document
"
);
o
.
jio
.
check
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
return
reverse
(
jio
.
check
({
"
_id
"
:
"
doc1
"
}));
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Repair document
"
);
o
.
jio
.
repair
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
}).
then
(
function
(
answer
)
{
// check documents from localstorage
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 1, no synchro done
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 2, revision synchro done
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 3, revision synchro done
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.2-222
"
),
o
.
doc2_2
,
"
Check document 3
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.2-222/haha
"
),
"
abc
"
,
"
Check attachment 3
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath4
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_2
,
"
Check revision tree 4, revision synchro done
"
);
deepEqual
(
answer
,
{
"
error
"
:
"
conflict
"
,
"
id
"
:
"
doc1
"
,
"
message
"
:
"
Some documents are different in the sub storages
"
,
"
method
"
:
"
check
"
,
"
reason
"
:
"
Storage contents differ
"
,
"
result
"
:
"
error
"
,
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
},
"
Check document
"
);
return
jio
.
repair
({
"
_id
"
:
"
doc1
"
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
repair
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Repair document
"
);
// check document trees
return
jio_leaves
.
get
({
"
_id
"
:
"
doc1.revision_tree.json
"
});
}).
then
(
function
(
answers
)
{
var
i
;
for
(
i
=
0
;
i
<
answers
.
length
;
i
+=
1
)
{
deepEqual
(
answers
[
i
].
data
,
shared
.
doctree2_2
,
"
Check revision tree
"
+
i
+
"
,
"
+
(
i
?
""
:
"
no
"
)
+
"
synchro done
"
);
}
// check document 2
return
jio_leaves
[
2
].
get
({
"
_id
"
:
"
doc1.2-222
"
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
shared
.
doc2_2
,
"
Check document 2
"
);
// check attachment 2
return
jio_leaves
[
2
].
getAttachment
({
"
_id
"
:
"
doc1.2-222
"
,
"
_attachment
"
:
"
haha
"
});
}).
then
(
function
(
answer
)
{
return
tool
.
readBlobAsBinaryString
(
answer
.
data
);
}).
then
(
function
(
event
)
{
deepEqual
(
event
.
target
.
result
,
"
abc
"
,
"
Check attachment 2
"
);
// add documents to localstorage
o
.
doctree2_3
=
deepClone
(
o
.
doctree2_2
);
o
.
doctree2_3
.
children
[
0
].
children
.
unshift
({
shared
.
doctree2_3
=
tool
.
deepClone
(
shared
.
doctree2_2
);
shared
.
doctree2_3
.
children
=
JSON
.
parse
(
shared
.
doctree2_3
.
children
);
shared
.
doctree2_3
.
children
[
0
].
children
.
unshift
({
"
rev
"
:
"
2-223
"
,
"
status
"
:
"
available
"
,
"
children
"
:
[]
});
o
.
doc2_3
=
{
"
_id
"
:
"
doc1.2-223
"
,
"
title
"
:
"
C
"
};
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
,
o
.
doctree2_3
);
util
.
jsonlocalstorage
.
setItem
(
o
.
localpath1
+
"
/
"
+
o
.
doc2_3
.
_id
,
o
.
doc2_3
);
shared
.
doctree2_3
.
children
=
JSON
.
stringify
(
shared
.
doctree2_3
.
children
);
shared
.
doc2_3
=
{
"
_id
"
:
"
doc1.2-223
"
,
"
title
"
:
"
C
"
};
return
jio_leaves
[
0
].
put
(
shared
.
doctree2_3
);
}).
then
(
function
()
{
return
jio_leaves
[
0
].
put
(
shared
.
doc2_3
);
}).
then
(
function
()
{
// document synchronisation with conflict
o
.
spy
(
o
,
"
status
"
,
41
,
"
Check document
"
);
o
.
jio
.
check
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
return
reverse
(
jio
.
check
({
"
_id
"
:
"
doc1
"
}));
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
error
"
:
"
conflict
"
,
"
id
"
:
"
doc1
"
,
"
message
"
:
"
Some documents are different in the sub storages
"
,
"
method
"
:
"
check
"
,
"
reason
"
:
"
Storage contents differ
"
,
"
result
"
:
"
error
"
,
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
},
"
Check document
"
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
doc1
"
},
"
Repair document
"
);
o
.
jio
.
repair
({
"
_id
"
:
"
doc1
"
},
o
.
f
);
o
.
tick
(
o
,
50000
);
return
jio
.
repair
({
"
_id
"
:
"
doc1
"
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
doc1
"
,
"
method
"
:
"
repair
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Repair document
"
);
// check documents from localstorage
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath1
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 1, rev synchro
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath2
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 2, rev synchro
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 3, rev synchro
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath3
+
"
/doc1.2-223
"
),
o
.
doc2_3
,
"
Check document 3
"
);
deepEqual
(
util
.
jsonlocalstorage
.
getItem
(
o
.
localpath4
+
"
/doc1.revision_tree.json
"
),
o
.
doctree2_3
,
"
Check revision tree 4, rev synchro
"
);
return
jio_leaves
.
get
({
"
_id
"
:
"
doc1.revision_tree.json
"
});
util
.
closeAndcleanUpJio
(
o
.
jio
);
}).
then
(
function
(
answers
)
{
var
i
;
for
(
i
=
0
;
i
<
answers
.
length
;
i
+=
1
)
{
deepEqual
(
answers
[
i
].
data
,
shared
.
doctree2_3
,
"
Check revision tree
"
+
i
+
"
,
"
+
(
i
?
""
:
"
no
"
)
+
"
synchro done
"
);
}
// check document 2
return
jio_leaves
[
2
].
get
({
"
_id
"
:
"
doc1.2-223
"
});
}).
then
(
function
(
answer
)
{
deepEqual
(
answer
.
data
,
shared
.
doc2_3
,
"
Check document 2
"
);
}).
fail
(
unexpectedError
).
always
(
start
);
}
test
(
"
Storage Synchronisation (Repair) 4x [Rev + Local]
"
,
function
()
{
replicateStorageSynchronisationGenerator
(
this
,
{
replicateStorageSynchronisationGenerator
({
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc1
"
,
"
application_name
"
:
"
1
"
"
application_name
"
:
"
1
"
,
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc2
"
,
"
application_name
"
:
"
1
"
"
application_name
"
:
"
1
"
,
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc3
"
,
"
application_name
"
:
"
1
"
"
application_name
"
:
"
1
"
,
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc4
"
,
"
application_name
"
:
"
1
"
"
application_name
"
:
"
1
"
,
"
mode
"
:
"
memory
"
}
}]
}
,
"
1
"
);
});
});
test
(
"
Storage Synchronisation (Repair) 2x [Rep 2x [Rev + Local]]
"
,
function
()
{
replicateStorageSynchronisationGenerator
(
this
,
{
replicateStorageSynchronisationGenerator
({
"
type
"
:
"
replicaterevision
"
,
"
storage_list
"
:
[{
"
type
"
:
"
replicaterevision
"
,
...
...
@@ -1015,14 +1326,16 @@
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc1
"
,
"
application_name
"
:
"
2
"
"
application_name
"
:
"
2
"
,
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc2
"
,
"
application_name
"
:
"
2
"
"
application_name
"
:
"
2
"
,
"
mode
"
:
"
memory
"
}
}]
},
{
...
...
@@ -1032,18 +1345,20 @@
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc3
"
,
"
application_name
"
:
"
2
"
"
application_name
"
:
"
2
"
,
"
mode
"
:
"
memory
"
}
},
{
"
type
"
:
"
revision
"
,
"
sub_storage
"
:
{
"
type
"
:
"
local
"
,
"
username
"
:
"
usyncreprevlocloc4
"
,
"
application_name
"
:
"
2
"
"
application_name
"
:
"
2
"
,
"
mode
"
:
"
memory
"
}
}]
}]
}
,
"
2
"
);
});
}
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment