Skip to content

Unit tests for the project #8

@mpmartins

Description

@mpmartins

Hey @yuval-k, Happy easter.

The more I touch this project, the more I get excited about the possibilities... :D

I wanted to open a discussion with you about the project unit tests/integration tests.

First, just wanted to say that we need to find a way to create some unit tests for the project. I couldn't find the time to study that in detail, but maybe we can use a library like https://github.com/jtenner/as-pect.

But, what I really wanted to share is that I converted your example of integration tests implemented in an HTML file to a javascript file that can be triggered using node. Take a look at my example below:

const assert = require("assert");
const fs = require("fs");
const loader = require("@assemblyscript/loader");
const util = require('util');
const utf8Decoder = new util.TextDecoder('utf-8');

/**
 * This function is used to inject values into Web Assembly VM memory.
 * 
 * @param {String} value - value to be injected into WebAssembly memory
 * @param {Number} value_ptr_ptr - pointer to the memory address that starts this variable
 * @param {Number} value_size_ptr - pointer to the memory address with variable size
 */
function injectStringIntoMemory(value, value_ptr_ptr, value_size_ptr) { 
  
  const value_size = value.length;
  let bytes = globalExports.malloc(value_size);
  if (bytes === 0) {
      throw "can't allocate";
  }

  var moduleMemory = globalExports.memory.buffer;

  var confMem = new Uint8Array(moduleMemory, bytes, value_size);
  for(let i = 0; i < value_size; i++){
      confMem[i]=value.charCodeAt(i);
  }

  var confPtr = new Uint32Array(moduleMemory, value_ptr_ptr, 1);
  confPtr[0] = bytes;
  var confSizePtr = new Uint32Array(moduleMemory, value_size_ptr, 1);
  confSizePtr[0] = value_size;

  console.info("injectStringIntoMemory: " + value + " to " + value_ptr_ptr + ":" + value_size_ptr);
}

//Mocks and hardcoded values
const root_id_string = "expo_filter_root_id"
const config = "expo_filter_configuration_value1";

const imports = {
  wasi_unstable: {
    proc_exit: console.trace
  },
  env: {
    memory: new WebAssembly.Memory({
      initial: 1,
      maximum: 1
    }),
    abort: console.trace,
    proxy_log(level, logMessage, messageSize) {
      var mem = new Uint8Array(globalExports.memory.buffer);
      let buf = mem.slice(logMessage, logMessage + messageSize);
      let msg = "proxy_log: " + utf8Decoder.decode(buf);
      switch(level) { 
        case 1: { 
          console.debug(msg); 
          break; 
        } 
        case 2: { 
          console.info(msg);
          break; 
        } 
        case 3: { 
          console.warn(msg);
          break; 
        } 
        case 4: { 
          console.error(msg);
          break; 
        } 
        default: { 
          console.trace(msg); 
          break; 
        } 
      }
      return 0;
    },
    proxy_get_configuration(configuration_ptr, configuration_size) {
      console.debug("proxy_get_configuration: " + config + ":" + configuration_ptr + ":" + configuration_size);
      injectStringIntoMemory(config, configuration_ptr, configuration_size);
      return config;
    },
    proxy_get_property(path_ptr, path_size, value_ptr_ptr, value_size_ptr) { 
      // we only support one property now, the root id.
      const prop = root_id_string;
      console.debug("proxy_get_property: " + prop + ":" + path_ptr + "-" + path_size + ":" + value_ptr_ptr + "-" + value_size_ptr);
      injectStringIntoMemory(prop, value_ptr_ptr, value_size_ptr);
      return prop;
    },
    proxy_get_status: console.trace,
    proxy_set_tick_period_milliseconds: console.trace,
    proxy_get_current_time_nanoseconds: console.trace,
    proxy_set_property: console.trace,
    proxy_continue_request: console.trace,
    proxy_continue_response: console.trace,
    proxy_send_local_response: console.trace,
    proxy_clear_route_cache: console.trace,
    proxy_get_shared_data: console.trace,
    proxy_set_shared_data: console.trace,
    proxy_register_shared_queue: console.trace,
    proxy_resolve_shared_queue: console.trace,
    proxy_dequeue_shared_queue: console.trace,
    proxy_enqueue_shared_queue: console.trace,
    proxy_add_header_map_value: console.trace,
    proxy_get_header_map_value: console.trace,
    proxy_get_header_map_pairs: console.trace,
    proxy_set_header_map_pairs: console.trace,
    proxy_replace_header_map_value: console.trace,
    proxy_remove_header_map_value: console.trace,
    proxy_get_header_map_size: console.trace,
    proxy_get_buffer_bytes: console.trace,
    proxy_get_buffer_status: console.trace,
    proxy_http_call: console.trace,
    proxy_grpc_call: console.trace,
    proxy_grpc_stream: console.trace,
    proxy_grpc_cancel: console.trace,
    proxy_grpc_close: console.trace,
    proxy_grpc_send: console.trace,
    proxy_define_metric: console.trace,
    proxy_increment_metric: console.trace,
    proxy_record_metric: console.trace,
    proxy_get_metric: console.trace,
    proxy_set_effective_context: console.trace,
    proxy_done: console.trace
  }
}

/**
 * Simple Unit test to check if the Filter can be initialized using wasm and making calls the proxy makes to initialize them.
 */
function testModuleLoading() {
  var wasm = loader.instantiateSync(fs.readFileSync(__dirname + "/../build/untouched.wasm"), imports);

  let exports = wasm;
  globalExports = exports;
  let context_id = 0;
  const root_context_id = context_id++;

  // Proxy calling Filter to initialize context
  exports.proxy_on_context_create(context_id, root_context_id);

  // Proxy calling Filter when VM is starting
  assert(exports.proxy_on_vm_start(context_id, root_context_id) === 1, "Failed to start VM.");

  // Initializing Filter
  assert(exports.proxy_on_configure(context_id++, config.length) === 1, "Failed to start filter"); 

  fs.writeFileSync("tests/memory.dump", new DataView(exports.memory.buffer, 0, exports.memory.buffer.byteLength));

  //Trying to trigger a request to the filter
  //const headers = [{"x-wmt-expo":"test"}];
  //exports.proxy_on_context_create(context_id, root_context_id);
  //let result = exports.proxy_on_request_headers(context_id, null);
  //console.log(result);
};

testModuleLoading();

This way, we can trigger the tests by just running the "node tests" command.

Thanks,
Mario

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions