# QC tests

## Introduction

QC tests are defined and parametrised out of source in YAML files. In the project definition file, the `qc.definitions` and `qc.parameters` keys point to, respectively, the definition and parametrisation files for the QCs to be applied to a given project.

Different QCs may be defined for different projects by saving them to separate definition files; conversely, the same QCs may be reused across projects.

The parameters for each QC test are saved to a separate file. This is to allow QCs to be reused across projects, possibly with different parameters.

## Running

For all projects that have QCs defined, the tests can be run by calling the [`lib/www/server/lib/qc.js`](/lib/www/server/lib/qc.js) script. This can be done from a cronjob, e.g.,:

```cron
# max-old-space-size increases the memory available to Node.js, to deal with complicated tests or large projects.
*/5 * * * * NODE_OPTIONS="--max-old-space-size=4096" node $HOME/software/lib/www/server/lib/qc.js >/dev/null

```

## QC definition file

The QC definition YAML file should consist of a list of tests. These may be organised hierarchically if the user wishes to do so.

A QC definition consists of the following attributes:

Attribute     | Description
--------------|-------------
`name`        | A short name for the test or hierarchical group.
`description` | A more detailed description. Markdown is accepted.
`disabled`    | If `true`, the test or branch will not be run.
`iterate`     | What to iterate over. It can take one of three values: `shots`, `sequences` or `lines`. If not present it defaults to `shots`, which means the script will be called once per every shot in the prospect.
`labels`      | Array of labels to apply to the test or to the branch.
`children`    | Any element having a `children` attribute becomes a branch. The contents of this attribute are a list of tests or branches, same as the top-level list.
`check`       | A script consisting of JavaScript code which defines the test that is to be run. Tests that pass should return **`true`** whereas failing tests should return a string with a message describing the failure. Note that it is valid to have both `check` and `children` in the same item.

### Test definitions

Tests can be defined as arbitrary JavaScript, which will be run in a sandbox. The sandboxed code does not have access to the filesystem or the `console` object.

The result of the test is the last expression evaluated by the script. This should be the primitive **`true`** if the test is successful, or a string describing the failure if it is not.

The script has access to the following variables:

#### `parameters`

An object containing all the parameter definitions for the project, for instance:

```javascript
{
  gunDepth: 6,
  gunDepthTolerance: 0.5,
  gunTiming: 0.9999,
  gunTimingSubarrayAverage: 0.5,
  gunPressureNominal: 2000,
  gunPressureToleranceRatio: 0.025,
  crosslineError: 12,
  crosslineErrorAverage: 9,
  inlineErrorRunningAverageValue: 2,
  inlineErrorRunningAverageShots: 40
}
```

#### `currentItem`

The item being iterated over. This can be of type `Shot`, `Sequence`, or `Preplot` depending on the value of this test's `iterate` attribute.

#### `shots`

An array of `Shot` objects.

Example:

```javascript
{
  type: 'final',
  _id: [ 7, 1764 ],
  sequence: 7,
  line: 5500,
  point: 1764,
  objref: 3,
  tstamp: "2020-09-07T04:10:13.680Z",
  hash: '2173892:1599458941.3070147:1599458941.3070147:80621034',
  geometry: '{"type":"Point","coordinates":[2.471571453,59.169725413]}',
  error_i: 2.7102108739654795,
  error_j: -0.06460360411324473,
  preplot_geometry: '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:23031"}},"coordinates":[469883.4,6559284.9]}',
  raw_geometry: '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:23031"}},"coordinates":[469881.87,6559285.76]}',
  final_geometry: '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:23031"}},"coordinates":[469881.09,6559286.22]}',
  pp_meta: {},
  raw_meta: {
    smsrc: {
      guns: [Array],
      line: '1054980007S00000',
      mask: 38,
      shot: 1764,
      time: "b'20/09/07:04:10:13'",
      spare: '',
      header: '*SMSRC',
      spread: 3,
      volume: 3050,
      blk_siz: 2282,
      manifold: 2027,
      num_auto: 0,
      num_guns: 52,
      trg_mode: 'E',
      avg_delta: 0,
      num_delta: 0,
      std_delta: 0.073,
      baro_press: null,
      num_active: 52,
      num_nofire: 0,
      src_number: 2,
      num_subarray: 6
    }
  },
  final_meta: {},
  _: [Function]
}
```

#### `sequences`

An array of `Sequence` objects.

Example:

```javascript
{
    "_id": 9,
    "sequence": 9,
    "line": 5562,
    "fsp": 2580,
    "lsp": 996,
    "fsp_final": 2548,
    "lsp_final": 1000,
    "ts0": "2020-09-07T08:34:13.112Z",
    "ts1": "2020-09-07T10:47:49.116Z",
    "ts0_final": "2020-09-07T08:36:58.984Z",
    "ts1_final": "2020-09-07T10:47:28.608Z",
    "duration": {
        "hours": 2,
        "minutes": 13,
        "seconds": 36,
        "milliseconds": 4
    },
    "duration_final": {
        "hours": 2,
        "minutes": 10,
        "seconds": 29,
        "milliseconds": 624
    },
    "num_preplots": 775,
    "num_points": 775,
    "missing_shots": 0,
    "length": 19350.1845360761,
    "azimuth": 26.443105805883572,
    "remarks": "",
    "remarks_final": "",
    "status": "final"
    _: [Function]
}

```

#### `preplots`

An array of `Preplot` objects.

Example:

```javascript
{
  _id: [ null, 2348, 5130 ],
  line: 5130,
  point: 2348,
  class: 'V',
  ntba: false,
  geometry: '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:23031"}},"coordinates":[470769.8,6550688.8]}',
  meta: {},
  count: 0
}
```

#### The `_` function

Each of the above objects has a function named `_`. This is a helper to quickly access own nested attributes without having to check if the attribute or one of its parents exist. For instance, on a `Shot` item, `currentItem._('raw_meta.smsrc')` will return the SmartSource gun data if it exists, or undefined if either `smsrc` or `raw_meta` are not defined.
