# Pings

## Submission API

### `submit`
Collect and queue a custom ping for eventual uploading.

{{#include ../../../shared/blockquote-info.html}}

##### Glean-owned pings are submitted automatically

> Products do not need to submit Glean built-in pings,
> as their scheduling is managed internally. The APIs
> on this page are only relevant for products defining
> [custom pings](../../user/pings/custom.md#defining-a-custom-ping).

By default, if the ping doesn't currently have any events or metrics set, `submit` will do nothing.  However, if the `send_if_empty` flag is set to true in the ping definition, it will always be submitted.

For example, to submit the custom ping defined in [Adding new custom pings](../../user/pings/custom.md#defining-a-custom-ping):

{{#include ../../../shared/tab_header.md}}

<div data-lang="Kotlin" class="tab">

```kotlin
import org.mozilla.yourApplication.GleanMetrics.Pings
Pings.search.submit(
    Pings.searchReasonCodes.performed
)
```

</div>

<div data-lang="Java" class="tab">

```java
import org.mozilla.yourApplication.GleanMetrics.Pings

Pings.INSTANCE.search.submit(
    Pings.INSTANCE.searchReasonCodes.performed
);
```

</div>

<div data-lang="Swift" class="tab">

```swift
import Glean

GleanMetrics.Pings.shared.search.submit(
    reason: .performed
)
```

</div>

<div data-lang="Python" class="tab">

```Python
from glean import load_pings

pings = load_pings("pings.yaml")

pings.search.submit(pings.search_reason_codes.PERFORMED)
```

</div>

<div data-lang="Rust" class="tab">

```Rust
use glean::Pings;

pings::search.submit(pings::SearchReasonCodes::Performed);
```

</div>

<div data-lang="JavaScript" class="tab">

```js
import * as pings from "./path/to/generated/files/pings.js";

pings.search.submit("performed");
```
</div>

<div data-lang="Firefox Desktop" class="tab">

**C++**

```cpp
mozilla::glean_pings::Search.Submit("performed"_ns);
```

**JavaScript**

```js
GleanPings.search.submit("performed");
```

</div>

{{#include ../../../shared/tab_footer.md}}

If none of the metrics for the ping contain data the ping is not sent (unless `send_if_empty` is set to true in the definition file)

## Testing API

### `testBeforeNextSubmit`

Runs a validation function before the ping is collected.

{{#include ../../../shared/tab_header.md}}

<div data-lang="Kotlin" class="tab">

```kotlin
import org.mozilla.yourApplication.GleanMetrics.Search
import org.mozilla.yourApplication.GleanMetrics.Pings

// Record some data.
Search.defaultEngine.add(5);

// Instruct the ping API to validate the ping data.
var validatorRun = false
Pings.search.testBeforeNextSubmit { reason ->
    assertEquals(Pings.searchReasonCodes.performed, reason)
    assertEquals(5, Search.defaultEngine.testGetValue())
    validatorRun = true
}

// Submit the ping.
Pings.search.submit(
    Pings.searchReasonCodes.performed
)

// Verify that the validator run.
assertTrue(validatorRun)
```

</div>

<div data-lang="Java" class="tab">

```java
import org.mozilla.yourApplication.GleanMetrics.Search
import org.mozilla.yourApplication.GleanMetrics.Pings

// Record some data.
Search.INSTANCE.defaultEngine.add(5);

// Instruct the ping API to validate the ping data.
boolean validatorRun = false;
Pings.INSTANCE.search.testBeforeNextSubmit((reason) -> {
    assertEquals(Pings.searchReasonCodes.performed, reason);
    assertEquals(5, Search.INSTANCE.defaultEngine.testGetValue());
    validatorRun = true;
});

// Submit the ping.
Pings.INSTANCE.search.submit(
    Pings.INSTANCE.searchReasonCodes.performed
);

// Verify that the validator run.
assertTrue(validatorRun);
```

</div>

<div data-lang="Swift" class="tab">

```swift
@testable import Glean

// Record some data.
Search.defaultEngine.add(5)

// Instruct the ping API to validate the ping data.
var validatorRun = false
GleanMetrics.pings.shared.search.testBeforeNextSubmit { reason in
    XCTAssertEqual(.performed, reason, "Unexpected reason for search ping submitted")
    XCTAssertEqual(5, try Search.defaultEngine.testGetValue(), "Unexpected value for default engine in search ping")
    validatorRun = true
}

// Submit the ping.
GleanMetrics.Pings.shared.search.submit(
    reason: .performed
)

// Verify that the validator run.
XCTAssert(validatorRun, "Expected validator to be called by now.")
```

</div>

<div data-lang="Python" class="tab">

```Python
from glean import load_metrics, load_pings

pings = load_pings("pings.yaml")
metrics = load_metrics("metrics.yaml")

# Record some data.
metrics.search.default_engine.add(5)

# Need a mutable object and plain booleans are not.
callback_was_called = [False]

def check_custom_ping(reason):
    assert reason == pings.search_reason_codes.PERFORMED
    assert 5 == metrics.search.default_engine.test_get_value()
    callback_was_called[0] = True

# Instruct the ping API to validate the ping data.
pings.search.test_before_next_submit(check_custom_ping)

# Submit the ping.
pings.search.submit(pings.search_reason_codes.PERFORMED)

# Verify that the validator run.
assert callback_was_called[0]
```

</div>

<div data-lang="Rust" class="tab">

```Rust
use glean::Pings;
use glean_metrics;

// Record some data.
search::default_engine.add(5);

// Instruct the ping API to validate the ping data.
pings::search.test_before_next_submit(move |reason| {
    assert_eq!(pings::SearchReasonCodes::Performed, reason);
    assert_eq!(5, search::default_engine.test_get_value(None).unwrap());
});

// When the `submit` API is not directly called by the
// test code, it may be worth checking that the validator
// function run by using a canary boolean in the closure
// used in `test_before_next_submit` and asserting on its
// value after submission.

// Submit the ping.
pings::search.submit(pings::SearchReasonCodes::Performed);
```

</div>

<div data-lang="JavaScript" class="tab">

```js
import * as search from "./path/to/generated/files/search.js";
import * as pings from "./path/to/generated/files/pings.js";

// Record some data.
search.defaultEngine.add(5);

// Instruct the ping API to validate the ping data.
let validatorRun = false;
const p = pings.search.testBeforeNextSubmit(async reason => {
  assert.strictEqual(reason, "performed");
  assert.strictEqual(await search.defaultEngine.testGetValue(), 5);
  validatorRun = true;
});

// Submit the ping.
pings.search.submit("performed");
// Wait for the validation to finish.
assert.doesNotThrow(await p);

// Verify that the validator run.
assert.ok(validatorRun);
```

</div>

<div data-lang="Firefox Desktop" class="tab"></div>

{{#include ../../../shared/tab_footer.md}}
