Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
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
Tomáš Peterka
jio
Commits
713a80e2
Commit
713a80e2
authored
Oct 17, 2013
by
Jonathan Rivalan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
s3Storage modification to take into account jio v2 API && first unit test passed
parent
147409ff
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
2009 additions
and
0 deletions
+2009
-0
src/jio.storage/s3storage.js
src/jio.storage/s3storage.js
+987
-0
test/jio.storage/s3storage.livetests.html
test/jio.storage/s3storage.livetests.html
+40
-0
test/jio.storage/s3storage.tests.js
test/jio.storage/s3storage.tests.js
+982
-0
No files found.
src/jio.storage/s3storage.js
0 → 100644
View file @
713a80e2
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, btoa, b64_hmac_sha1, jQuery, XMLHttpRequest, XHRwrapper,
FormData*/
/**
* JIO S3 Storage. Type = "s3".
* Amazon S3 "database" storage.
*/
// define([module_name], [dependencies], module);
(
function
(
dependencies
,
module
)
{
"
use strict
"
;
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
return
define
(
dependencies
,
module
);
}
module
(
jIO
,
jQuery
,
{
b64_hmac_sha1
:
b64_hmac_sha1
});
}([
'
jio
'
,
'
jquery
'
,
'
sha1
'
],
function
(
jIO
,
$
,
sha1
)
{
"
use strict
"
;
var
b64_hmac_sha1
=
sha1
.
b64_hmac_sha1
;
jIO
.
addStorage
(
"
s3
"
,
function
(
spec
,
my
)
{
var
evt
,
that
,
priv
=
{};
that
=
this
;
// attributes
priv
.
username
=
spec
.
username
||
''
;
priv
.
AWSIdentifier
=
spec
.
AWSIdentifier
||
''
;
priv
.
password
=
spec
.
password
||
''
;
priv
.
server
=
spec
.
server
||
''
;
/*||> "private,
public-read,
public-read-write,
authenticated-read,
bucket-owner-read,
bucket-owner-full-control" <||*/
priv
.
acl
=
spec
.
acl
||
''
;
priv
.
actionStatus
=
spec
.
actionStatus
||
''
;
priv
.
contenTType
=
spec
.
contenTType
||
''
;
/**
* Update [doc] the document object and remove [doc] keys
* which are not in [new_doc]. It only changes [doc] keys not starting
* with an underscore.
* ex: doc: {key:value1,_key:value2} with
* new_doc: {key:value3,_key:value4} updates
* doc: {key:value3,_key:value2}.
* @param {object} doc The original document object.
* @param {object} new_doc The new document object
**/
priv
.
secureDocId
=
function
(
string
)
{
var
split
=
string
.
split
(
'
/
'
),
i
;
if
(
split
[
0
]
===
''
)
{
split
=
split
.
slice
(
1
);
}
for
(
i
=
0
;
i
<
split
.
length
;
i
+=
1
)
{
if
(
split
[
i
]
===
''
)
{
return
''
;
}
}
return
split
.
join
(
'
%2F
'
);
};
/**
* Replace substrings to another strings
* @method recursiveReplace
* @param {string} string The string to do replacement
* @param {array} list_of_replacement An array of couple
* ["substring to select", "selected substring replaced by this string"].
* @return {string} The replaced string
*/
priv
.
recursiveReplace
=
function
(
string
,
list_of_replacement
)
{
var
i
,
split_string
=
string
.
split
(
list_of_replacement
[
0
][
0
]);
if
(
list_of_replacement
[
1
])
{
for
(
i
=
0
;
i
<
split_string
.
length
;
i
+=
1
)
{
split_string
[
i
]
=
priv
.
recursiveReplace
(
split_string
[
i
],
list_of_replacement
.
slice
(
1
)
);
}
}
return
split_string
.
join
(
list_of_replacement
[
0
][
1
]);
};
/**
* Changes / to %2F, % to %25 and . to _.
* @method secureName
* @param {string} name The name to secure
* @return {string} The secured name
*/
priv
.
secureName
=
function
(
name
)
{
return
priv
.
recursiveReplace
(
name
,
[[
"
/
"
,
"
%2F
"
],
[
"
%
"
,
"
%25
"
]]);
};
/**
* Restores the original name from a secured name
* @method restoreName
* @param {string} secured_name The secured name to restore
* @return {string} The original name
*/
priv
.
restoreName
=
function
(
secured_name
)
{
return
priv
.
recursiveReplace
(
secured_name
,
[[
"
%2F
"
,
"
/
"
],
[
"
%25
"
,
"
%
"
]]);
};
/**
* Convert document id and attachment id to a file name
* @method idsToFileName
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id (optional)
* @return {string} The file name
*/
priv
.
idsToFileName
=
function
(
doc_id
,
attachment_id
)
{
doc_id
=
priv
.
secureName
(
doc_id
).
split
(
"
.
"
).
join
(
"
_.
"
);
if
(
typeof
attachment_id
===
"
string
"
)
{
attachment_id
=
priv
.
secureName
(
attachment_id
).
split
(
"
.
"
).
join
(
"
_.
"
);
return
doc_id
+
"
.
"
+
attachment_id
;
}
return
doc_id
;
};
/**
* Convert a file name to a document id (and attachment id if there)
* @method fileNameToIds
* @param {string} file_name The file name to convert
* @return {array} ["document id", "attachment id"] or ["document id"]
*/
priv
.
fileNameToIds
=
function
(
file_name
)
{
var
separator_index
=
-
1
,
split
=
file_name
.
split
(
"
.
"
);
split
.
slice
(
0
,
-
1
).
forEach
(
function
(
file_name_part
,
index
)
{
if
(
file_name_part
.
slice
(
-
1
)
!==
"
_
"
)
{
separator_index
=
index
;
}
});
if
(
separator_index
===
-
1
)
{
return
[
priv
.
restoreName
(
priv
.
restoreName
(
file_name
).
split
(
"
_.
"
).
join
(
"
.
"
))];
}
return
[
priv
.
restoreName
(
priv
.
restoreName
(
split
.
slice
(
0
,
separator_index
+
1
).
join
(
"
.
"
)
).
split
(
"
_.
"
).
join
(
"
.
"
)),
priv
.
restoreName
(
priv
.
restoreName
(
split
.
slice
(
separator_index
+
1
).
join
(
"
.
"
)
).
split
(
"
_.
"
).
join
(
"
.
"
))
];
};
/**
* Removes the last character if it is a "/". "/a/b/c/" become "/a/b/c"
* @method removeSlashIfLast
* @param {string} string The string to modify
* @return {string} The modified string
*/
priv
.
removeSlashIfLast
=
function
(
string
)
{
if
(
string
[
string
.
length
-
1
]
===
"
/
"
)
{
return
string
.
slice
(
0
,
-
1
);
}
return
string
;
};
that
.
documentObjectUpdate
=
function
(
doc
,
new_doc
)
{
var
k
;
for
(
k
in
doc
)
{
if
(
doc
.
hasOwnProperty
(
k
))
{
if
(
k
[
0
]
!==
'
_
'
)
{
delete
doc
[
k
];
}
}
}
for
(
k
in
new_doc
)
{
if
(
new_doc
.
hasOwnProperty
(
k
))
{
if
(
k
[
0
]
!==
'
_
'
)
{
doc
[
k
]
=
new_doc
[
k
];
}
}
}
};
/**
* Checks if an object has no enumerable keys
* @method objectIsEmpty
* @param {object} obj The object
* @return {boolean} true if empty, else false
*/
that
.
objectIsEmpty
=
function
(
obj
)
{
var
k
;
for
(
k
in
obj
)
{
if
(
obj
.
hasOwnProperty
(
k
))
{
return
false
;
}
}
return
true
;
};
// ===================== overrides ======================
that
.
specToStore
=
function
()
{
return
{
"
username
"
:
priv
.
username
,
"
password
"
:
priv
.
password
,
"
server
"
:
priv
.
server
,
"
acl
"
:
priv
.
acl
};
};
that
.
validateState
=
function
()
{
// xxx complete error message
// jjj completion below
if
(
typeof
priv
.
AWSIdentifier
===
"
string
"
&&
priv
.
AWSIdentifier
===
''
)
{
return
'
Need at least one parameter "Aws login".
'
;
}
if
(
typeof
priv
.
password
===
"
string
"
&&
priv
.
password
===
''
)
{
return
'
Need at least one parameter "password".
'
;
}
if
(
typeof
priv
.
server
===
"
string
"
&&
priv
.
server
===
''
)
{
return
'
Need at least one parameter "server".
'
;
}
return
''
;
};
// =================== S3 Specifics =================
/**
* Encoding the signature using a stringToSign
* Encoding the policy
* @method buildStringToSign
* @param {string} http_verb The HTTP method
* @param {string} content_md5 The md5 content
* @param {string} content_type The content type
* @param {number} expires The expires time
* @param {string} x_amz_headers The specific amazon headers
* @param {string} path_key The path of the document
* @return {string} The generated signature
*/
// xxx no need to make it public, use private -> "priv" (not "that")
priv
.
buildStringToSign
=
function
(
http_verb
,
content_md5
,
content_type
,
expires
,
x_amz_headers
,
path_key
)
{
//example :
// var StringToSign = S3.buildStringToSign(S3.httpVerb,'','','',
// 'x-amz-date:'+S3.requestUTC,'/jio1st/prive.json');
var
StringToSign
=
http_verb
+
'
\n
'
+
content_md5
+
'
\n
'
//content-md5
+
content_type
+
'
\n
'
//content-type
+
expires
+
'
\n
'
//expires
+
x_amz_headers
+
'
\n
'
//x-amz headers
+
path_key
;
//path key
return
StringToSign
;
};
that
.
encodePolicy
=
function
(
form
)
{
//generates the policy
//enables the choice for the http response code
var
http_code
,
s3_policy
,
Signature
=
''
;
s3_policy
=
{
"
expiration
"
:
"
2020-01-01T00:00:00Z
"
,
"
conditions
"
:
[
{
"
bucket
"
:
priv
.
server
},
[
"
starts-with
"
,
"
$key
"
,
""
],
{
"
acl
"
:
priv
.
acl
},
{
"
success_action_redirect
"
:
""
},
{
"
success_action_status
"
:
http_code
},
[
"
starts-with
"
,
"
$Content-Type
"
,
""
],
[
"
content-length-range
"
,
0
,
524288000
]
]
};
//base64 encoding of the policy (native base64 js >>
// .btoa() = encode, .atob() = decode)
priv
.
b64_policy
=
btoa
(
JSON
.
stringify
(
s3_policy
));
//generates the signature value using the policy and the secret access key
//use of sha1.js to generate the signature
Signature
=
that
.
signature
(
priv
.
b64_policy
);
};
that
.
signature
=
function
(
string
)
{
var
Signature
=
b64_hmac_sha1
(
priv
.
password
,
string
);
return
Signature
;
};
function
xhr_onreadystatechange
(
docId
,
command
,
obj
,
http
,
jio
,
isAttachment
,
callback
)
{
obj
.
onreadystatechange
=
function
()
{
var
response
,
err
=
''
;
if
(
obj
.
readyState
===
4
)
{
if
(
this
.
status
===
204
||
this
.
status
===
201
||
this
.
status
===
200
)
{
switch
(
http
)
{
case
"
POST
"
:
command
.
success
(
this
.
status
,{
id
:
docId
});
break
;
case
'
PUT
'
:
if
(
jio
===
true
)
{
command
.
success
(
this
.
status
);
}
else
{
callback
(
this
.
responseText
);
}
break
;
case
'
GET
'
:
if
(
jio
===
true
)
{
if
(
typeof
this
.
responseText
!==
'
string
'
)
{
response
=
JSON
.
parse
(
this
.
responseText
);
response
.
_attachments
=
response
.
_attachments
||
{};
delete
response
.
_attachments
;
//command.success(JSON.stringify(response));
}
else
{
if
(
isAttachment
===
true
)
{
//command.success(this.responseText);
}
else
{
//command.success(JSON.parse(this.responseText));
}
}
}
else
{
callback
(
this
.
responseText
);
}
break
;
case
'
DELETE
'
:
if
(
jio
===
true
)
{
if
(
isAttachment
===
false
)
{
command
.
success
(
this
.
status
);
}
else
{
command
.
success
(
this
.
status
);
}
}
else
{
callback
(
this
.
responseText
);
}
break
;
}
}
else
{
err
=
this
;
if
(
this
.
status
===
405
)
{
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err
.
error
=
"
not_allowed
"
;
command
.
error
(
err
);
}
if
(
this
.
status
===
404
)
{
if
(
http
===
'
GET
'
)
{
if
(
jio
===
true
)
{
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err
.
statustext
=
"
not_foud
"
;
err
.
reason
=
"
file does not exist
"
;
err
.
error
=
"
not_found
"
;
command
.
error
(
err
);
}
else
{
callback
(
'
404
'
);
}
}
else
{
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err
.
error
=
"
not_found
"
;
command
.
error
(
err
);
}
}
if
(
this
.
status
===
409
)
{
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err
.
error
=
"
already_exists
"
;
command
.
error
(
err
);
}
}
}
}
}
priv
.
updateMeta
=
function
(
doc
,
docid
,
attachid
,
action
,
data
)
{
doc
.
_attachments
=
doc
.
_attachments
||
{};
switch
(
action
)
{
case
"
add
"
:
doc
.
_attachments
[
attachid
]
=
data
;
//nothing happens
doc
=
JSON
.
stringify
(
doc
);
break
;
case
"
remove
"
:
if
(
doc
.
_attachments
!==
undefined
)
{
delete
doc
.
_attachments
[
attachid
];
}
doc
=
JSON
.
stringify
(
doc
);
break
;
case
"
update
"
:
doc
.
_attachments
[
attachid
]
=
data
;
//update happened in the put request
doc
=
JSON
.
stringify
(
doc
);
break
;
}
return
doc
;
};
priv
.
createError
=
function
(
status
,
message
,
reason
)
{
var
error
=
{
"
status
"
:
status
,
"
message
"
:
message
,
"
reason
"
:
reason
};
switch
(
status
)
{
case
404
:
error
.
statusText
=
"
Not found
"
;
break
;
case
405
:
error
.
statusText
=
"
Method Not Allowed
"
;
break
;
case
409
:
error
.
statusText
=
"
Conflicts
"
;
break
;
case
24
:
error
.
statusText
=
"
Corrupted Document
"
;
break
;
}
error
.
error
=
error
.
statusText
.
toLowerCase
().
split
(
"
"
).
join
(
"
_
"
);
return
error
;
};
that
.
encodeAuthorization
=
function
(
key
,
mime
)
{
//GET oriented method
var
requestUTC
,
httpVerb
,
StringToSign
,
Signature
;
requestUTC
=
new
Date
().
toUTCString
();
httpVerb
=
"
GET
"
;
StringToSign
=
priv
.
buildStringToSign
(
httpVerb
,
''
,
'
application/json
'
,
''
,
'
x-amz-date:
'
+
requestUTC
,
'
/
'
+
priv
.
server
+
'
/
'
+
key
);
Signature
=
b64_hmac_sha1
(
priv
.
password
,
StringToSign
);
return
Signature
;
};
that
.
XHRwrapper
=
function
(
command
,
docId
,
attachId
,
http
,
mime
,
data
,
jio
,
is_attachment
,
callback
)
{
var
docFile
,
requestUTC
,
StringToSign
,
url
,
Signature
,
xhr
;
docFile
=
priv
.
secureName
(
priv
.
idsToFileName
(
docId
,
attachId
||
undefined
));
requestUTC
=
new
Date
().
toUTCString
();
StringToSign
=
priv
.
buildStringToSign
(
http
,
''
,
mime
,
''
,
'
x-amz-date:
'
+
requestUTC
,
'
/
'
+
priv
.
server
+
'
/
'
+
docFile
);
url
=
'
http://s3.amazonaws.com/
'
+
priv
.
server
+
'
/
'
+
docFile
;
Signature
=
b64_hmac_sha1
(
priv
.
password
,
StringToSign
);
xhr
=
new
XMLHttpRequest
();
xhr
.
open
(
http
,
url
,
true
);
xhr
.
setRequestHeader
(
"
HTTP-status-code
"
,
"
100
"
);
xhr
.
setRequestHeader
(
"
x-amz-date
"
,
requestUTC
);
xhr
.
setRequestHeader
(
"
Authorization
"
,
"
AWS
"
+
priv
.
AWSIdentifier
+
"
:
"
+
Signature
);
xhr
.
setRequestHeader
(
"
Content-Type
"
,
mime
);
xhr
.
responseType
=
'
text
'
;
xhr_onreadystatechange
(
docId
,
command
,
xhr
,
http
,
jio
,
is_attachment
,
callback
);
if
(
http
===
'
PUT
'
)
{
xhr
.
send
(
data
);
}
else
{
xhr
.
send
(
null
);
}
};
// ==================== commands ====================
/**
* Create a document in local storage.
* @method post
* @param {object} command The JIO command
**/
that
.
post
=
function
(
command
)
{
//as S3 encoding key are directly inserted within the FormData(),
//use of XHRwrapper function ain't pertinent
var
doc
,
doc_id
,
mime
;
doc
=
command
.
cloneDoc
();
doc_id
=
command
.
getDocId
();
function
postDocument
()
{
var
http_response
,
fd
,
Signature
,
xhr
;
doc_id
=
priv
.
secureName
(
priv
.
idsToFileName
(
doc_id
));
//Meant to deep-serialize in order to avoid
//conflicts due to the multipart enctype
doc
=
JSON
.
stringify
(
doc
);
http_response
=
''
;
fd
=
new
FormData
();
//virtually builds the form fields
//filename
fd
.
append
(
'
key
'
,
doc_id
);
//file access authorizations
priv
.
acl
=
""
;
fd
.
append
(
'
acl
'
,
priv
.
acl
);
//content-type
priv
.
contenTType
=
"
text/plain
"
;
fd
.
append
(
'
Content-Type
'
,
priv
.
contenTType
);
//allows specification of a success url redirection
fd
.
append
(
'
success_action_redirect
'
,
''
);
//allows to specify the http code response if the request is successful
fd
.
append
(
'
success_action_status
'
,
http_response
);
//login AWS
fd
.
append
(
'
AWSAccessKeyId
'
,
priv
.
AWSIdentifier
);
//exchange policy with the amazon s3 service
//can be common to all uploads or specific
that
.
encodePolicy
(
fd
);
//priv.b64_policy = that.encodePolicy(fd);
fd
.
append
(
'
policy
'
,
priv
.
b64_policy
);
//signature through the base64.hmac.sha1(secret key, policy) method
Signature
=
b64_hmac_sha1
(
priv
.
password
,
priv
.
b64_policy
);
fd
.
append
(
'
signature
'
,
Signature
);
//uploaded content !!may must be a string rather than an object
fd
.
append
(
'
file
'
,
doc
);
xhr
=
new
XMLHttpRequest
();
xhr_onreadystatechange
(
doc_id
,
command
,
xhr
,
'
POST
'
,
true
,
false
,
''
);
xhr
.
open
(
'
POST
'
,
'
https://
'
+
priv
.
server
+
'
.s3.amazonaws.com/
'
,
true
);
xhr
.
send
(
fd
);
}
if
(
doc_id
===
''
||
doc_id
===
undefined
)
{
doc_id
=
'
no_document_id_
'
+
((
Math
.
random
()
*
10
).
toString
().
split
(
'
.
'
))[
1
];
doc
.
_id
=
doc_id
;
}
mime
=
'
text/plain; charset=UTF-8
'
;
that
.
XHRwrapper
(
command
,
doc_id
,
''
,
'
GET
'
,
mime
,
''
,
false
,
false
,
function
(
response
)
{
if
(
response
===
'
404
'
)
{
postDocument
();
}
else
{
//si ce n'est pas une 404,
//alors on renvoit une erreur 405
return
command
.
error
(
409
,
"
Document already exists
"
,
"
Cannot create document
"
);
}
}
);
};
/**
* Get a document or attachment
* @method get
* @param {object} command The JIO command
**/
that
.
get
=
function
(
command
,
metadata
,
option
)
{
var
docId
,
attachId
,
isJIO
,
mime
;
docId
=
metadata
.
_id
;
isJIO
=
true
;
mime
=
'
text/plain; charset=UTF-8
'
;
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
GET
'
,
mime
,
''
,
isJIO
,
false
);
};
that
.
getAttachment
=
function
(
command
)
{
var
docId
,
attachId
,
isJIO
,
mime
;
docId
=
command
.
getDocId
();
attachId
=
command
.
getAttachmentId
();
isJIO
=
true
;
mime
=
'
text/plain; charset=UTF-8
'
;
that
.
XHRwrapper
(
command
,
docId
,
attachId
,
'
GET
'
,
mime
,
''
,
isJIO
,
true
);
};
/**
* Create or update a document in local storage.
* @method put
* @param {object} command The JIO command
**/
that
.
put
=
function
(
command
,
metadata
,
options
)
{
var
doc
,
docId
,
mime
;
doc
=
metadata
;
docId
=
doc
.
_id
;
mime
=
'
text/plain; charset=UTF-8
'
;
//pas d'attachment dans un put simple
function
putDocument
()
{
var
attachId
,
data
,
isJIO
;
attachId
=
''
;
data
=
JSON
.
stringify
(
doc
);
isJIO
=
true
;
that
.
XHRwrapper
(
command
,
docId
,
attachId
,
'
PUT
'
,
mime
,
data
,
isJIO
,
false
);
}
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
GET
'
,
mime
,
''
,
false
,
false
,
function
(
response
)
{
//if (response === '404') {}
if
(
response
.
_attachments
!==
undefined
)
{
doc
.
_attachments
=
response
.
_attachments
;
}
putDocument
();
}
);
};
that
.
putAttachment
=
function
(
command
)
{
var
mon_document
,
docId
,
attachId
,
mime
,
attachment_id
,
attachment_data
,
attachment_md5
,
attachment_mimetype
,
attachment_length
;
mon_document
=
null
;
docId
=
command
.
getDocId
();
attachId
=
command
.
getAttachmentId
()
||
''
;
mime
=
'
text/plain; charset=UTF-8
'
;
//récupération des variables de l'attachement
attachment_id
=
command
.
getAttachmentId
();
attachment_data
=
command
.
getAttachmentData
();
attachment_md5
=
command
.
md5SumAttachmentData
();
attachment_mimetype
=
command
.
getAttachmentMimeType
();
attachment_length
=
command
.
getAttachmentLength
();
function
putAttachment
()
{
that
.
XHRwrapper
(
command
,
docId
,
attachId
,
'
PUT
'
,
mime
,
attachment_data
,
false
,
true
,
function
(
reponse
)
{
command
.
success
({
// response
"
ok
"
:
true
,
"
id
"
:
docId
,
"
attachment
"
:
attachId
//"rev": current_revision
});
}
);
}
function
putDocument
()
{
var
attachment_obj
,
data
,
doc
;
attachment_obj
=
{
//"revpos": 3, // optional
"
digest
"
:
attachment_md5
,
"
content_type
"
:
attachment_mimetype
,
"
length
"
:
attachment_length
};
data
=
JSON
.
parse
(
mon_document
);
doc
=
priv
.
updateMeta
(
data
,
docId
,
attachId
,
"
add
"
,
attachment_obj
);
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
PUT
'
,
mime
,
doc
,
false
,
false
,
function
(
reponse
)
{
putAttachment
();
}
);
}
function
getDocument
()
{
//XHRwrapper(command,'PUT','text/plain; charset=UTF-8',true);
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
GET
'
,
mime
,
''
,
false
,
false
,
function
(
reponse
)
{
if
(
reponse
===
'
404
'
)
{
return
command
.
error
(
priv
.
createError
(
404
,
"
Cannot find document
"
,
"
Document does not exist
"
));
}
mon_document
=
reponse
;
putDocument
();
}
);
}
getDocument
();
};
/**
* Remove a document or attachment
* @method remove
* @param {object} command The JIO command
*/
that
.
remove
=
function
(
command
)
{
var
docId
,
mime
;
docId
=
command
.
getDocId
();
mime
=
'
text/plain; charset=UTF-8
'
;
function
deleteDocument
()
{
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
DELETE
'
,
mime
,
''
,
true
,
false
,
function
(
reponse
)
{
command
.
success
({
// response
"
ok
"
:
true
,
"
id
"
:
docId
//"rev": current_revision
});
}
);
}
function
myCallback
(
response
)
{
}
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
GET
'
,
mime
,
''
,
false
,
false
,
function
(
response
)
{
var
attachKeys
,
keys
;
attachKeys
=
(
JSON
.
parse
(
response
)).
_attachments
;
for
(
keys
in
attachKeys
)
{
if
(
attachKeys
.
hasOwnProperty
(
keys
))
{
that
.
XHRwrapper
(
command
,
docId
,
keys
,
'
DELETE
'
,
mime
,
''
,
false
,
false
,
myCallback
);
}
}
deleteDocument
();
}
);
};
that
.
removeAttachment
=
function
(
command
)
{
var
mon_document
,
docId
,
attachId
,
mime
,
attachment_id
,
attachment_data
,
attachment_md5
,
attachment_mimetype
,
attachment_length
;
mon_document
=
null
;
docId
=
command
.
getDocId
();
attachId
=
command
.
getAttachmentId
()
||
''
;
mime
=
'
text/plain; charset=UTF-8
'
;
//récupération des variables de l'attachement
attachment_id
=
command
.
getAttachmentId
();
attachment_data
=
command
.
getAttachmentData
();
attachment_md5
=
command
.
md5SumAttachmentData
();
attachment_mimetype
=
command
.
getAttachmentMimeType
();
attachment_length
=
command
.
getAttachmentLength
();
function
removeAttachment
()
{
that
.
XHRwrapper
(
command
,
docId
,
attachId
,
'
DELETE
'
,
mime
,
''
,
true
,
true
,
function
(
reponse
)
{
}
);
}
function
putDocument
()
{
var
data
,
doc
;
data
=
JSON
.
parse
(
mon_document
);
doc
=
priv
.
updateMeta
(
data
,
docId
,
attachId
,
"
remove
"
,
''
);
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
PUT
'
,
mime
,
doc
,
false
,
false
,
function
(
reponse
)
{
removeAttachment
();
}
);
}
function
getDocument
()
{
that
.
XHRwrapper
(
command
,
docId
,
''
,
'
GET
'
,
mime
,
''
,
false
,
false
,
function
(
reponse
)
{
mon_document
=
reponse
;
putDocument
();
}
);
}
getDocument
();
};
/**
* Get all filenames belonging to a user from the document index
* @method allDocs
* @param {object} command The JIO command
**/
that
.
allDocs
=
function
(
command
)
{
var
mon_document
,
mime
;
mon_document
=
null
;
mime
=
'
text/plain; charset=UTF-8
'
;
function
makeJSON
()
{
var
keys
,
resultTable
,
counter
,
allDocResponse
,
count
,
countB
,
dealCallback
,
errCallback
,
i
,
keyId
,
Signature
,
callURL
,
requestUTC
,
parse
,
checkCounter
;
keys
=
$
(
mon_document
).
find
(
'
Key
'
);
resultTable
=
[];
counter
=
0
;
keys
.
each
(
function
(
index
)
{
var
that
,
filename
,
docId
;
that
=
$
(
this
);
filename
=
that
.
context
.
textContent
;
docId
=
priv
.
idsToFileName
(
priv
.
fileNameToIds
(
filename
)[
0
]);
if
(
counter
===
0
)
{
counter
+=
1
;
resultTable
.
push
(
docId
);
}
else
if
(
docId
!==
resultTable
[
counter
-
1
])
{
counter
+=
1
;
resultTable
.
push
(
docId
);
}
});
allDocResponse
=
{
// document content will be added to response
"
total_rows
"
:
resultTable
.
length
,
"
offset
"
:
0
,
"
rows
"
:
[]
};
//needed to save the index within the $.ajax.success() callback
count
=
resultTable
.
length
-
1
;
countB
=
0
;
dealCallback
=
function
(
i
,
countB
,
allDoc
)
{
return
function
(
doc
,
statustext
,
response
)
{
allDoc
.
rows
[
i
].
doc
=
response
.
responseText
;
if
(
count
===
0
)
{
command
.
success
(
allDoc
);
}
else
{
count
-=
1
;
}
};
};
errCallback
=
function
(
err
)
{
if
(
err
.
status
===
404
)
{
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err
.
error
=
"
not_found
"
;
command
.
error
(
err
);
}
else
{
return
that
.
retry
(
err
);
}
};
i
=
resultTable
.
length
-
1
;
if
(
command
.
getOption
(
"
include_docs
"
)
===
true
)
{
for
(
i
;
i
>=
0
;
i
-=
1
)
{
keyId
=
resultTable
[
i
];
Signature
=
that
.
encodeAuthorization
(
keyId
);
callURL
=
'
http://
'
+
priv
.
server
+
'
.s3.amazonaws.com/
'
+
keyId
;
requestUTC
=
new
Date
().
toUTCString
();
parse
=
true
;
allDocResponse
.
rows
[
i
]
=
{
"
id
"
:
priv
.
fileNameToIds
(
keyId
).
join
(),
"
key
"
:
keyId
,
"
value
"
:
{}
};
checkCounter
=
i
;
$
.
ajax
({
contentType
:
''
,
crossdomain
:
true
,
url
:
callURL
,
type
:
'
GET
'
,
headers
:
{
'
Authorization
'
:
"
AWS
"
+
"
"
+
priv
.
AWSIdentifier
+
"
:
"
+
Signature
,
'
x-amz-date
'
:
requestUTC
,
'
Content-Type
'
:
'
application/json
'
//'Content-MD5' : ''
//'Content-Length' : ,
//'Expect' : ,
//'x-amz-security-token' : ,
},
success
:
dealCallback
(
i
,
countB
,
allDocResponse
),
error
:
errCallback
(
command
.
error
)
});
countB
+=
1
;
}
}
else
{
for
(
i
;
i
>=
0
;
i
-=
1
)
{
keyId
=
resultTable
[
i
];
allDocResponse
.
rows
[
i
]
=
{
"
id
"
:
priv
.
fileNameToIds
(
keyId
).
join
(),
"
key
"
:
keyId
,
"
value
"
:
{}
};
}
command
.
success
(
allDocResponse
);
}
}
function
getXML
()
{
//XHRwrapper(command,'PUT','text/plain; charset=UTF-8',true);
that
.
XHRwrapper
(
command
,
''
,
''
,
'
GET
'
,
mime
,
''
,
false
,
false
,
function
(
reponse
)
{
mon_document
=
reponse
;
makeJSON
();
}
);
}
getXML
();
//fin alldocs
};
});
}));
test/jio.storage/s3storage.livetests.html
0 → 100644
View file @
713a80e2
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
/>
<title>
JIO S3 Storage Qunit Live Tests
</title>
<link
rel=
"stylesheet"
href=
"../../lib/qunit/qunit.css"
/>
<script
src=
"../../lib/qunit/qunit.js"
></script>
<script
src=
"../../lib/rsvp/rsvp-custom.js"
></script>
<script
src=
"../../lib/jquery/jquery.min.js"
></script>
<script
src=
"../../src/sha256.amd.js"
></script>
<script
src=
"../../jio.js"
></script>
<script
src=
"../../complex_queries.js"
></script>
<script
src=
"../../src/sha1.amd.js"
></script>
<script
src=
"../../src/jio.storage/s3storage.js"
></script>
<script
src=
"../jio/util.js"
></script>
</head>
<body>
<script>
var
s3storage_spec
=
{};
console
.
log
(
location
.
href
);
location
.
href
.
split
(
'
?
'
)[
1
].
split
(
'
&
'
).
forEach
(
function
(
item
)
{
s3storage_spec
[
item
.
split
(
'
=
'
)[
0
]]
=
decodeURI
(
item
.
split
(
'
=
'
).
slice
(
1
).
join
(
'
=
'
)).
replace
(
/%3A/ig
,
'
:
'
).
replace
(
/%2F/ig
,
'
/
'
);
});
</script>
<h3>
JIO initialization
</h3>
<form
method=
"get"
action=
""
>
<input
type=
"hidden"
name=
"type"
value=
"s3"
/>
<input
type=
"text"
name=
"url"
placeholder=
"URL"
/>
<input
type=
"text"
name=
"server"
placeholder=
"Bucket"
/>
<input
type=
"text"
name=
"AWSIdentifier"
placeholder=
"AWSIdentifier"
/>
<input
type=
"password"
name=
"password"
placeholder=
"Password"
/>
<input
type=
"submit"
value=
"Run Tests"
/>
</form>
<br
/>
<div
id=
"qunit"
></div>
<script
src=
"s3storage.tests.js"
></script>
</body>
</html>
test/jio.storage/s3storage.tests.js
0 → 100644
View file @
713a80e2
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global module, test, stop, start, expect, ok, deepEqual, location, sinon,
davstorage_spec, RSVP, jIO, test_util, dav_storage, btoa */
(
function
()
{
"
use strict
"
;
var
spec
,
use_fake_server
=
true
;
if
(
typeof
s3storage_spec
===
'
object
'
)
{
use_fake_server
=
false
;
spec
=
s3storage_spec
;
console
.
log
(
spec
);
}
else
{
spec
=
dav_storage
.
createDescription
(
"
http://localhost
"
,
"
none
"
);
}
module
(
"
S3 Storage
"
);
function
success
(
promise
)
{
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
,
notify
)
{
/*jslint unparam: true*/
promise
.
then
(
resolve
,
resolve
,
notify
);
},
function
()
{
promise
.
cancel
();
});
}
test
(
"
Scenario
"
,
function
()
{
var
server
,
responses
=
[],
shared
=
{},
jio
=
jIO
.
createJIO
(
spec
,
{
"
workspace
"
:
{},
"
max_retry
"
:
2
});
stop
();
if
(
use_fake_server
)
{
/*jslint regexp: true */
server
=
sinon
.
fakeServer
.
create
();
server
.
autoRespond
=
true
;
server
.
autoRespondAfter
=
5
;
server
.
respondWith
(
/.*/
,
function
(
xhr
)
{
var
response
=
responses
.
shift
();
if
(
response
)
{
return
xhr
.
respond
.
apply
(
xhr
,
response
);
}
ok
(
false
,
"
No response associated to the latest request!
"
);
});
}
else
{
responses
.
push
=
function
()
{
return
;
};
server
=
{
restore
:
function
()
{
return
;
}};
}
function
postNewDocument
()
{
responses
.
push
([
404
,
{},
''
]);
// GET
responses
.
push
([
201
,
{},
''
]);
// PUT
return
jio
.
post
({
"
title
"
:
"
Unique ID
"
});
}
function
postNewDocumentTest
(
answer
)
{
var
uuid
=
answer
.
id
;
answer
.
id
=
"
<uuid>
"
;
deepEqual
(
answer
,
{
"
id
"
:
"
<uuid>
"
,
"
method
"
:
"
post
"
,
"
result
"
:
"
success
"
,
"
status
"
:
201
,
"
statusText
"
:
"
Created
"
},
"
Post a new document
"
);
ok
(
test_util
.
isUuid
(
uuid
),
"
New document id should look like
"
+
"
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx :
"
+
uuid
);
shared
.
created_document_id
=
uuid
;
}
function
getCreatedDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
shared
.
created_document_id
,
"
title
"
:
"
Unique ID
"
})]);
// GET
return
jio
.
get
({
"
_id
"
:
shared
.
created_document_id
});
}
function
getCreatedDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
data
"
:
{
"
_id
"
:
shared
.
created_document_id
,
"
title
"
:
"
Unique ID
"
},
"
id
"
:
shared
.
created_document_id
,
"
method
"
:
"
get
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
Get new document
"
);
}
function
postSpecificDocument
()
{
responses
.
push
([
404
,
{},
''
]);
// GET
responses
.
push
([
201
,
{},
''
]);
// PUT
return
jio
.
post
({
"
_id
"
:
"
b
"
,
"
title
"
:
"
Bee
"
});
}
function
postSpecificDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
b
"
,
"
method
"
:
"
post
"
,
"
result
"
:
"
success
"
,
"
status
"
:
201
,
"
statusText
"
:
"
Created
"
},
"
Post specific document
"
);
}
function
listDocuments
()
{
responses
.
push
([
207
,
{
"
Content-Type
"
:
"
text/xml
"
},
'
<?xml version="1.0" encoding="utf-8"?>
'
+
'
<D:multistatus xmlns:D="DAV:">
'
+
'
<D:response xmlns:lp2="http://apache.
'
+
'
org/dav/props/" xmlns:lp1="DAV:">
'
+
'
<D:href>/uploads/</D:href>
'
+
'
<D:propstat>
'
+
'
<D:prop>
'
+
'
<lp1:resourcetype><D:collection/></lp1:resourcetype>
'
+
'
<lp1:creationdate>2013-09-19T11:54:43Z</lp1:creationdate>
'
+
'
<lp1:getlastmodified>Thu, 19 Sep 2013 11:54:43 GMT
'
+
'
</lp1:getlastmodified>
'
+
'
<lp1:getetag>"240be-1000-4e6bb383e5fbb"</lp1:getetag>
'
+
'
<D:supportedlock>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:exclusive/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:shared/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
</D:supportedlock>
'
+
'
<D:lockdiscovery/>
'
+
'
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
'
+
'
</D:prop>
'
+
'
<D:status>HTTP/1.1 200 OK</D:status>
'
+
'
</D:propstat>
'
+
'
</D:response>
'
+
'
<D:response xmlns:lp2="http://apache.org/dav/props/"
'
+
'
xmlns:lp1="DAV:">
'
+
'
<D:href>/uploads/
'
+
shared
.
created_document_id
+
'
</D:href>
'
+
'
<D:propstat>
'
+
'
<D:prop>
'
+
'
<lp1:resourcetype/>
'
+
'
<lp1:creationdate>2013-09-19T11:54:43Z</lp1:creationdate>
'
+
'
<lp1:getcontentlength>66</lp1:getcontentlength>
'
+
'
<lp1:getlastmodified>Thu, 19 Sep 2013 11:54:43 GMT
'
+
'
</lp1:getlastmodified>
'
+
'
<lp1:getetag>"20529-42-4e6bb383d0d30"</lp1:getetag>
'
+
'
<lp2:executable>F</lp2:executable>
'
+
'
<D:supportedlock>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:exclusive/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:shared/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
</D:supportedlock>
'
+
'
<D:lockdiscovery/>
'
+
'
</D:prop>
'
+
'
<D:status>HTTP/1.1 200 OK</D:status>
'
+
'
</D:propstat>
'
+
'
</D:response>
'
+
'
<D:response xmlns:lp2="http://apache.org/dav/props/"
'
+
'
xmlns:lp1="DAV:">
'
+
'
<D:href>/uploads/b</D:href>
'
+
'
<D:propstat>
'
+
'
<D:prop>
'
+
'
<lp1:resourcetype/>
'
+
'
<lp1:creationdate>2013-09-19T11:54:43Z</lp1:creationdate>
'
+
'
<lp1:getcontentlength>25</lp1:getcontentlength>
'
+
'
<lp1:getlastmodified>Thu, 19 Sep 2013 11:54:43 GMT
'
+
'
</lp1:getlastmodified>
'
+
'
<lp1:getetag>"20da3-19-4e6bb383e5fbb"</lp1:getetag>
'
+
'
<lp2:executable>F</lp2:executable>
'
+
'
<D:supportedlock>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:exclusive/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:shared/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
</D:supportedlock>
'
+
'
<D:lockdiscovery/>
'
+
'
</D:prop>
'
+
'
<D:status>HTTP/1.1 200 OK</D:status>
'
+
'
</D:propstat>
'
+
'
</D:response>
'
+
'
</D:multistatus>
'
]);
// PROPFIND
return
jio
.
allDocs
();
}
function
list2DocumentsTest
(
answer
)
{
if
(
answer
&&
answer
.
data
&&
Array
.
isArray
(
answer
.
data
.
rows
))
{
answer
.
data
.
rows
.
sort
(
function
(
a
)
{
return
a
.
id
===
"
b
"
?
1
:
0
;
});
}
deepEqual
(
answer
,
{
"
data
"
:
{
"
total_rows
"
:
2
,
"
rows
"
:
[{
"
id
"
:
shared
.
created_document_id
,
"
value
"
:
{}
},
{
"
id
"
:
"
b
"
,
"
value
"
:
{}
}]
},
"
method
"
:
"
allDocs
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
List 2 documents
"
);
}
function
removeCreatedDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
shared
.
created_document_id
,
"
title
"
:
"
Unique ID
"
})]);
// GET
responses
.
push
([
204
,
{},
''
]);
// DELETE
return
jio
.
remove
({
"
_id
"
:
shared
.
created_document_id
});
}
function
removeCreatedDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
shared
.
created_document_id
,
"
method
"
:
"
remove
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove first document.
"
);
}
function
removeSpecificDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
b
"
,
"
title
"
:
"
Bee
"
})]);
// GET
responses
.
push
([
204
,
{},
''
]);
// DELETE
return
jio
.
remove
({
"
_id
"
:
"
b
"
});
}
function
removeSpecificDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
b
"
,
"
method
"
:
"
remove
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove second document.
"
);
}
function
listEmptyStorage
()
{
responses
.
push
([
207
,
{
"
Content-Type
"
:
"
text/xml
"
},
'
<?xml version="1.0" encoding="utf-8"?>
'
+
'
<D:multistatus xmlns:D="DAV:">
'
+
'
<D:response xmlns:lp2="http://apache.org/dav/props/"
'
+
'
xmlns:lp1="DAV:">
'
+
'
<D:href>/uploads/</D:href>
'
+
'
<D:propstat>
'
+
'
<D:prop>
'
+
'
<lp1:resourcetype><D:collection/></lp1:resourcetype>
'
+
'
<lp1:creationdate>2013-09-19T11:54:43Z</lp1:creationdate>
'
+
'
<lp1:getlastmodified>Thu, 19 Sep 2013 11:54:43 GMT
'
+
'
</lp1:getlastmodified>
'
+
'
<lp1:getetag>"240be-1000-4e6bb3840a9ac"</lp1:getetag>
'
+
'
<D:supportedlock>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:exclusive/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
<D:lockentry>
'
+
'
<D:lockscope><D:shared/></D:lockscope>
'
+
'
<D:locktype><D:write/></D:locktype>
'
+
'
</D:lockentry>
'
+
'
</D:supportedlock>
'
+
'
<D:lockdiscovery/>
'
+
'
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
'
+
'
</D:prop>
'
+
'
<D:status>HTTP/1.1 200 OK</D:status>
'
+
'
</D:propstat>
'
+
'
</D:response>
'
+
'
</D:multistatus>
'
]);
// PROPFIND
return
jio
.
allDocs
();
}
function
listEmptyStorageTest
(
answer
)
{
deepEqual
(
answer
,
{
"
data
"
:
{
"
total_rows
"
:
0
,
"
rows
"
:
[]
},
"
method
"
:
"
allDocs
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
List empty storage
"
);
}
function
putNewDocument
()
{
responses
.
push
([
404
,
{},
''
]);
// GET
responses
.
push
([
200
,
{},
''
]);
// PUT
return
jio
.
put
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
});
}
function
putNewDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
a
"
,
"
method
"
:
"
put
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
Put new document
"
);
}
function
getCreatedDocument2
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
})]);
// GET
return
jio
.
get
({
"
_id
"
:
"
a
"
});
}
function
getCreatedDocument2Test
(
answer
)
{
deepEqual
(
answer
,
{
"
data
"
:
{
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
},
"
id
"
:
"
a
"
,
"
method
"
:
"
get
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
Get new document
"
);
}
function
postSameDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
})]);
// GET
return
success
(
jio
.
post
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
}));
}
function
postSameDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
error
"
:
"
conflict
"
,
"
id
"
:
"
a
"
,
"
message
"
:
"
DavStorage, cannot overwrite document metadata.
"
,
"
method
"
:
"
post
"
,
"
reason
"
:
"
Document exists
"
,
"
result
"
:
"
error
"
,
"
status
"
:
409
,
"
statusText
"
:
"
Conflict
"
},
"
Unable to post the same document (conflict)
"
);
}
function
createAttachment
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
})]);
// GET
responses
.
push
([
201
,
{},
''
]);
// PUT (attachment)
responses
.
push
([
204
,
{},
''
]);
// PUT (metadata)
return
jio
.
putAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
aa
"
,
"
_data
"
:
"
aaa
"
,
"
_content_type
"
:
"
text/plain
"
});
}
function
createAttachmentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
aa
"
,
"
digest
"
:
"
sha256-9834876dcfb05cb167a5c24953eba58c4
"
+
"
ac89b1adf57f28f2f9d09af107ee8f0
"
,
"
id
"
:
"
a
"
,
"
method
"
:
"
putAttachment
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Create new attachment
"
);
}
function
updateAttachment
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-9834876dcfb05cb167a5c24953eba58c4
"
+
"
ac89b1adf57f28f2f9d09af107ee8f0
"
,
"
length
"
:
3
}
}
})]);
// GET
responses
.
push
([
204
,
{},
''
]);
// PUT (attachment)
responses
.
push
([
204
,
{},
''
]);
// PUT (metadata)
return
jio
.
putAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
aa
"
,
"
_data
"
:
"
aab
"
,
"
_content_type
"
:
"
text/plain
"
});
}
function
updateAttachmentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
aa
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
id
"
:
"
a
"
,
"
method
"
:
"
putAttachment
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Update last attachment
"
);
}
function
createAnotherAttachment
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
}
}
})]);
// GET
responses
.
push
([
201
,
{},
''
]);
// PUT (attachment)
responses
.
push
([
204
,
{},
''
]);
// PUT (metadata)
return
jio
.
putAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
ab
"
,
"
_data
"
:
"
aba
"
,
"
_content_type
"
:
"
text/plain
"
});
}
function
createAnotherAttachmentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
ab
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
id
"
:
"
a
"
,
"
method
"
:
"
putAttachment
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Create another attachment
"
);
}
function
updateLastDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hey
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
},
"
ab
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
length
"
:
3
}
}
})]);
// GET
responses
.
push
([
204
,
{},
''
]);
// PUT
return
jio
.
put
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
});
}
function
updateLastDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
a
"
,
"
method
"
:
"
put
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Update document metadata
"
);
}
function
getFirstAttachment
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
},
"
ab
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
length
"
:
3
}
}
})]);
// GET
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
"
aab
"
]);
// GET
return
jio
.
getAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
aa
"
});
}
function
getFirstAttachmentTest
(
answer
)
{
var
blob
=
answer
.
data
;
answer
.
data
=
"
<blob>
"
;
deepEqual
(
answer
,
{
"
attachment
"
:
"
aa
"
,
"
data
"
:
"
<blob>
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
id
"
:
"
a
"
,
"
method
"
:
"
getAttachment
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
Get first attachment
"
);
return
jIO
.
util
.
readBlobAsText
(
blob
).
then
(
function
(
e
)
{
deepEqual
(
blob
.
type
,
"
text/plain
"
,
"
Check blob type
"
);
deepEqual
(
e
.
target
.
result
,
"
aab
"
,
"
Check blob text content
"
);
},
function
(
err
)
{
deepEqual
(
err
,
"
no error
"
,
"
Check blob text content
"
);
});
}
function
getSecondAttachment
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
},
"
ab
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
length
"
:
3
}
}
})]);
// GET
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
"
aba
"
]);
// GET
return
jio
.
getAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
ab
"
});
}
function
getSecondAttachmentTest
(
answer
)
{
var
blob
=
answer
.
data
;
answer
.
data
=
"
<blob>
"
;
deepEqual
(
answer
,
{
"
attachment
"
:
"
ab
"
,
"
data
"
:
"
<blob>
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
id
"
:
"
a
"
,
"
method
"
:
"
getAttachment
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
Get first attachment
"
);
return
jIO
.
util
.
readBlobAsText
(
blob
).
then
(
function
(
e
)
{
deepEqual
(
blob
.
type
,
"
text/plain
"
,
"
Check blob type
"
);
deepEqual
(
e
.
target
.
result
,
"
aba
"
,
"
Check blob text content
"
);
},
function
(
err
)
{
deepEqual
(
err
,
"
no error
"
,
"
Check blob text content
"
);
});
}
function
getLastDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
},
"
ab
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
length
"
:
3
}
}
})]);
// GET
return
jio
.
get
({
"
_id
"
:
"
a
"
});
}
function
getLastDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
data
"
:
{
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
},
"
ab
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
length
"
:
3
}
}
},
"
id
"
:
"
a
"
,
"
method
"
:
"
get
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
Get last document metadata
"
);
}
function
removeSecondAttachment
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
},
"
ab
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-e124adcce1fb2f88e1ea799c3d0820845
"
+
"
ed343e6c739e54131fcb3a56e4bc1bd
"
,
"
length
"
:
3
}
}
})]);
// GET
responses
.
push
([
204
,
{},
''
]);
// PUT
responses
.
push
([
204
,
{},
''
]);
// DELETE
return
jio
.
removeAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
ab
"
});
}
function
removeSecondAttachmentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
ab
"
,
"
id
"
:
"
a
"
,
"
method
"
:
"
removeAttachment
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove second document
"
);
}
function
getInexistentSecondAttachment
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
}
}
})]);
// GET
return
success
(
jio
.
getAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
ab
"
}));
}
function
getInexistentSecondAttachmentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
ab
"
,
"
error
"
:
"
not_found
"
,
"
id
"
:
"
a
"
,
"
message
"
:
"
DavStorage, unable to get attachment.
"
,
"
method
"
:
"
getAttachment
"
,
"
reason
"
:
"
missing attachment
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Get inexistent second attachment
"
);
}
function
getOneAttachmentDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
}
}
})]);
// GET
return
jio
.
get
({
"
_id
"
:
"
a
"
});
}
function
getOneAttachmentDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
data
"
:
{
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
}
},
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
},
"
id
"
:
"
a
"
,
"
method
"
:
"
get
"
,
"
result
"
:
"
success
"
,
"
status
"
:
200
,
"
statusText
"
:
"
Ok
"
},
"
Get document metadata
"
);
}
function
removeSecondAttachmentAgain
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
}
}
})]);
// GET
return
success
(
jio
.
removeAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
ab
"
}));
}
function
removeSecondAttachmentAgainTest
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
ab
"
,
"
error
"
:
"
not_found
"
,
"
id
"
:
"
a
"
,
"
message
"
:
"
DavStorage, document attachment not found.
"
,
"
method
"
:
"
removeAttachment
"
,
"
reason
"
:
"
missing attachment
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Remove inexistent attachment
"
);
}
function
removeDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
a
"
,
"
title
"
:
"
Hoo
"
,
"
_attachments
"
:
{
"
aa
"
:
{
"
content_type
"
:
"
text/plain
"
,
"
digest
"
:
"
sha256-38760eabb666e8e61ee628a17c4090cc5
"
+
"
0728e095ff24218119d51bd22475363
"
,
"
length
"
:
3
}
}
})]);
// GET
responses
.
push
([
204
,
{},
''
]);
// DELETE (metadata)
responses
.
push
([
204
,
{},
''
]);
// DELETE (attachment aa)
return
jio
.
remove
({
"
_id
"
:
"
a
"
});
}
function
removeDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
a
"
,
"
method
"
:
"
remove
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Remove document and its attachments
"
);
}
function
getInexistentFirstAttachment
()
{
responses
.
push
([
404
,
{},
''
]);
// GET
return
success
(
jio
.
getAttachment
({
"
_id
"
:
"
a
"
,
"
_attachment
"
:
"
aa
"
}));
}
function
getInexistentFirstAttachmentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
attachment
"
:
"
aa
"
,
"
error
"
:
"
not_found
"
,
"
id
"
:
"
a
"
,
"
message
"
:
"
DavStorage, unable to get attachment.
"
,
"
method
"
:
"
getAttachment
"
,
"
reason
"
:
"
missing document
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Get inexistent first attachment
"
);
}
function
getInexistentDocument
()
{
responses
.
push
([
404
,
{},
''
]);
// GET
return
success
(
jio
.
get
({
"
_id
"
:
"
a
"
}));
}
function
getInexistentDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
error
"
:
"
not_found
"
,
"
id
"
:
"
a
"
,
"
message
"
:
"
DavStorage, unable to get document.
"
,
"
method
"
:
"
get
"
,
"
reason
"
:
"
Not Found
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Get inexistent document
"
);
}
function
removeInexistentDocument
()
{
responses
.
push
([
404
,
{},
''
]);
// GET
return
success
(
jio
.
remove
({
"
_id
"
:
"
a
"
}));
}
function
removeInexistentDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
error
"
:
"
not_found
"
,
"
id
"
:
"
a
"
,
"
message
"
:
"
DavStorage, unable to get metadata.
"
,
"
method
"
:
"
remove
"
,
"
reason
"
:
"
Not Found
"
,
"
result
"
:
"
error
"
,
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
},
"
Remove already removed document
"
);
}
function
unexpectedError
(
error
)
{
if
(
error
instanceof
Error
)
{
deepEqual
([
error
.
name
+
"
:
"
+
error
.
message
,
error
],
"
UNEXPECTED ERROR
"
,
"
Unexpected error
"
);
}
else
{
deepEqual
(
error
,
"
UNEXPECTED ERROR
"
,
"
Unexpected error
"
);
}
}
// # Post new documents, list them and remove them
// post a 201
//postNewDocument().then(postNewDocumentTest).
// get 200
//then(getCreatedDocument).then(getCreatedDocumentTest).
// post b 201
//then(postSpecificDocument).then(postSpecificDocumentTest).
// allD 200 2 documents
//then(listDocuments).then(list2DocumentsTest).
// remove a 204
//then(removeCreatedDocument).then(removeCreatedDocumentTest).
// remove b 204
//then(removeSpecificDocument).then(removeSpecificDocumentTest).
// allD 200 empty storage
//then(listEmptyStorage).then(listEmptyStorageTest).
// # Create and update documents, and some attachment and remove them
// put 201
putNewDocument
().
then
(
putNewDocumentTest
).
// get 200
//then(getCreatedDocument2).then(getCreatedDocument2Test).
// post 409
//then(postSameDocument).then(postSameDocumentTest).
// putA a 204
//then(createAttachment).then(createAttachmentTest).
// putA a 204
//then(updateAttachment).then(updateAttachmentTest).
// putA b 204
//then(createAnotherAttachment).then(createAnotherAttachmentTest).
// put 204
//then(updateLastDocument).then(updateLastDocumentTest).
// getA a 200
//then(getFirstAttachment).then(getFirstAttachmentTest).
// getA b 200
//then(getSecondAttachment).then(getSecondAttachmentTest).
// get 200
//then(getLastDocument).then(getLastDocumentTest).
// removeA b 204
//then(removeSecondAttachment).then(removeSecondAttachmentTest).
// getA b 404
//then(getInexistentSecondAttachment).
//then(getInexistentSecondAttachmentTest).
// get 200
//then(getOneAttachmentDocument).then(getOneAttachmentDocumentTest).
// removeA b 404
//then(removeSecondAttachmentAgain).then(removeSecondAttachmentAgainTest).
// remove 204
//then(removeDocument).then(removeDocumentTest).
// getA a 404
//then(getInexistentFirstAttachment).then(getInexistentFirstAttachmentTest).
// get 404
//then(getInexistentDocument).then(getInexistentDocumentTest).
// remove 404
//then(removeInexistentDocument).then(removeInexistentDocumentTest).
// check 204
//then(checkDocument).done(checkDocumentTest).
//then(checkStorage).done(checkStorageTest).
fail
(
unexpectedError
).
always
(
start
).
always
(
server
.
restore
.
bind
(
server
));
});
}());
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