Skip to content

Commit 8d10d5a

Browse files
author
Ronald Holshausen
committed
feat: got basic provider verifier working
1 parent d533bb7 commit 8d10d5a

File tree

10 files changed

+417
-79
lines changed

10 files changed

+417
-79
lines changed

examples/v3/todo/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ json2xml==3.3.2
33
pytest==5.4.2
44
pact-python==2.0.0b0
55
requests==2.23.0
6+
pytest-flask==1.1.0

examples/v3/todo/src/todo_provider.py

+45-38
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,53 @@
33
from json2xml.utils import readfromstring
44
import json
55

6-
app = Flask(__name__)
76

7+
def create_app():
8+
app = Flask(__name__)
89

9-
@app.route('/projects')
10-
def projects():
11-
todo_response = [
12-
{
13-
'id': 1,
14-
'name': "Project 1",
15-
'type': "activity",
16-
'due': "2016-02-11T09:46:56.023Z",
17-
'tasks': [
18-
{
19-
'done': True,
20-
'id': 1,
21-
'name': "Task 1",
22-
},
23-
{
24-
'done': True,
25-
'id': 2,
26-
'name': "Task 2",
27-
},
28-
{
29-
'done': True,
30-
'id': 3,
31-
'name': "Task 3",
32-
},
33-
{
34-
'done': True,
35-
'id': 4,
36-
'name': "Task 4",
37-
},
38-
]
39-
}
40-
]
41-
if request.headers['accept'] == 'application/xml':
42-
return json2xml.Json2xml(readfromstring(json.dumps(todo_response)), wrapper='projects').to_xml()
43-
else:
44-
return jsonify(todo_response)
10+
@app.route('/')
11+
def index():
12+
return ''
13+
14+
@app.route('/projects')
15+
def projects():
16+
todo_response = [
17+
{
18+
'id': 1,
19+
'name': "Project 1",
20+
'type': "activity",
21+
'due': "2016-02-11T09:46:56.023Z",
22+
'tasks': [
23+
{
24+
'done': True,
25+
'id': 1,
26+
'name': "Task 1",
27+
},
28+
{
29+
'done': True,
30+
'id': 2,
31+
'name': "Task 2",
32+
},
33+
{
34+
'done': True,
35+
'id': 3,
36+
'name': "Task 3",
37+
},
38+
{
39+
'done': True,
40+
'id': 4,
41+
'name': "Task 4",
42+
},
43+
]
44+
}
45+
]
46+
if request.headers['accept'] == 'application/xml':
47+
return json2xml.Json2xml(readfromstring(json.dumps(todo_response)), wrapper='projects').to_xml()
48+
else:
49+
return jsonify(todo_response)
50+
51+
return app
4552

4653

4754
if __name__ == '__main__':
48-
app.run(debug=True, port=5001)
55+
create_app().run(debug=True, port=5001)

examples/v3/todo/tests/provider.spec.js

-39
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pytest
2+
from ..src.todo_provider import create_app
3+
from pact import VerifierV3
4+
from flask import url_for
5+
6+
7+
@pytest.fixture(scope='session')
8+
def app():
9+
return create_app()
10+
11+
12+
@pytest.mark.usefixtures('live_server')
13+
def test_pact_verification():
14+
verifier = VerifierV3(provider='TodoServiceV3',
15+
provider_base_url=url_for('index', _external=True))
16+
assert verifier.verify_pacts(
17+
sources=['./pacts/TodoApp-TodoServiceV3.json']
18+
)
19+

pact-python-v3/Cargo.lock

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pact-python-v3/Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,20 @@ serde_json = "1.0"
2020
uuid = { version = "0.8", features = ["v4"] }
2121
lazy_static = "1.4.0"
2222
bytes = { version = "1", features = ["serde"] }
23+
url = "2.2.0"
24+
ansi_term = "0.12.1"
25+
async-trait = "0.1.24"
26+
regex = "1"
2327

2428
[dependencies.cpython]
2529
version = "0.5"
2630
features = ["extension-module"]
2731

32+
[dependencies.reqwest]
33+
version = "0.11.0"
34+
default-features = false
35+
features = ["rustls-tls"]
36+
2837
[target.x86_64-apple-darwin]
2938
rustflags = [
3039
"-C", "link-arg=-undefined",

pact-python-v3/src/lib.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::cell::RefCell;
22
use std::collections::HashMap;
33
use std::fs;
44
use std::str::FromStr;
5-
use std::sync::Mutex;
5+
use std::sync::{Mutex, Arc};
66

77
use bytes::Bytes;
88
use cpython::*;
@@ -22,6 +22,9 @@ use pact_mock_server_ffi::bodies::{process_array, process_object};
2222
use serde_json::{json, Value};
2323
use serde_json::map::Map;
2424
use uuid::Uuid;
25+
use crate::verifier::{setup_provider_config, PythonProviderStateExecutor};
26+
27+
mod verifier;
2528

2629
lazy_static! {
2730
static ref MANAGER: Mutex<ServerManager> = Mutex::new(ServerManager::new());
@@ -31,6 +34,7 @@ py_module_initializer!(pact_python_v3, |py, m| {
3134
m.add(py, "__doc__", "Pact Python V3 support (provided by Pact-Rust FFI)")?;
3235
m.add(py, "init", py_fn!(py, init_lib(*args, **kwargs)))?;
3336
m.add(py, "generate_datetime_string", py_fn!(py, generate_datetime_string(format: &str)))?;
37+
m.add(py, "verify_provider", py_fn!(py, verify_provider(*args, **kwargs)))?;
3438
m.add_class::<PactNative>(py)?;
3539
Ok(())
3640
});
@@ -501,3 +505,32 @@ fn json_to_pyobj(py: Python, val: &Value) -> PyObject {
501505
Value::Object(map) => map.iter().map(|(key, value)| (key.clone(), json_to_pyobj(py, value))).collect::<HashMap<String, PyObject>>().to_py_object(py).into_object()
502506
}
503507
}
508+
509+
fn verify_provider(
510+
py: Python,
511+
args: &PyTuple,
512+
kwargs: Option<&PyDict>
513+
) -> PyResult<PyBool> {
514+
let arg1 = args.get_item(py, 0);
515+
let provider = arg1.cast_as::<PyString>(py)?.to_string_lossy(py);
516+
let arg2 = args.get_item(py, 1);
517+
let base_url = arg2.cast_as::<PyString>(py)?.to_string_lossy(py);
518+
let arg3 = args.get_item(py, 2);
519+
let options = arg3.cast_as::<PyDict>(py)?;
520+
521+
debug!("Verifying provider '{}' running at '{}'", provider, base_url);
522+
let (provider_info, source, options, filter, consumers) = setup_provider_config(py, provider.as_ref(), base_url.as_ref(), options)?;
523+
524+
debug!("Pact sources = {:?}", source);
525+
let result = pact_verifier::verify_provider(
526+
provider_info,
527+
source,
528+
filter,
529+
consumers,
530+
options,
531+
&Arc::new(PythonProviderStateExecutor::new())
532+
);
533+
debug!("result = {}", result);
534+
535+
Ok(PyBool::get(py, result))
536+
}

0 commit comments

Comments
 (0)