Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dturn committed Oct 23, 2019
1 parent 175b1f9 commit 118b289
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 66 deletions.
9 changes: 1 addition & 8 deletions lib/krane/global_deploy_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,10 @@ class GlobalDeployTask

# Initializes the deploy task
#
# @param namespace [String] Kubernetes namespace
# @param context [String] Kubernetes context
# @param logger [Object] Logger object (defaults to an instance of KubernetesDeploy::FormattedLogger)
# @param kubectl_instance [Kubectl] Kubectl instance
# @param bindings [Hash] Bindings parsed by KubernetesDeploy::BindingsParser
# @param max_watch_seconds [Integer] Timeout in seconds
# @param selector [Hash] Selector(s) parsed by KubernetesDeploy::LabelSelector
# @param template_paths [Array<String>] An array of template paths
# @param template_dir [String] Path to a directory with templates (deprecated)
# @param protected_namespaces [Array<String>] Array of protected Kubernetes namespaces (defaults
# to KubernetesDeploy::DeployTask::PROTECTED_NAMESPACES)
# @param render_erb [Boolean] Enable ERB rendering
def initialize(context:, max_watch_seconds: nil, selector: nil, template_paths: [])
template_paths = template_paths.map { |path| File.expand_path(path) }

Expand Down Expand Up @@ -81,6 +73,7 @@ def run!(verify_result: true, prune: true)

logger.phase_heading("Deploying all resources")
deploy!(resources, verify_result, prune)

StatsD.event("Deployment succeeded",
"Successfully deployed all resources to #{context}",
alert_type: "success", tags: statsd_tags << "status:success")
Expand Down
5 changes: 3 additions & 2 deletions lib/kubernetes-deploy/deploy_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def resource_deployer
selector: @selector, statsd_tags: statsd_tags, current_sha: @current_sha)
end

def global_resource_names
def global_resource_kinds
cluster_resource_discoverer.global_resource_kinds
end

Expand Down Expand Up @@ -291,6 +291,7 @@ def validate_globals(resources)
end

def check_initial_status(resources)
@task_config.global_kinds = global_resource_kinds.map(&:downcase)
cache = ResourceCache.new(@task_config)
KubernetesDeploy::Concurrency.split_across_threads(resources) { |r| r.sync(cache) }
resources.each { |r| @logger.info(r.pretty_status) }
Expand All @@ -309,7 +310,7 @@ def discover_resources
current_sha: @current_sha, bindings: @bindings) do |r_def|
crd = crds_by_kind[r_def["kind"]]&.first
r = KubernetesResource.build(namespace: @namespace, context: @context, logger: @logger, definition: r_def,
statsd_tags: @namespace_tags, crd: crd, global_names: global_resource_names)
statsd_tags: @namespace_tags, crd: crd, global_names: global_resource_kinds)
resources << r
@logger.info(" - #{r.id}")
end
Expand Down
2 changes: 1 addition & 1 deletion lib/kubernetes-deploy/kubernetes_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def debug_message(cause = nil, info_hash = {})
def fetch_events(kubectl)
return {} unless exists?
out, _err, st = kubectl.run("get", "events", "--output=go-template=#{Event.go_template_for(type, name)}",
log_failure: false)
log_failure: false, use_namespace: !global?)
return {} unless st.success?

event_collector = Hash.new { |hash, key| hash[key] = [] }
Expand Down
76 changes: 76 additions & 0 deletions test/helpers/mock_resource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

MockResource = Struct.new(:id, :hits_to_complete, :status) do
def debug_message(*)
@debug_message
end

def sync(_cache)
@hits ||= 0
@hits += 1
end

def after_sync
end

def type
"MockResource"
end
alias_method :kubectl_resource_type, :type

def pretty_timeout_type
end

def deploy_method
:apply
end

def file_path
"/dev/null"
end

def deploy_started_at=(_)
end

def sensitive_template_content?
true
end

def global?
false
end

def deploy_succeeded?
status == "success" && hits_complete?
end

def deploy_failed?
status == "failed" && hits_complete?
end

def deploy_timed_out?
status == "timeout" && hits_complete?
end

def timeout
hits_to_complete
end

def sync_debug_info(_)
@debug_message = "Something went wrong"
end

def pretty_status
"#{id} #{status} (#{@hits} hits)"
end

def report_status_to_statsd(watch_time)
end

private

def hits_complete?
@hits ||= 0
@hits >= hits_to_complete
end
end
4 changes: 2 additions & 2 deletions test/helpers/resource_cache_test_helper.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# frozen_string_literal: true
module ResourceCacheTestHelper
def stub_kind_get(kind, items: [], times: 1)
def stub_kind_get(kind, items: [], times: 1, use_namespace: true)
stub_kubectl_response(
"get",
kind,
"--chunk-size=0",
resp: { items: items },
kwargs: { attempts: 5, output_is_sensitive: false, use_namespace: true },
kwargs: { attempts: 5, output_is_sensitive: false, use_namespace: use_namespace },
times: times,
)
end
Expand Down
2 changes: 1 addition & 1 deletion test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def mock_output_stream
end

def task_config(context: KubeclientHelper::TEST_CONTEXT, namespace: @namespace, logger: @logger)
KubernetesDeploy::TaskConfig.new(context, namespace, logger)
@task_config ||= KubernetesDeploy::TaskConfig.new(context, namespace, logger)
end

def krane_black_box(command, args = "")
Expand Down
96 changes: 96 additions & 0 deletions test/unit/kubernetes-deploy/resource_deployer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# frozen_string_literal: true
require 'test_helper'
require 'kubernetes-deploy/resource_deployer'

class ResourceDeployerTest < KubernetesDeploy::TestCase
def test_deploy_prune_builds_whitelist
whitelist_kind = "fake_kind"
resource = build_mock_resource
KubernetesDeploy::Kubectl.any_instance.expects(:run).with do |*args|
args.include?("--prune-whitelist=#{whitelist_kind}")
end.returns(["", "", stub(success?: true)])
resource_deployer(kubectl_times: 0, prune_whitelist: [whitelist_kind]).deploy!([resource], false, true)
end

def test_deploy_no_prune_doesnt_prune
whitelist_kind = "fake_kind"
resource = build_mock_resource
KubernetesDeploy::Kubectl.any_instance.expects(:run).with do |*args|
!args.include?("--prune-whitelist=#{whitelist_kind}")
end.returns(["", "", stub(success?: true)])
resource_deployer(kubectl_times: 0, prune_whitelist: [whitelist_kind]).deploy!([resource], false, false)
end

def test_deploy_verify_false_message
resource = build_mock_resource
resource_deployer.deploy!([resource], false, false)
logger.print_summary(:done) # Force logger to flush
assert_logs_match_all(["Deploy result verification is disabled for this deploy."])
end

def test_deploy_time_out_error
resource = build_mock_resource(final_status: "timeout")
watcher = mock("ResourceWatcher")
watcher.expects(:run).returns(true)
KubernetesDeploy::ResourceWatcher.expects(:new).returns(watcher)
assert_raises(KubernetesDeploy::DeploymentTimeoutError) do
resource_deployer.deploy!([resource], true, false)
end
end

def test_deploy_verify_false_no_timeout
resource = build_mock_resource(final_status: "timeout")
resource_deployer.deploy!([resource], false, false)
logger.print_summary(:done) # Force logger to flush
assert_logs_match_all(["Deploy result verification is disabled for this deploy."])
end

def test_deploy_failure_error
resource = build_mock_resource(final_status: "failure")
watcher = mock("ResourceWatcher")
watcher.expects(:run).returns(true)
KubernetesDeploy::ResourceWatcher.expects(:new).returns(watcher)
assert_raises(KubernetesDeploy::FatalDeploymentError) do
resource_deployer.deploy!([resource], true, false)
end
end

def test_deploy_verify_false_no_failure_error
resource = build_mock_resource(final_status: "failure")
resource_deployer.deploy!([resource], false, false)
logger.print_summary(:done) # Force logger to flush
assert_logs_match_all(["Deploy result verification is disabled for this deploy."])
end

def test_predeploy_priority_resources_respectes_pre_deploy_list
kind = "MockResource"
resource = build_mock_resource
watcher = mock("ResourceWatcher")
watcher.expects(:run).returns(true)
KubernetesDeploy::ResourceWatcher.expects(:new).returns(watcher)
priority_list = [kind]
resource_deployer.predeploy_priority_resources([resource], priority_list)
end

def test_predeploy_priority_resources_respectes_empty_pre_deploy_list
resource = build_mock_resource
priority_list = []
KubernetesDeploy::ResourceWatcher.expects(:new).times(0)
resource_deployer(kubectl_times: 0).predeploy_priority_resources([resource], priority_list)
end

private

def resource_deployer(kubectl_times: 2, prune_whitelist: [])
unless kubectl_times == 0
KubernetesDeploy::Kubectl.expects(:new).returns(build_runless_kubectl).times(kubectl_times)
end
@deployer = KubernetesDeploy::ResourceDeployer.new(current_sha: 'test-sha',
statsd_tags: [], task_config: task_config, prune_whitelist: prune_whitelist,
max_watch_seconds: 60, selector: nil)
end

def build_mock_resource(final_status: "success", hits_to_complete: 0, name: "web-pod")
MockResource.new(name, hits_to_complete, final_status)
end
end
52 changes: 0 additions & 52 deletions test/unit/kubernetes-deploy/resource_watcher_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,58 +123,6 @@ def build_watcher(resources)
)
end

MockResource = Struct.new(:id, :hits_to_complete, :status) do
def debug_message(*)
@debug_message
end

def sync(_cache)
@hits ||= 0
@hits += 1
end

def after_sync
end

def type
"MockResource"
end
alias_method :kubectl_resource_type, :type

def deploy_succeeded?
status == "success" && hits_complete?
end

def deploy_failed?
status == "failed" && hits_complete?
end

def deploy_timed_out?
status == "timeout" && hits_complete?
end

def timeout
hits_to_complete
end

def sync_debug_info(_)
@debug_message = "Something went wrong"
end

def pretty_status
"#{id} #{status} (#{@hits} hits)"
end

def report_status_to_statsd(watch_time)
end

private

def hits_complete?
@hits >= hits_to_complete
end
end

def build_mock_resource(final_status: "success", hits_to_complete: 1, name: "web-pod")
MockResource.new(name, hits_to_complete, final_status)
end
Expand Down
17 changes: 17 additions & 0 deletions test/unit/resource_cache_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ def test_get_instance_populates_the_cache_and_returns_instance_hash
assert_equal(pods[1].kubectl_response, @cache.get_instance("FakePod", pods[1].name))
end

def test_get_instance_populates_the_cache_and_returns_instance_hash_global_kind
@task_config.global_kinds = %w(FakeNode).map(&:downcase)
nodes = build_fake_nodes(2)
stub_kind_get("FakeNode", items: nodes.map(&:kubectl_response), times: 1, use_namespace: false)
assert_equal(nodes[0].kubectl_response, @cache.get_instance("FakeNode", nodes[0].name))
assert_equal(nodes[1].kubectl_response, @cache.get_instance("FakeNode", nodes[1].name))
end

def test_get_instance_returns_empty_hash_if_pod_not_found
pods = build_fake_pods(2)
stub_kind_get("FakePod", items: pods.map(&:kubectl_response), times: 1)
Expand Down Expand Up @@ -81,6 +89,10 @@ def test_concurrently_syncing_huge_numbers_of_resources_makes_exactly_one_kubect

private

def build_fake_nodes(num)
num.times.map { |n| FakeNode.new("node#{n}") }
end

def build_fake_pods(num)
num.times.map { |n| FakePod.new("pod#{n}") }
end
Expand Down Expand Up @@ -141,4 +153,9 @@ def sync(mediator)
end
class FakePod < MockResource; end
class FakeConfigMap < MockResource; end
class FakeNode < MockResource
def global?
true
end
end
end

0 comments on commit 118b289

Please sign in to comment.