Hello Team! I have a new question about the Config...
# pact-plugins
a
Hello Team! I have a new question about the Configure Interaction request and numeric data types. When a user creates a contract with a definition such as:
Copy code
"request": { "id": 1 },
The configure interaction request receives a payload like this:
Copy code
"request": Value { kind: Some(StructValue(Struct { fields: {"id": Value { kind: Some(NumberValue(1.0)) } } })) }
Now in the contract the the value to match against is
1.0
and not
1
. In the consumer test a message is sent to the mock server with the payload:
Copy code
{
  "id": 1
}
When the mock server receives this request we try to match against all interactions in the pact but we get a mismatch for this field as:
Copy code
1.1) [$.id] Expected '0.0' to be equal to '0'
I have been trying to debug and fix this issue and it looks to me like the following is happening: 1. The pact framework is taking the consumer contract and converting it to a protobuf payload to send to the plugin 2. This process converted the id field to a Value:Kind:Number(&f64) 3. In the plugin we decode the protobuf payload using
proto_value_to_json
(I think I took this directly from your protobuf plugin) and for a number Kind it runs:
serde_json::json!(n)
4. serde is seeing the f64 and creating a Value::Number(Number::Float)) 5. So now we have lost the information that the original number was an int and not a float and our comparison fails when we receive an int It seems to me that serde has a good way of handling the different number types but the prost_types definition of
Kind::NumberValue(f64),
is reducing the amount of information that can be conveyed to the plugin about a numeric field during the configure interaction request. I had a search online around protobuf number types and it looked like different types of numbers are supported so I'm not understanding why prost_types treats all numbers as floats. I am not very familiar with protobuf at all though so I probably am just missing something. In the mean time we are encouraging the users to define the contract as
{ "id": "matching(integer, 1)" }
but I think it should be possible for them to just specify the contract as
{ "id": 1 }
and have it work. This did work when we were using the core application/json matcher but I am assuming that is because the type information is not lost when passing the values around in rust.
u
Ah, right! That's because this is the proto definition for Struct:
Copy code
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of these
// variants. Absence of any variant indicates an error.
//
// The JSON representation for `Value` is JSON value.
message Value {
  // The kind of value.
  oneof kind {
    // Represents a null value.
    NullValue null_value = 1;
    // Represents a double value.
    double number_value = 2;
    // Represents a string value.
    string string_value = 3;
    // Represents a boolean value.
    bool bool_value = 4;
    // Represents a structured value.
    Struct struct_value = 5;
    // Represents a repeated `Value`.
    ListValue list_value = 6;
  }
}
Numbers are represented with doubles.
😆 1
I'll need to think about how to deal with this.
m
Looks like we’re running into problem #5 😛
(kind of, I suppose technically in this case protobuf does support other number types)