mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-09 23:18:10 -05:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07af5f91c8 | ||
|
|
fda6a9fede | ||
|
|
d2245a2e34 | ||
|
|
a12a8130b8 | ||
|
|
b436d2a96d | ||
|
|
05b0f270c4 | ||
|
|
f24f71e4e0 | ||
|
|
63a00f775f | ||
|
|
5a946caf35 | ||
|
|
16c016a171 | ||
|
|
284af65534 |
@@ -33,3 +33,5 @@
|
||||
^_dev$
|
||||
^.claude$
|
||||
^README-npm\.md$
|
||||
^CRAN-SUBMISSION$
|
||||
^LICENSE\.md$
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Type: Package
|
||||
Package: shiny
|
||||
Title: Web Application Framework for R
|
||||
Version: 1.12.0
|
||||
Version: 1.12.1.9000
|
||||
Authors@R: c(
|
||||
person("Winston", "Chang", , "winston@posit.co", role = "aut",
|
||||
comment = c(ORCID = "0000-0002-1576-2126")),
|
||||
@@ -69,7 +69,7 @@ Description: Makes it incredibly easy to build interactive web
|
||||
applications with R. Automatic "reactive" binding between inputs and
|
||||
outputs and extensive prebuilt widgets make it possible to build
|
||||
beautiful, responsive, and powerful applications with minimal effort.
|
||||
License: GPL-3 | file LICENSE
|
||||
License: MIT + file LICENSE
|
||||
URL: https://shiny.posit.co/, https://github.com/rstudio/shiny
|
||||
BugReports: https://github.com/rstudio/shiny/issues
|
||||
Depends:
|
||||
@@ -191,6 +191,7 @@ Collate:
|
||||
'otel-reactive-update.R'
|
||||
'otel-session.R'
|
||||
'otel-shiny.R'
|
||||
'otel-with.R'
|
||||
'priorityqueue.R'
|
||||
'progress.R'
|
||||
'react.R'
|
||||
|
||||
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (c) 2025 shiny authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1011
LICENSE.note
Normal file
1011
LICENSE.note
Normal file
File diff suppressed because it is too large
Load Diff
@@ -165,6 +165,7 @@ export(isTruthy)
|
||||
export(isolate)
|
||||
export(key_missing)
|
||||
export(loadSupport)
|
||||
export(localOtelCollect)
|
||||
export(mainPanel)
|
||||
export(makeReactiveBinding)
|
||||
export(markRenderFunction)
|
||||
@@ -329,6 +330,7 @@ export(verticalLayout)
|
||||
export(wellPanel)
|
||||
export(withLogErrors)
|
||||
export(withMathJax)
|
||||
export(withOtelCollect)
|
||||
export(withProgress)
|
||||
export(withReactiveDomain)
|
||||
export(withTags)
|
||||
|
||||
26
NEWS.md
26
NEWS.md
@@ -1,3 +1,29 @@
|
||||
# shiny (development version)
|
||||
|
||||
# shiny 1.12.1
|
||||
|
||||
## New features
|
||||
|
||||
* `withOtelCollect()` and `localOtelCollect()` temporarily control
|
||||
OpenTelemetry collection levels during reactive expression creation,
|
||||
allowing you to enable or disable telemetry collection for specific modules
|
||||
or sections of code. (#4333)
|
||||
|
||||
## Bug fixes and minor improvements
|
||||
|
||||
* OpenTelemetry code attributes now include both the preferred attribute names
|
||||
(`code.file.path`, `code.line.number`, `code.column.number`) and the
|
||||
deprecated names (`code.filepath`, `code.lineno`, `code.column`) to follow
|
||||
OpenTelemetry semantic conventions while maintaining backward compatibility.
|
||||
The deprecated names will be removed in a future release after Logfire
|
||||
supports the preferred names. (#4325)
|
||||
|
||||
* `ExtendedTask` now captures the OpenTelemetry recording state at
|
||||
initialization time rather than at invocation time, ensuring consistent span
|
||||
recording behavior regardless of runtime configuration changes. (#4334)
|
||||
|
||||
* Timer tests are now skipped on CRAN. (#4327)
|
||||
|
||||
# shiny 1.12.0
|
||||
|
||||
## OpenTelemetry support
|
||||
|
||||
@@ -520,7 +520,7 @@ bindCache.reactiveExpr <- function(x, ..., cache = "app") {
|
||||
|
||||
local({
|
||||
impl <- attr(res, "observable", exact = TRUE)
|
||||
impl$.otelAttrs <- append_otel_srcref_attrs(x_otel_attrs, call_srcref)
|
||||
impl$.otelAttrs <- append_otel_srcref_attrs(x_otel_attrs, call_srcref, fn_name = "bindCache")
|
||||
})
|
||||
|
||||
if (has_otel_collect("reactivity")) {
|
||||
|
||||
@@ -240,7 +240,7 @@ bindEvent.reactiveExpr <- function(x, ..., ignoreNULL = TRUE, ignoreInit = FALSE
|
||||
|
||||
local({
|
||||
impl <- attr(res, "observable", exact = TRUE)
|
||||
impl$.otelAttrs <- append_otel_srcref_attrs(x_otel_attrs, call_srcref)
|
||||
impl$.otelAttrs <- append_otel_srcref_attrs(x_otel_attrs, call_srcref, fn_name = "bindEvent")
|
||||
})
|
||||
|
||||
|
||||
@@ -341,7 +341,7 @@ bindEvent.Observer <- function(x, ..., ignoreNULL = TRUE, ignoreInit = FALSE,
|
||||
|
||||
class(x) <- c("Observer.event", class(x))
|
||||
call_srcref <- get_call_srcref(-1)
|
||||
x$.otelAttrs <- append_otel_srcref_attrs(x$.otelAttrs, call_srcref)
|
||||
x$.otelAttrs <- append_otel_srcref_attrs(x$.otelAttrs, call_srcref, fn_name = "bindEvent")
|
||||
|
||||
if (has_otel_collect("reactivity")) {
|
||||
x <- enable_otel_observe(x)
|
||||
|
||||
@@ -41,6 +41,28 @@
|
||||
#' is, a function that quickly returns a promise) and allows even that very
|
||||
#' session to immediately unblock and carry on with other user interactions.
|
||||
#'
|
||||
#' @section OpenTelemetry Integration:
|
||||
#'
|
||||
#' When an `ExtendedTask` is created, if OpenTelemetry tracing is enabled for
|
||||
#' `"reactivity"` (see [withOtelCollect()]), the `ExtendedTask` will record
|
||||
#' spans for each invocation of the task. The tracing level at `invoke()` time
|
||||
#' does not affect whether spans are recorded; only the tracing level when
|
||||
#' calling `ExtendedTask$new()` matters.
|
||||
#'
|
||||
#' The OTel span will be named based on the label created from the variable the
|
||||
#' `ExtendedTask` is assigned to. If no label can be determined, the span will
|
||||
#' be named `<anonymous>`. Similar to other Shiny OpenTelemetry spans, the span
|
||||
#' will also include source reference attributes and session ID attributes.
|
||||
#'
|
||||
#' ```r
|
||||
#' withOtelCollect("all", {
|
||||
#' my_task <- ExtendedTask$new(function(...) { ... })
|
||||
#' })
|
||||
#'
|
||||
#' # Span recorded for this invocation: ExtendedTask my_task
|
||||
#' my_task$invoke(...)
|
||||
#' ```
|
||||
#'
|
||||
#' @examplesIf rlang::is_interactive() && rlang::is_installed("mirai")
|
||||
#' library(shiny)
|
||||
#' library(bslib)
|
||||
@@ -140,9 +162,13 @@ ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
|
||||
private$otel_log_label_add_to_queue <- otel_log_label_extended_task_add_to_queue(label, domain = domain)
|
||||
|
||||
private$otel_attrs <- c(
|
||||
otel_srcref_attributes(call_srcref),
|
||||
otel_srcref_attributes(call_srcref, "ExtendedTask"),
|
||||
otel_session_id_attrs(domain)
|
||||
) %||% list()
|
||||
|
||||
# Capture this value at init-time, not run-time
|
||||
# This way, the span is only created if otel was enabled at time of creation... just like other spans
|
||||
private$is_recording_otel <- has_otel_collect("reactivity")
|
||||
},
|
||||
#' @description
|
||||
#' Starts executing the long-running operation. If this `ExtendedTask` is
|
||||
@@ -175,7 +201,7 @@ ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
|
||||
private$invocation_queue$add(list(args = args, call = call))
|
||||
} else {
|
||||
|
||||
if (has_otel_collect("reactivity")) {
|
||||
if (private$is_recording_otel) {
|
||||
private$otel_span <- start_otel_span(
|
||||
private$otel_span_label,
|
||||
attributes = private$otel_attrs
|
||||
@@ -253,6 +279,7 @@ ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
|
||||
otel_span_label = NULL,
|
||||
otel_log_label_add_to_queue = NULL,
|
||||
otel_attrs = list(),
|
||||
is_recording_otel = FALSE,
|
||||
otel_span = NULL,
|
||||
|
||||
do_invoke = function(args, call = NULL) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Very similar to srcrefFromShinyCall(),
|
||||
# however, this works when the function does not have a srcref attr set
|
||||
otel_srcref_attributes <- function(srcref) {
|
||||
otel_srcref_attributes <- function(srcref, fn_name = NULL) {
|
||||
if (is.function(srcref)) {
|
||||
srcref <- getSrcRefs(srcref)[[1]][[1]]
|
||||
}
|
||||
@@ -16,8 +16,16 @@ otel_srcref_attributes <- function(srcref) {
|
||||
# Semantic conventions for code: https://opentelemetry.io/docs/specs/semconv/registry/attributes/code/
|
||||
#
|
||||
# Inspiration from https://github.com/r-lib/testthat/pull/2087/files#diff-92de3306849d93d6f7e76c5aaa1b0c037e2d716f72848f8a1c70536e0c8a1564R123-R124
|
||||
filename <- attr(srcref, "srcfile")$filename
|
||||
dropNulls(list(
|
||||
"code.filepath" = attr(srcref, "srcfile")$filename,
|
||||
"code.function.name" = fn_name,
|
||||
# Location attrs
|
||||
"code.file.path" = filename,
|
||||
"code.line.number" = srcref[1],
|
||||
"code.column.number" = srcref[2],
|
||||
# Remove these deprecated location names once Logfire supports the preferred names
|
||||
# https://github.com/pydantic/logfire/issues/1559
|
||||
"code.filepath" = filename,
|
||||
"code.lineno" = srcref[1],
|
||||
"code.column" = srcref[2]
|
||||
))
|
||||
@@ -41,12 +49,12 @@ get_call_srcref <- function(which_offset = 0) {
|
||||
}
|
||||
|
||||
|
||||
append_otel_srcref_attrs <- function(attrs, call_srcref) {
|
||||
append_otel_srcref_attrs <- function(attrs, call_srcref, fn_name) {
|
||||
if (is.null(call_srcref)) {
|
||||
return(attrs)
|
||||
}
|
||||
|
||||
srcref_attrs <- otel_srcref_attributes(call_srcref)
|
||||
srcref_attrs <- otel_srcref_attributes(call_srcref, fn_name)
|
||||
if (is.null(srcref_attrs)) {
|
||||
return(attrs)
|
||||
}
|
||||
|
||||
@@ -30,12 +30,7 @@ has_otel_collect <- function(collect) {
|
||||
|
||||
# Run expr with otel collection disabled
|
||||
with_no_otel_collect <- function(expr) {
|
||||
withr::with_options(
|
||||
list(
|
||||
shiny.otel.collect = "none"
|
||||
),
|
||||
expr
|
||||
)
|
||||
withOtelCollect("none", expr)
|
||||
}
|
||||
|
||||
|
||||
|
||||
125
R/otel-with.R
Normal file
125
R/otel-with.R
Normal file
@@ -0,0 +1,125 @@
|
||||
#' Temporarily set OpenTelemetry (OTel) collection level
|
||||
#'
|
||||
#' @description
|
||||
#' Control Shiny's OTel collection level for particular reactive expression(s).
|
||||
#'
|
||||
#' `withOtelCollect()` sets the OpenTelemetry collection level for
|
||||
#' the duration of evaluating `expr`. `localOtelCollect()` sets the collection
|
||||
#' level for the remainder of the current function scope.
|
||||
#'
|
||||
#' @details
|
||||
#' Note that `"session"` and `"reactive_update"` levels are not permitted as
|
||||
#' these are runtime-specific levels that should only be set permanently via
|
||||
#' `options(shiny.otel.collect = ...)` or the `SHINY_OTEL_COLLECT` environment
|
||||
#' variable, not temporarily during reactive expression creation.
|
||||
#'
|
||||
#' @section Best practice:
|
||||
#'
|
||||
#' Best practice is to set the collection level for code that *creates* reactive
|
||||
#' expressions, not code that *runs* them. For instance:
|
||||
#'
|
||||
#' ```r
|
||||
#' # Disable telemetry for a reactive expression
|
||||
#' withOtelCollect("none", {
|
||||
#' my_reactive <- reactive({ ... })
|
||||
#' })
|
||||
#'
|
||||
#' # Disable telemetry for a render function
|
||||
#' withOtelCollect("none", {
|
||||
#' output$my_plot <- renderPlot({ ... })
|
||||
#' })
|
||||
#'
|
||||
#' #' # Disable telemetry for an observer
|
||||
#' withOtelCollect("none", {
|
||||
#' observe({ ... }))
|
||||
#' })
|
||||
#'
|
||||
#' # Disable telemetry for an entire module
|
||||
#' withOtelCollect("none", {
|
||||
#' my_result <- my_module("my_id")
|
||||
#' })
|
||||
#' # Use `my_result` as normal here
|
||||
#' ```
|
||||
#'
|
||||
#' NOTE: It's not recommended to pipe existing reactive objects into
|
||||
#' `withOtelCollect()` since they won't inherit their intended OTel settings,
|
||||
#' leading to confusion.
|
||||
#'
|
||||
#' @param collect Character string specifying the OpenTelemetry collection level.
|
||||
#' Must be one of the following:
|
||||
#'
|
||||
#' * `"none"` - No telemetry data collected
|
||||
#' * `"reactivity"` - Collect reactive execution spans (includes session and
|
||||
#' reactive update events)
|
||||
#' * `"all"` - All available telemetry (currently equivalent to `"reactivity"`)
|
||||
#' @param expr Expression to evaluate with the specified collection level
|
||||
#' (for `withOtelCollect()`).
|
||||
#' @param envir Environment where the collection level should be set
|
||||
#' (for `localOtelCollect()`). Defaults to the parent frame.
|
||||
#'
|
||||
#' @return
|
||||
#' * `withOtelCollect()` returns the value of `expr`.
|
||||
#' * `localOtelCollect()` is called for its side effect and returns the previous
|
||||
#' `collect` value invisibly.
|
||||
#'
|
||||
#' @seealso See the `shiny.otel.collect` option within [`shinyOptions`]. Setting
|
||||
#' this value will globally control OpenTelemetry collection levels.
|
||||
#'
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' # Temporarily disable telemetry collection
|
||||
#' withOtelCollect("none", {
|
||||
#' # Code here won't generate telemetry
|
||||
#' reactive({ input$x + 1 })
|
||||
#' })
|
||||
#'
|
||||
#' # Collect reactivity telemetry but not other events
|
||||
#' withOtelCollect("reactivity", {
|
||||
#' # Reactive execution will be traced
|
||||
#' observe({ print(input$x) })
|
||||
#' })
|
||||
#'
|
||||
#' # Use local variant in a function
|
||||
#' my_function <- function() {
|
||||
#' localOtelCollect("none")
|
||||
#' # Rest of function executes without telemetry
|
||||
#' reactive({ input$y * 2 })
|
||||
#' }
|
||||
#' }
|
||||
#'
|
||||
#' @rdname withOtelCollect
|
||||
#' @export
|
||||
withOtelCollect <- function(collect, expr) {
|
||||
collect <- as_otel_collect_with(collect)
|
||||
|
||||
withr::with_options(
|
||||
list(shiny.otel.collect = collect),
|
||||
expr
|
||||
)
|
||||
}
|
||||
|
||||
#' @rdname withOtelCollect
|
||||
#' @export
|
||||
localOtelCollect <- function(collect, envir = parent.frame()) {
|
||||
collect <- as_otel_collect_with(collect)
|
||||
|
||||
old <- withr::local_options(
|
||||
list(shiny.otel.collect = collect),
|
||||
.local_envir = envir
|
||||
)
|
||||
|
||||
invisible(old)
|
||||
}
|
||||
|
||||
# Helper function to validate collect levels for with/local functions
|
||||
# Only allows "none", "reactivity", and "all" - not "session" or "reactive_update"
|
||||
as_otel_collect_with <- function(collect) {
|
||||
if (!is.character(collect)) {
|
||||
stop("`collect` must be a character vector.")
|
||||
}
|
||||
|
||||
allowed_levels <- c("none", "reactivity", "all")
|
||||
collect <- match.arg(collect, allowed_levels, several.ok = FALSE)
|
||||
|
||||
return(collect)
|
||||
}
|
||||
@@ -231,7 +231,7 @@ reactiveVal <- function(value = NULL, label = NULL) {
|
||||
|
||||
rv <- ReactiveVal$new(value, label)
|
||||
if (!is.null(call_srcref)) {
|
||||
rv$.otelAttrs <- otel_srcref_attributes(call_srcref)
|
||||
rv$.otelAttrs <- otel_srcref_attributes(call_srcref, fn_name = "reactiveVal")
|
||||
}
|
||||
|
||||
ret <- structure(
|
||||
@@ -646,7 +646,7 @@ reactiveValues <- function(...) {
|
||||
defaultLabel = impl$.label
|
||||
)
|
||||
|
||||
impl$.otelAttrs <- otel_srcref_attributes(call_srcref)
|
||||
impl$.otelAttrs <- otel_srcref_attributes(call_srcref, fn_name = "reactiveValues")
|
||||
}
|
||||
|
||||
impl$mset(args)
|
||||
@@ -1130,7 +1130,7 @@ reactive <- function(
|
||||
|
||||
call_srcref <- get_call_srcref()
|
||||
if (!is.null(call_srcref)) {
|
||||
o$.otelAttrs <- otel_srcref_attributes(call_srcref)
|
||||
o$.otelAttrs <- otel_srcref_attributes(call_srcref, fn_name = "reactive")
|
||||
}
|
||||
|
||||
ret <- structure(
|
||||
@@ -1587,7 +1587,7 @@ observe <- function(
|
||||
..stacktraceon = ..stacktraceon
|
||||
)
|
||||
if (!is.null(call_srcref)) {
|
||||
o$.otelAttrs <- otel_srcref_attributes(call_srcref)
|
||||
o$.otelAttrs <- otel_srcref_attributes(call_srcref, fn_name = "observe")
|
||||
}
|
||||
|
||||
if (has_otel_collect("reactivity")) {
|
||||
@@ -2055,7 +2055,7 @@ reactive_poll_impl <- function(
|
||||
otel_label_reactive_poll(label, domain = impl$.domain)
|
||||
else if (fnName == "reactiveFileReader")
|
||||
otel_label_reactive_file_reader(label, domain = impl$.domain)
|
||||
impl$.otelAttrs <- append_otel_srcref_attrs(impl$.otelAttrs, call_srcref)
|
||||
impl$.otelAttrs <- append_otel_srcref_attrs(impl$.otelAttrs, call_srcref, fn_name = fnName)
|
||||
})
|
||||
|
||||
return(re)
|
||||
@@ -2522,7 +2522,7 @@ observeEvent <- function(eventExpr, handlerExpr,
|
||||
})
|
||||
|
||||
if (!is.null(call_srcref)) {
|
||||
o$.otelAttrs <- otel_srcref_attributes(call_srcref)
|
||||
o$.otelAttrs <- otel_srcref_attributes(call_srcref, fn_name = "observeEvent")
|
||||
}
|
||||
if (has_otel_collect("reactivity")) {
|
||||
o <- enable_otel_observe(o)
|
||||
@@ -2571,7 +2571,7 @@ eventReactive <- function(eventExpr, valueExpr,
|
||||
|
||||
if (!is.null(call_srcref)) {
|
||||
impl <- attr(r, "observable", exact = TRUE)
|
||||
impl$.otelAttrs <- otel_srcref_attributes(call_srcref)
|
||||
impl$.otelAttrs <- otel_srcref_attributes(call_srcref, fn_name = "eventReactive")
|
||||
}
|
||||
if (has_otel_collect("reactivity")) {
|
||||
r <- enable_otel_reactive_expr(r)
|
||||
@@ -2778,7 +2778,7 @@ debounce <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
|
||||
local({
|
||||
er_impl <- attr(er, "observable", exact = TRUE)
|
||||
er_impl$.otelLabel <- otel_label_debounce(label, domain = domain)
|
||||
er_impl$.otelAttrs <- append_otel_srcref_attrs(er_impl$.otelAttrs, call_srcref)
|
||||
er_impl$.otelAttrs <- append_otel_srcref_attrs(er_impl$.otelAttrs, call_srcref, fn_name = "debounce")
|
||||
})
|
||||
|
||||
with_no_otel_collect({
|
||||
@@ -2877,7 +2877,7 @@ throttle <- function(r, millis, priority = 100, domain = getDefaultReactiveDomai
|
||||
local({
|
||||
er_impl <- attr(er, "observable", exact = TRUE)
|
||||
er_impl$.otelLabel <- otel_label_throttle(label, domain = domain)
|
||||
er_impl$.otelAttrs <- append_otel_srcref_attrs(er_impl$.otelAttrs, call_srcref)
|
||||
er_impl$.otelAttrs <- append_otel_srcref_attrs(er_impl$.otelAttrs, call_srcref, fn_name = "throttle")
|
||||
})
|
||||
|
||||
er
|
||||
|
||||
@@ -160,20 +160,30 @@ getShinyOption <- function(name, default = NULL) {
|
||||
# ' side devmode features. Currently the primary feature is the client-side
|
||||
# ' error console.}
|
||||
### end shiny.client_devmode
|
||||
#' \item{shiny.otel.collect (defaults to `Sys.getenv("SHINY_OTEL_COLLECT", "all")`)}{Determines how Shiny will
|
||||
#' interact with OpenTelemetry.
|
||||
#' \item{shiny.otel.collect (defaults to `Sys.getenv("SHINY_OTEL_COLLECT",
|
||||
#' "all")`)}{Determines how Shiny will interact with OpenTelemetry.
|
||||
#'
|
||||
#' Supported values:
|
||||
#' * `"none"` - No Shiny OpenTelemetry tracing.
|
||||
#' * `"session"` - Adds session start/end spans.
|
||||
#' * `"reactive_update"` - Spans for any synchronous/asynchronous reactive update. (Includes `"session"` features).
|
||||
#' * `"reactivity"` - Spans for all reactive expressions. (Includes `"reactive_update"` features).
|
||||
#' * `"all"` - All Shiny OpenTelemetry tracing. Currently equivalent to `"reactivity"`.
|
||||
#' * `"reactive_update"` - Spans for any synchronous/asynchronous reactive
|
||||
#' update. (Includes `"session"` features).
|
||||
#' * `"reactivity"` - Spans for all reactive expressions and logs for setting
|
||||
#' reactive vals and values. (Includes `"reactive_update"` features). This
|
||||
#' option must be set when creating any reactive objects that should record
|
||||
#' OpenTelemetry spans / logs. See [`withOtelCollect()`] and
|
||||
#' [`localOtelCollect()`] for ways to set this option locally when creating
|
||||
#' your reactive expressions.
|
||||
#' * `"all"` - All Shiny OpenTelemetry tracing. Currently equivalent to
|
||||
#' `"reactivity"`.
|
||||
#'
|
||||
#' This option is useful for debugging and profiling while in production. This
|
||||
#' option will only be useful if the `otelsdk` package is installed and
|
||||
#' `otel::is_tracing_enabled()` returns `TRUE`. Please have any OpenTelemetry
|
||||
#' environment variables set before starting your Shiny app.}
|
||||
#' environment variables set before loading any relevant R packages.
|
||||
#'
|
||||
#' To set this option locally within a specific part of your Shiny
|
||||
#' application, see [`withOtelCollect()`] and [`localOtelCollect()`].}
|
||||
#' \item{shiny.otel.sanitize.errors (defaults to `TRUE`)}{If `TRUE`, fatal and unhandled errors will be sanitized before being sent to the OpenTelemetry backend. The default value of `TRUE` is set to avoid potentially sending sensitive information to the OpenTelemetry backend. If you want the full error message and stack trace to be sent to the OpenTelemetry backend, set this option to `FALSE` or use `safeError(e)`.}
|
||||
#' }
|
||||
#'
|
||||
|
||||
@@ -136,7 +136,9 @@ markRenderFunction <- function(
|
||||
|
||||
otelAttrs <-
|
||||
otel_srcref_attributes(
|
||||
attr(renderFunc, "wrappedFunc", exact = TRUE)
|
||||
attr(renderFunc, "wrappedFunc", exact = TRUE),
|
||||
# Can't retrieve the render function used at this point, so just use NULL
|
||||
fn_name = NULL
|
||||
)
|
||||
|
||||
ret <- structure(
|
||||
|
||||
@@ -61,7 +61,7 @@ We welcome contributions to the **shiny** package. Please see our [CONTRIBUTING.
|
||||
|
||||
## License
|
||||
|
||||
The shiny package as a whole is licensed under the GPLv3. See the [LICENSE](LICENSE) file for more details.
|
||||
The shiny package as a whole is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
|
||||
|
||||
## R version support
|
||||
|
||||
|
||||
158
cran-comments.md
158
cran-comments.md
@@ -1,121 +1,129 @@
|
||||
## Comments
|
||||
|
||||
#### 2025-12-01
|
||||
#### 2025-12-08
|
||||
|
||||
Hi CRAN,
|
||||
Test has been removed from CRAN checks.
|
||||
|
||||
We made changes to underlying structures that packages are not suppose to test. PRs were provided for each failing package.
|
||||
Also added a couple bug fixes as found by users.
|
||||
|
||||
Maintainer change: From Winston Chang to Carson Sievert.
|
||||
|
||||
Please let me know if you need any further information.
|
||||
Please let me know if you need any further changes.
|
||||
|
||||
Thank you,
|
||||
Carson
|
||||
|
||||
#### 2025-12-04
|
||||
|
||||
Error:
|
||||
|
||||
```
|
||||
Check Details
|
||||
Version: 1.12.0
|
||||
Check: tests
|
||||
Result: ERROR
|
||||
Running ‘testthat.R’ [100s/394s]
|
||||
Running the tests in ‘tests/testthat.R’ failed.
|
||||
Complete output:
|
||||
> library(testthat)
|
||||
> library(shiny)
|
||||
>
|
||||
> test_check("shiny")
|
||||
Saving _problems/test-timer-35.R
|
||||
[ FAIL 1 | WARN 0 | SKIP 22 | PASS 1981 ]
|
||||
|
||||
══ Skipped tests (22) ══════════════════════════════════════════════════════════
|
||||
• File system is not case-sensitive (1): 'test-app.R:36:5'
|
||||
• I'm not sure of a great way to test this without timers. (1):
|
||||
'test-test-server.R:216:3'
|
||||
• Not testing in CI (1): 'test-devmode.R:17:3'
|
||||
• On CRAN (18): 'test-actionButton.R:59:1', 'test-busy-indication.R:1:1',
|
||||
'test-busy-indication.R:15:1', 'test-busy-indication.R:50:1',
|
||||
'test-otel-error.R:1:1', 'test-otel-mock.R:1:1', 'test-pkgdown.R:3:3',
|
||||
'test-reactivity.r:146:1', 'test-reactivity.r:1240:5',
|
||||
'test-reactivity.r:1240:5', 'test-stacks-deep.R:93:1',
|
||||
'test-stacks-deep.R:141:1', 'test-stacks.R:140:3', 'test-tabPanel.R:46:1',
|
||||
'test-tabPanel.R:66:1', 'test-tabPanel.R:73:1', 'test-tabPanel.R:83:1',
|
||||
'test-utils.R:177:3'
|
||||
• {shinytest2} is not installed (1): 'test-test-shinyAppTemplate.R:2:1'
|
||||
|
||||
══ Failed tests ════════════════════════════════════════════════════════════════
|
||||
── Failure ('test-timer.R:35:3'): Unscheduling works ───────────────────────────
|
||||
Expected `timerCallbacks$.times` to be identical to `origTimes`.
|
||||
Differences:
|
||||
`attr(actual, 'row.names')` is an integer vector ()
|
||||
`attr(expected, 'row.names')` is a character vector ()
|
||||
|
||||
|
||||
[ FAIL 1 | WARN 0 | SKIP 22 | PASS 1981 ]
|
||||
Error:
|
||||
! Test failures.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
|
||||
#### 2025-12-03
|
||||
|
||||
```
|
||||
Dear maintainer,
|
||||
|
||||
Please see the problems shown on
|
||||
<https://cran.r-project.org/web/checks/check_results_shiny.html>.
|
||||
|
||||
Please correct before 2025-12-17 to safely retain your package on CRAN.
|
||||
|
||||
The CRAN Team
|
||||
```
|
||||
|
||||
## `R CMD check` results:
|
||||
|
||||
The maintainer change is correctly detected. The URL check sometimes flags a 429
|
||||
error from Wikipedia, which is a temporary issue since the URL is valid when
|
||||
visited manually.
|
||||
0 errors | 0 warning | 1 note
|
||||
|
||||
```
|
||||
* checking CRAN incoming feasibility ... [19s] NOTE
|
||||
Maintainer: 'Carson Sievert <barret@posit.co>'
|
||||
─ checking CRAN incoming feasibility ... [7s/70s] NOTE (1m 9.5s)
|
||||
Maintainer: ‘Carson Sievert <carson@posit.co>’
|
||||
|
||||
New maintainer:
|
||||
Carson Sievert <barret@posit.co>
|
||||
Old maintainer(s):
|
||||
Winston Chang <winston@posit.co>
|
||||
|
||||
Found the following (possibly) invalid URLs:
|
||||
URL: https://en.wikipedia.org/wiki/Reactive_programming
|
||||
From: README.md
|
||||
Status: 429
|
||||
Message: Too Many Requests
|
||||
Days since last update: 5
|
||||
```
|
||||
|
||||
|
||||
## Reverse dependency fixes
|
||||
|
||||
The revdep checks below are failing due to changes made in https://github.com/rstudio/shiny/pull/4249 .
|
||||
|
||||
Unresolved PRs submitted in 2025/06:
|
||||
* omicsTools - https://github.com/cheemalab/omicsTools/pull/1
|
||||
* shinyGovstyle - https://github.com/dfe-analytical-services/shinyGovstyle/pull/155
|
||||
* ShinyLink - https://github.com/cdc-addm/ShinyLink/pull/3
|
||||
* shinySbm - https://github.com/Jo-Theo/shinySbm/pull/2
|
||||
|
||||
Unresolved PR submitted in 2025/10/29:
|
||||
* biodosetools - PR made 2025/10/29 - https://github.com/biodosetools-team/biodosetools/pull/64
|
||||
* inshiny - PR made 2025/10/29 - https://github.com/nicholasdavies/inshiny/pull/1
|
||||
|
||||
## Reverse dependency false positives
|
||||
|
||||
* SouthParkRshiny - New NOTE about installed package size. This is unrelated to any new changes in Shiny.
|
||||
|
||||
> ```
|
||||
> * checking installed package size ... NOTE
|
||||
> installed size is 8.6Mb
|
||||
> sub-directories of 1Mb or more:
|
||||
> data 8.0Mb
|
||||
> ```
|
||||
|
||||
## revdepcheck results
|
||||
|
||||
We checked 1395 reverse dependencies (1388 from CRAN + 7 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
We checked 1383 reverse dependencies (1376 from CRAN + 7 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
|
||||
* We saw 7 new problems
|
||||
* We failed to check 21 packages
|
||||
* We saw 0 new problems
|
||||
* We failed to check 31 packages
|
||||
|
||||
Issues with CRAN packages are summarised below.
|
||||
|
||||
### New problems
|
||||
(This reports the first line of each new failure)
|
||||
|
||||
* biodosetools
|
||||
checking tests ... ERROR
|
||||
|
||||
* inshiny
|
||||
checking examples ... ERROR
|
||||
checking tests ... ERROR
|
||||
checking re-building of vignette outputs ... ERROR
|
||||
|
||||
* omicsTools
|
||||
checking tests ... ERROR
|
||||
|
||||
* shinyGovstyle
|
||||
checking tests ... ERROR
|
||||
|
||||
* ShinyLink
|
||||
checking tests ... ERROR
|
||||
|
||||
* shinySbm
|
||||
checking tests ... ERROR
|
||||
|
||||
* SouthParkRshiny
|
||||
checking installed package size ... NOTE
|
||||
|
||||
### Failed to check
|
||||
|
||||
* AssumpSure
|
||||
* boinet
|
||||
* brms
|
||||
* cheem
|
||||
* ctsem
|
||||
* detourr
|
||||
* FAfA
|
||||
* fio
|
||||
* fitteR
|
||||
* FossilSimShiny
|
||||
* GDINA
|
||||
* ggsem
|
||||
* grandR
|
||||
* hbsaems
|
||||
* langevitour
|
||||
* lavaan.shiny
|
||||
* lcsm
|
||||
* linkspotter
|
||||
* loon.shiny
|
||||
* MOsemiind
|
||||
* MVN
|
||||
* pandemonium
|
||||
* polarisR
|
||||
* RCTrep
|
||||
* rstanarm
|
||||
* semdrw
|
||||
* shotGroups
|
||||
* sphereML
|
||||
* spinifex
|
||||
* SurprisalAnalysis
|
||||
* TestAnaAPP
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
/*! shiny 1.12.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.12.1.9000 | (c) 2012-2025 Posit Software, PBC. | License: MIT + file LICENSE */
|
||||
:where([data-shiny-busy-spinners] .recalculating){position:relative}[data-shiny-busy-spinners] .recalculating{min-height:var(--shiny-spinner-size, 32px)}[data-shiny-busy-spinners] .recalculating:after{position:absolute;content:"";--_shiny-spinner-url: var(--shiny-spinner-url, url(spinners/ring.svg));--_shiny-spinner-color: var(--shiny-spinner-color, var(--bs-primary, #007bc2));--_shiny-spinner-size: var(--shiny-spinner-size, 32px);--_shiny-spinner-delay: var(--shiny-spinner-delay, 1s);background:var(--_shiny-spinner-color);width:var(--_shiny-spinner-size);height:var(--_shiny-spinner-size);inset:calc(50% - var(--_shiny-spinner-size) / 2);mask-image:var(--_shiny-spinner-url);-webkit-mask-image:var(--_shiny-spinner-url);opacity:0;animation-delay:var(--_shiny-spinner-delay);animation-name:fade-in;animation-duration:.25s;animation-fill-mode:forwards}[data-shiny-busy-spinners] .recalculating:has(>*),[data-shiny-busy-spinners] .recalculating:empty{opacity:1}[data-shiny-busy-spinners] .recalculating>*:not(.recalculating){opacity:var(--_shiny-fade-opacity);transition:opacity .25s ease var(--shiny-spinner-delay, 1s)}[data-shiny-busy-spinners] .recalculating.html-widget-output{visibility:inherit!important}[data-shiny-busy-spinners] .recalculating.html-widget-output>*{visibility:hidden}[data-shiny-busy-spinners] .recalculating.html-widget-output :after{visibility:visible}[data-shiny-busy-spinners] .recalculating.shiny-html-output:not(.shiny-table-output):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(.recalculating:not(.shiny-html-output)):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(.recalculating.shiny-table-output):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(#shiny-disconnected-overlay):after{display:none}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, transparent, var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), transparent ) );--_shiny-pulse-height: var(--shiny-pulse-height, 3px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.2s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-direction:alternate;animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:has(#shiny-disconnected-overlay):after{display:none}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes busy-page-pulse{0%{left:-14%;right:97%}45%{left:0%;right:14%}55%{left:14%;right:0%}to{left:97%;right:-14%}}.shiny-spinner-output-container{--shiny-spinner-size: 0px}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
/*! shiny 1.12.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.12.1.9000 | (c) 2012-2025 Posit Software, PBC. | License: MIT + file LICENSE */
|
||||
"use strict";(()=>{document.documentElement.classList.add("autoreload-enabled");var c=window.location.protocol==="https:"?"wss:":"ws:",s=window.location.pathname.replace(/\/?$/,"/")+"autoreload/",i=`${c}//${window.location.host}${s}`,l=document.currentScript?.dataset?.wsUrl||i;async function u(o){let e=new WebSocket(o),n=!1;return new Promise((a,r)=>{e.onopen=()=>{n=!0},e.onerror=t=>{r(t)},e.onclose=()=>{n?a(!1):r(new Error("WebSocket connection failed"))},e.onmessage=function(t){t.data==="autoreload"&&a(!0)}})}async function d(o){return new Promise(e=>setTimeout(e,o))}async function w(){for(;;){try{if(await u(l)){window.location.reload();return}}catch{console.debug("Giving up on autoreload");return}await d(1e3)}}w().catch(o=>{console.error(o)});})();
|
||||
//# sourceMappingURL=shiny-autoreload.js.map
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
/*! shiny 1.12.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.12.1.9000 | (c) 2012-2025 Posit Software, PBC. | License: MIT + file LICENSE */
|
||||
#showcase-well{border-radius:0}.shiny-code{background-color:#fff;margin-bottom:0}.shiny-code code{font-family:Menlo,Consolas,Courier New,monospace}.shiny-code-container{margin-top:20px;clear:both}.shiny-code-container h3{display:inline;margin-right:15px}.showcase-header{font-size:16px;font-weight:400}.showcase-code-link{text-align:right;padding:15px}#showcase-app-container{vertical-align:top}#showcase-code-tabs{margin-right:15px}#showcase-code-tabs pre{border:none;line-height:1em}#showcase-code-tabs .nav,#showcase-code-tabs ul{margin-bottom:0}#showcase-code-tabs .tab-content{border-style:solid;border-color:#e5e5e5;border-width:0px 1px 1px 1px;overflow:auto;border-bottom-right-radius:4px;border-bottom-left-radius:4px}#showcase-app-code{width:100%}#showcase-code-position-toggle{float:right}#showcase-sxs-code{padding-top:20px;vertical-align:top}.showcase-code-license{display:block;text-align:right}#showcase-code-content pre{background-color:#fff}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
/*! shiny 1.12.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.12.1.9000 | (c) 2012-2025 Posit Software, PBC. | License: MIT + file LICENSE */
|
||||
"use strict";(()=>{var m=400;function c(e,s){let t=0;if(e.nodeType===3){let n=e.nodeValue?.replace(/\n/g,"").length??0;if(n>=s)return{element:e,offset:s};t+=n}else if(e.nodeType===1&&e.firstChild){let n=c(e.firstChild,s);if(n.element!==null)return n;t+=n.offset}return e.nextSibling?c(e.nextSibling,s-t):{element:null,offset:t}}function a(e,s,t){let n=0;for(let l=0;l<e.childNodes.length;l++){let i=e.childNodes[l];if(i.nodeType===3){let o=/\n/g,d;for(;(d=o.exec(i.nodeValue))!==null;)if(n++,n===s)return c(i,d.index+t+1)}else if(i.nodeType===1){let o=a(i,s-n,t);if(o.element!==null)return o;n+=o.offset}}return{element:null,offset:n}}function g(e,s){if(!document.createRange)return;let t=document.getElementById("srcref_"+e);if(!t){t=document.createElement("span"),t.id="srcref_"+e;let n=e,l=document.getElementById(s.replace(/\./g,"_")+"_code");if(!l)return;let i=a(l,n[0],n[4]),o=a(l,n[2],n[5]);if(i.element===null||o.element===null)return;let d=document.createRange();i.element.parentNode?.nodeName==="SPAN"&&i.element!==o.element?d.setStartBefore(i.element.parentNode):d.setStart(i.element,i.offset),o.element.parentNode?.nodeName==="SPAN"&&i.element!==o.element?d.setEndAfter(o.element.parentNode):d.setEnd(o.element,o.offset),d.surroundContents(t)}$(t).stop(!0,!0).effect("highlight",null,1600)}window.Shiny&&window.Shiny.addCustomMessageHandler("showcase-src",function(e){e.srcref&&e.srcfile&&g(e.srcref,e.srcfile)});var r=!1,u=function(e,s){let t=s?m:1,n=e?document.getElementById("showcase-sxs-code"):document.getElementById("showcase-code-inline"),l=e?document.getElementById("showcase-code-inline"):document.getElementById("showcase-sxs-code");if(document.getElementById("showcase-app-metadata")===null){let o=$("#showcase-well");e?o.fadeOut(t):o.fadeIn(t)}if(n===null||l===null){console.warn("Could not find the host elements for the code tabs. This is likely a bug in the showcase app.");return}$(n).hide(),$(l).fadeOut(t,function(){let o=document.getElementById("showcase-code-tabs");if(o===null){console.warn("Could not find the code tabs element. This is likely a bug in the showcase app.");return}if(l.removeChild(o),n.appendChild(o),e?p():document.getElementById("showcase-code-content")?.removeAttribute("style"),$(n).fadeIn(t),!e&&(document.getElementById("showcase-app-container")?.removeAttribute("style"),s)){let f=$(n).offset()?.top;f!==void 0&&$(document.body).animate({scrollTop:f})}let d=document.getElementById("readme-md");d!==null&&(d.parentElement?.removeChild(d),e?(l.appendChild(d),$(l).fadeIn(t)):document.getElementById("showcase-app-metadata")?.appendChild(d)),document.getElementById("showcase-code-position-toggle").innerHTML=e?'<i class="fa fa-level-down"></i> show below':'<i class="fa fa-level-up"></i> show with app'}),e&&$(document.body).animate({scrollTop:0},t),r=e,h(e&&s),$(window).trigger("resize")};function h(e){let t=960,n=1,l=document.getElementById("showcase-app-code").offsetWidth;l/2>960?t=l/2:l*.66>960?t=960:(t=l*.66,n=t/960),$("#showcase-app-container").animate({width:t+"px",zoom:n*100+"%"},e?m:0)}var w=function(){u(!r,!0)},y=function(){document.body.offsetWidth>1350&&u(!0,!1)};function p(){document.getElementById("showcase-code-content").style.height=$(window).height()+"px"}function E(){let e=document.getElementById("showcase-markdown-content");if(e!==null){let s=document.getElementById("readme-md");if(s!==null){let t=e.content.cloneNode(!0);s.appendChild(t)}}}$(window).resize(function(){r&&(h(!1),p())});window.toggleCodePosition=w;$(window).on("load",y);$(window).on("load",E);window.hljs&&window.hljs.initHighlightingOnLoad();})();
|
||||
//# sourceMappingURL=shiny-showcase.js.map
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
/*! shiny 1.12.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.12.1.9000 | (c) 2012-2025 Posit Software, PBC. | License: MIT + file LICENSE */
|
||||
"use strict";(()=>{var t=eval;window.addEventListener("message",function(a){let e=a.data;e.code&&t(e.code)});})();
|
||||
//# sourceMappingURL=shiny-testmode.js.map
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*! shiny 1.12.0 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.12.1.9000 | (c) 2012-2025 Posit Software, PBC. | License: MIT + file LICENSE */
|
||||
"use strict";
|
||||
(() => {
|
||||
var __create = Object.create;
|
||||
@@ -7206,7 +7206,7 @@ ${duplicateIdMsg}`;
|
||||
// srcts/src/shiny/index.ts
|
||||
var ShinyClass = class {
|
||||
constructor() {
|
||||
this.version = "1.12.0";
|
||||
this.version = "1.12.1.9000";
|
||||
const { inputBindings, fileInputBinding: fileInputBinding2 } = initInputBindings();
|
||||
const { outputBindings } = initOutputBindings();
|
||||
setFileInputBinding(fileInputBinding2);
|
||||
|
||||
4
inst/www/shared/shiny.min.js
vendored
4
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -45,6 +45,29 @@ is, a function that quickly returns a promise) and allows even that very
|
||||
session to immediately unblock and carry on with other user interactions.
|
||||
}
|
||||
|
||||
\section{OpenTelemetry Integration}{
|
||||
|
||||
|
||||
When an \code{ExtendedTask} is created, if OpenTelemetry tracing is enabled for
|
||||
\code{"reactivity"} (see \code{\link[=withOtelCollect]{withOtelCollect()}}), the \code{ExtendedTask} will record
|
||||
spans for each invocation of the task. The tracing level at \code{invoke()} time
|
||||
does not affect whether spans are recorded; only the tracing level when
|
||||
calling \code{ExtendedTask$new()} matters.
|
||||
|
||||
The OTel span will be named based on the label created from the variable the
|
||||
\code{ExtendedTask} is assigned to. If no label can be determined, the span will
|
||||
be named \verb{<anonymous>}. Similar to other Shiny OpenTelemetry spans, the span
|
||||
will also include source reference attributes and session ID attributes.
|
||||
|
||||
\if{html}{\out{<div class="sourceCode r">}}\preformatted{withOtelCollect("all", \{
|
||||
my_task <- ExtendedTask$new(function(...) \{ ... \})
|
||||
\})
|
||||
|
||||
# Span recorded for this invocation: ExtendedTask my_task
|
||||
my_task$invoke(...)
|
||||
}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
\examples{
|
||||
\dontshow{if (rlang::is_interactive() && rlang::is_installed("mirai")) withAutoprint(\{ # examplesIf}
|
||||
library(shiny)
|
||||
|
||||
@@ -130,22 +130,31 @@ ragg package. See \code{\link[=plotPNG]{plotPNG()}} for more information.}
|
||||
Cairo package. See \code{\link[=plotPNG]{plotPNG()}} for more information.}
|
||||
\item{shiny.devmode (defaults to \code{NULL})}{Option to enable Shiny Developer Mode. When set,
|
||||
different default \code{getOption(key)} values will be returned. See \code{\link[=devmode]{devmode()}} for more details.}
|
||||
\item{shiny.otel.collect (defaults to \code{Sys.getenv("SHINY_OTEL_COLLECT", "all")})}{Determines how Shiny will
|
||||
interact with OpenTelemetry.
|
||||
\item{shiny.otel.collect (defaults to \code{Sys.getenv("SHINY_OTEL_COLLECT", "all")})}{Determines how Shiny will interact with OpenTelemetry.
|
||||
|
||||
Supported values:
|
||||
\itemize{
|
||||
\item \code{"none"} - No Shiny OpenTelemetry tracing.
|
||||
\item \code{"session"} - Adds session start/end spans.
|
||||
\item \code{"reactive_update"} - Spans for any synchronous/asynchronous reactive update. (Includes \code{"session"} features).
|
||||
\item \code{"reactivity"} - Spans for all reactive expressions. (Includes \code{"reactive_update"} features).
|
||||
\item \code{"all"} - All Shiny OpenTelemetry tracing. Currently equivalent to \code{"reactivity"}.
|
||||
\item \code{"reactive_update"} - Spans for any synchronous/asynchronous reactive
|
||||
update. (Includes \code{"session"} features).
|
||||
\item \code{"reactivity"} - Spans for all reactive expressions and logs for setting
|
||||
reactive vals and values. (Includes \code{"reactive_update"} features). This
|
||||
option must be set when creating any reactive objects that should record
|
||||
OpenTelemetry spans / logs. See \code{\link[=withOtelCollect]{withOtelCollect()}} and
|
||||
\code{\link[=localOtelCollect]{localOtelCollect()}} for ways to set this option locally when creating
|
||||
your reactive expressions.
|
||||
\item \code{"all"} - All Shiny OpenTelemetry tracing. Currently equivalent to
|
||||
\code{"reactivity"}.
|
||||
}
|
||||
|
||||
This option is useful for debugging and profiling while in production. This
|
||||
option will only be useful if the \code{otelsdk} package is installed and
|
||||
\code{otel::is_tracing_enabled()} returns \code{TRUE}. Please have any OpenTelemetry
|
||||
environment variables set before starting your Shiny app.}
|
||||
environment variables set before loading any relevant R packages.
|
||||
|
||||
To set this option locally within a specific part of your Shiny
|
||||
application, see \code{\link[=withOtelCollect]{withOtelCollect()}} and \code{\link[=localOtelCollect]{localOtelCollect()}}.}
|
||||
\item{shiny.otel.sanitize.errors (defaults to \code{TRUE})}{If \code{TRUE}, fatal and unhandled errors will be sanitized before being sent to the OpenTelemetry backend. The default value of \code{TRUE} is set to avoid potentially sending sensitive information to the OpenTelemetry backend. If you want the full error message and stack trace to be sent to the OpenTelemetry backend, set this option to \code{FALSE} or use \code{safeError(e)}.}
|
||||
}
|
||||
}
|
||||
|
||||
107
man/withOtelCollect.Rd
Normal file
107
man/withOtelCollect.Rd
Normal file
@@ -0,0 +1,107 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/otel-with.R
|
||||
\name{withOtelCollect}
|
||||
\alias{withOtelCollect}
|
||||
\alias{localOtelCollect}
|
||||
\title{Temporarily set OpenTelemetry (OTel) collection level}
|
||||
\usage{
|
||||
withOtelCollect(collect, expr)
|
||||
|
||||
localOtelCollect(collect, envir = parent.frame())
|
||||
}
|
||||
\arguments{
|
||||
\item{collect}{Character string specifying the OpenTelemetry collection level.
|
||||
Must be one of the following:
|
||||
|
||||
\if{html}{\out{<div class="sourceCode">}}\preformatted{* `"none"` - No telemetry data collected
|
||||
* `"reactivity"` - Collect reactive execution spans (includes session and
|
||||
reactive update events)
|
||||
* `"all"` - All available telemetry (currently equivalent to `"reactivity"`)
|
||||
}\if{html}{\out{</div>}}}
|
||||
|
||||
\item{expr}{Expression to evaluate with the specified collection level
|
||||
(for \code{withOtelCollect()}).}
|
||||
|
||||
\item{envir}{Environment where the collection level should be set
|
||||
(for \code{localOtelCollect()}). Defaults to the parent frame.}
|
||||
}
|
||||
\value{
|
||||
\itemize{
|
||||
\item \code{withOtelCollect()} returns the value of \code{expr}.
|
||||
\item \code{localOtelCollect()} is called for its side effect and returns the previous
|
||||
\code{collect} value invisibly.
|
||||
}
|
||||
}
|
||||
\description{
|
||||
Control Shiny's OTel collection level for particular reactive expression(s).
|
||||
|
||||
\code{withOtelCollect()} sets the OpenTelemetry collection level for
|
||||
the duration of evaluating \code{expr}. \code{localOtelCollect()} sets the collection
|
||||
level for the remainder of the current function scope.
|
||||
}
|
||||
\details{
|
||||
Note that \code{"session"} and \code{"reactive_update"} levels are not permitted as
|
||||
these are runtime-specific levels that should only be set permanently via
|
||||
\code{options(shiny.otel.collect = ...)} or the \code{SHINY_OTEL_COLLECT} environment
|
||||
variable, not temporarily during reactive expression creation.
|
||||
}
|
||||
\section{Best practice}{
|
||||
|
||||
|
||||
Best practice is to set the collection level for code that \emph{creates} reactive
|
||||
expressions, not code that \emph{runs} them. For instance:
|
||||
|
||||
\if{html}{\out{<div class="sourceCode r">}}\preformatted{# Disable telemetry for a reactive expression
|
||||
withOtelCollect("none", \{
|
||||
my_reactive <- reactive(\{ ... \})
|
||||
\})
|
||||
|
||||
# Disable telemetry for a render function
|
||||
withOtelCollect("none", \{
|
||||
output$my_plot <- renderPlot(\{ ... \})
|
||||
\})
|
||||
|
||||
#' # Disable telemetry for an observer
|
||||
withOtelCollect("none", \{
|
||||
observe(\{ ... \}))
|
||||
\})
|
||||
|
||||
# Disable telemetry for an entire module
|
||||
withOtelCollect("none", \{
|
||||
my_result <- my_module("my_id")
|
||||
\})
|
||||
# Use `my_result` as normal here
|
||||
}\if{html}{\out{</div>}}
|
||||
|
||||
NOTE: It's not recommended to pipe existing reactive objects into
|
||||
\code{withOtelCollect()} since they won't inherit their intended OTel settings,
|
||||
leading to confusion.
|
||||
}
|
||||
|
||||
\examples{
|
||||
\dontrun{
|
||||
# Temporarily disable telemetry collection
|
||||
withOtelCollect("none", {
|
||||
# Code here won't generate telemetry
|
||||
reactive({ input$x + 1 })
|
||||
})
|
||||
|
||||
# Collect reactivity telemetry but not other events
|
||||
withOtelCollect("reactivity", {
|
||||
# Reactive execution will be traced
|
||||
observe({ print(input$x) })
|
||||
})
|
||||
|
||||
# Use local variant in a function
|
||||
my_function <- function() {
|
||||
localOtelCollect("none")
|
||||
# Rest of function executes without telemetry
|
||||
reactive({ input$y * 2 })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
\seealso{
|
||||
See the \code{shiny.otel.collect} option within \code{\link{shinyOptions}}. Setting
|
||||
this value will globally control OpenTelemetry collection levels.
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
"url": "git+https://github.com/rstudio/shiny.git"
|
||||
},
|
||||
"name": "@posit/shiny",
|
||||
"version": "1.12.0",
|
||||
"license": "GPL-3.0-only",
|
||||
"version": "1.12.1-alpha.9000",
|
||||
"license": "MIT",
|
||||
"main": "",
|
||||
"browser": "",
|
||||
"types": "srcts/types/extras/globalShiny.d.ts",
|
||||
|
||||
@@ -1,47 +1,45 @@
|
||||
# Revdeps
|
||||
|
||||
## Failed to check (28)
|
||||
## Failed to check (38)
|
||||
|
||||
|package |version |error |warning |note |
|
||||
|:--------------------|:-------|:-----|:-------|:----|
|
||||
|ADAMgui |? | | | |
|
||||
|AssumpSure |? | | | |
|
||||
|boinet |1.5.0 |1 | | |
|
||||
|brms |? | | | |
|
||||
|cheem |? | | | |
|
||||
|ctsem |3.10.4 |1 | |1 |
|
||||
|detourr |? | | | |
|
||||
|EMMAgeo |? | | | |
|
||||
|FactEff |? | | | |
|
||||
|FAfA |? | | | |
|
||||
|fio |0.1.6 |1 | | |
|
||||
|fitteR |? | | | |
|
||||
|FossilSimShiny |? | | | |
|
||||
|GDINA |? | | | |
|
||||
|ggsem |? | | | |
|
||||
|grandR |? | | | |
|
||||
|GSVA |? | | | |
|
||||
|hbsaems |0.1.1 |1 | | |
|
||||
|hbsaems |? | | | |
|
||||
|langevitour |? | | | |
|
||||
|lavaan.shiny |? | | | |
|
||||
|lcsm |? | | | |
|
||||
|linkspotter |1.3.0 |1 | | |
|
||||
|linkspotter |? | | | |
|
||||
|loon.shiny |? | | | |
|
||||
|MOsemiind |0.1.0 |1 | | |
|
||||
|MVN |6.2 |1 | | |
|
||||
|MVN |? | | | |
|
||||
|pandemonium |? | | | |
|
||||
|polarisR |? | | | |
|
||||
|Prostar |? | | | |
|
||||
|RCTrep |1.2.0 |1 | | |
|
||||
|recmap |? | | | |
|
||||
|rstanarm |2.32.2 |1 | | |
|
||||
|semdrw |? | | | |
|
||||
|shotGroups |? | | | |
|
||||
|sphereML |? | | | |
|
||||
|spinifex |? | | | |
|
||||
|StatTeacherAssistant |? | | | |
|
||||
|SurprisalAnalysis |? | | | |
|
||||
|TestAnaAPP |? | | | |
|
||||
|
||||
## New problems (7)
|
||||
|
||||
|package |version |error |warning |note |
|
||||
|:---------------|:-------|:------|:-------|:--------|
|
||||
|[biodosetools](problems.md#biodosetools)|3.7.1 |__+1__ | | |
|
||||
|[inshiny](problems.md#inshiny)|0.1.0 |__+3__ | | |
|
||||
|[omicsTools](problems.md#omicstools)|1.0.5 |__+1__ | | |
|
||||
|[shinyGovstyle](problems.md#shinygovstyle)|0.1.0 |__+1__ | | |
|
||||
|[ShinyLink](problems.md#shinylink)|0.2.2 |__+1__ | | |
|
||||
|[shinySbm](problems.md#shinysbm)|0.1.5 |__+1__ | |1 |
|
||||
|[SouthParkRshiny](problems.md#southparkrshiny)|1.0.0 | | |1 __+1__ |
|
||||
|
||||
|
||||
@@ -1,58 +1,42 @@
|
||||
## revdepcheck results
|
||||
|
||||
We checked 1395 reverse dependencies (1388 from CRAN + 7 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
We checked 1383 reverse dependencies (1376 from CRAN + 7 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
|
||||
* We saw 7 new problems
|
||||
* We failed to check 21 packages
|
||||
* We saw 0 new problems
|
||||
* We failed to check 31 packages
|
||||
|
||||
Issues with CRAN packages are summarised below.
|
||||
|
||||
### New problems
|
||||
(This reports the first line of each new failure)
|
||||
|
||||
* biodosetools
|
||||
checking tests ... ERROR
|
||||
|
||||
* inshiny
|
||||
checking examples ... ERROR
|
||||
checking tests ... ERROR
|
||||
checking re-building of vignette outputs ... ERROR
|
||||
|
||||
* omicsTools
|
||||
checking tests ... ERROR
|
||||
|
||||
* shinyGovstyle
|
||||
checking tests ... ERROR
|
||||
|
||||
* ShinyLink
|
||||
checking tests ... ERROR
|
||||
|
||||
* shinySbm
|
||||
checking tests ... ERROR
|
||||
|
||||
* SouthParkRshiny
|
||||
checking installed package size ... NOTE
|
||||
|
||||
### Failed to check
|
||||
|
||||
* AssumpSure (NA)
|
||||
* boinet (NA)
|
||||
* brms (NA)
|
||||
* cheem (NA)
|
||||
* ctsem (NA)
|
||||
* detourr (NA)
|
||||
* FAfA (NA)
|
||||
* fio (NA)
|
||||
* fitteR (NA)
|
||||
* FossilSimShiny (NA)
|
||||
* GDINA (NA)
|
||||
* ggsem (NA)
|
||||
* grandR (NA)
|
||||
* hbsaems (NA)
|
||||
* langevitour (NA)
|
||||
* lavaan.shiny (NA)
|
||||
* lcsm (NA)
|
||||
* linkspotter (NA)
|
||||
* loon.shiny (NA)
|
||||
* MOsemiind (NA)
|
||||
* MVN (NA)
|
||||
* pandemonium (NA)
|
||||
* polarisR (NA)
|
||||
* RCTrep (NA)
|
||||
* rstanarm (NA)
|
||||
* semdrw (NA)
|
||||
* shotGroups (NA)
|
||||
* sphereML (NA)
|
||||
* spinifex (NA)
|
||||
* SurprisalAnalysis (NA)
|
||||
* TestAnaAPP (NA)
|
||||
|
||||
@@ -1,353 +1 @@
|
||||
# biodosetools
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 3.7.1
|
||||
* GitHub: https://github.com/biodosetools-team/biodosetools
|
||||
* Source code: https://github.com/cran/biodosetools
|
||||
* Date/Publication: 2025-10-22 08:10:02 UTC
|
||||
* Number of recursive dependencies: 132
|
||||
|
||||
Run `revdepcheck::cloud_details(, "biodosetools")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking tests ... ERROR
|
||||
```
|
||||
Running ‘testthat.R’
|
||||
Running the tests in ‘tests/testthat.R’ failed.
|
||||
Complete output:
|
||||
> library(testthat)
|
||||
> library(biodosetools)
|
||||
Loading required package: shiny
|
||||
Loading required package: golem
|
||||
>
|
||||
> test_check("biodosetools")
|
||||
! Problem with `glm()` -> constraint ML optimization will be used instead
|
||||
...
|
||||
- "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">"
|
||||
- " <span class=\"action-label\">go</span>"
|
||||
- "</button>"
|
||||
+ "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">go</button>"
|
||||
|
||||
|
||||
[ FAIL 2 | WARN 1 | SKIP 1 | PASS 455 ]
|
||||
Error:
|
||||
! Test failures.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
# inshiny
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 0.1.0
|
||||
* GitHub: https://github.com/nicholasdavies/inshiny
|
||||
* Source code: https://github.com/cran/inshiny
|
||||
* Date/Publication: 2025-09-09 14:00:13 UTC
|
||||
* Number of recursive dependencies: 53
|
||||
|
||||
Run `revdepcheck::cloud_details(, "inshiny")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking examples ... ERROR
|
||||
```
|
||||
Running examples in ‘inshiny-Ex.R’ failed
|
||||
The error most likely occurred in:
|
||||
|
||||
> ### Name: inline_button
|
||||
> ### Title: Inline action button
|
||||
> ### Aliases: inline_button
|
||||
>
|
||||
> ### ** Examples
|
||||
>
|
||||
> ui <- bslib::page_fixed(
|
||||
...
|
||||
+ label = shiny::span(style = "font-style:italic", "button"),
|
||||
+ icon = shiny::icon("play"),
|
||||
+ meaning = "Update button", accent = "success"),
|
||||
+ "."
|
||||
+ )
|
||||
+ )
|
||||
Error in check_tags(widget, shiny::tags$button(), "shiny::actionButton()") :
|
||||
Unexpected tag structure from shiny::actionButton(). Please contact the package maintainer.
|
||||
Calls: <Anonymous> ... div -> dots_list -> inline -> inline_button -> check_tags
|
||||
Execution halted
|
||||
```
|
||||
|
||||
* checking tests ... ERROR
|
||||
```
|
||||
Running ‘testthat.R’
|
||||
Running the tests in ‘tests/testthat.R’ failed.
|
||||
Complete output:
|
||||
> # This file is part of the standard setup for testthat.
|
||||
> # It is recommended that you do not modify it.
|
||||
> #
|
||||
> # Where should you do additional test configuration?
|
||||
> # Learn more about the roles of various files in:
|
||||
> # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
|
||||
> # * https://testthat.r-lib.org/articles/special-files.html
|
||||
...
|
||||
▆
|
||||
1. ├─inshiny:::cc(...)
|
||||
2. │ └─base::cat(as.character(x)) at ./helper.R:2:5
|
||||
3. └─inshiny::inline_button(...)
|
||||
4. └─inshiny:::check_tags(widget, shiny::tags$button(), "shiny::actionButton()")
|
||||
|
||||
[ FAIL 2 | WARN 0 | SKIP 9 | PASS 24 ]
|
||||
Error:
|
||||
! Test failures.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
* checking re-building of vignette outputs ... ERROR
|
||||
```
|
||||
Error(s) in re-building vignettes:
|
||||
--- re-building ‘inshiny.Rmd’ using rmarkdown
|
||||
|
||||
Quitting from inshiny.Rmd:64-86 [unnamed-chunk-3]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<error/rlang_error>
|
||||
Error in `check_tags()`:
|
||||
! Unexpected tag structure from shiny::actionButton(). Please contact the package maintainer.
|
||||
---
|
||||
Backtrace:
|
||||
...
|
||||
|
||||
Error: processing vignette 'inshiny.Rmd' failed with diagnostics:
|
||||
Unexpected tag structure from shiny::actionButton(). Please contact the package maintainer.
|
||||
--- failed re-building ‘inshiny.Rmd’
|
||||
|
||||
SUMMARY: processing the following file failed:
|
||||
‘inshiny.Rmd’
|
||||
|
||||
Error: Vignette re-building failed.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
# omicsTools
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 1.0.5
|
||||
* GitHub: https://github.com/YaoxiangLi/omicsTools
|
||||
* Source code: https://github.com/cran/omicsTools
|
||||
* Date/Publication: 2023-07-03 16:20:02 UTC
|
||||
* Number of recursive dependencies: 88
|
||||
|
||||
Run `revdepcheck::cloud_details(, "omicsTools")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking tests ... ERROR
|
||||
```
|
||||
Running ‘spelling.R’
|
||||
Running ‘testthat.R’
|
||||
Running the tests in ‘tests/testthat.R’ failed.
|
||||
Complete output:
|
||||
> # This file is part of the standard setup for testthat.
|
||||
> # It is recommended that you do not modify it.
|
||||
> #
|
||||
> # Where should you do additional test configuration?
|
||||
> # Learn more about the roles of various files in:
|
||||
> # * https://r-pkgs.org/tests.html
|
||||
...
|
||||
- "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">"
|
||||
- " <span class=\"action-label\">go</span>"
|
||||
- "</button>"
|
||||
+ "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">go</button>"
|
||||
|
||||
|
||||
[ FAIL 2 | WARN 0 | SKIP 1 | PASS 94 ]
|
||||
Error:
|
||||
! Test failures.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
# shinyGovstyle
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 0.1.0
|
||||
* GitHub: https://github.com/moj-analytical-services/shinyGovstyle
|
||||
* Source code: https://github.com/cran/shinyGovstyle
|
||||
* Date/Publication: 2024-09-12 14:40:02 UTC
|
||||
* Number of recursive dependencies: 49
|
||||
|
||||
Run `revdepcheck::cloud_details(, "shinyGovstyle")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking tests ... ERROR
|
||||
```
|
||||
Running ‘testthat.R’
|
||||
Running the tests in ‘tests/testthat.R’ failed.
|
||||
Complete output:
|
||||
> library(testthat)
|
||||
> library(shinyGovstyle)
|
||||
>
|
||||
> test_check("shinyGovstyle")
|
||||
Saving _problems/test-backlink_Input-7.R
|
||||
[ FAIL 1 | WARN 0 | SKIP 0 | PASS 125 ]
|
||||
|
||||
...
|
||||
══ Failed tests ════════════════════════════════════════════════════════════════
|
||||
── Failure ('test-backlink_Input.R:4:3'): backlink works ───────────────────────
|
||||
Expected `backlink_check$children[[1]][[2]]` to be identical to "Back".
|
||||
Differences:
|
||||
target is NULL, current is character
|
||||
|
||||
[ FAIL 1 | WARN 0 | SKIP 0 | PASS 125 ]
|
||||
Error:
|
||||
! Test failures.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
# ShinyLink
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 0.2.2
|
||||
* GitHub: NA
|
||||
* Source code: https://github.com/cran/ShinyLink
|
||||
* Date/Publication: 2023-01-18 11:40:05 UTC
|
||||
* Number of recursive dependencies: 128
|
||||
|
||||
Run `revdepcheck::cloud_details(, "ShinyLink")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking tests ... ERROR
|
||||
```
|
||||
Running ‘spelling.R’
|
||||
Running ‘testthat.R’
|
||||
Running the tests in ‘tests/testthat.R’ failed.
|
||||
Complete output:
|
||||
> # This file is part of the standard setup for testthat.
|
||||
> # It is recommended that you do not modify it.
|
||||
> #
|
||||
> # Where should you do additional test configuration?
|
||||
> # Learn more about the roles of various files in:
|
||||
> # * https://r-pkgs.org/tests.html
|
||||
...
|
||||
- "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">"
|
||||
- " <span class=\"action-label\">go</span>"
|
||||
- "</button>"
|
||||
+ "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">go</button>"
|
||||
|
||||
|
||||
[ FAIL 2 | WARN 0 | SKIP 1 | PASS 145 ]
|
||||
Error:
|
||||
! Test failures.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
# shinySbm
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 0.1.5
|
||||
* GitHub: https://github.com/Jo-Theo/shinySbm
|
||||
* Source code: https://github.com/cran/shinySbm
|
||||
* Date/Publication: 2023-09-07 21:50:02 UTC
|
||||
* Number of recursive dependencies: 134
|
||||
|
||||
Run `revdepcheck::cloud_details(, "shinySbm")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking tests ... ERROR
|
||||
```
|
||||
Running ‘spelling.R’
|
||||
Running ‘testthat.R’
|
||||
Running the tests in ‘tests/testthat.R’ failed.
|
||||
Complete output:
|
||||
> # This file is part of the standard setup for testthat.
|
||||
> # It is recommended that you do not modify it.
|
||||
> #
|
||||
> # Where should you do additional test configuration?
|
||||
> # Learn more about the roles of various files in:
|
||||
> # * https://r-pkgs.org/tests.html
|
||||
...
|
||||
- "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">"
|
||||
- " <span class=\"action-label\">go</span>"
|
||||
- "</button>"
|
||||
+ "<button id=\"go_filter\" type=\"button\" class=\"btn btn-default action-button\" style=\"display: none;\">go</button>"
|
||||
|
||||
|
||||
[ FAIL 2 | WARN 0 | SKIP 1 | PASS 141 ]
|
||||
Error:
|
||||
! Test failures.
|
||||
Execution halted
|
||||
```
|
||||
|
||||
## In both
|
||||
|
||||
* checking Rd files ... NOTE
|
||||
```
|
||||
checkRd: (-1) FungusTreeNetwork.Rd:15-21: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) FungusTreeNetwork.Rd:22-28: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) FungusTreeNetwork.Rd:33-34: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) FungusTreeNetwork.Rd:33: Lost braces; missing escapes or markup?
|
||||
33 | \item{tree_tree}{Results of \code{estimateSimpleSBM} for {sbm}
|
||||
| ^
|
||||
checkRd: (-1) FungusTreeNetwork.Rd:35-36: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) FungusTreeNetwork.Rd:35: Lost braces; missing escapes or markup?
|
||||
35 | \item{fungus_tree}{Results of \code{estimateBipartiteSBM} for {sbm}
|
||||
| ^
|
||||
...
|
||||
checkRd: (-1) visSbm.default.Rd:25: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:26: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:43-44: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:45: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:46: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:47: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:48: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:49: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:50: Lost braces in \itemize; meant \describe ?
|
||||
checkRd: (-1) visSbm.default.Rd:51: Lost braces in \itemize; meant \describe ?
|
||||
```
|
||||
|
||||
# SouthParkRshiny
|
||||
|
||||
<details>
|
||||
|
||||
* Version: 1.0.0
|
||||
* GitHub: https://github.com/Amalan-ConStat/SouthParkRshiny
|
||||
* Source code: https://github.com/cran/SouthParkRshiny
|
||||
* Date/Publication: 2024-03-09 11:10:08 UTC
|
||||
* Number of recursive dependencies: 112
|
||||
|
||||
Run `revdepcheck::cloud_details(, "SouthParkRshiny")` for more info
|
||||
|
||||
</details>
|
||||
|
||||
## Newly broken
|
||||
|
||||
* checking installed package size ... NOTE
|
||||
```
|
||||
installed size is 8.6Mb
|
||||
sub-directories of 1Mb or more:
|
||||
data 8.0Mb
|
||||
```
|
||||
|
||||
## In both
|
||||
|
||||
* checking data for non-ASCII characters ... NOTE
|
||||
```
|
||||
Note: found 1562 marked UTF-8 strings
|
||||
```
|
||||
|
||||
*Wow, no problems at all. :)*
|
||||
31
tests/testthat/helper-otel.R
Normal file
31
tests/testthat/helper-otel.R
Normal file
@@ -0,0 +1,31 @@
|
||||
# Helper function to create a mock otel span
|
||||
create_mock_otel_span <- function(name = "test_span") {
|
||||
structure(
|
||||
list(
|
||||
name = name,
|
||||
activate = function(...) NULL,
|
||||
end = function(...) NULL
|
||||
),
|
||||
class = "otel_span"
|
||||
)
|
||||
}
|
||||
|
||||
# Helper function to create a mock tracer
|
||||
create_mock_tracer <- function() {
|
||||
structure(
|
||||
list(
|
||||
name = "mock_tracer",
|
||||
is_enabled = function() TRUE,
|
||||
start_span = function(name, ...) create_mock_otel_span(name)
|
||||
),
|
||||
class = "otel_tracer"
|
||||
)
|
||||
}
|
||||
|
||||
# Helper function to create a mock logger
|
||||
create_mock_logger <- function() {
|
||||
structure(
|
||||
list(name = "mock_logger"),
|
||||
class = "otel_logger"
|
||||
)
|
||||
}
|
||||
@@ -101,9 +101,30 @@ test_that("otel_srcref_attributes extracts attributes from srcref object", {
|
||||
|
||||
attrs <- otel_srcref_attributes(srcref)
|
||||
|
||||
# Preferred attribute names
|
||||
expect_equal(attrs[["code.file.path"]], "/path/to/myfile.R")
|
||||
expect_equal(attrs[["code.line.number"]], 15)
|
||||
expect_equal(attrs[["code.column.number"]], 8)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
|
||||
# Deprecated attribute names (for backward compatibility)
|
||||
expect_equal(attrs[["code.filepath"]], "/path/to/myfile.R")
|
||||
expect_equal(attrs[["code.lineno"]], 15)
|
||||
expect_equal(attrs[["code.column"]], 8)
|
||||
|
||||
# Test with function name
|
||||
attrs_with_fn <- otel_srcref_attributes(srcref, fn_name = "myFunction")
|
||||
|
||||
# Preferred names
|
||||
expect_equal(attrs_with_fn[["code.file.path"]], "/path/to/myfile.R")
|
||||
expect_equal(attrs_with_fn[["code.line.number"]], 15)
|
||||
expect_equal(attrs_with_fn[["code.column.number"]], 8)
|
||||
expect_equal(attrs_with_fn[["code.function.name"]], "myFunction")
|
||||
|
||||
# Deprecated names
|
||||
expect_equal(attrs_with_fn[["code.filepath"]], "/path/to/myfile.R")
|
||||
expect_equal(attrs_with_fn[["code.lineno"]], 15)
|
||||
expect_equal(attrs_with_fn[["code.column"]], 8)
|
||||
})
|
||||
|
||||
test_that("otel_srcref_attributes handles NULL srcref", {
|
||||
@@ -127,9 +148,21 @@ test_that("otel_srcref_attributes extracts from function with srcref", {
|
||||
{
|
||||
attrs <- otel_srcref_attributes(mock_func)
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "function_file.R")
|
||||
expect_equal(attrs[["code.lineno"]], 42)
|
||||
expect_equal(attrs[["code.column"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "function_file.R")
|
||||
expect_equal(attrs[["code.line.number"]], 42)
|
||||
expect_equal(attrs[["code.column.number"]], 12)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
|
||||
# Test with function name
|
||||
attrs_with_fn <- otel_srcref_attributes(
|
||||
mock_func,
|
||||
fn_name = "testFunction"
|
||||
)
|
||||
|
||||
expect_equal(attrs_with_fn[["code.file.path"]], "function_file.R")
|
||||
expect_equal(attrs_with_fn[["code.line.number"]], 42)
|
||||
expect_equal(attrs_with_fn[["code.column.number"]], 12)
|
||||
expect_equal(attrs_with_fn[["code.function.name"]], "testFunction")
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -186,11 +219,27 @@ test_that("otel_srcref_attributes drops NULL values", {
|
||||
|
||||
attrs <- otel_srcref_attributes(srcref)
|
||||
|
||||
# Should only contain lineno and column, not filepath
|
||||
expect_equal(length(attrs), 2)
|
||||
# Should only contain lineno and column (both preferred and deprecated)
|
||||
expect_equal(length(attrs), 4) # 2 preferred + 2 deprecated
|
||||
# Preferred names
|
||||
expect_equal(attrs[["code.line.number"]], 10)
|
||||
expect_equal(attrs[["code.column.number"]], 5)
|
||||
expect_false("code.file.path" %in% names(attrs))
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
# Deprecated names
|
||||
expect_equal(attrs[["code.lineno"]], 10)
|
||||
expect_equal(attrs[["code.column"]], 5)
|
||||
expect_false("code.filepath" %in% names(attrs))
|
||||
|
||||
# Test with function name - NULL fn_name should still be dropped
|
||||
attrs_with_null_fn <- otel_srcref_attributes(srcref, fn_name = NULL)
|
||||
expect_equal(length(attrs_with_null_fn), 4)
|
||||
expect_false("code.function.name" %in% names(attrs_with_null_fn))
|
||||
|
||||
# Test with function name provided
|
||||
attrs_with_fn <- otel_srcref_attributes(srcref, fn_name = "testFunc")
|
||||
expect_equal(length(attrs_with_fn), 5) # 4 location + 1 function name
|
||||
expect_equal(attrs_with_fn[["code.function.name"]], "testFunc")
|
||||
})
|
||||
|
||||
test_that("otel_srcref_attributes handles missing srcfile", {
|
||||
@@ -202,8 +251,13 @@ test_that("otel_srcref_attributes handles missing srcfile", {
|
||||
|
||||
attrs <- otel_srcref_attributes(srcref)
|
||||
|
||||
# Should only contain lineno and column
|
||||
expect_equal(length(attrs), 2)
|
||||
# Should only contain lineno and column (both preferred and deprecated)
|
||||
expect_equal(length(attrs), 4) # 2 preferred + 2 deprecated
|
||||
# Preferred names
|
||||
expect_equal(attrs[["code.line.number"]], 10)
|
||||
expect_equal(attrs[["code.column.number"]], 5)
|
||||
expect_false("code.file.path" %in% names(attrs))
|
||||
# Deprecated names
|
||||
expect_equal(attrs[["code.lineno"]], 10)
|
||||
expect_equal(attrs[["code.column"]], 5)
|
||||
expect_false("code.filepath" %in% names(attrs))
|
||||
@@ -217,9 +271,10 @@ test_that("reactive() captures otel attributes from source reference", {
|
||||
x <- get_reactive_objects()$reactive
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 4)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 4)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "reactive")
|
||||
})
|
||||
|
||||
test_that("reactiveVal() captures otel attributes from source reference", {
|
||||
@@ -228,9 +283,10 @@ test_that("reactiveVal() captures otel attributes from source reference", {
|
||||
# Test the attribute extraction that would be used in reactiveVal
|
||||
attrs <- attr(x, ".impl")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 5)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 5)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "reactiveVal")
|
||||
})
|
||||
|
||||
test_that("reactiveValues() captures otel attributes from source reference", {
|
||||
@@ -238,36 +294,41 @@ test_that("reactiveValues() captures otel attributes from source reference", {
|
||||
|
||||
attrs <- .subset2(x, "impl")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 6)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 6)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "reactiveValues")
|
||||
})
|
||||
|
||||
test_that("observe() captures otel attributes from source reference", {
|
||||
x <- get_reactive_objects()$observe
|
||||
attrs <- x$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 7)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 7)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "observe")
|
||||
})
|
||||
|
||||
test_that("otel attributes integration with render functions", {
|
||||
x <- get_reactive_objects()$renderText
|
||||
attrs <- attr(x, "otelAttrs")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 8)
|
||||
expect_equal(attrs[["code.column"]], 20)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 8)
|
||||
expect_equal(attrs[["code.column.number"]], 20)
|
||||
# Render functions should NOT have code.function.name
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
})
|
||||
|
||||
test_that("observeEvent() captures otel attributes from source reference", {
|
||||
x <- get_reactive_objects()$observeEvent
|
||||
attrs <- x$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 9)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 9)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "observeEvent")
|
||||
})
|
||||
|
||||
test_that("otel attributes follow OpenTelemetry semantic conventions", {
|
||||
@@ -282,15 +343,33 @@ test_that("otel attributes follow OpenTelemetry semantic conventions", {
|
||||
|
||||
attrs <- otel_srcref_attributes(srcref)
|
||||
|
||||
# Check that attribute names follow the convention
|
||||
# Check that preferred attribute names follow the convention
|
||||
expect_true("code.file.path" %in% names(attrs))
|
||||
expect_true("code.line.number" %in% names(attrs))
|
||||
expect_true("code.column.number" %in% names(attrs))
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
|
||||
# Check that deprecated names are also present
|
||||
expect_true("code.filepath" %in% names(attrs))
|
||||
expect_true("code.lineno" %in% names(attrs))
|
||||
expect_true("code.column" %in% names(attrs))
|
||||
|
||||
# Check that values are of correct types
|
||||
expect_true(is.character(attrs[["code.filepath"]]))
|
||||
expect_true(is.numeric(attrs[["code.lineno"]]))
|
||||
expect_true(is.numeric(attrs[["code.column"]]))
|
||||
# Check that values are of correct types (preferred names)
|
||||
expect_true(is.character(attrs[["code.file.path"]]))
|
||||
expect_true(is.numeric(attrs[["code.line.number"]]))
|
||||
expect_true(is.numeric(attrs[["code.column.number"]]))
|
||||
|
||||
# Check that deprecated names have same values
|
||||
expect_equal(attrs[["code.file.path"]], attrs[["code.filepath"]])
|
||||
expect_equal(attrs[["code.line.number"]], attrs[["code.lineno"]])
|
||||
expect_equal(attrs[["code.column.number"]], attrs[["code.column"]])
|
||||
|
||||
# Test with function name
|
||||
attrs_with_fn <- otel_srcref_attributes(srcref, fn_name = "myFunc")
|
||||
|
||||
expect_true("code.function.name" %in% names(attrs_with_fn))
|
||||
expect_true(is.character(attrs_with_fn[["code.function.name"]]))
|
||||
expect_equal(attrs_with_fn[["code.function.name"]], "myFunc")
|
||||
})
|
||||
|
||||
test_that("dropNulls helper works correctly in otel_srcref_attributes", {
|
||||
@@ -302,7 +381,7 @@ test_that("dropNulls helper works correctly in otel_srcref_attributes", {
|
||||
)
|
||||
|
||||
attrs <- otel_srcref_attributes(srcref)
|
||||
expect_equal(length(attrs), 3)
|
||||
expect_equal(length(attrs), 6) # 3 preferred + 3 deprecated
|
||||
|
||||
# Test with missing filename (NULL)
|
||||
srcref_no_file <- structure(
|
||||
@@ -312,16 +391,17 @@ test_that("dropNulls helper works correctly in otel_srcref_attributes", {
|
||||
attr(srcref_no_file, "srcfile") <- list(filename = NULL)
|
||||
|
||||
attrs_no_file <- otel_srcref_attributes(srcref_no_file)
|
||||
expect_equal(length(attrs_no_file), 2)
|
||||
expect_equal(length(attrs_no_file), 4) # 2 preferred + 2 deprecated
|
||||
expect_false("code.file.path" %in% names(attrs_no_file))
|
||||
expect_false("code.filepath" %in% names(attrs_no_file))
|
||||
})
|
||||
|
||||
test_that("otel attributes are used in reactive context execution", {
|
||||
# Test that otel attributes are properly passed through to spans
|
||||
mock_attrs <- list(
|
||||
"code.filepath" = "context_test.R",
|
||||
"code.lineno" = 42L,
|
||||
"code.column" = 8L
|
||||
"code.file.path" = "context_test.R",
|
||||
"code.line.number" = 42L,
|
||||
"code.column.number" = 8L
|
||||
)
|
||||
|
||||
# Test the context info structure used in react.R
|
||||
@@ -342,9 +422,9 @@ test_that("otel attributes are combined with session attributes", {
|
||||
# as happens in the reactive system
|
||||
|
||||
srcref_attrs <- list(
|
||||
"code.filepath" = "session_test.R",
|
||||
"code.lineno" = 15L,
|
||||
"code.column" = 5L
|
||||
"code.file.path" = "session_test.R",
|
||||
"code.line.number" = 15L,
|
||||
"code.column.number" = 5L
|
||||
)
|
||||
|
||||
session_attrs <- list(
|
||||
@@ -355,8 +435,8 @@ test_that("otel attributes are combined with session attributes", {
|
||||
combined_attrs <- c(srcref_attrs, session_attrs)
|
||||
|
||||
expect_equal(length(combined_attrs), 4)
|
||||
expect_equal(combined_attrs[["code.filepath"]], "session_test.R")
|
||||
expect_equal(combined_attrs[["code.lineno"]], 15L)
|
||||
expect_equal(combined_attrs[["code.file.path"]], "session_test.R")
|
||||
expect_equal(combined_attrs[["code.line.number"]], 15L)
|
||||
expect_equal(combined_attrs[["session.id"]], "test-session-123")
|
||||
})
|
||||
|
||||
@@ -364,25 +444,28 @@ test_that("eventReactive() captures otel attributes from source reference", {
|
||||
x <- get_reactive_objects()$eventReactive
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 10)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 10)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "eventReactive")
|
||||
})
|
||||
|
||||
test_that("renderText() with bindCache() captures otel attributes", {
|
||||
x <- get_reactive_objects()$renderCacheA
|
||||
attrs <- attr(x, "otelAttrs")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
})
|
||||
|
||||
test_that("renderText() with bindEvent() captures otel attributes", {
|
||||
x <- get_reactive_objects()$renderEventA
|
||||
attrs <- attr(x, "otelAttrs")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
})
|
||||
|
||||
test_that(
|
||||
@@ -391,8 +474,9 @@ test_that(
|
||||
x <- get_reactive_objects()$renderCacheEventA
|
||||
attrs <- attr(x, "otelAttrs")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
}
|
||||
)
|
||||
|
||||
@@ -400,16 +484,18 @@ test_that("bindCache() wrapping renderText() captures otel attributes", {
|
||||
x <- get_reactive_objects()$renderCacheB
|
||||
attrs <- attr(x, "otelAttrs")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
})
|
||||
|
||||
test_that("bindEvent() wrapping renderText() captures otel attributes", {
|
||||
x <- get_reactive_objects()$renderEventB
|
||||
attrs <- attr(x, "otelAttrs")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
})
|
||||
|
||||
test_that(
|
||||
@@ -418,8 +504,9 @@ test_that(
|
||||
x <- get_reactive_objects()$renderCacheEventB
|
||||
attrs <- attr(x, "otelAttrs")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_false("code.function.name" %in% names(attrs))
|
||||
}
|
||||
)
|
||||
|
||||
@@ -427,32 +514,36 @@ test_that("observe() with bindEvent() captures otel attributes", {
|
||||
x <- get_reactive_objects()$observeEventA
|
||||
attrs <- x$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindEvent")
|
||||
})
|
||||
|
||||
test_that("bindEvent() wrapping observe() captures otel attributes", {
|
||||
x <- get_reactive_objects()$observeEventB
|
||||
attrs <- x$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindEvent")
|
||||
})
|
||||
|
||||
test_that("reactive() with bindCache() captures otel attributes", {
|
||||
x <- get_reactive_objects()$reactiveCacheA
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindCache")
|
||||
})
|
||||
|
||||
test_that("reactive() with bindEvent() captures otel attributes", {
|
||||
x <- get_reactive_objects()$reactiveEventA
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindEvent")
|
||||
})
|
||||
|
||||
test_that(
|
||||
@@ -461,8 +552,9 @@ test_that(
|
||||
x <- get_reactive_objects()$reactiveCacheEventA
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindEvent")
|
||||
}
|
||||
)
|
||||
|
||||
@@ -470,16 +562,18 @@ test_that("bindCache() wrapping reactive() captures otel attributes", {
|
||||
x <- get_reactive_objects()$reactiveCacheB
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindCache")
|
||||
})
|
||||
|
||||
test_that("bindEvent() wrapping reactive() captures otel attributes", {
|
||||
x <- get_reactive_objects()$reactiveEventB
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindEvent")
|
||||
})
|
||||
|
||||
test_that(
|
||||
@@ -488,8 +582,9 @@ test_that(
|
||||
x <- get_reactive_objects()$reactiveCacheEventB
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "bindEvent")
|
||||
}
|
||||
)
|
||||
|
||||
@@ -498,16 +593,18 @@ test_that("debounce() creates new reactive with otel attributes", {
|
||||
x <- get_reactive_objects()$debounce
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "debounce")
|
||||
})
|
||||
|
||||
test_that("throttle() creates new reactive with otel attributes", {
|
||||
x <- get_reactive_objects()$throttle
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "throttle")
|
||||
})
|
||||
|
||||
# Tests for ExtendedTask
|
||||
@@ -518,8 +615,9 @@ test_that("ExtendedTask is created and is an R6 object", {
|
||||
|
||||
attrs <- .subset2(x, ".__enclos_env__")$private$otel_attrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "ExtendedTask")
|
||||
})
|
||||
|
||||
# Tests for reactivePoll
|
||||
@@ -531,8 +629,9 @@ test_that("reactivePoll() captures otel attributes from source reference", {
|
||||
|
||||
expect_equal(as.character(otelLabel), "reactivePoll r_poll")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "reactivePoll")
|
||||
})
|
||||
|
||||
# Tests for reactiveFileReader
|
||||
@@ -544,8 +643,9 @@ test_that("reactiveFileReader() captures otel attributes from source reference",
|
||||
|
||||
expect_equal(as.character(otelLabel), "reactiveFileReader r_file")
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.lineno"]], 12)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_gt(attrs[["code.line.number"]], 12)
|
||||
expect_equal(attrs[["code.function.name"]], "reactiveFileReader")
|
||||
})
|
||||
|
||||
# Tests for explicit labels
|
||||
@@ -553,9 +653,10 @@ test_that("reactive() with explicit label still captures otel attributes", {
|
||||
x <- get_reactive_objects()$reactiveLabeled
|
||||
attrs <- attr(x, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 38)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 38)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "reactive")
|
||||
|
||||
# Verify label is preserved
|
||||
label <- attr(x, "observable")$.label
|
||||
@@ -566,9 +667,10 @@ test_that("observe() with explicit label still captures otel attributes", {
|
||||
x <- get_reactive_objects()$observeLabeled
|
||||
attrs <- x$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.lineno"]], 39)
|
||||
expect_equal(attrs[["code.column"]], 3)
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.line.number"]], 39)
|
||||
expect_equal(attrs[["code.column.number"]], 3)
|
||||
expect_equal(attrs[["code.function.name"]], "observe")
|
||||
|
||||
# Verify label is preserved
|
||||
expect_equal(x$.label, "my_observer")
|
||||
@@ -583,10 +685,10 @@ test_that("reactive created inside function captures function srcref", {
|
||||
r <- create_reactive()
|
||||
attrs <- attr(r, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
# Line number should point to where reactive() is called inside the function
|
||||
expect_true(is.numeric(attrs[["code.lineno"]]))
|
||||
expect_true(is.numeric(attrs[["code.column"]]))
|
||||
expect_true(is.numeric(attrs[["code.line.number"]]))
|
||||
expect_true(is.numeric(attrs[["code.column.number"]]))
|
||||
})
|
||||
|
||||
test_that("observe created inside function captures function srcref", {
|
||||
@@ -597,9 +699,9 @@ test_that("observe created inside function captures function srcref", {
|
||||
o <- create_observer()
|
||||
attrs <- o$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(attrs[["code.lineno"]]))
|
||||
expect_true(is.numeric(attrs[["code.column"]]))
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(attrs[["code.line.number"]]))
|
||||
expect_true(is.numeric(attrs[["code.column.number"]]))
|
||||
})
|
||||
|
||||
test_that("reactive returned from function preserves srcref", {
|
||||
@@ -610,8 +712,8 @@ test_that("reactive returned from function preserves srcref", {
|
||||
counter <- make_counter(42)
|
||||
attrs <- attr(counter, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(attrs[["code.lineno"]]))
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(attrs[["code.line.number"]]))
|
||||
})
|
||||
|
||||
test_that("reactiveVal created in function captures srcref", {
|
||||
@@ -622,8 +724,8 @@ test_that("reactiveVal created in function captures srcref", {
|
||||
rv <- create_val()
|
||||
attrs <- attr(rv, ".impl")$.otelAttrs
|
||||
|
||||
expect_equal(attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(attrs[["code.lineno"]]))
|
||||
expect_equal(attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(attrs[["code.line.number"]]))
|
||||
})
|
||||
|
||||
test_that("nested reactive expressions preserve individual srcrefs", {
|
||||
@@ -633,17 +735,17 @@ test_that("nested reactive expressions preserve individual srcrefs", {
|
||||
})
|
||||
|
||||
outer_attrs <- attr(outer_reactive, "observable")$.otelAttrs
|
||||
expect_equal(outer_attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(outer_attrs[["code.lineno"]]))
|
||||
expect_equal(outer_attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(outer_attrs[["code.line.number"]]))
|
||||
|
||||
# Get the inner reactive by executing outer
|
||||
withReactiveDomain(MockShinySession$new(), {
|
||||
inner_reactive <- isolate(outer_reactive())
|
||||
inner_attrs <- attr(inner_reactive, "observable")$.otelAttrs
|
||||
|
||||
expect_equal(inner_attrs[["code.filepath"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(inner_attrs[["code.lineno"]]))
|
||||
expect_equal(inner_attrs[["code.file.path"]], "test-otel-attr-srcref.R")
|
||||
expect_true(is.numeric(inner_attrs[["code.line.number"]]))
|
||||
# Inner should have different line number than outer
|
||||
expect_false(inner_attrs[["code.lineno"]] == outer_attrs[["code.lineno"]])
|
||||
expect_false(inner_attrs[["code.line.number"]] == outer_attrs[["code.line.number"]])
|
||||
})
|
||||
})
|
||||
|
||||
219
tests/testthat/test-otel-extended-task.R
Normal file
219
tests/testthat/test-otel-extended-task.R
Normal file
@@ -0,0 +1,219 @@
|
||||
# Tests for ExtendedTask otel behavior
|
||||
|
||||
ex_task_42 <- function() {
|
||||
ExtendedTask$new(function() {
|
||||
promises::promise_resolve(42)
|
||||
})
|
||||
}
|
||||
|
||||
test_that("ExtendedTask captures otel collection state at initialization", {
|
||||
# Test that has_otel_collect is called at init, not at invoke time
|
||||
withr::local_options(list(shiny.otel.collect = "reactivity"))
|
||||
|
||||
# Enable otel tracing
|
||||
local_mocked_bindings(
|
||||
otel_is_tracing_enabled = function() TRUE
|
||||
)
|
||||
|
||||
task <- ex_task_42()
|
||||
|
||||
# Check that is_recording_otel is captured at init time
|
||||
expect_true(task$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
test_that("ExtendedTask sets is_recording_otel to FALSE when otel disabled", {
|
||||
# Enable otel tracing
|
||||
local_mocked_bindings(
|
||||
otel_is_tracing_enabled = function() FALSE
|
||||
)
|
||||
|
||||
# Test with all level
|
||||
withr::with_options(list(shiny.otel.collect = "all"), {
|
||||
task1 <- ex_task_42()
|
||||
expect_false(task1$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
# Test with reactivity level
|
||||
withr::with_options(list(shiny.otel.collect = "reactivity"), {
|
||||
task1 <- ex_task_42()
|
||||
expect_false(task1$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
# Test with session level (should be FALSE)
|
||||
withr::with_options(list(shiny.otel.collect = "session"), {
|
||||
task2 <- ex_task_42()
|
||||
expect_false(task2$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
# Test with none level (should be FALSE)
|
||||
withr::with_options(list(shiny.otel.collect = "none"), {
|
||||
task3 <- ex_task_42()
|
||||
expect_false(task3$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
})
|
||||
|
||||
test_that("ExtendedTask sets is_recording_otel based on has_otel_collect at init", {
|
||||
# Enable otel tracing
|
||||
local_mocked_bindings(
|
||||
otel_is_tracing_enabled = function() TRUE
|
||||
)
|
||||
|
||||
# Test with all level
|
||||
withr::with_options(list(shiny.otel.collect = "all"), {
|
||||
task1 <- ex_task_42()
|
||||
expect_true(task1$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
# Test with reactivity level
|
||||
withr::with_options(list(shiny.otel.collect = "reactivity"), {
|
||||
task1 <- ex_task_42()
|
||||
expect_true(task1$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
# Test with session level (should be FALSE)
|
||||
withr::with_options(list(shiny.otel.collect = "session"), {
|
||||
task2 <- ex_task_42()
|
||||
expect_false(task2$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
# Test with none level (should be FALSE)
|
||||
withr::with_options(list(shiny.otel.collect = "none"), {
|
||||
task3 <- ex_task_42()
|
||||
expect_false(task3$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
})
|
||||
|
||||
test_that("ExtendedTask uses init-time otel setting even if option changes later", {
|
||||
|
||||
# Enable otel tracing
|
||||
local_mocked_bindings(
|
||||
otel_is_tracing_enabled = function() TRUE
|
||||
)
|
||||
|
||||
# Test that changing the option after init doesn't affect the task
|
||||
withr::with_options(list(shiny.otel.collect = "reactivity"), {
|
||||
task <- ex_task_42()
|
||||
})
|
||||
|
||||
# Capture the initial state
|
||||
expect_true(task$.__enclos_env__$private$is_recording_otel)
|
||||
|
||||
# Change the option after initialization
|
||||
withr::with_options(list(shiny.otel.collect = "none"), {
|
||||
# The task should still have the init-time setting
|
||||
expect_true(task$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
test_that("ExtendedTask respects session level otel collection", {
|
||||
# Test that session level doesn't enable reactivity spans
|
||||
withr::local_options(list(shiny.otel.collect = "session"))
|
||||
|
||||
task <- ex_task_42()
|
||||
|
||||
# Should not record otel at session level
|
||||
expect_false(task$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
test_that("ExtendedTask respects reactive_update level otel collection", {
|
||||
# Test that reactive_update level doesn't enable reactivity spans
|
||||
withr::local_options(list(shiny.otel.collect = "reactive_update"))
|
||||
|
||||
task <- ex_task_42()
|
||||
|
||||
# Should not record otel at reactive_update level
|
||||
expect_false(task$.__enclos_env__$private$is_recording_otel)
|
||||
})
|
||||
|
||||
test_that("ExtendedTask creates span only when is_recording_otel is TRUE", {
|
||||
# Test that span is only created when otel is enabled
|
||||
withr::local_options(list(shiny.otel.collect = "reactivity"))
|
||||
|
||||
span_created <- FALSE
|
||||
|
||||
local_mocked_bindings(
|
||||
start_otel_span = function(...) {
|
||||
span_created <<- TRUE
|
||||
create_mock_otel_span("extended_task")
|
||||
},
|
||||
otel_is_tracing_enabled = function() TRUE
|
||||
)
|
||||
|
||||
with_shiny_otel_record({
|
||||
withReactiveDomain(MockShinySession$new(), {
|
||||
task <- ex_task_42()
|
||||
|
||||
# Reset the flag
|
||||
span_created <- FALSE
|
||||
|
||||
# Invoke the task
|
||||
isolate({
|
||||
task$invoke()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
# Span should have been created because is_recording_otel is TRUE
|
||||
expect_true(span_created)
|
||||
})
|
||||
|
||||
test_that("ExtendedTask does not create span when is_recording_otel is FALSE", {
|
||||
# Test that span is not created when otel is disabled
|
||||
withr::local_options(list(shiny.otel.collect = "none"))
|
||||
|
||||
span_created <- FALSE
|
||||
|
||||
local_mocked_bindings(
|
||||
start_otel_span = function(...) {
|
||||
span_created <<- TRUE
|
||||
create_mock_otel_span("extended_task")
|
||||
}
|
||||
)
|
||||
|
||||
withReactiveDomain(MockShinySession$new(), {
|
||||
task <- ex_task_42()
|
||||
|
||||
# Invoke the task
|
||||
isolate({
|
||||
task$invoke()
|
||||
})
|
||||
})
|
||||
|
||||
# Span should not have been created because is_recording_otel is FALSE
|
||||
expect_false(span_created)
|
||||
})
|
||||
|
||||
|
||||
test_that("Multiple ExtendedTask invocations use same is_recording_otel value", {
|
||||
# Enable otel tracing
|
||||
withr::local_options(list(shiny.otel.collect = "reactivity"))
|
||||
local_mocked_bindings(
|
||||
otel_is_tracing_enabled = function() TRUE
|
||||
)
|
||||
|
||||
withReactiveDomain(MockShinySession$new(), {
|
||||
task <- ex_task_42()
|
||||
|
||||
# Verify is_recording_otel is TRUE at init
|
||||
expect_true(task$.__enclos_env__$private$is_recording_otel)
|
||||
|
||||
# Change option after initialization (should not affect the task)
|
||||
withr::with_options(
|
||||
list(shiny.otel.collect = "none"),
|
||||
{
|
||||
# The task should still have the init-time setting
|
||||
expect_true(task$.__enclos_env__$private$is_recording_otel)
|
||||
|
||||
# Verify is_recording_otel doesn't change on invocation
|
||||
isolate({
|
||||
task$invoke()
|
||||
})
|
||||
|
||||
# Still should be TRUE after invoke
|
||||
expect_true(task$.__enclos_env__$private$is_recording_otel)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -68,9 +68,12 @@ test_that("reactive bindCache labels are created", {
|
||||
})
|
||||
|
||||
test_that("ExtendedTask otel labels are created", {
|
||||
ex_task <- ExtendedTask$new(function() { promises::then(promises::promise_resolve(42), force) })
|
||||
# Record everything
|
||||
localOtelCollect("all")
|
||||
|
||||
info <- with_shiny_otel_record({
|
||||
ex_task <- ExtendedTask$new(function() { promises::then(promises::promise_resolve(42), force) })
|
||||
|
||||
ex_task$invoke()
|
||||
while(!later::loop_empty()) {
|
||||
later::run_now()
|
||||
@@ -79,30 +82,22 @@ test_that("ExtendedTask otel labels are created", {
|
||||
|
||||
trace <- info$traces[[1]]
|
||||
|
||||
expect_equal(
|
||||
trace$name,
|
||||
"ExtendedTask ex_task"
|
||||
)
|
||||
|
||||
expect_equal(trace$name, "ExtendedTask ex_task")
|
||||
|
||||
# Module test
|
||||
withReactiveDomain(MockShinySession$new(), {
|
||||
ex2_task <- ExtendedTask$new(function() { promises::then(promises::promise_resolve(42), force) })
|
||||
|
||||
info <- with_shiny_otel_record({
|
||||
ex2_task <- ExtendedTask$new(function() { promises::then(promises::promise_resolve(42), force) })
|
||||
ex2_task$invoke()
|
||||
while(!later::loop_empty()) {
|
||||
later::run_now()
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
trace <- info$traces[[1]]
|
||||
|
||||
expect_equal(
|
||||
trace$name,
|
||||
"ExtendedTask mock-session:ex2_task"
|
||||
)
|
||||
expect_equal(trace$name, "ExtendedTask mock-session:ex2_task")
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,47 @@
|
||||
skip_on_cran()
|
||||
skip_if_not_installed("otelsdk")
|
||||
|
||||
expect_code_attrs <- function(trace) {
|
||||
expect_code_attrs <- function(trace, expected_fn_name = NULL) {
|
||||
testthat::expect_true(!is.null(trace))
|
||||
testthat::expect_true(is.list(trace$attributes))
|
||||
|
||||
# Check preferred attribute names
|
||||
testthat::expect_true(is.character(trace$attributes[["code.file.path"]]))
|
||||
testthat::expect_equal(trace$attributes[["code.file.path"]], "test-otel-mock.R")
|
||||
testthat::expect_true(is.numeric(trace$attributes[["code.line.number"]]))
|
||||
testthat::expect_true(is.numeric(trace$attributes[["code.column.number"]]))
|
||||
|
||||
# Check deprecated attribute names (for backward compatibility)
|
||||
testthat::expect_true(is.character(trace$attributes[["code.filepath"]]))
|
||||
testthat::expect_equal(trace$attributes[["code.filepath"]], "test-otel-mock.R")
|
||||
testthat::expect_true(is.numeric(trace$attributes[["code.lineno"]]))
|
||||
testthat::expect_true(is.numeric(trace$attributes[["code.column"]]))
|
||||
|
||||
# Verify deprecated names match preferred names
|
||||
testthat::expect_equal(
|
||||
trace$attributes[["code.file.path"]],
|
||||
trace$attributes[["code.filepath"]]
|
||||
)
|
||||
testthat::expect_equal(
|
||||
trace$attributes[["code.line.number"]],
|
||||
trace$attributes[["code.lineno"]]
|
||||
)
|
||||
testthat::expect_equal(
|
||||
trace$attributes[["code.column.number"]],
|
||||
trace$attributes[["code.column"]]
|
||||
)
|
||||
|
||||
# Check code.function.name if expected
|
||||
if (!is.null(expected_fn_name)) {
|
||||
testthat::expect_true(
|
||||
is.character(trace$attributes[["code.function.name"]])
|
||||
)
|
||||
testthat::expect_equal(
|
||||
trace$attributes[["code.function.name"]],
|
||||
expected_fn_name
|
||||
)
|
||||
}
|
||||
|
||||
invisible(trace)
|
||||
}
|
||||
MOCK_SESSION_TOKEN <- "test-session-token"
|
||||
@@ -21,7 +54,7 @@ expect_session_id <- function(trace) {
|
||||
invisible(trace)
|
||||
}
|
||||
|
||||
expect_trace <- function(traces, name, pos = 1) {
|
||||
expect_trace <- function(traces, name, pos = 1, expected_fn_name = NULL) {
|
||||
# Filter to traces with the given name
|
||||
trace_set <- traces[which(names(traces) == name)]
|
||||
testthat::expect_gte(length(trace_set), pos)
|
||||
@@ -30,7 +63,7 @@ expect_trace <- function(traces, name, pos = 1) {
|
||||
trace <- trace_set[[pos]]
|
||||
testthat::expect_true(is.list(trace))
|
||||
|
||||
expect_code_attrs(trace)
|
||||
expect_code_attrs(trace, expected_fn_name = expected_fn_name)
|
||||
expect_session_id(trace)
|
||||
|
||||
trace
|
||||
@@ -78,9 +111,9 @@ for (bind in c("all", "reactivity")) {
|
||||
session$flushReact()
|
||||
})
|
||||
|
||||
expect_trace(traces, "observe mock-session:<anonymous>")
|
||||
expect_trace(traces, "observe mock-session:my_observe")
|
||||
expect_trace(traces, "observe mock-session:labeled observer")
|
||||
expect_trace(traces, "observe mock-session:<anonymous>", 1, "observe")
|
||||
expect_trace(traces, "observe mock-session:my_observe", 1, "observe")
|
||||
expect_trace(traces, "observe mock-session:labeled observer", 1, "observe")
|
||||
})
|
||||
|
||||
test_that(paste0("bind='", bind, "' handles reactiveVal / reactiveValues"), {
|
||||
@@ -104,7 +137,7 @@ for (bind in c("all", "reactivity")) {
|
||||
expect_equal(rv(), 1)
|
||||
})
|
||||
|
||||
expect_trace(traces, "observe mock-session:<anonymous>")
|
||||
expect_trace(traces, "observe mock-session:<anonymous>", 1, "observe")
|
||||
|
||||
# TODO-future: Add tests to see the `Set reactiveVal mock-session:rv` logs
|
||||
# Requires: https://github.com/r-lib/otelsdk/issues/21
|
||||
@@ -131,10 +164,16 @@ for (bind in c("all", "reactivity")) {
|
||||
expect_equal(r3(), 42)
|
||||
})
|
||||
|
||||
observe_trace <- expect_trace(traces, "observe mock-session:obs_r3")
|
||||
r_trace <- expect_trace(traces, "reactive mock-session:r")
|
||||
r2_trace <- expect_trace(traces, "reactive mock-session:<anonymous>")
|
||||
r3_trace <- expect_trace(traces, "reactive mock-session:labeled_rv")
|
||||
observe_trace <- expect_trace(
|
||||
traces, "observe mock-session:obs_r3", 1, "observe"
|
||||
)
|
||||
r_trace <- expect_trace(traces, "reactive mock-session:r", 1, "reactive")
|
||||
r2_trace <- expect_trace(
|
||||
traces, "reactive mock-session:<anonymous>", 1, "reactive"
|
||||
)
|
||||
r3_trace <- expect_trace(
|
||||
traces, "reactive mock-session:labeled_rv", 1, "reactive"
|
||||
)
|
||||
|
||||
expect_equal(r_trace$parent, r2_trace$span_id)
|
||||
expect_equal(r2_trace$parent, r3_trace$span_id)
|
||||
@@ -157,7 +196,9 @@ for (bind in c("all", "reactivity")) {
|
||||
expect_equal(output$txt, "Hello, world!")
|
||||
})
|
||||
|
||||
expect_trace(traces, "output mock-session:txt")
|
||||
# Outputs (render functions) should NOT have code.function.name
|
||||
trace <- expect_trace(traces, "output mock-session:txt", 1, NULL)
|
||||
expect_false("code.function.name" %in% names(trace$attributes))
|
||||
})
|
||||
|
||||
test_that(paste0("bind='", bind, "' extended tasks are supported"), {
|
||||
@@ -183,18 +224,28 @@ for (bind in c("all", "reactivity")) {
|
||||
traces <- test_server_with_otel(session, server, bind = bind, {
|
||||
session$flushReact()
|
||||
|
||||
while(!later::loop_empty()) {
|
||||
while (!later::loop_empty()) {
|
||||
later::run_now()
|
||||
session$flushReact()
|
||||
}
|
||||
session$flushReact()
|
||||
})
|
||||
|
||||
invoke_obs <- expect_trace(traces, "observe mock-session:invoke task")
|
||||
render1_trace <- expect_trace(traces, "output mock-session:result")
|
||||
ex_task_trace <- expect_trace(traces, "ExtendedTask mock-session:rand_task")
|
||||
invoke_obs <- expect_trace(
|
||||
traces, "observe mock-session:invoke task", 1, "observe"
|
||||
)
|
||||
# Render functions should NOT have code.function.name
|
||||
render1_trace <- expect_trace(traces, "output mock-session:result", 1, NULL)
|
||||
expect_false("code.function.name" %in% names(render1_trace$attributes))
|
||||
|
||||
render2_trace <- expect_trace(traces, "output mock-session:result", pos = 2)
|
||||
ex_task_trace <- expect_trace(
|
||||
traces, "ExtendedTask mock-session:rand_task", 1, "ExtendedTask"
|
||||
)
|
||||
|
||||
render2_trace <- expect_trace(
|
||||
traces, "output mock-session:result", pos = 2, NULL
|
||||
)
|
||||
expect_false("code.function.name" %in% names(render2_trace$attributes))
|
||||
|
||||
expect_equal(invoke_obs$span_id, ex_task_trace$parent)
|
||||
})
|
||||
@@ -222,9 +273,11 @@ test_that("bind = 'reactivity' traces reactive components", {
|
||||
})
|
||||
|
||||
# Should trace reactive components (equivalent to "all")
|
||||
expect_trace(traces, "observe mock-session:test_obs")
|
||||
expect_trace(traces, "reactive mock-session:r")
|
||||
expect_trace(traces, "output mock-session:txt")
|
||||
expect_trace(traces, "observe mock-session:test_obs", 1, "observe")
|
||||
expect_trace(traces, "reactive mock-session:r", 1, "reactive")
|
||||
# Render functions should NOT have code.function.name
|
||||
txt_trace <- expect_trace(traces, "output mock-session:txt", 1, NULL)
|
||||
expect_false("code.function.name" %in% names(txt_trace$attributes))
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,37 +1,5 @@
|
||||
# Tests for otel-shiny.R functions
|
||||
|
||||
# Helper function to create a mock otel span
|
||||
create_mock_otel_span <- function(name = "test_span") {
|
||||
structure(
|
||||
list(
|
||||
name = name,
|
||||
activate = function(...) NULL,
|
||||
end = function(...) NULL
|
||||
),
|
||||
class = "otel_span"
|
||||
)
|
||||
}
|
||||
|
||||
# Helper function to create a mock tracer
|
||||
create_mock_tracer <- function() {
|
||||
structure(
|
||||
list(
|
||||
name = "mock_tracer",
|
||||
is_enabled = function() TRUE,
|
||||
start_span = function(name, ...) create_mock_otel_span(name)
|
||||
),
|
||||
class = "otel_tracer"
|
||||
)
|
||||
}
|
||||
|
||||
# Helper function to create a mock logger
|
||||
create_mock_logger <- function() {
|
||||
structure(
|
||||
list(name = "mock_logger"),
|
||||
class = "otel_logger"
|
||||
)
|
||||
}
|
||||
|
||||
test_that("otel_tracer_name constant is correct", {
|
||||
expect_equal(otel_tracer_name, "co.posit.r-package.shiny")
|
||||
})
|
||||
|
||||
316
tests/testthat/test-otel-with.R
Normal file
316
tests/testthat/test-otel-with.R
Normal file
@@ -0,0 +1,316 @@
|
||||
test_that("withOtelCollect sets collection level temporarily", {
|
||||
# Save original option
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
# Set a baseline option
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
# Test that withOtelCollect temporarily changes the option
|
||||
result <- withOtelCollect("none", {
|
||||
getOption("shiny.otel.collect")
|
||||
})
|
||||
|
||||
expect_equal(result, "none")
|
||||
|
||||
# Verify option is restored after expression
|
||||
expect_equal(getOption("shiny.otel.collect"), "all")
|
||||
})
|
||||
|
||||
test_that("withOtelCollect returns value of expr", {
|
||||
result <- withOtelCollect("none", {
|
||||
42
|
||||
})
|
||||
|
||||
expect_equal(result, 42)
|
||||
|
||||
# Test with more complex return value
|
||||
result <- withOtelCollect("reactivity", {
|
||||
list(a = 1, b = "test")
|
||||
})
|
||||
|
||||
expect_equal(result, list(a = 1, b = "test"))
|
||||
})
|
||||
|
||||
test_that("withOtelCollect validates collect level", {
|
||||
expect_error(
|
||||
withOtelCollect("invalid", { 1 }),
|
||||
"'arg' should be one of"
|
||||
)
|
||||
|
||||
expect_error(
|
||||
withOtelCollect(123, { 1 }),
|
||||
"`collect` must be a character vector"
|
||||
)
|
||||
|
||||
expect_error(
|
||||
withOtelCollect(c("all", "none"), { 1 }),
|
||||
"'arg' must be of length 1"
|
||||
)
|
||||
})
|
||||
|
||||
test_that("withOtelCollect rejects session and reactive_update levels", {
|
||||
expect_error(
|
||||
withOtelCollect("session", { 1 }),
|
||||
"'arg' should be one of"
|
||||
)
|
||||
|
||||
expect_error(
|
||||
withOtelCollect("reactive_update", { 1 }),
|
||||
"'arg' should be one of"
|
||||
)
|
||||
})
|
||||
|
||||
test_that("withOtelCollect works with all valid collect levels", {
|
||||
for (level in c("none", "reactivity", "all")) {
|
||||
result <- withOtelCollect(level, {
|
||||
getOption("shiny.otel.collect")
|
||||
})
|
||||
expect_equal(result, level)
|
||||
}
|
||||
})
|
||||
|
||||
test_that("withOtelCollect nests correctly", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
result <- withOtelCollect("reactivity", {
|
||||
outer <- getOption("shiny.otel.collect")
|
||||
inner <- withOtelCollect("none", {
|
||||
getOption("shiny.otel.collect")
|
||||
})
|
||||
restored <- getOption("shiny.otel.collect")
|
||||
|
||||
list(outer = outer, inner = inner, restored = restored)
|
||||
})
|
||||
|
||||
expect_equal(result$outer, "reactivity")
|
||||
expect_equal(result$inner, "none")
|
||||
expect_equal(result$restored, "reactivity")
|
||||
expect_equal(getOption("shiny.otel.collect"), "all")
|
||||
})
|
||||
|
||||
test_that("withOtelCollect restores option even on error", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
expect_error(
|
||||
withOtelCollect("none", {
|
||||
stop("test error")
|
||||
}),
|
||||
"test error"
|
||||
)
|
||||
|
||||
# Option should still be restored
|
||||
expect_equal(getOption("shiny.otel.collect"), "all")
|
||||
})
|
||||
|
||||
test_that("localOtelCollect sets collection level in function scope", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
test_func <- function() {
|
||||
localOtelCollect("none")
|
||||
getOption("shiny.otel.collect")
|
||||
}
|
||||
|
||||
result <- test_func()
|
||||
expect_equal(result, "none")
|
||||
|
||||
# Option should be restored after function exits
|
||||
expect_equal(getOption("shiny.otel.collect"), "all")
|
||||
})
|
||||
|
||||
test_that("localOtelCollect returns previous collect value invisibly", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
result <- withVisible(localOtelCollect("none"))
|
||||
|
||||
# Should return a list with the old option value
|
||||
expect_type(result$value, "list")
|
||||
expect_equal(result$value$shiny.otel.collect, "all")
|
||||
expect_false(result$visible)
|
||||
})
|
||||
|
||||
test_that("localOtelCollect validates collect level", {
|
||||
expect_error(
|
||||
localOtelCollect("invalid"),
|
||||
"'arg' should be one of"
|
||||
)
|
||||
|
||||
expect_error(
|
||||
localOtelCollect(NULL),
|
||||
"`collect` must be a character vector"
|
||||
)
|
||||
|
||||
expect_error(
|
||||
localOtelCollect(c("all", "none")),
|
||||
"'arg' must be of length 1"
|
||||
)
|
||||
})
|
||||
|
||||
test_that("localOtelCollect rejects session and reactive_update levels", {
|
||||
expect_error(
|
||||
localOtelCollect("session"),
|
||||
"'arg' should be one of"
|
||||
)
|
||||
|
||||
expect_error(
|
||||
localOtelCollect("reactive_update"),
|
||||
"'arg' should be one of"
|
||||
)
|
||||
})
|
||||
|
||||
test_that("localOtelCollect works with all valid collect levels", {
|
||||
for (level in c("none", "reactivity", "all")) {
|
||||
test_func <- function() {
|
||||
localOtelCollect(level)
|
||||
getOption("shiny.otel.collect")
|
||||
}
|
||||
result <- test_func()
|
||||
expect_equal(result, level)
|
||||
}
|
||||
})
|
||||
|
||||
test_that("localOtelCollect respects envir parameter", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
outer_func <- function() {
|
||||
env <- environment()
|
||||
|
||||
inner_func <- function() {
|
||||
localOtelCollect("none", envir = env)
|
||||
}
|
||||
|
||||
inner_func()
|
||||
getOption("shiny.otel.collect")
|
||||
}
|
||||
|
||||
result <- outer_func()
|
||||
expect_equal(result, "none")
|
||||
expect_equal(getOption("shiny.otel.collect"), "all")
|
||||
})
|
||||
|
||||
test_that("localOtelCollect scope is limited to function", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
func1 <- function() {
|
||||
localOtelCollect("reactivity")
|
||||
getOption("shiny.otel.collect")
|
||||
}
|
||||
|
||||
func2 <- function() {
|
||||
localOtelCollect("none")
|
||||
getOption("shiny.otel.collect")
|
||||
}
|
||||
|
||||
result1 <- func1()
|
||||
result2 <- func2()
|
||||
|
||||
expect_equal(result1, "reactivity")
|
||||
expect_equal(result2, "none")
|
||||
expect_equal(getOption("shiny.otel.collect"), "all")
|
||||
})
|
||||
|
||||
test_that("withOtelCollect and localOtelCollect work together", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
result <- withOtelCollect("reactivity", {
|
||||
outer <- getOption("shiny.otel.collect")
|
||||
|
||||
test_func <- function() {
|
||||
localOtelCollect("none")
|
||||
getOption("shiny.otel.collect")
|
||||
}
|
||||
|
||||
inner <- test_func()
|
||||
restored <- getOption("shiny.otel.collect")
|
||||
|
||||
list(outer = outer, inner = inner, restored = restored)
|
||||
})
|
||||
|
||||
expect_equal(result$outer, "reactivity")
|
||||
expect_equal(result$inner, "none")
|
||||
expect_equal(result$restored, "reactivity")
|
||||
expect_equal(getOption("shiny.otel.collect"), "all")
|
||||
})
|
||||
|
||||
test_that("withOtelCollect affects otel_collect_is_enabled", {
|
||||
# This tests integration with the otel collection system
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
# With "none", nothing except "none" should be enabled
|
||||
result <- withOtelCollect("none", {
|
||||
list(
|
||||
none = otel_collect_is_enabled("none"),
|
||||
session = otel_collect_is_enabled("session"),
|
||||
reactivity = otel_collect_is_enabled("reactivity")
|
||||
)
|
||||
})
|
||||
|
||||
expect_true(result$none)
|
||||
expect_false(result$session)
|
||||
expect_false(result$reactivity)
|
||||
|
||||
# With "reactivity", reactivity and below should be enabled, but not "all"
|
||||
result <- withOtelCollect("reactivity", {
|
||||
list(
|
||||
none = otel_collect_is_enabled("none"),
|
||||
session = otel_collect_is_enabled("session"),
|
||||
reactive_update = otel_collect_is_enabled("reactive_update"),
|
||||
reactivity = otel_collect_is_enabled("reactivity"),
|
||||
all = otel_collect_is_enabled("all")
|
||||
)
|
||||
})
|
||||
|
||||
expect_true(result$none)
|
||||
expect_true(result$session)
|
||||
expect_true(result$reactive_update)
|
||||
expect_true(result$reactivity)
|
||||
expect_false(result$all)
|
||||
})
|
||||
|
||||
test_that("localOtelCollect affects otel_collect_is_enabled", {
|
||||
original <- getOption("shiny.otel.collect")
|
||||
on.exit(options(shiny.otel.collect = original), add = TRUE)
|
||||
|
||||
options(shiny.otel.collect = "all")
|
||||
|
||||
test_func <- function() {
|
||||
localOtelCollect("reactivity")
|
||||
list(
|
||||
session = otel_collect_is_enabled("session"),
|
||||
reactive_update = otel_collect_is_enabled("reactive_update"),
|
||||
reactivity = otel_collect_is_enabled("reactivity"),
|
||||
all = otel_collect_is_enabled("all")
|
||||
)
|
||||
}
|
||||
|
||||
result <- test_func()
|
||||
|
||||
expect_true(result$session)
|
||||
expect_true(result$reactive_update)
|
||||
expect_true(result$reactivity)
|
||||
expect_false(result$all)
|
||||
})
|
||||
@@ -1,3 +1,8 @@
|
||||
# Dev CRAN had some issues with comparisons between integer(0) and character(0)
|
||||
# Skipping tests on CRAN as CI is enough to verify functionality
|
||||
# Related: https://github.com/rstudio/shiny/issues/4326
|
||||
skip_on_cran()
|
||||
|
||||
test_that("Scheduling works", {
|
||||
ran <- FALSE
|
||||
fun <- function() {
|
||||
@@ -32,8 +37,13 @@ test_that("Unscheduling works", {
|
||||
# Unregister
|
||||
taskHandle()
|
||||
|
||||
expect_identical(timerCallbacks$.times, origTimes)
|
||||
expect_identical(timerCallbacks$.funcs$keys(), origFuncKeys)
|
||||
# Split into two sections to avoid `expect_equal(integer(0), character(0))` comparison on dev CRAN
|
||||
if (length(origTimes) == 0) {
|
||||
expect_equal(0, length(timerCallbacks$.times))
|
||||
} else {
|
||||
expect_equal(timerCallbacks$.times, origTimes)
|
||||
}
|
||||
expect_equal(timerCallbacks$.funcs$keys(), origFuncKeys)
|
||||
})
|
||||
|
||||
test_that("Vectorized unscheduling works", {
|
||||
|
||||
@@ -214,6 +214,10 @@ reference:
|
||||
- runTests
|
||||
- testServer
|
||||
- MockShinySession
|
||||
- title: OpenTelemetry
|
||||
desc: Functions for OpenTelemetry tracing integration
|
||||
contents:
|
||||
- withOtelCollect
|
||||
- title: Superseded
|
||||
desc: Functions that have been `r lifecycle::badge("superseded")`
|
||||
contents:
|
||||
|
||||
Reference in New Issue
Block a user