datadog-ci 1.0.0.beta4 → 1.0.0.beta6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -2
  3. data/lib/datadog/ci/contrib/contrib.rb +31 -0
  4. data/lib/datadog/ci/contrib/minitest/reporter.rb +1 -1
  5. data/lib/datadog/ci/contrib/minitest/runnable.rb +1 -1
  6. data/lib/datadog/ci/contrib/minitest/runner.rb +1 -1
  7. data/lib/datadog/ci/contrib/rspec/example.rb +2 -1
  8. data/lib/datadog/ci/contrib/rspec/example_group.rb +1 -0
  9. data/lib/datadog/ci/contrib/rspec/knapsack_pro/extension.rb +0 -1
  10. data/lib/datadog/ci/contrib/rspec/knapsack_pro/patcher.rb +26 -0
  11. data/lib/datadog/ci/contrib/rspec/knapsack_pro/runner.rb +2 -1
  12. data/lib/datadog/ci/contrib/rspec/patcher.rb +6 -4
  13. data/lib/datadog/ci/contrib/rspec/runner.rb +2 -1
  14. data/lib/datadog/ci/contrib/selenium/capybara_driver.rb +45 -0
  15. data/lib/datadog/ci/contrib/selenium/configuration/settings.rb +32 -0
  16. data/lib/datadog/ci/contrib/selenium/driver.rb +45 -0
  17. data/lib/datadog/ci/contrib/selenium/ext.rb +30 -0
  18. data/lib/datadog/ci/contrib/selenium/integration.rb +48 -0
  19. data/lib/datadog/ci/contrib/selenium/navigation.rb +74 -0
  20. data/lib/datadog/ci/contrib/selenium/patcher.rb +36 -0
  21. data/lib/datadog/ci/contrib/selenium/rum.rb +45 -0
  22. data/lib/datadog/ci/ext/test.rb +18 -5
  23. data/lib/datadog/ci/ext/transport.rb +3 -0
  24. data/lib/datadog/ci/span.rb +5 -0
  25. data/lib/datadog/ci/test_visibility/recorder.rb +4 -0
  26. data/lib/datadog/ci/transport/api/agentless.rb +11 -3
  27. data/lib/datadog/ci/transport/gzip.rb +12 -0
  28. data/lib/datadog/ci/transport/http.rb +35 -3
  29. data/lib/datadog/ci/version.rb +1 -1
  30. data/lib/datadog/ci.rb +1 -0
  31. metadata +12 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 035d75d50e0e09c7895bc0e434c5ac1e0655618763ac724a94989833e0c07d61
4
- data.tar.gz: bfbd5d6ff101ef51e59d3546d110f906f178c23602241f85b3a8b413524a9900
3
+ metadata.gz: a905eacfa2face6f297e027aa344b9b36f99d7f7f2120ab6946b2e9c650c390b
4
+ data.tar.gz: 537bd49690464320a74f88d9a0c392dcac10b83575407d703cf756a71ea8c29e
5
5
  SHA512:
6
- metadata.gz: c1b6463b913cbff1e20a2c3f4fcaa6c47814ba693eee5682fa41c3baa74f9e92414b4e554ec8407807d6eeb1744f0c76d87bb0889bd0e639c6ebdc3de1dcd180
7
- data.tar.gz: dca4568f30dbaef22e8fac94389e682beb21ba6f92f0578553ff01d2ad289f38d33f899c79bef604f3f83906d6c31b9e64a9495cc3dc986fb321bd810430780d
6
+ metadata.gz: 8c87d7be67c31a970d0f6e75fcc4a0305719604afe02eac4061fd9c43a2539632f7a6f9199aafdaf55438913e721280ec2e5ac30f75d5921dd4bb3bdc1638f5a
7
+ data.tar.gz: '0838f7ce0df3bdf19a9a9c2c0df6c1b8ef0a96421e7043bfa339b6aa8d7a04f204a8c2a0dcb1cccb80f13df4a47a5da16c127a756d5064512120ea35a9beb8d0'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.0.0.beta6] - 2024-05-29
4
+
5
+ ### Added
6
+
7
+ * Browser tests support via selenium integration ([#183][])
8
+
9
+ ## [1.0.0.beta5] - 2024-05-23
10
+
11
+ ### Changed
12
+
13
+ * accept gzipped responses from API ([#170][])
14
+
15
+ ### Fixed
16
+
17
+ * Fix Knapsack Pro integration ([#180][])
18
+
3
19
  ## [1.0.0.beta4] - 2024-05-14
4
20
 
5
21
  ### Added
@@ -238,7 +254,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
238
254
 
239
255
  - Ruby versions < 2.7 no longer supported ([#8][])
240
256
 
241
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.0.beta4...main
257
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.0.beta6...main
258
+ [1.0.0.beta6]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.0.beta5...v1.0.0.beta6
259
+ [1.0.0.beta5]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.0.beta4...v1.0.0.beta5
242
260
  [1.0.0.beta4]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.0.beta3...v1.0.0.beta4
243
261
  [1.0.0.beta3]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.0.beta2...v1.0.0.beta3
244
262
  [1.0.0.beta2]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.0.beta1...v1.0.0.beta2
@@ -334,7 +352,10 @@ Currently test suite level visibility is not used by our instrumentation: it wil
334
352
  [#166]: https://github.com/DataDog/datadog-ci-rb/issues/166
335
353
  [#167]: https://github.com/DataDog/datadog-ci-rb/issues/167
336
354
  [#168]: https://github.com/DataDog/datadog-ci-rb/issues/168
355
+ [#170]: https://github.com/DataDog/datadog-ci-rb/issues/170
337
356
  [#172]: https://github.com/DataDog/datadog-ci-rb/issues/172
338
357
  [#173]: https://github.com/DataDog/datadog-ci-rb/issues/173
339
358
  [#174]: https://github.com/DataDog/datadog-ci-rb/issues/174
340
- [#175]: https://github.com/DataDog/datadog-ci-rb/issues/175
359
+ [#175]: https://github.com/DataDog/datadog-ci-rb/issues/175
360
+ [#180]: https://github.com/DataDog/datadog-ci-rb/issues/180
361
+ [#183]: https://github.com/DataDog/datadog-ci-rb/issues/183
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "integration"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Contrib
8
+ # This method auto instruments all test libraries (ex: selenium-webdriver).
9
+ # It is intended to be called when test session starts to add additional capabilities to test visibility.
10
+ #
11
+ # This method does not automatically instrument test frameworks (ex: RSpec, Cucumber, etc), it requires
12
+ # test framework to be already instrumented.
13
+ def self.auto_instrument_on_session_start!
14
+ Datadog.logger.debug("Auto instrumenting all integrations...")
15
+
16
+ Integration.registry.each do |name, integration|
17
+ next unless integration.auto_instrument?
18
+
19
+ Datadog.logger.debug "#{name} is allowed to be auto instrumented"
20
+
21
+ patch_results = integration.patch
22
+ if patch_results == true
23
+ Datadog.logger.debug("#{name} is patched")
24
+ else
25
+ Datadog.logger.debug("#{name} is not patched (#{patch_results})")
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -13,7 +13,7 @@ module Datadog
13
13
  end
14
14
 
15
15
  module InstanceMethods
16
- def report(*)
16
+ def report(*args)
17
17
  return super unless datadog_configuration[:enabled]
18
18
 
19
19
  res = super
@@ -10,7 +10,7 @@ module Datadog
10
10
  end
11
11
 
12
12
  module ClassMethods
13
- def run(*)
13
+ def run(*args)
14
14
  return super unless datadog_configuration[:enabled]
15
15
  return super if Helpers.parallel?(self)
16
16
 
@@ -13,7 +13,7 @@ module Datadog
13
13
  end
14
14
 
15
15
  module ClassMethods
16
- def init_plugins(*)
16
+ def init_plugins(*args)
17
17
  super
18
18
 
19
19
  return unless datadog_configuration[:enabled]
@@ -16,7 +16,8 @@ module Datadog
16
16
  end
17
17
 
18
18
  module InstanceMethods
19
- def run(*)
19
+ def run(*args)
20
+ return super if ::RSpec.configuration.dry_run?
20
21
  return super unless datadog_configuration[:enabled]
21
22
 
22
23
  test_name = full_description.strip
@@ -16,6 +16,7 @@ module Datadog
16
16
  # Instance methods for configuration
17
17
  module ClassMethods
18
18
  def run(reporter = ::RSpec::Core::NullReporter)
19
+ return super if ::RSpec.configuration.dry_run?
19
20
  return super unless datadog_configuration[:enabled]
20
21
  return super unless top_level?
21
22
 
@@ -8,7 +8,6 @@ module Datadog
8
8
  module CI
9
9
  module Contrib
10
10
  module RSpec
11
- # Instrument RSpec::Core::Example
12
11
  module KnapsackPro
13
12
  module Extension
14
13
  def self.included(base)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module RSpec
7
+ module KnapsackPro
8
+ module Patcher
9
+ def self.patch
10
+ if defined?(::KnapsackPro::Extensions::RSpecExtension::Runner) &&
11
+ ::RSpec::Core::Runner.ancestors.include?(::KnapsackPro::Extensions::RSpecExtension::Runner)
12
+ # knapsack already patched rspec runner
13
+ require_relative "runner"
14
+ ::RSpec::Core::Runner.include(KnapsackPro::Runner)
15
+ else
16
+ # knapsack didn't patch rspec runner yet
17
+ require_relative "extension"
18
+ ::KnapsackPro::Extensions::RSpecExtension.include(KnapsackPro::Extension)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -14,7 +14,8 @@ module Datadog
14
14
  end
15
15
 
16
16
  module InstanceMethods
17
- def knapsack__run_specs(*)
17
+ def knapsack__run_specs(*args)
18
+ return super if ::RSpec.configuration.dry_run?
18
19
  return super unless datadog_configuration[:enabled]
19
20
 
20
21
  test_session = CI.start_test_session(
@@ -27,14 +27,16 @@ module Datadog
27
27
  ::RSpec::Queue::Runner.include(Runner)
28
28
  end
29
29
 
30
- # Knapsack Pro test runner instrumentation
31
- # https://github.com/KnapsackPro/knapsack_pro-ruby
32
30
  if knapsack_pro?
33
- require_relative "knapsack_pro/extension"
34
- ::KnapsackPro::Extensions::RSpecExtension.include(KnapsackPro::Extension)
31
+ # Knapsack Pro test runner instrumentation
32
+ # https://github.com/KnapsackPro/knapsack_pro-ruby
33
+ require_relative "knapsack_pro/patcher"
34
+ Datadog::CI::Contrib::RSpec::KnapsackPro::Patcher.patch
35
35
  end
36
36
 
37
+ # default rspec test runner instrumentation
37
38
  ::RSpec::Core::Runner.include(Runner)
39
+
38
40
  ::RSpec::Core::Example.include(Example)
39
41
  ::RSpec::Core::ExampleGroup.include(ExampleGroup)
40
42
  end
@@ -14,7 +14,8 @@ module Datadog
14
14
  end
15
15
 
16
16
  module InstanceMethods
17
- def run_specs(*)
17
+ def run_specs(*args)
18
+ return super if ::RSpec.configuration.dry_run?
18
19
  return super unless datadog_configuration[:enabled]
19
20
 
20
21
  test_session = CI.start_test_session(
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/tracing/contrib/patcher"
4
+
5
+ require_relative "ext"
6
+ require_relative "rum"
7
+ require_relative "../../ext/test"
8
+
9
+ module Datadog
10
+ module CI
11
+ module Contrib
12
+ module Selenium
13
+ # instruments Capybara::Selenium::Driver
14
+ module CapybaraDriver
15
+ def self.included(base)
16
+ base.prepend(InstanceMethods)
17
+ end
18
+
19
+ module InstanceMethods
20
+ def reset!
21
+ return super unless datadog_configuration[:enabled]
22
+
23
+ Datadog.logger.debug("[Selenium] Capybara session reset event")
24
+
25
+ RUM.stop_rum_session(@browser)
26
+
27
+ Datadog.logger.debug("[Selenium] RUM session stopped, deleting cookie")
28
+ @browser.manage.delete_cookie(Ext::COOKIE_TEST_EXECUTION_ID)
29
+ rescue ::Selenium::WebDriver::Error::WebDriverError => e
30
+ Datadog.logger.debug("[Selenium] Error while resetting Capybara session: #{e.message}")
31
+ ensure
32
+ super
33
+ end
34
+
35
+ private
36
+
37
+ def datadog_configuration
38
+ Datadog.configuration.ci[:selenium]
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/core"
4
+
5
+ require_relative "../ext"
6
+ require_relative "../../settings"
7
+
8
+ module Datadog
9
+ module CI
10
+ module Contrib
11
+ module Selenium
12
+ module Configuration
13
+ # Custom settings for the Selenium integration
14
+ # @public_api
15
+ class Settings < Datadog::CI::Contrib::Settings
16
+ option :enabled do |o|
17
+ o.type :bool
18
+ o.env Ext::ENV_ENABLED
19
+ o.default true
20
+ end
21
+
22
+ option :rum_flush_wait_millis do |o|
23
+ o.type :int
24
+ o.env Ext::ENV_RUM_FLUSH_WAIT_MILLIS
25
+ o.default 500
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/tracing/contrib/patcher"
4
+
5
+ require_relative "ext"
6
+ require_relative "rum"
7
+ require_relative "../../ext/test"
8
+
9
+ module Datadog
10
+ module CI
11
+ module Contrib
12
+ module Selenium
13
+ # instruments Selenium::WebDriver::Driver
14
+ module Driver
15
+ def self.included(base)
16
+ base.prepend(InstanceMethods)
17
+ end
18
+
19
+ module InstanceMethods
20
+ def quit
21
+ return super unless datadog_configuration[:enabled]
22
+
23
+ Datadog.logger.debug("[Selenium] Driver quit event")
24
+
25
+ RUM.stop_rum_session(@bridge)
26
+
27
+ Datadog.logger.debug("[Selenium] RUM session stopped, deleting cookie")
28
+ @bridge.manage.delete_cookie(Ext::COOKIE_TEST_EXECUTION_ID)
29
+ rescue ::Selenium::WebDriver::Error::WebDriverError => e
30
+ Datadog.logger.debug("[Selenium] Error while quitting Selenium driver: #{e.message}")
31
+ ensure
32
+ super
33
+ end
34
+
35
+ private
36
+
37
+ def datadog_configuration
38
+ Datadog.configuration.ci[:selenium]
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module Selenium
7
+ # Selenium integration constants
8
+ # @public_api
9
+ module Ext
10
+ ENV_ENABLED = "DD_CIVISIBILITY_SELENIUM_ENABLED"
11
+ ENV_RUM_FLUSH_WAIT_MILLIS = "DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS"
12
+
13
+ COOKIE_TEST_EXECUTION_ID = "datadog-ci-visibility-test-execution-id"
14
+
15
+ SCRIPT_IS_RUM_ACTIVE = <<~JS
16
+ return !!window.DD_RUM
17
+ JS
18
+ SCRIPT_STOP_RUM_SESSION = <<~JS
19
+ if (window.DD_RUM && window.DD_RUM.stopSession) {
20
+ window.DD_RUM.stopSession();
21
+ return true;
22
+ } else {
23
+ return false;
24
+ }
25
+ JS
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration"
4
+ require_relative "configuration/settings"
5
+ require_relative "patcher"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Contrib
10
+ module Selenium
11
+ # Description of Selenium integration
12
+ class Integration
13
+ include Datadog::CI::Contrib::Integration
14
+
15
+ MINIMUM_VERSION = Gem::Version.new("4.0.0")
16
+
17
+ register_as :selenium
18
+
19
+ def self.version
20
+ Gem.loaded_specs["selenium-webdriver"]&.version
21
+ end
22
+
23
+ def self.loaded?
24
+ !defined?(::Selenium).nil? && !defined?(::Selenium::WebDriver).nil? &&
25
+ !defined?(::Selenium::WebDriver::Driver).nil?
26
+ end
27
+
28
+ def self.compatible?
29
+ super && version >= MINIMUM_VERSION
30
+ end
31
+
32
+ # additional instrumentations for test helpers are auto instrumented on test session start
33
+ def auto_instrument?
34
+ true
35
+ end
36
+
37
+ def new_configuration
38
+ Configuration::Settings.new
39
+ end
40
+
41
+ def patcher
42
+ Patcher
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/tracing/contrib/patcher"
4
+
5
+ require_relative "ext"
6
+ require_relative "../../ext/test"
7
+
8
+ module Datadog
9
+ module CI
10
+ module Contrib
11
+ module Selenium
12
+ # instruments Selenium::WebDriver::Navigation
13
+ module Navigation
14
+ def self.included(base)
15
+ base.prepend(InstanceMethods)
16
+ end
17
+
18
+ module InstanceMethods
19
+ def to(url)
20
+ result = super
21
+
22
+ return result unless datadog_configuration[:enabled]
23
+
24
+ Datadog.logger.debug("[Selenium] Navigation to #{url}")
25
+
26
+ # on session reset Capybara navigates to about:blank
27
+ return result if url == "about:blank"
28
+
29
+ active_test = Datadog::CI.active_test
30
+ Datadog.logger.debug("[Selenium] Active test: #{active_test}")
31
+
32
+ return result unless active_test
33
+
34
+ # Set the test's trace id as a cookie in browser session
35
+ cookie_hash = {name: Ext::COOKIE_TEST_EXECUTION_ID, value: active_test.trace_id.to_s}
36
+ Datadog.logger.debug { "[Selenium] Setting cookie: #{cookie_hash}" }
37
+ @bridge.manage.add_cookie(cookie_hash)
38
+
39
+ # set the test type to browser
40
+ active_test.set_tag(CI::Ext::Test::TAG_TYPE, CI::Ext::Test::Type::BROWSER)
41
+
42
+ # set the tags specific to the browser test
43
+ active_test.set_tag(CI::Ext::Test::TAG_BROWSER_DRIVER, "selenium")
44
+ active_test.set_tag(
45
+ CI::Ext::Test::TAG_BROWSER_DRIVER_VERSION,
46
+ Integration.version
47
+ )
48
+ active_test.set_tag(
49
+ CI::Ext::Test::TAG_BROWSER_NAME,
50
+ @bridge.browser
51
+ )
52
+ active_test.set_tag(
53
+ CI::Ext::Test::TAG_BROWSER_VERSION,
54
+ @bridge.capabilities.browser_version
55
+ )
56
+
57
+ result
58
+ rescue ::Selenium::WebDriver::Error::WebDriverError => e
59
+ Datadog.logger.debug("[Selenium] Error while navigating: #{e.message}")
60
+
61
+ result
62
+ end
63
+
64
+ private
65
+
66
+ def datadog_configuration
67
+ Datadog.configuration.ci[:selenium]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/tracing/contrib/patcher"
4
+
5
+ require_relative "capybara_driver"
6
+ require_relative "driver"
7
+ require_relative "navigation"
8
+
9
+ module Datadog
10
+ module CI
11
+ module Contrib
12
+ module Selenium
13
+ # Patcher enables patching of 'Selenium::WebDriver' module.
14
+ module Patcher
15
+ include Datadog::Tracing::Contrib::Patcher
16
+
17
+ module_function
18
+
19
+ def target_version
20
+ Integration.version
21
+ end
22
+
23
+ def patch
24
+ ::Selenium::WebDriver::Driver.include(Driver)
25
+ ::Selenium::WebDriver::Navigation.include(Navigation)
26
+
27
+ # capybara calls `reset!` after each test, so we need to patch it as well
28
+ if defined?(::Capybara::Selenium::Driver)
29
+ ::Capybara::Selenium::Driver.include(CapybaraDriver)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/tracing/contrib/patcher"
4
+
5
+ require_relative "ext"
6
+ require_relative "../../ext/test"
7
+ require_relative "../../utils/parsing"
8
+
9
+ module Datadog
10
+ module CI
11
+ module Contrib
12
+ module Selenium
13
+ # Provides functionality to interact with Datadog Real User Monitoring product
14
+ # via executing JavaScript code in the browser.
15
+ #
16
+ # Relevant docs: https://docs.datadoghq.com/real_user_monitoring/browser/
17
+ module RUM
18
+ def self.is_rum_active?(script_executor)
19
+ is_rum_active_script_result = script_executor.execute_script(Ext::SCRIPT_IS_RUM_ACTIVE)
20
+ Datadog.logger.debug { "[Selenium] SCRIPT_IS_RUM_ACTIVE result is #{is_rum_active_script_result.inspect}" }
21
+ Utils::Parsing.convert_to_bool(is_rum_active_script_result)
22
+ end
23
+
24
+ def self.stop_rum_session(script_executor)
25
+ config = Datadog.configuration.ci[:selenium]
26
+ if is_rum_active?(script_executor)
27
+ Datadog::CI.active_test&.set_tag(
28
+ CI::Ext::Test::TAG_IS_RUM_ACTIVE,
29
+ "true"
30
+ )
31
+
32
+ result = script_executor.execute_script(Ext::SCRIPT_STOP_RUM_SESSION)
33
+ Datadog.logger.debug { "[Selenium] SCRIPT_STOP_RUM_SESSION result is #{result.inspect}" }
34
+
35
+ # introduce a delay to allow the RUM session to be stopped
36
+ delay = config[:rum_flush_wait_millis] / 1000.0
37
+ Datadog.logger.debug { "[Selenium] Waiting for #{delay} seconds" }
38
+ sleep(delay)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -8,6 +8,7 @@ module Datadog
8
8
  module Test
9
9
  CONTEXT_ORIGIN = "ciapp-test"
10
10
 
11
+ # Base test visibility tags
11
12
  TAG_FRAMEWORK = "test.framework"
12
13
  TAG_FRAMEWORK_VERSION = "test.framework_version"
13
14
  TAG_NAME = "test.name"
@@ -34,16 +35,13 @@ module Datadog
34
35
  # Code coverage tags
35
36
  TAG_CODE_COVERAGE_ENABLED = "test.code_coverage.enabled"
36
37
 
37
- # those tags are special and used to correlate tests with the test sessions, suites, and modules
38
- # they are transient and not sent to the backend
38
+ # Special tags, not sent to the backend.
39
+ # these tags are special and used to correlate tests with the test sessions, suites, and modules
39
40
  TAG_TEST_SESSION_ID = "_test.session_id"
40
41
  TAG_TEST_MODULE_ID = "_test.module_id"
41
42
  TAG_TEST_SUITE_ID = "_test.suite_id"
42
43
  TRANSIENT_TAGS = [TAG_TEST_SESSION_ID, TAG_TEST_MODULE_ID, TAG_TEST_SUITE_ID].freeze
43
44
 
44
- # tags that are common for the whole session and can be inherited from the test session
45
- INHERITABLE_TAGS = [TAG_FRAMEWORK, TAG_FRAMEWORK_VERSION].freeze
46
-
47
45
  # Environment runtime tags
48
46
  TAG_OS_ARCHITECTURE = "os.architecture"
49
47
  TAG_OS_PLATFORM = "os.platform"
@@ -51,10 +49,24 @@ module Datadog
51
49
  TAG_RUNTIME_NAME = "runtime.name"
52
50
  TAG_RUNTIME_VERSION = "runtime.version"
53
51
 
52
+ # Tags for browser tests
53
+ # true if Datadog RUM was detected in the page(s) loaded by Selenium
54
+ TAG_IS_RUM_ACTIVE = "test.is_rum_active"
55
+ TAG_BROWSER_DRIVER = "test.browser.driver"
56
+ # version of selenium driver used
57
+ TAG_BROWSER_DRIVER_VERSION = "test.browser.driver_version"
58
+ # name of the browser (Chrome, Firefox, Edge, etc), if multiple browsers then this tag is empty
59
+ TAG_BROWSER_NAME = "test.browser.name"
60
+ # version of the browser, if multiple browsers or multiple versions then this tag is empty
61
+ TAG_BROWSER_VERSION = "test.browser.version"
62
+
54
63
  # internal APM tag to mark a span as a test span
55
64
  TAG_SPAN_KIND = "span.kind"
56
65
  SPAN_KIND_TEST = "test"
57
66
 
67
+ # tags that are common for the whole session and can be inherited from the test session
68
+ INHERITABLE_TAGS = [TAG_FRAMEWORK, TAG_FRAMEWORK_VERSION].freeze
69
+
58
70
  # could be either "test" or "suite" depending on whether we skip individual tests or whole suites
59
71
  # we use test skipping for Ruby
60
72
  ITR_TEST_SKIPPING_MODE = "test"
@@ -71,6 +83,7 @@ module Datadog
71
83
  # test types (e.g. test, benchmark, browser)
72
84
  module Type
73
85
  TEST = "test"
86
+ BROWSER = "browser"
74
87
  BENCHMARK = "benchmark" # DEV: not used yet, will be used when benchmarks are supported
75
88
  end
76
89
  end
@@ -7,6 +7,7 @@ module Datadog
7
7
  DEFAULT_DD_SITE = "datadoghq.com"
8
8
 
9
9
  HEADER_DD_API_KEY = "DD-API-KEY"
10
+ HEADER_ACCEPT_ENCODING = "Accept-Encoding"
10
11
  HEADER_CONTENT_TYPE = "Content-Type"
11
12
  HEADER_CONTENT_ENCODING = "Content-Encoding"
12
13
  HEADER_EVP_SUBDOMAIN = "X-Datadog-EVP-Subdomain"
@@ -48,6 +49,8 @@ module Datadog
48
49
  CONTENT_TYPE_JSON = "application/json"
49
50
  CONTENT_TYPE_MULTIPART_FORM_DATA = "multipart/form-data"
50
51
  CONTENT_ENCODING_GZIP = "gzip"
52
+
53
+ GZIP_MAGIC_NUMBER = "\x1F\x8B".b
51
54
  end
52
55
  end
53
56
  end
@@ -23,6 +23,11 @@ module Datadog
23
23
  tracer_span.id
24
24
  end
25
25
 
26
+ # @return [Integer] the trace ID of the trace this span belongs to
27
+ def trace_id
28
+ tracer_span.trace_id
29
+ end
30
+
26
31
  # @return [String] the name of the span.
27
32
  def name
28
33
  tracer_span.name
@@ -10,6 +10,7 @@ require_relative "context/global"
10
10
  require_relative "context/local"
11
11
 
12
12
  require_relative "../codeowners/parser"
13
+ require_relative "../contrib/contrib"
13
14
  require_relative "../ext/app_types"
14
15
  require_relative "../ext/test"
15
16
  require_relative "../ext/environment"
@@ -57,6 +58,9 @@ module Datadog
57
58
  def start_test_session(service: nil, tags: {})
58
59
  return skip_tracing unless test_suite_level_visibility_enabled
59
60
 
61
+ # finds and instruments additional test libraries that we support (ex: selenium-webdriver)
62
+ Contrib.auto_instrument_on_session_start!
63
+
60
64
  @global_context.fetch_or_activate_test_session do
61
65
  tracer_span = start_datadog_tracer_span(
62
66
  "test.session", build_span_options(service, Ext::AppTypes::TYPE_TEST_SESSION)
@@ -26,7 +26,14 @@ module Datadog
26
26
  def api_request(path:, payload:, headers: {}, verb: "post")
27
27
  super
28
28
 
29
- perform_request(@api_http, path: path, payload: payload, headers: headers, verb: verb)
29
+ perform_request(
30
+ @api_http,
31
+ path: path,
32
+ payload: payload,
33
+ headers: headers,
34
+ verb: verb,
35
+ accept_compressed_response: true
36
+ )
30
37
  end
31
38
 
32
39
  def citestcov_request(path:, payload:, headers: {}, verb: "post")
@@ -37,12 +44,13 @@ module Datadog
37
44
 
38
45
  private
39
46
 
40
- def perform_request(http_client, path:, payload:, headers:, verb:)
47
+ def perform_request(http_client, path:, payload:, headers:, verb:, accept_compressed_response: false)
41
48
  http_client.request(
42
49
  path: path,
43
50
  payload: payload,
44
51
  headers: headers_with_default(headers),
45
- verb: verb
52
+ verb: verb,
53
+ accept_compressed_response: accept_compressed_response
46
54
  )
47
55
  end
48
56
 
@@ -16,6 +16,18 @@ module Datadog
16
16
  gzip_writer.close
17
17
  sio.string
18
18
  end
19
+
20
+ def decompress(input)
21
+ sio = StringIO.new(input)
22
+ gzip_reader = Zlib::GzipReader.new(
23
+ sio,
24
+ external_encoding: Encoding::UTF_8,
25
+ internal_encoding: Encoding::UTF_8
26
+ )
27
+ gzip_reader.read || ""
28
+ ensure
29
+ gzip_reader&.close
30
+ end
19
31
  end
20
32
  end
21
33
  end
@@ -32,12 +32,24 @@ module Datadog
32
32
  @compress = compress.nil? ? false : compress
33
33
  end
34
34
 
35
- def request(path:, payload:, headers:, verb: "post", retries: MAX_RETRIES, backoff: INITIAL_BACKOFF)
35
+ def request(
36
+ path:,
37
+ payload:,
38
+ headers:,
39
+ verb: "post",
40
+ retries: MAX_RETRIES,
41
+ backoff: INITIAL_BACKOFF,
42
+ accept_compressed_response: false
43
+ )
36
44
  if compress
37
45
  headers[Ext::Transport::HEADER_CONTENT_ENCODING] = Ext::Transport::CONTENT_ENCODING_GZIP
38
46
  payload = Gzip.compress(payload)
39
47
  end
40
48
 
49
+ if accept_compressed_response
50
+ headers[Ext::Transport::HEADER_ACCEPT_ENCODING] = Ext::Transport::CONTENT_ENCODING_GZIP
51
+ end
52
+
41
53
  Datadog.logger.debug do
42
54
  "Sending #{verb} request: host=#{host}; port=#{port}; ssl_enabled=#{ssl}; " \
43
55
  "compression_enabled=#{compress}; path=#{path}; payload_size=#{payload.size}"
@@ -91,12 +103,32 @@ module Datadog
91
103
  @adapter ||= Datadog::Core::Transport::HTTP::Adapters::Net.new(settings)
92
104
  end
93
105
 
94
- # this is needed because Datadog::Tracing::Writer is not fully compatiple with Datadog::Core::Transport
95
- # TODO: remove when CI implements its own worker
106
+ # adds compatibility with Datadog::Tracing transport and
107
+ # provides ungzipping capabilities
96
108
  class ResponseDecorator < ::SimpleDelegator
109
+ def payload
110
+ return @decompressed_payload if defined?(@decompressed_payload)
111
+
112
+ if gzipped?(__getobj__.payload)
113
+ Datadog.logger.debug("Decompressing gzipped response payload")
114
+ @decompressed_payload = Gzip.decompress(__getobj__.payload)
115
+ else
116
+ __getobj__.payload
117
+ end
118
+ end
119
+
97
120
  def trace_count
98
121
  0
99
122
  end
123
+
124
+ def gzipped?(payload)
125
+ return false if payload.nil? || payload.empty?
126
+
127
+ first_bytes = payload[0, 2]
128
+ return false if first_bytes.nil? || first_bytes.empty?
129
+
130
+ first_bytes.b == Datadog::CI::Ext::Transport::GZIP_MAGIC_NUMBER
131
+ end
100
132
  end
101
133
 
102
134
  class AdapterSettings
@@ -6,7 +6,7 @@ module Datadog
6
6
  MAJOR = "1"
7
7
  MINOR = "0"
8
8
  PATCH = "0"
9
- PRE = "beta4"
9
+ PRE = "beta6"
10
10
  BUILD = nil
11
11
  # PRE and BUILD above are modified for dev gems during gem build GHA workflow
12
12
 
data/lib/datadog/ci.rb CHANGED
@@ -376,6 +376,7 @@ end
376
376
  require_relative "ci/contrib/cucumber/integration"
377
377
  require_relative "ci/contrib/rspec/integration"
378
378
  require_relative "ci/contrib/minitest/integration"
379
+ require_relative "ci/contrib/selenium/integration"
379
380
 
380
381
  # Configuration extensions
381
382
  require_relative "ci/configuration/extensions"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog-ci
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta4
4
+ version: 1.0.0.beta6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-14 00:00:00.000000000 Z
11
+ date: 2024-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: datadog
@@ -66,6 +66,7 @@ files:
66
66
  - lib/datadog/ci/configuration/components.rb
67
67
  - lib/datadog/ci/configuration/extensions.rb
68
68
  - lib/datadog/ci/configuration/settings.rb
69
+ - lib/datadog/ci/contrib/contrib.rb
69
70
  - lib/datadog/ci/contrib/cucumber/configuration/settings.rb
70
71
  - lib/datadog/ci/contrib/cucumber/ext.rb
71
72
  - lib/datadog/ci/contrib/cucumber/formatter.rb
@@ -89,9 +90,18 @@ files:
89
90
  - lib/datadog/ci/contrib/rspec/ext.rb
90
91
  - lib/datadog/ci/contrib/rspec/integration.rb
91
92
  - lib/datadog/ci/contrib/rspec/knapsack_pro/extension.rb
93
+ - lib/datadog/ci/contrib/rspec/knapsack_pro/patcher.rb
92
94
  - lib/datadog/ci/contrib/rspec/knapsack_pro/runner.rb
93
95
  - lib/datadog/ci/contrib/rspec/patcher.rb
94
96
  - lib/datadog/ci/contrib/rspec/runner.rb
97
+ - lib/datadog/ci/contrib/selenium/capybara_driver.rb
98
+ - lib/datadog/ci/contrib/selenium/configuration/settings.rb
99
+ - lib/datadog/ci/contrib/selenium/driver.rb
100
+ - lib/datadog/ci/contrib/selenium/ext.rb
101
+ - lib/datadog/ci/contrib/selenium/integration.rb
102
+ - lib/datadog/ci/contrib/selenium/navigation.rb
103
+ - lib/datadog/ci/contrib/selenium/patcher.rb
104
+ - lib/datadog/ci/contrib/selenium/rum.rb
95
105
  - lib/datadog/ci/contrib/settings.rb
96
106
  - lib/datadog/ci/ext/app_types.rb
97
107
  - lib/datadog/ci/ext/environment.rb