Unable to serialise request object to protocol buffer:

I am getting the serialisation error when sending the following data as a payload to the gRPC request.

Sample Test:

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

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

export default () => {
  client.connect('host-eu-west-1.amazonaws.com:9008', {
    plaintext: true
  });

  const data = {
    "key": {
    "name": "Hello",
    "path": "0"
    },
    "hash": [72,
          101,
          108,
          108,
          111,
          72,
          101,
          108,
          108,
          111,
          72,
          101,
          108,
          108,
          111,
          72,
          101,
          108,
          108,
          111,
          72,
          101,
          108,
          108,
          111,
          72,
          101,
          108,
          108,
          111,
          10,
          12]
    };

  const response = client.invoke('proto.Service/SignIn', data);

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


  console.log(JSON.stringify(response.message));

  client.close();
  sleep(1);
};

Example Proto

message Request {
  key key = 1;
  bytes hash = 2; // array of bytes containing the hash you wish to sign
}

message Response {
  bytes sign = 1; // array of bytes containing signature of the hash
  bytes public = 2; // array of bytes containing the public key
}

And the error response I am getting is

ERRO[0000] unable to serialise request object to protocol buffer: proto: (line 1:52): invalid value for bytes type: [
        at go.k6.io/k6/js/common.Bind.func1 (native)
        at file:///Users/ven/Documents/k6-grpc/signintestdebug.js:59:66(88)  executor=per-vu-iterations scenario=default source=stacktrace

Hello @VenQA

This was an interesting question! It appears that one must be careful around encodings when using bytes type. After some experimenting, here’s what worked for me with the mock service:

import { b64encode } from 'k6/encoding';
// ... 
    var bytes = [72,
        101,
        108,
        108,
        111,
        72,
        101,
        108,
        108,
        111,
        72,
        101,
        108,
        108,
        111,
        72,
        101,
        108,
        108,
        111,
        72,
        101,
        108,
        108,
        111,
        72,
        101,
        108,
        108,
        111,
        10,
        12];
    var hash = "";
    for (var i = 0; i < bytes.length; i++) {
        hash += String.fromCharCode(bytes[i]);
    }
    console.log(hash)
    const data = {
        "key": {
            "name": "Hello",
            "path": "0"
        },
        "hash": b64encode(hash)
    };

I think if you have your input in strings, you can omit conversion from bytes to string too? I kept that only because I wanted to use your input array, just in case. In other words, a simple string + base64 encoding should suffice for correct processing by gRPC.

Also, in case bytes would be easier, it is possible to also use ArrayBuffer and similar structs as well. For example:

    let hash = new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]).buffer;
    const data = {
        "key": {
            "name": "Hello",
            "path": "0"
        },
        "hash": b64encode(hash)
    };

Additional info on base64 in k6 is here: https://k6.io/docs/javascript-api/k6-encoding/b64encode-input-encoding/

1 Like

Hi @olha
Successfully submitted the request with your solution.
Many thanks.

@olha
Would it be possible to decode the response to buffer type?
The response I am getting is

INFO[0000] {"signature":"MEUCIQDz5zCfFlKyi2DWMJaJ4MFg4u6uNKJUcdJLFdexRzxVPQIgPQrADNuXZfdHdypTV1MxHwhmYZUUnkwYWpYj4YwNXUQ=","publicKey":"A42XeZWd8dcKe1VjLH3WvrKrU/0Ek2Fxa7eBXiyPj3bX"}  source=console

But the response I am expecting is

{
  "signature": {
    "type": "Buffer",
    "data": [
      48,
      68,
      2,
      32,
      108,
      192,
      126,
      80,
      69,
      41,
      31,
      32,
      21,
      212,
      11,
      25,
      145,
      102,
      160,
      209,
      38,
      169,
      41,
      248,
      126,
      252,
      93,
      166,
      12,
      14,
      143,
      11,
      25,
      91,
      126,
      34,
      2,
      32,
      90,
      117,
      233,
      120,
      191,
      174,
      179,
      191,
      241,
      11,
      69,
      22,
      15,
      240,
      133,
      200,
      25,
      115,
      17,
      231,
      24,
      232,
      241,
      188,
      71,
      137,
      212,
      49,
      107,
      19,
      123,
      37
    ]
  },
  "public_key": {
    "type": "Buffer",
    "data": [
      3,
      141,
      151,
      121,
      149,
      157,
      241,
      215,
      10,
      123,
      85,
      99,
      44,
      125,
      214,
      190,
      178,
      171,
      83,
      253,
      4,
      147,
      97,
      113,
      107,
      183,
      129,
      94,
      44,
      143,
      143,
      118,
      215
    ]
  }
}

Thank you

@VenQA I think you can simply use b64decode function for a reverse operation on the returned values; smth like:

let dec = new Uint8Array(b64decode(res.signature));
const iterator = dec.values();
for (const value of iterator) {
   console.log(value);
}

@olha Thank you for your help.

1 Like