Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

NaN float values fail in gRPC tests and in console.log #3990

Open
hanlaur opened this issue Oct 16, 2024 · 1 comment
Open

NaN float values fail in gRPC tests and in console.log #3990

hanlaur opened this issue Oct 16, 2024 · 1 comment
Assignees
Labels

Comments

@hanlaur
Copy link

hanlaur commented Oct 16, 2024

Brief summary

I am trying to load test gRPC service where some inputs are arrays of floats and the arrays may contain NaNvalues.

The gRPC.Client().invoke serialization fails due toNaN value being incorrectly treated as null. Same applies to Infinity values.

Error message from the gRPC invoke:

ERRO[0000] GoError: unable to serialise request object to protocol buffer: proto: (line 1:39): invalid value for float type: null

Similar (possibly related) behavior is visible also with console.log when logging objects/arrays where NaN values get logged as null. Logging individual NaN values works fine.

k6 version

k6 v0.54.0 (go1.23.1, darwin/amd64)

OS

MacOS 14.7

Docker version and image (if applicable)

No response

Steps to reproduce the problem

Below is a simplified test demonstrating the behavior for both gRPC.Client().invoke and console.log:

test.js:

import { check } from 'k6';
import grpc from 'k6/net/grpc';

const client = new grpc.Client();
client.load(['.'], 'dummy.proto');

export default () => {
  client.connect('localhost:8081', {
    plaintext: true,
  });

  const payload = {
    single_float: NaN,
    array_float: [1.0, NaN, Infinity, -Infinity, 5.0]
  };


  // Will be logged incorrectly: {"single_float":null,"array_float":[1,null,null,null,3]}
  console.log(payload)

  // Will be logged correctly: NaN
  console.log("single float", payload.single_float)

  // Will be logged correctly
  for (let i = 0; i < payload.array_float.length; i++) {
    console.log("array", i, payload.array_float[i])
  }

  // Will fail: GoError: unable to serialise request object to protocol buffer: proto: (line 1:39): invalid value for float type: null
  const response = client.invoke('dummy.DummyService/Do', payload);

  console.log(response)

  check(response, {
    'status is OK': (r) => r && r.status === grpc.StatusOK,
    });

  client.close();
};

dummy.proto:

syntax = "proto3";

package dummy;

service DummyService
{
  rpc Do(DummyRequest) returns (DummyResponse) {}
}


message DummyRequest
{
  float single_float = 1;
  repeated float array_float = 2;
}

message DummyResponse
{
  float single_float = 1;
}

resulting log messages when executing test

INFO[0000] {"single_float":null,"array_float":[1,null,null,null,5]}  source=console
INFO[0000] single float NaN                              source=console
INFO[0000] array 0 1                                     source=console
INFO[0000] array 1 NaN                                   source=console
INFO[0000] array 2 Infinity                              source=console
INFO[0000] array 3 -Infinity                             source=console
INFO[0000] array 4 5                                     source=console
ERRO[0000] GoError: unable to serialise request object to protocol buffer: proto: (line 1:39): invalid value for float type: null

Expected behaviour

NaN value in the payload should be properly encoded as NaN float in the gRPC call and should not cause error.

Actual behaviour

NaN value in the payload causes error:
ERRO[0000] GoError: unable to serialise request object to protocol buffer: proto: (line 1:39): invalid value for float type: null

@oleiade
Copy link
Member

oleiade commented Oct 21, 2024

Thank you for reporting this to us @hanlaur 🙇🏻

I just looked into it a little bit and it would appear indeed that we apply some JSON serialization over the second argument of the invoke call under the hood:

b, err := req.ToObject(c.vu.Runtime()).MarshalJSON()

I assume the JSON marshalling treats Nan, Infinity, and -Infinity as null (which I imagine is what JSON is supposed to do), instead of maintaining the expected representation.

cc @olegbespalov

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants