Add functional test for chained substitution

This adds a functional test for chained substitution.

For this test to pass a subtle bug had to be fixed in
the code in DocumentDict wrapper. It was possible for
instances of this class to return a NEW object when
`self.data` was invoked causing
`substitution_src.data.update(data)` to fail when
attempting to update a substitution source with updated
layered data because -- if data={} at that moment in time --
the code in DocumentDict would return a NEW object {}.

This was because `self.get('data') or {}` would return {}
on the RHS instead of self['data'] because self['data']
itself would be {} which would evaluate to false in terms
of truthiness resulting in the wrong object ref being returned...
essentially causing the update to fail. This has been
fixed.

Change-Id: I23ad0010e1d7df73e8e1a1456ba21b3e611bb0dd
This commit is contained in:
Mark Burnett 2018-03-21 13:49:51 -05:00 committed by Bryan Strassner
parent cce6ddaf6e
commit 44114dad3b
4 changed files with 109 additions and 4 deletions

View File

@ -113,7 +113,8 @@ class RenderedDocumentsResource(api_base.BaseResource):
# been pre-validated during ingestion. Documents are post-validated
# below, regardless.
document_layering = layering.DocumentLayering(
documents, substitution_sources, validate=False)
documents, substitution_sources=substitution_sources,
validate=False)
rendered_documents = document_layering.render()
except (errors.InvalidDocumentLayer,
errors.InvalidDocumentParent,

View File

@ -39,15 +39,18 @@ class DocumentDict(dict):
@property
def schema(self):
return self.get('schema') or ''
schema = self.get('schema')
return schema if schema is not None else ''
@property
def metadata(self):
return self.get('metadata') or {}
metadata = self.get('metadata')
return metadata if metadata is not None else {}
@property
def data(self):
return self.get('data') or {}
data = self.get('data')
return data if data is not None else {}
@data.setter
def data(self, value):

View File

@ -0,0 +1,51 @@
# Tests to verify "chained" substitution from document A -> B -> C
#
# 1. Purges existing data to ensure test isolation
# 2. Creates a new revision with documents in it.
# 3. Verifies first substitution (A -> B)
# 4. Verifies second substitution (B -> C)
defaults:
request_headers:
content-type: application/x-yaml
response_headers:
content-type: application/x-yaml
tests:
- name: purge
desc: Begin testing from known state.
DELETE: /api/v1.0/revisions
status: 204
response_headers: null
- name: create
desc: Create documents.
PUT: /api/v1.0/buckets/mop/documents
status: 200
data: <@resources/chained-substitution.yaml
- name: verify_intermediate_substitution
desc: Check for chained substitution
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/rendered-documents
query_parameters:
sort: schema
status: 200
query_parameters:
schema: example/Middle/v1
response_multidoc_jsonpaths:
$.`len`: 1
$.[0].data:
mid_key: original-data
- name: verify_final_substitution
desc: Check for chained substitution
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/rendered-documents
query_parameters:
sort: schema
status: 200
query_parameters:
schema: example/Dest/v1
response_multidoc_jsonpaths:
$.`len`: 1
$.[0].data:
dest_key: original-data

View File

@ -0,0 +1,50 @@
---
schema: deckhand/LayeringPolicy/v1
metadata:
schema: metadata/Control/v1
name: layering-policy
data:
layerOrder:
- one
---
schema: example/Source/v1
metadata:
schema: metadata/Document/v1
name: source
layeringDefinition:
abstract: false
layer: one
data: original-data
---
schema: example/Middle/v1
metadata:
schema: metadata/Document/v1
name: middle
layeringDefinition:
abstract: false
layer: one
substitutions:
- src:
schema: example/Source/v1
name: source
path: .
dest:
path: .mid_key
data: {}
---
schema: example/Dest/v1
metadata:
schema: metadata/Document/v1
name: dest
layeringDefinition:
abstract: false
layer: one
substitutions:
- src:
schema: example/Middle/v1
name: middle
path: .mid_key
dest:
path: .dest_key
data: {}
...