forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_env_diff.rb
More file actions
172 lines (163 loc) · 8.15 KB
/
Copy pathtest_env_diff.rb
File metadata and controls
172 lines (163 loc) · 8.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# frozen_string_literal: true
require_relative "spec_helper"
# EnvDiffCommand compares two env snapshots and reports drift. Historically it
# diffed digest, startCommand, and env-var KEY sets — but the banner also
# advertised "custom domains", which the diff loop never actually compared.
# These tests pin the custom-domain comparison so the banner is honest:
#
# 1. Identical custom_domains across both envs => no drift line.
# 2. Differing custom_domains => a drift line that names the service and the
# offending domains, in both directions (missing-in-a / missing-in-b).
#
# We exercise the pure diff helper (diff_services) directly so the test does
# not need to stand up Railway GraphQL — the helper takes two already-built
# snapshots and returns the drift array.
class EnvDiffTest < Minitest::Test
def snapshot_with(domains_a: [], domains_b: [])
# Two single-service snapshots that agree on everything EXCEPT the
# custom_domains set, so any drift surfaced is attributable to domains.
snap_a = {
"services" => [
{
"name" => "showcase-shell",
"digest" => "sha256:abc",
"start_command" => nil,
"env_keys" => %w[PORT NODE_ENV],
"custom_domains" => domains_a,
},
],
}
snap_b = {
"services" => [
{
"name" => "showcase-shell",
"digest" => "sha256:abc",
"start_command" => nil,
"env_keys" => %w[PORT NODE_ENV],
"custom_domains" => domains_b,
},
],
}
[snap_a, snap_b]
end
def test_identical_custom_domains_no_drift
snap_a, snap_b = snapshot_with(
domains_a: ["shell.copilotkit.ai"],
domains_b: ["shell.copilotkit.ai"],
)
cmd = Railway::EnvDiffCommand.new(%w[staging production])
drift = cmd.diff_services(snap_a, snap_b, "staging", "production")
assert_empty drift
end
def test_differing_custom_domains_reported_both_directions
snap_a, snap_b = snapshot_with(
domains_a: ["only-in-staging.copilotkit.ai"],
domains_b: ["only-in-prod.copilotkit.ai"],
)
cmd = Railway::EnvDiffCommand.new(%w[staging production])
drift = cmd.diff_services(snap_a, snap_b, "staging", "production")
# One finding per direction, each naming the offending domain.
missing_in_b = drift.find { |l| l.include?("custom domains missing in production") }
missing_in_a = drift.find { |l| l.include?("custom domains missing in staging") }
assert missing_in_b, "expected a 'missing in production' finding, got: #{drift.inspect}"
assert missing_in_a, "expected a 'missing in staging' finding, got: #{drift.inspect}"
assert_includes missing_in_b, "only-in-staging.copilotkit.ai"
assert_includes missing_in_a, "only-in-prod.copilotkit.ai"
end
# A service that exists in one snapshot but not the other must surface a
# "missing in <env>" drift line. This also exercises the missing-service
# branch that was previously untested.
def test_service_missing_in_one_env_reported
snap_a = {
"services" => [
{ "name" => "showcase-shell", "digest" => "sha256:abc",
"start_command" => nil, "env_keys" => %w[PORT], "custom_domains" => [] },
{ "name" => "extra-svc", "digest" => "sha256:def",
"start_command" => nil, "env_keys" => %w[PORT], "custom_domains" => [] },
],
}
snap_b = {
"services" => [
{ "name" => "showcase-shell", "digest" => "sha256:abc",
"start_command" => nil, "env_keys" => %w[PORT], "custom_domains" => [] },
],
}
cmd = Railway::EnvDiffCommand.new(%w[staging production])
drift = cmd.diff_services(snap_a, snap_b, "staging", "production")
missing = drift.find { |l| l.include?("extra-svc") && l.include?("missing in production") }
assert missing, "expected 'extra-svc missing in production', got: #{drift.inspect}"
end
# A snapshot lacking a "services" key must not raise NoMethodError. NOTE:
# because the missing "services" key makes find_service return nil for the
# one service that exists only in snap_b, this case exercises ONLY the
# top-level `["services"] || []` guard and the missing-service branch — it
# `next`s before ever reaching the env_keys / custom_domains comparison.
# The env_keys/custom_domains accessors are pinned separately below.
def test_snapshot_without_services_key_does_not_crash
snap_a = {} # no "services" key at all
snap_b = {
"services" => [
{ "name" => "showcase-shell", "digest" => "sha256:abc",
"start_command" => nil, "env_keys" => %w[PORT], "custom_domains" => [] },
],
}
cmd = Railway::EnvDiffCommand.new(%w[staging production])
drift = cmd.diff_services(snap_a, snap_b, "staging", "production")
missing = drift.find { |l| l.include?("showcase-shell") && l.include?("missing in staging") }
assert missing, "expected 'showcase-shell missing in staging', got: #{drift.inspect}"
end
# A service present in BOTH snapshots where one side OMITS "env_keys"
# (e.g. a v1/partial/hand-edited snapshot read from a git SHA) must not
# raise NoMethodError. This genuinely reaches the env_keys comparison
# branch (find_service returns the service on both sides, so the method
# does NOT `next`). Without an `|| []` guard, `sa["env_keys"] - sb[...]`
# raises `undefined method '-' for nil`.
def test_service_without_env_keys_does_not_crash
snap_a = {
"services" => [
# No "env_keys" key at all on this side.
{ "name" => "showcase-shell", "digest" => "sha256:abc",
"start_command" => nil, "custom_domains" => [] },
],
}
snap_b = {
"services" => [
{ "name" => "showcase-shell", "digest" => "sha256:abc",
"start_command" => nil, "env_keys" => %w[PORT NODE_ENV],
"custom_domains" => [] },
],
}
cmd = Railway::EnvDiffCommand.new(%w[staging production])
drift = cmd.diff_services(snap_a, snap_b, "staging", "production")
# snap_a is missing both keys present in snap_b, so they must be
# reported as "missing in staging" (the a-side env).
missing_in_a = drift.find { |l| l.include?("env keys missing in staging") }
assert missing_in_a, "expected an 'env keys missing in staging' finding, got: #{drift.inspect}"
assert_includes missing_in_a, "PORT"
assert_includes missing_in_a, "NODE_ENV"
end
# Symmetric to the env_keys case: a service present in BOTH snapshots where
# one side OMITS "custom_domains" must not raise NoMethodError when the
# other side has domains to diff against. Pins the custom_domains guard at
# the comparison branch (not just the missing-service branch).
def test_service_without_custom_domains_does_not_crash
snap_a = {
"services" => [
{ "name" => "showcase-shell", "digest" => "sha256:abc",
"start_command" => nil, "env_keys" => %w[PORT] },
],
}
snap_b = {
"services" => [
{ "name" => "showcase-shell", "digest" => "sha256:abc",
"start_command" => nil, "env_keys" => %w[PORT],
"custom_domains" => ["shell.copilotkit.ai"] },
],
}
cmd = Railway::EnvDiffCommand.new(%w[staging production])
drift = cmd.diff_services(snap_a, snap_b, "staging", "production")
missing_in_a = drift.find { |l| l.include?("custom domains missing in staging") }
assert missing_in_a, "expected a 'custom domains missing in staging' finding, got: #{drift.inspect}"
assert_includes missing_in_a, "shell.copilotkit.ai"
end
end