@@ -180,6 +180,158 @@ describe('PATCH', () => {
180180 } )
181181 } )
182182
183+ describe ( 'inserting (= append with WHERE)' , ( ) => {
184+ describe ( 'on a resource with read-only access' , ( ) => {
185+ it ( 'returns a 403' , ( ) =>
186+ request . patch ( '/read-only.ttl' )
187+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
188+ . set ( 'Content-Type' , 'text/n3' )
189+ . send ( n3Patch ( `
190+ <> p:patches <https://tim.localhost:7777/read-only.ttl>;
191+ p:insert { ?a <y> <z>. };
192+ p:where { ?a <b> <c>. }.`
193+ ) )
194+ . expect ( 403 )
195+ . then ( response => {
196+ assert . include ( response . text , 'Access denied' )
197+ } )
198+ )
199+
200+ it ( 'does not modify the file' , ( ) => {
201+ assert . equal ( read ( 'patch/read-only.ttl' ) ,
202+ '<a> <b> <c>.\n<d> <e> <f>.\n' )
203+ } )
204+ } )
205+
206+ describe ( 'on a non-existing file' , ( ) => {
207+ after ( ( ) => rm ( 'patch/new.ttl' ) )
208+
209+ it ( 'returns a 409' , ( ) =>
210+ request . patch ( '/new.ttl' )
211+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
212+ . set ( 'Content-Type' , 'text/n3' )
213+ . send ( n3Patch ( `
214+ <> p:patches <https://tim.localhost:7777/new.ttl>;
215+ p:insert { ?a <y> <z>. };
216+ p:where { ?a <b> <c>. }.`
217+ ) )
218+ . expect ( 409 )
219+ . then ( response => {
220+ assert . include ( response . text , 'The patch could not be applied' )
221+ } )
222+ )
223+
224+ it ( 'does not create the file' , ( ) => {
225+ assert . isFalse ( fs . existsSync ( 'patch/new.ttl' ) )
226+ } )
227+ } )
228+
229+ describe . skip ( 'on a resource with append-only access' , ( ) => {
230+ before ( ( ) => backup ( 'patch/append-only.ttl' ) )
231+ after ( ( ) => restore ( 'patch/append-only.ttl' ) )
232+
233+ it ( 'returns a 403' , ( ) =>
234+ request . patch ( '/append-only.ttl' )
235+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
236+ . set ( 'Content-Type' , 'text/n3' )
237+ . send ( n3Patch ( `
238+ <> p:patches <https://tim.localhost:7777/append-only.ttl>;
239+ p:insert { ?a <y> <z>. };
240+ p:where { ?a <b> <c>. }.`
241+ ) )
242+ . expect ( 403 )
243+ . then ( response => {
244+ assert . include ( response . text , 'Access denied' )
245+ } )
246+ )
247+
248+ it ( 'does not modify the file' , ( ) => {
249+ assert . equal ( read ( 'patch/append-only.ttl' ) ,
250+ '<a> <b> <c>.\n<d> <e> <f>.\n' )
251+ } )
252+ } )
253+
254+ describe . skip ( 'on a resource with write-only access' , ( ) => {
255+ before ( ( ) => backup ( 'patch/write-only.ttl' ) )
256+ after ( ( ) => restore ( 'patch/write-only.ttl' ) )
257+
258+ // Allowing the delete would either return 200 or 409,
259+ // thereby incorrectly giving the user (guess-based) read access;
260+ // therefore, we need to return 403.
261+ it ( 'returns a 403' , ( ) =>
262+ request . patch ( '/write-only.ttl' )
263+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
264+ . set ( 'Content-Type' , 'text/n3' )
265+ . send ( n3Patch ( `
266+ <> p:patches <https://tim.localhost:7777/write-only.ttl>;
267+ p:insert { ?a <y> <z>. };
268+ p:where { ?a <b> <c>. }.`
269+ ) )
270+ . expect ( 403 )
271+ . then ( response => {
272+ assert . include ( response . text , 'Access denied' )
273+ } )
274+ )
275+
276+ it ( 'does not modify the file' , ( ) => {
277+ assert . equal ( read ( 'patch/append-only.ttl' ) ,
278+ '<a> <b> <c>.\n<d> <e> <f>.\n' )
279+ } )
280+ } )
281+
282+ describe ( 'on a resource with read-write access' , ( ) => {
283+ describe ( 'with a matching WHERE clause' , ( ) => {
284+ before ( ( ) => backup ( 'patch/read-write.ttl' ) )
285+ after ( ( ) => restore ( 'patch/read-write.ttl' ) )
286+
287+ it ( 'returns a 200' , ( ) =>
288+ request . patch ( '/read-write.ttl' )
289+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
290+ . set ( 'Content-Type' , 'text/n3' )
291+ . send ( n3Patch ( `
292+ <> p:patches <https://tim.localhost:7777/read-write.ttl>;
293+ p:where { ?a <b> <c>. };
294+ p:insert { ?a <y> <z>. }.`
295+ ) )
296+ . expect ( 200 )
297+ . then ( response => {
298+ assert . include ( response . text , 'Patch applied successfully' )
299+ } )
300+ )
301+
302+ it ( 'patches the file' , ( ) => {
303+ assert . equal ( read ( 'patch/read-write.ttl' ) ,
304+ '@prefix : </read-write.ttl#>.\n@prefix tim: </>.\n\ntim:a tim:b tim:c; tim:y tim:z.\n\ntim:d tim:e tim:f.\n\n' )
305+ } )
306+ } )
307+
308+ describe ( 'with a non-matching WHERE clause' , ( ) => {
309+ before ( ( ) => backup ( 'patch/read-write.ttl' ) )
310+ after ( ( ) => restore ( 'patch/read-write.ttl' ) )
311+
312+ it ( 'returns a 409' , ( ) =>
313+ request . patch ( '/read-write.ttl' )
314+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
315+ . set ( 'Content-Type' , 'text/n3' )
316+ . send ( n3Patch ( `
317+ <> p:patches <https://tim.localhost:7777/read-write.ttl>;
318+ p:where { ?a <y> <z>. };
319+ p:insert { ?a <s> <t>. }.`
320+ ) )
321+ . expect ( 409 )
322+ . then ( response => {
323+ assert . include ( response . text , 'The patch could not be applied' )
324+ } )
325+ )
326+
327+ it ( 'does not change the file' , ( ) => {
328+ assert . equal ( read ( 'patch/read-write.ttl' ) ,
329+ '<a> <b> <c>.\n<d> <e> <f>.\n' )
330+ } )
331+ } )
332+ } )
333+ } )
334+
183335 describe ( 'deleting' , ( ) => {
184336 describe ( 'on a resource with read-only access' , ( ) => {
185337 it ( 'returns a 403' , ( ) =>
@@ -323,10 +475,60 @@ describe('PATCH', () => {
323475 '<a> <b> <c>.\n<d> <e> <f>.\n' )
324476 } )
325477 } )
478+
479+ describe ( 'with a matching WHERE clause' , ( ) => {
480+ before ( ( ) => backup ( 'patch/read-write.ttl' ) )
481+ after ( ( ) => restore ( 'patch/read-write.ttl' ) )
482+
483+ it ( 'returns a 200' , ( ) =>
484+ request . patch ( '/read-write.ttl' )
485+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
486+ . set ( 'Content-Type' , 'text/n3' )
487+ . send ( n3Patch ( `
488+ <> p:patches <https://tim.localhost:7777/read-write.ttl>;
489+ p:where { ?a <b> <c>. };
490+ p:delete { ?a <b> <c>. }.`
491+ ) )
492+ . expect ( 200 )
493+ . then ( response => {
494+ assert . include ( response . text , 'Patch applied successfully' )
495+ } )
496+ )
497+
498+ it ( 'patches the file' , ( ) => {
499+ assert . equal ( read ( 'patch/read-write.ttl' ) ,
500+ '@prefix : </read-write.ttl#>.\n@prefix tim: </>.\n\ntim:d tim:e tim:f.\n\n' )
501+ } )
502+ } )
503+
504+ describe ( 'with a non-matching WHERE clause' , ( ) => {
505+ before ( ( ) => backup ( 'patch/read-write.ttl' ) )
506+ after ( ( ) => restore ( 'patch/read-write.ttl' ) )
507+
508+ it ( 'returns a 409' , ( ) =>
509+ request . patch ( '/read-write.ttl' )
510+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
511+ . set ( 'Content-Type' , 'text/n3' )
512+ . send ( n3Patch ( `
513+ <> p:patches <https://tim.localhost:7777/read-write.ttl>;
514+ p:where { ?a <y> <z>. };
515+ p:delete { ?a <b> <c>. }.`
516+ ) )
517+ . expect ( 409 )
518+ . then ( response => {
519+ assert . include ( response . text , 'The patch could not be applied' )
520+ } )
521+ )
522+
523+ it ( 'does not change the file' , ( ) => {
524+ assert . equal ( read ( 'patch/read-write.ttl' ) ,
525+ '<a> <b> <c>.\n<d> <e> <f>.\n' )
526+ } )
527+ } )
326528 } )
327529 } )
328530
329- describe ( 'deleting and inserting' , ( ) => {
531+ describe ( 'deleting and appending/ inserting' , ( ) => {
330532 describe ( 'on a resource with read-only access' , ( ) => {
331533 it ( 'returns a 403' , ( ) =>
332534 request . patch ( '/read-only.ttl' )
@@ -426,6 +628,21 @@ describe('PATCH', () => {
426628 } )
427629
428630 describe ( 'on a resource with read-write access' , ( ) => {
631+ it ( 'executes deletes before inserts' , ( ) =>
632+ request . patch ( '/read-write.ttl' )
633+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
634+ . set ( 'Content-Type' , 'text/n3' )
635+ . send ( n3Patch ( `
636+ <> p:patches <https://tim.localhost:7777/read-write.ttl>;
637+ p:insert { <x> <y> <z>. };
638+ p:delete { <x> <y> <z>. }.`
639+ ) )
640+ . expect ( 409 )
641+ . then ( response => {
642+ assert . include ( response . text , 'The patch could not be applied' )
643+ } )
644+ )
645+
429646 describe ( 'with a patch for existing data' , ( ) => {
430647 before ( ( ) => backup ( 'patch/read-write.ttl' ) )
431648 after ( ( ) => restore ( 'patch/read-write.ttl' ) )
@@ -436,8 +653,8 @@ describe('PATCH', () => {
436653 . set ( 'Content-Type' , 'text/n3' )
437654 . send ( n3Patch ( `
438655 <> p:patches <https://tim.localhost:7777/read-write.ttl>;
439- p:insert { <x> <y> <z>. };
440- p:delete { <a> <b> <c>. }.`
656+ p:insert { <x> <y> <z>. };
657+ p:delete { <a> <b> <c>. }.`
441658 ) )
442659 . expect ( 200 )
443660 . then ( response => {
@@ -461,8 +678,8 @@ describe('PATCH', () => {
461678 . set ( 'Content-Type' , 'text/n3' )
462679 . send ( n3Patch ( `
463680 <> p:patches <https://tim.localhost:7777/read-write.ttl>;
464- p:insert { <x> <y> <z>. };
465- p:delete { <q> <s> <s>. }.`
681+ p:insert { <x> <y> <z>. };
682+ p:delete { <q> <s> <s>. }.`
466683 ) )
467684 . expect ( 409 )
468685 . then ( response => {
@@ -476,20 +693,57 @@ describe('PATCH', () => {
476693 } )
477694 } )
478695
479- it ( 'executes deletes before inserts' , ( ) =>
480- request . patch ( '/read-write.ttl' )
481- . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
482- . set ( 'Content-Type' , 'text/n3' )
483- . send ( n3Patch ( `
484- <> p:patches <https://tim.localhost:7777/read-write.ttl>;
485- p:insert { <x> <y> <z>. };
486- p:delete { <x> <y> <z>. }.`
487- ) )
488- . expect ( 409 )
489- . then ( response => {
490- assert . include ( response . text , 'The patch could not be applied' )
491- } )
696+ describe ( 'with a matching WHERE clause' , ( ) => {
697+ before ( ( ) => backup ( 'patch/read-write.ttl' ) )
698+ after ( ( ) => restore ( 'patch/read-write.ttl' ) )
699+
700+ it ( 'returns a 200' , ( ) =>
701+ request . patch ( '/read-write.ttl' )
702+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
703+ . set ( 'Content-Type' , 'text/n3' )
704+ . send ( n3Patch ( `
705+ <> p:patches <https://tim.localhost:7777/read-write.ttl>;
706+ p:where { ?a <b> <c>. };
707+ p:insert { ?a <y> <z>. };
708+ p:delete { ?a <b> <c>. }.`
709+ ) )
710+ . expect ( 200 )
711+ . then ( response => {
712+ assert . include ( response . text , 'Patch applied successfully' )
713+ } )
492714 )
715+
716+ it ( 'patches the file' , ( ) => {
717+ assert . equal ( read ( 'patch/read-write.ttl' ) ,
718+ '@prefix : </read-write.ttl#>.\n@prefix tim: </>.\n\ntim:a tim:y tim:z.\n\ntim:d tim:e tim:f.\n\n' )
719+ } )
720+ } )
721+
722+ describe ( 'with a non-matching WHERE clause' , ( ) => {
723+ before ( ( ) => backup ( 'patch/read-write.ttl' ) )
724+ after ( ( ) => restore ( 'patch/read-write.ttl' ) )
725+
726+ it ( 'returns a 409' , ( ) =>
727+ request . patch ( '/read-write.ttl' )
728+ . set ( 'Authorization' , `Bearer ${ userCredentials } ` )
729+ . set ( 'Content-Type' , 'text/n3' )
730+ . send ( n3Patch ( `
731+ <> p:patches <https://tim.localhost:7777/read-write.ttl>;
732+ p:where { ?a <y> <z>. };
733+ p:insert { ?a <y> <z>. };
734+ p:delete { ?a <b> <c>. }.`
735+ ) )
736+ . expect ( 409 )
737+ . then ( response => {
738+ assert . include ( response . text , 'The patch could not be applied' )
739+ } )
740+ )
741+
742+ it ( 'does not change the file' , ( ) => {
743+ assert . equal ( read ( 'patch/read-write.ttl' ) ,
744+ '<a> <b> <c>.\n<d> <e> <f>.\n' )
745+ } )
746+ } )
493747 } )
494748 } )
495749} )
0 commit comments