Skip to content

Commit

Permalink
test: Introduce with_fake_seam_connect test helper to allow testing…
Browse files Browse the repository at this point in the history
… against fake-seam-connect node package (#160)

Co-authored-by: Seam Bot <[email protected]>
  • Loading branch information
andrii-balitskyi and seambot authored Nov 18, 2024
1 parent a1a621e commit 413cf00
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ jobs:
uses: ./.github/actions/setup
with:
ruby_version: ${{ matrix.ruby }}
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Test
run: bundle exec rake test
lint:
Expand Down
8 changes: 4 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ GEM
thor (1.3.2)
unicode-display_width (2.6.0)
uri (1.0.1)
webmock (3.0.1)
addressable (>= 2.3.6)
webmock (3.24.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff
hashdiff (>= 0.4.0, < 2.0.0)

PLATFORMS
ruby
Expand All @@ -127,7 +127,7 @@ DEPENDENCIES
simplecov (~> 0.21)
simplecov-console (~> 0.9)
standard (~> 1.3)
webmock (~> 3.0.0)
webmock (~> 3.24.0)

BUNDLED WITH
2.5.16
127 changes: 126 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
"pregenerate": "markdown-toc -i README.md --bullets '-'",
"generate": "node generate-routes.js",
"postgenerate": "rake format",
"format": "prettier --write --ignore-path .gitignore ."
"format": "prettier --write --ignore-path .gitignore .",
"start": "fake-seam-connect --seed"
},
"devDependencies": {
"@seamapi/fake-seam-connect": "1.72.1",
"@seamapi/nextlove-sdk-generator": "1.14.10",
"@seamapi/types": "1.286.1",
"del": "^7.1.0",
Expand Down
2 changes: 1 addition & 1 deletion seam.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "simplecov", "~> 0.21"
spec.add_development_dependency "simplecov-console", "~> 0.9"
spec.add_development_dependency "standard", "~> 1.3"
spec.add_development_dependency "webmock", "~> 3.0.0"
spec.add_development_dependency "webmock", "~> 3.24.0"
end
18 changes: 18 additions & 0 deletions spec/integration/basic_usage_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

RSpec.describe "Basic SDK Usage" do
it "can list devices" do
with_fake_seam_connect do |_, endpoint, seed|
seam = Seam.new(api_key: seed["seam_apikey1_token"], endpoint: endpoint)
devices = seam.devices.list
expect(devices).to be_a(Array)
expect(devices).not_to be_nil
expect(devices.length).to be > 0

device = devices.first
expect(device).to be_a(Seam::Resources::Device)
expect(device.device_id).to be_a(String)
expect(device.created_at).to be_a(Time)
end
end
end
101 changes: 98 additions & 3 deletions spec/support/helpers.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,106 @@
# frozen_string_literal: true
require "socket"
require "json"
require "net/http"
require "uri"

module Helpers
DEFAULT_TIMEOUT = 30
MAX_ATTEMPTS = 5

def stub_seam_request(method, path, response, status: 200, headers: {})
stub_request(
method,
"#{Seam::DEFAULT_ENDPOINT}#{path}"
).to_return(status: status, body: response.to_json,
headers: {"Content-Type" => "application/json"}.merge(headers))
).to_return(
status: status,
body: response.to_json,
headers: {"Content-Type" => "application/json"}.merge(headers)
)
end

def with_fake_seam_connect
port = find_available_port
ENV["PORT"] = port.to_s
endpoint = "http://localhost:#{port}"

pid = start_server
WebMock.disable_net_connect!(allow_localhost: true)

wait_for_server(endpoint)
seed = get_seed(endpoint)
seam = initialize_seam_client(endpoint, seed)
verify_server_health!(endpoint)

yield seam, endpoint, seed
ensure
cleanup_server(pid)
end

private

def find_available_port
TCPServer.new("127.0.0.1", 0).tap do |server|
@port = server.addr[1]
server.close
end
@port
end

def start_server
Process.spawn("npm run start", pgroup: true)
end

def initialize_seam_client(endpoint, seed)
Seam.new(
endpoint: endpoint,
api_key: seed["seam_apikey1_token"]
)
end

def verify_server_health!(endpoint)
uri = URI.parse("#{endpoint}/health")
response = Net::HTTP.get_response(uri)
raise "Fake test server not healthy" unless response.is_a?(Net::HTTPSuccess)
end

def wait_for_server(endpoint, max_attempts: MAX_ATTEMPTS, timeout: DEFAULT_TIMEOUT)
start_time = Time.now
attempts = 0

begin
uri = URI.parse("#{endpoint}/health")
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = 5
http.open_timeout = 5
response = http.get(uri.path)
raise unless response.is_a?(Net::HTTPSuccess)
rescue => e
attempts += 1
if attempts < max_attempts && (Time.now - start_time) < timeout
sleep(1)
retry
else
raise "Fake test server failed to start after #{attempts} attempts or #{timeout}s timeout: #{e.message}"
end
end
end

def get_seed(endpoint)
uri = URI.parse("#{endpoint}/_fake/default_seed")
response = Net::HTTP.get(uri)
JSON.parse(response)
rescue => e
raise "Failed to get seed from fake test server: #{e.message}"
end

def cleanup_server(pid)
return unless pid

begin
Process.kill("-TERM", Process.getpgid(pid))
Process.wait(pid)
rescue Errno::ESRCH, Errno::ECHILD
# Process already terminated
end
end
end

0 comments on commit 413cf00

Please sign in to comment.