From b44f9a98a7e26c9e9f364fa2d87d03d34fe48d97 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 21 Jan 2025 14:42:05 +0100 Subject: [PATCH] first version of cuprite integration --- Steepfile | 1 + lib/datadog/ci.rb | 1 + .../contrib/cuprite/configuration/settings.rb | 34 +++++++ lib/datadog/ci/contrib/cuprite/driver.rb | 90 +++++++++++++++++++ lib/datadog/ci/contrib/cuprite/ext.rb | 15 ++++ lib/datadog/ci/contrib/cuprite/integration.rb | 44 +++++++++ lib/datadog/ci/contrib/cuprite/patcher.rb | 24 +++++ lib/datadog/ci/utils/rum.rb | 2 +- .../cuprite/configuration/settings.rbs | 12 +++ sig/datadog/ci/contrib/cuprite/driver.rbs | 29 ++++++ sig/datadog/ci/contrib/cuprite/ext.rbs | 11 +++ .../ci/contrib/cuprite/integration.rbs | 23 +++++ sig/datadog/ci/contrib/cuprite/patcher.rbs | 13 +++ vendor/rbs/cuprite/0/driver.rbs | 34 +++++++ 14 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 lib/datadog/ci/contrib/cuprite/configuration/settings.rb create mode 100644 lib/datadog/ci/contrib/cuprite/driver.rb create mode 100644 lib/datadog/ci/contrib/cuprite/ext.rb create mode 100644 lib/datadog/ci/contrib/cuprite/integration.rb create mode 100644 lib/datadog/ci/contrib/cuprite/patcher.rb create mode 100644 sig/datadog/ci/contrib/cuprite/configuration/settings.rbs create mode 100644 sig/datadog/ci/contrib/cuprite/driver.rbs create mode 100644 sig/datadog/ci/contrib/cuprite/ext.rbs create mode 100644 sig/datadog/ci/contrib/cuprite/integration.rbs create mode 100644 sig/datadog/ci/contrib/cuprite/patcher.rbs create mode 100644 vendor/rbs/cuprite/0/driver.rbs diff --git a/Steepfile b/Steepfile index 7a3d755f..deb2a0b2 100644 --- a/Steepfile +++ b/Steepfile @@ -33,4 +33,5 @@ target :lib do library "timecop" library "webmock" library "simplecov" + library "cuprite" end diff --git a/lib/datadog/ci.rb b/lib/datadog/ci.rb index 2720ad23..51d0da44 100644 --- a/lib/datadog/ci.rb +++ b/lib/datadog/ci.rb @@ -418,6 +418,7 @@ def test_optimisation # Additional test libraries (auto instrumented later on test session start) require_relative "ci/contrib/selenium/integration" +require_relative "ci/contrib/cuprite/integration" require_relative "ci/contrib/simplecov/integration" # Configuration extensions diff --git a/lib/datadog/ci/contrib/cuprite/configuration/settings.rb b/lib/datadog/ci/contrib/cuprite/configuration/settings.rb new file mode 100644 index 00000000..0e9e5f05 --- /dev/null +++ b/lib/datadog/ci/contrib/cuprite/configuration/settings.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require "datadog/core" + +require_relative "../ext" +require_relative "../../settings" + +require_relative "../../../ext/rum" + +module Datadog + module CI + module Contrib + module Cuprite + module Configuration + # Custom settings for the Cuprite integration + # @public_api + class Settings < Datadog::CI::Contrib::Settings + option :enabled do |o| + o.type :bool + o.env Ext::ENV_ENABLED + o.default true + end + + option :rum_flush_wait_millis do |o| + o.type :int + o.env CI::Ext::RUM::ENV_RUM_FLUSH_WAIT_MILLIS + o.default 500 + end + end + end + end + end + end +end diff --git a/lib/datadog/ci/contrib/cuprite/driver.rb b/lib/datadog/ci/contrib/cuprite/driver.rb new file mode 100644 index 00000000..d812e115 --- /dev/null +++ b/lib/datadog/ci/contrib/cuprite/driver.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require_relative "../patcher" + +require_relative "../../ext/rum" +require_relative "../../ext/test" +require_relative "../../utils/rum" + +module Datadog + module CI + module Contrib + module Cuprite + # instruments Capybara::Cuprite::Driver + module Driver + def self.included(base) + base.prepend(InstanceMethods) + end + + module InstanceMethods + def visit(url) + result = super + + return result unless datadog_configuration[:enabled] + + Datadog.logger.debug("[Cuprite] Navigation to #{url}") + + # on session reset Capybara navigates to about:blank + return result if url == "about:blank" + + active_test = Datadog::CI.active_test + Datadog.logger.debug("[Cuprite] Active test: #{active_test}") + + return result unless active_test + + # Set the test's trace id as a cookie in browser session + Datadog.logger.debug do + "[Cuprite] Setting cookie #{CI::Ext::RUM::COOKIE_TEST_EXECUTION_ID} to #{active_test.trace_id}" + end + set_cookie(CI::Ext::RUM::COOKIE_TEST_EXECUTION_ID, active_test.trace_id.to_s) + + # set the test type to browser + active_test.set_tag(CI::Ext::Test::TAG_TYPE, CI::Ext::Test::Type::BROWSER) + + # set the tags specific to the browser test + active_test.set_tag(CI::Ext::Test::TAG_BROWSER_DRIVER, "cuprite") + active_test.set_tag(CI::Ext::Test::TAG_BROWSER_DRIVER_VERSION, datadog_integration.version) + active_test.set_tag(CI::Ext::Test::TAG_BROWSER_NAME, browser.options.browser_name) + active_test.set_tag(CI::Ext::Test::TAG_BROWSER_VERSION, browser.version) + + result + end + + def reset! + datadog_end_rum_session + + super + end + + def quit + datadog_end_rum_session + + super + end + + private + + def datadog_integration + CI::Contrib::Instrumentation.fetch_integration(:cuprite) + end + + def datadog_configuration + Datadog.configuration.ci[:cuprite] + end + + def datadog_end_rum_session + return unless datadog_configuration[:enabled] + + Datadog.logger.debug("[Cuprite] Driver quit event") + + Utils::RUM.stop_rum_session(self) + + Datadog.logger.debug("[Cuprite] RUM session stopped, deleting cookie") + remove_cookie(CI::Ext::RUM::COOKIE_TEST_EXECUTION_ID) + end + end + end + end + end + end +end diff --git a/lib/datadog/ci/contrib/cuprite/ext.rb b/lib/datadog/ci/contrib/cuprite/ext.rb new file mode 100644 index 00000000..31b22150 --- /dev/null +++ b/lib/datadog/ci/contrib/cuprite/ext.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Datadog + module CI + module Contrib + module Cuprite + # Cuprite integration constants + # @public_api + module Ext + ENV_ENABLED = "DD_CIVISIBILITY_CUPRITE_ENABLED" + end + end + end + end +end diff --git a/lib/datadog/ci/contrib/cuprite/integration.rb b/lib/datadog/ci/contrib/cuprite/integration.rb new file mode 100644 index 00000000..d5b87e59 --- /dev/null +++ b/lib/datadog/ci/contrib/cuprite/integration.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require_relative "../integration" +require_relative "configuration/settings" +require_relative "patcher" + +module Datadog + module CI + module Contrib + module Cuprite + # Description of Cuprite integration + class Integration < Contrib::Integration + MINIMUM_VERSION = Gem::Version.new("0.15.0") + + def version + Gem.loaded_specs["cuprite"]&.version + end + + def loaded? + !defined?(::Capybara).nil? && !defined?(::Capybara::Cuprite).nil? && + !defined?(::Capybara::Cuprite::Driver).nil? + end + + def compatible? + super && version >= MINIMUM_VERSION + end + + # additional instrumentations for test libraries are late instrumented on test session start + def late_instrument? + true + end + + def new_configuration + Configuration::Settings.new + end + + def patcher + Patcher + end + end + end + end + end +end diff --git a/lib/datadog/ci/contrib/cuprite/patcher.rb b/lib/datadog/ci/contrib/cuprite/patcher.rb new file mode 100644 index 00000000..348aad89 --- /dev/null +++ b/lib/datadog/ci/contrib/cuprite/patcher.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require_relative "../patcher" + +require_relative "driver" + +module Datadog + module CI + module Contrib + module Cuprite + # Patcher enables patching of 'Capybara::Cuprite::Driver' class. + module Patcher + include Datadog::CI::Contrib::Patcher + + module_function + + def patch + ::Capybara::Cuprite::Driver.include(Driver) + end + end + end + end + end +end diff --git a/lib/datadog/ci/utils/rum.rb b/lib/datadog/ci/utils/rum.rb index 0b9c6d6d..ab464296 100644 --- a/lib/datadog/ci/utils/rum.rb +++ b/lib/datadog/ci/utils/rum.rb @@ -20,7 +20,7 @@ def self.is_rum_active?(script_executor) Utils::Parsing.convert_to_bool(is_rum_active_script_result) end - def self.stop_rum_session(script_executor) + def self.stop_rum_session(script_executor, rum_flush_wait_millis: 500) config = Datadog.configuration.ci[:selenium] if is_rum_active?(script_executor) Datadog::CI.active_test&.set_tag( diff --git a/sig/datadog/ci/contrib/cuprite/configuration/settings.rbs b/sig/datadog/ci/contrib/cuprite/configuration/settings.rbs new file mode 100644 index 00000000..39795f8b --- /dev/null +++ b/sig/datadog/ci/contrib/cuprite/configuration/settings.rbs @@ -0,0 +1,12 @@ +module Datadog + module CI + module Contrib + module Cuprite + module Configuration + class Settings < Datadog::CI::Contrib::Settings + end + end + end + end + end +end diff --git a/sig/datadog/ci/contrib/cuprite/driver.rbs b/sig/datadog/ci/contrib/cuprite/driver.rbs new file mode 100644 index 00000000..6a20cc00 --- /dev/null +++ b/sig/datadog/ci/contrib/cuprite/driver.rbs @@ -0,0 +1,29 @@ +module Datadog + module CI + module Contrib + module Cuprite + module Driver + def self.included: (untyped base) -> untyped + + module InstanceMethods + include Capybara::Cuprite::Driver + + def visit: (untyped url) -> untyped + + def reset!: () -> untyped + + def quit: () -> untyped + + private + + def datadog_integration: () -> untyped + + def datadog_configuration: () -> untyped + + def datadog_end_rum_session: () -> (nil | untyped) + end + end + end + end + end +end diff --git a/sig/datadog/ci/contrib/cuprite/ext.rbs b/sig/datadog/ci/contrib/cuprite/ext.rbs new file mode 100644 index 00000000..2ae73967 --- /dev/null +++ b/sig/datadog/ci/contrib/cuprite/ext.rbs @@ -0,0 +1,11 @@ +module Datadog + module CI + module Contrib + module Cuprite + module Ext + ENV_ENABLED: "DD_CIVISIBILITY_CUPRITE_ENABLED" + end + end + end + end +end diff --git a/sig/datadog/ci/contrib/cuprite/integration.rbs b/sig/datadog/ci/contrib/cuprite/integration.rbs new file mode 100644 index 00000000..0f9deeb4 --- /dev/null +++ b/sig/datadog/ci/contrib/cuprite/integration.rbs @@ -0,0 +1,23 @@ +module Datadog + module CI + module Contrib + module Cuprite + class Integration < Contrib::Integration + MINIMUM_VERSION: Gem::Version + + def version: () -> untyped + + def loaded?: () -> bool + + def compatible?: () -> bool + + def late_instrument?: () -> true + + def new_configuration: () -> untyped + + def patcher: () -> untyped + end + end + end + end +end diff --git a/sig/datadog/ci/contrib/cuprite/patcher.rbs b/sig/datadog/ci/contrib/cuprite/patcher.rbs new file mode 100644 index 00000000..9abdfd4f --- /dev/null +++ b/sig/datadog/ci/contrib/cuprite/patcher.rbs @@ -0,0 +1,13 @@ +module Datadog + module CI + module Contrib + module Cuprite + module Patcher + include Datadog::CI::Contrib::Patcher + + def self?.patch: () -> untyped + end + end + end + end +end diff --git a/vendor/rbs/cuprite/0/driver.rbs b/vendor/rbs/cuprite/0/driver.rbs new file mode 100644 index 00000000..2e1279cb --- /dev/null +++ b/vendor/rbs/cuprite/0/driver.rbs @@ -0,0 +1,34 @@ +module Capybara +end + +module Capybara::Cuprite +end + +module Ferrum +end + +class Ferrum::Browser + def version: () -> String + + def options: () -> Ferrum::Browser::Options +end + +class Ferrum::Browser::Options + def browser_name: () -> String +end + +module Capybara::Cuprite::Driver + def visit: (String url) -> untyped + + def reset!: () -> void + + def quit: () -> void + + def set_cookie: (String name, String value, ?Hash[Symbol, untyped] options) -> void + + def remove_cookie: (String name, ?Hash[Symbol, untyped] options) -> void + + def execute_script: (String script, ?untyped args) -> untyped + + def browser: () -> Ferrum::Browser +end