+static int generate_capture_descr(struct lttng_condition *condition)
+{
+ int ret, i;
+ struct lttng_event_expr *expr = NULL;
+ const unsigned int basic_field_count = sizeof(test_capture_base_fields) /
+ sizeof(*test_capture_base_fields);
+ enum lttng_condition_status cond_status;
+
+ for (i = 0; i < basic_field_count; i++) {
+ diag("Adding capture descriptor '%s'",
+ test_capture_base_fields[i].field_name);
+
+ switch (test_capture_base_fields[i].field_type) {
+ case FIELD_TYPE_PAYLOAD:
+ expr = lttng_event_expr_event_payload_field_create(
+ test_capture_base_fields[i].field_name);
+ break;
+ case FIELD_TYPE_CONTEXT:
+ expr = lttng_event_expr_channel_context_field_create(
+ test_capture_base_fields[i].field_name);
+ break;
+ case FIELD_TYPE_ARRAY_FIELD:
+ {
+ int nb_matches;
+ unsigned int index;
+ char field_name[FIELD_NAME_MAX_LEN];
+ struct lttng_event_expr *array_expr = NULL;
+
+ nb_matches = sscanf(test_capture_base_fields[i].field_name,
+ "%[^[][%u]", field_name, &index);
+ if (nb_matches != 2) {
+ fail("Unexpected array field name format: field name = '%s'",
+ test_capture_base_fields[i].field_name);
+ ret = 1;
+ goto end;
+ }
+
+ array_expr = lttng_event_expr_event_payload_field_create(
+ field_name);
+
+ expr = lttng_event_expr_array_field_element_create(
+ array_expr, index);
+ break;
+ }
+ case FIELD_TYPE_APP_CONTEXT:
+ fail("Application context tests are not implemented yet.");
+ /* fallthrough. */
+ default:
+ ret = 1;
+ goto end;
+ }
+
+ if (expr == NULL) {
+ fail("Failed to create capture expression");
+ ret = -1;
+ goto end;
+ }
+
+ cond_status = lttng_condition_event_rule_matches_append_capture_descriptor(
+ condition, expr);
+ if (cond_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Failed to append capture descriptor");
+ ret = -1;
+ lttng_event_expr_destroy(expr);
+ goto end;
+ }
+ }
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static int validator_notification_trigger_capture(
+ enum lttng_domain_type domain,
+ struct lttng_notification *notification,
+ const int iteration)
+{
+ int ret;
+ unsigned int capture_count, i;
+ enum lttng_evaluation_event_rule_matches_status
+ event_rule_matches_evaluation_status;
+ enum lttng_event_field_value_status event_field_value_status;
+ const struct lttng_evaluation *evaluation;
+ const struct lttng_event_field_value *captured_fields;
+ bool at_least_one_error = false;
+
+ evaluation = lttng_notification_get_evaluation(notification);
+ if (evaluation == NULL) {
+ fail("Failed to get evaluation from notification during trigger capture test");
+ ret = 1;
+ goto end;
+ }
+
+ event_rule_matches_evaluation_status =
+ lttng_evaluation_event_rule_matches_get_captured_values(
+ evaluation, &captured_fields);
+ if (event_rule_matches_evaluation_status !=
+ LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
+ diag("Failed to get event rule evaluation captured values: status = %d",
+ (int) event_rule_matches_evaluation_status);
+ ret = 1;
+ goto end;
+ }
+
+ event_field_value_status =
+ lttng_event_field_value_array_get_length(captured_fields,
+ &capture_count);
+ if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("Failed to get count of captured value field array");
+ ret = 1;
+ goto end;
+ }
+
+ for (i = 0; i < capture_count; i++) {
+ const struct lttng_event_field_value *captured_field = NULL;
+ validate_cb validate;
+ bool expected;
+
+ diag("Validating capture of field '%s'",
+ test_capture_base_fields[i].field_name);
+ event_field_value_status =
+ lttng_event_field_value_array_get_element_at_index(
+ captured_fields, i,
+ &captured_field);
+
+ switch(domain) {
+ case LTTNG_DOMAIN_UST:
+ expected = test_capture_base_fields[i].expected_ust;
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ expected = test_capture_base_fields[i].expected_kernel;
+ break;
+ default:
+ fail("Unexpected domain encountered: domain = %d",
+ (int) domain);
+ ret = 1;
+ goto end;
+ }
+
+ if (domain == LTTNG_DOMAIN_UST) {
+ validate = test_capture_base_fields[i].validate_ust;
+ } else {
+ validate = test_capture_base_fields[i].validate_kernel;
+ }
+
+ if (!expected) {
+ ok(event_field_value_status == LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE,
+ "No payload captured");
+ continue;
+ }
+
+ if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ if (event_field_value_status ==
+ LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
+ fail("Expected a capture but it is unavailable");
+ } else {
+ fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
+ (int) event_field_value_status);
+ }
+
+ ret = 1;
+ goto end;
+ }
+
+ diag("Captured field of type %s",
+ field_value_type_to_str(
+ lttng_event_field_value_get_type(captured_field)));
+
+ assert(validate);
+ ret = validate(captured_field, iteration);
+ if (ret) {
+ at_least_one_error = true;
+ }
+ }
+
+ ret = at_least_one_error;
+
+end:
+ return ret;
+}
+
+static void test_tracepoint_event_rule_notification_capture(
+ enum lttng_domain_type domain_type)
+{
+ enum lttng_notification_channel_status nc_status;
+
+ int i, ret;
+ struct lttng_condition *condition = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_trigger *trigger = NULL;
+ const char *trigger_name = "my_precious";
+ const char *pattern;
+
+ if (domain_type == LTTNG_DOMAIN_UST) {
+ pattern = "tp:tptest";
+ } else {
+ pattern = "lttng_test_filter_event";
+ }
+
+ create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
+ NULL, domain_type, generate_capture_descr, &condition,
+ &trigger);
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ resume_application();
+
+ /* Get 3 notifications */
+ for (i = 0; i < 3; i++) {
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+ ok(notification, "Received notification");
+
+ /* Error */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ ret = validator_notification_trigger_name(notification, trigger_name);
+ if (ret) {
+ lttng_notification_destroy(notification);
+ goto end;
+ }
+
+ ret = validator_notification_trigger_capture(domain_type, notification, i);
+ if (ret) {
+ lttng_notification_destroy(notification);
+ goto end;
+ }
+
+ lttng_notification_destroy(notification);
+ }
+
+end:
+ suspend_application();
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_unregister_trigger(trigger);
+ lttng_trigger_destroy(trigger);
+ lttng_condition_destroy(condition);
+ return;
+}
+