Skip to content

Commit

Permalink
feat: handle the parameters and results from provider state callbacks #…
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed Mar 12, 2020
1 parent 50e4e61 commit d3f73e5
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 41 deletions.
2 changes: 1 addition & 1 deletion examples/v3/e2e/package.json
Expand Up @@ -6,7 +6,7 @@
"test": "npm run test:consumer && npm run test:publish && npm run test:provider",
"test:consumer": "./node_modules/.bin/mocha test/consumer.spec.js",
"test:publish": "node test/publish.js",
"test:provider": "LOG_LEVEL=debug RUST_BACKTRACE=1 ./node_modules/.bin/mocha test/provider.spec.js",
"test:provider": "LOG_LEVEL=info ./node_modules/.bin/mocha test/provider.spec.js",
"can-i-deploy": "npm run can-i-deploy:consumer && npm run can-i-deploy:provider",
"can-i-deploy:consumer": "$(find ../../ -name pact-broker | grep -e 'bin/pact-broker$' | head -n 1) can-i-deploy --pacticipant 'Matching Service' --latest --broker-base-url https://test.pact.dius.com.au --broker-username dXfltyFMgNOFZAxr8io9wJ37iUpY42M --broker-password O5AIZWxelWbLvqMd8PkAVycBJh2Psyg1",
"can-i-deploy:provider": "$(find ../../ -name pact-broker | grep -e 'bin/pact-broker$' | head -n 1) can-i-deploy --pacticipant 'Animal Profile Service' --latest --broker-base-url https://test.pact.dius.com.au --broker-username dXfltyFMgNOFZAxr8io9wJ37iUpY42M --broker-password O5AIZWxelWbLvqMd8PkAVycBJh2Psyg1",
Expand Down
1 change: 1 addition & 0 deletions examples/v3/e2e/provider.js
Expand Up @@ -17,6 +17,7 @@ server.use((req, res, next) => {
})

server.use((req, res, next) => {
console.log(req.headers)
const token = req.headers["authorization"] || ""

if (token !== "Bearer 1234") {
Expand Down
38 changes: 20 additions & 18 deletions examples/v3/e2e/test/provider.spec.js
Expand Up @@ -32,27 +32,29 @@ describe("Pact Verification", () => {
},

stateHandlers: {
"Has no animals": () => {
console.log('Has no animals called')
animalRepository.clear()
token = "1234"
return Promise.resolve({description: `Animals removed to the db`})
"Has no animals": (setup) => {
if (setup) {
animalRepository.clear()
token = "1234"
return Promise.resolve({description: `Animals removed to the db`})
}
},
"Has some animals": () => {
console.log('Has some animals called')
token = "1234"
importData()
return Promise.resolve({description: `Animals added to the db`, count: animalRepository.count()})
"Has some animals": (setup) => {
if (setup) {
token = "1234"
importData()
return Promise.resolve({description: `Animals added to the db`, count: animalRepository.count()})
}
},
"Has an animal with ID": (parameters) => {
console.log('Has an animal with ID ' + parameters.id + ' called')
token = "1234"
importData()
animalRepository.first().id = parameters.id
return Promise.resolve({description: `Animal with ID ${parameters.id} added to the db`, id: parameters.id})
"Has an animal with ID": (setup, parameters) => {
if (setup) {
token = "1234"
importData()
animalRepository.first().id = parameters.id
return Promise.resolve({description: `Animal with ID ${parameters.id} added to the db`, id: parameters.id})
}
},
"is not authenticated": () => {
console.log('is not authenticated')
"is not authenticated": (setup) => {
token = ""
return Promise.resolve({description: `Invalid bearer token generated`})
},
Expand Down
1 change: 0 additions & 1 deletion src/v3/native/src/utils.rs
@@ -1,6 +1,5 @@
use serde_json::Value;
use neon::prelude::*;
use neon::handle::Managed;

pub fn serde_value_to_js_object_attr<'a>(cx: &mut TaskContext, obj: &Handle<'a, JsObject>, key: &String, value: &Value) -> Result<bool, neon::result::Throw> {
match value {
Expand Down
58 changes: 37 additions & 21 deletions src/v3/native/src/verify.rs
Expand Up @@ -46,9 +46,9 @@ impl RequestFilterExecutor for RequestFilterCallback {
let vars = JsArray::new(cx, v.len() as u32);
v.iter().enumerate().for_each(|(i, val)| {
let qval = cx.string(val);
vars.set(cx, i as u32, qval);
vars.set(cx, i as u32, qval).unwrap();
});
js_query.set(cx, k.as_str(), vars);
js_query.set(cx, k.as_str(), vars).unwrap();
});
};

Expand All @@ -57,17 +57,17 @@ impl RequestFilterExecutor for RequestFilterCallback {
let vars = JsArray::new(cx, v.len() as u32);
v.iter().enumerate().for_each(|(i, val)| {
let hval = cx.string(val);
vars.set(cx, i as u32, hval);
vars.set(cx, i as u32, hval).unwrap();
});
js_headers.set(cx, k.as_str(), vars);
js_headers.set(cx, k.as_str(), vars).unwrap();
});
};

js_request.set(cx, "method", js_method);
js_request.set(cx, "path", js_path);
js_request.set(cx, "headers", js_headers);
js_request.set(cx, "query", js_query);
js_request.set(cx, "body", js_body);
js_request.set(cx, "method", js_method).unwrap();
js_request.set(cx, "path", js_path).unwrap();
js_request.set(cx, "headers", js_headers).unwrap();
js_request.set(cx, "query", js_query).unwrap();
js_request.set(cx, "body", js_body).unwrap();
let args = vec![js_request];
let result = callback.call(cx, this, args);

Expand Down Expand Up @@ -121,7 +121,7 @@ impl RequestFilterExecutor for RequestFilterCallback {
request.headers = Some(map)
}

sender.send(request);
sender.send(request).unwrap();
} else {
error!("Request filter did not return an object");
}
Expand All @@ -148,21 +148,37 @@ impl ProviderStateExecutor for ProviderStateCallback<'_> {
Some(callback) => {
let (sender, receiver) = mpsc::channel();
let state = provider_state.clone();
let iid = interaction_id.clone();
let result = callback.schedule_with(move |cx, this, callback| {
let args = if state.params.is_empty() {
vec![]
} else {
let args = if !state.params.is_empty() {
let js_parameter = JsObject::new(cx);
for (ref parameter, ref value) in state.params {
serde_value_to_js_object_attr(cx, &js_parameter, parameter, value);
serde_value_to_js_object_attr(cx, &js_parameter, parameter, value).unwrap();
};
vec![js_parameter]
vec![cx.boolean(setup).upcast::<JsValue>(), js_parameter.upcast::<JsValue>()]
} else {
vec![cx.boolean(setup).upcast::<JsValue>()]
};
let callback_result = callback.call(cx, this, args);
match callback_result {
Ok(val) => {
sender.send(Ok(hashmap!{})).unwrap();
},
Err(err) => {
error!("Provider state callback for '{}' failed: {}", state.name, err);
let error = ProviderStateError { description: format!("Provider state callback for '{}' failed: {}", state.name, err), interaction_id: iid };
sender.send(Result::<HashMap<String, serde_json::Value>, ProviderStateError>::Err(error)).unwrap();
}
};
let result = callback.call(cx, this, args);

});
match receiver.recv_timeout(Duration::from_millis(1000)) {
Ok(result) => Ok(result),
Ok(result) => {
debug!("Received {:?} from callback", result);
match result {
Ok(result) => Ok(hashmap!{}),
Err(err) => Err(err)
}
},
Err(_) => Err(ProviderStateError { description: format!("Provider state callback for '{}' timed out after 1000 ms", provider_state.name), interaction_id })
}
},
Expand Down Expand Up @@ -286,9 +302,9 @@ pub fn verify_provider(mut cx: FunctionContext) -> JsResult<JsUndefined> {
};

let request_filter = match config.get(&mut cx, "requestFilter") {
Ok(requestFilter) => match requestFilter.downcast::<JsFunction>() {
Ok(request_filter) => match request_filter.downcast::<JsFunction>() {
Ok(val) => {
let mut this = cx.this();
let this = cx.this();
Some(Box::new(RequestFilterCallback { callback_handler: EventHandler::new(&cx, this, val) }))
},
Err(_) => None
Expand All @@ -300,7 +316,7 @@ pub fn verify_provider(mut cx: FunctionContext) -> JsResult<JsUndefined> {
match config.get(&mut cx, "stateHandlers") {
Ok(state_handlers) => match state_handlers.downcast::<JsObject>() {
Ok(state_handlers) => {
let mut this = cx.this();
let this = cx.this();
let props = state_handlers.get_own_property_names(&mut cx).unwrap();
for prop in props.to_vec(&mut cx).unwrap() {
let prop_name = prop.downcast::<JsString>().unwrap().value();
Expand Down

0 comments on commit d3f73e5

Please sign in to comment.