Skip to content

Commit

Permalink
Kontena::Etcd::Test::FakeServer: TTL support with tick! to fake clock
Browse files Browse the repository at this point in the history
  • Loading branch information
Tero Marttila committed Dec 29, 2016
1 parent 9ecf4ba commit 04b27db
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 16 deletions.
45 changes: 29 additions & 16 deletions lib/kontena/etcd/test/fake_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,15 @@
module Kontena::Etcd::Test
class FakeServer < ServerBase
class Node
attr_reader :key, :created_index, :modified_index, :value, :nodes
attr_reader :key, :created_index, :modified_index, :value, :nodes, :expire

def initialize(key, index, value: nil, nodes: nil)
def initialize(key, index, value: nil, nodes: nil, expire: nil)
@key = key
@created_index = index
@modified_index = index
@value = value
@nodes = nodes
@expire = expire
end

def parent_path
Expand All @@ -75,9 +76,10 @@ def directory?
@nodes != nil
end

def update(index, value)
def update(index, value, expire: nil)
@modified_index = index
@value = value
@expire = expire
end
def delete(index)
@modified_index = index
Expand Down Expand Up @@ -159,10 +161,10 @@ def read(key)
end

# Write a node
def write(path, **attrs)
def write(path, ttl: nil, **attrs)
@index += 1

@nodes[path] = node = Node.new(path, @index, **attrs)
@nodes[path] = node = Node.new(path, @index, expire: ttl ? @clock + ttl : nil, **attrs)

# create parent dirs
child = node
Expand All @@ -175,10 +177,10 @@ def write(path, **attrs)
node
end

def update(node, value)
def update(node, value, ttl: nil)
@index += 1

node.update(@index, value)
node.update(@index, value, expire: ttl ? @clock + ttl : nil)
end

# recursively unlink node and any child nodes
Expand Down Expand Up @@ -232,6 +234,7 @@ def reset!
@nodes = {}
@logs = []
@modified = false
@clock = 0.0

mkdir('/')
@start_index = @index
Expand All @@ -253,6 +256,18 @@ def load!(tree)
@start_index = @index
end

# Advance clock and expire nodes
def tick!(offset)
@clock += offset

walk do |node|
next unless node.expire && @clock >= node.expire

remove(node)
log! :expire, node
end
end

# Return etcd index at start of test
def etcd_index
@start_index
Expand Down Expand Up @@ -295,6 +310,7 @@ def set(key, dir: nil, value: nil, ttl: nil, refresh: nil, prevExist: nil, prevI
key, node = read(key)

raise Error.new(400, 211, key), "Value provided on refresh" if refresh && value
raise Error.new(400, 212, key), "A TTL must be provided on refresh" if refresh && !ttl

if node
raise Error.new(412, 105, key), "Key already exists" if prevExist == false
Expand All @@ -310,24 +326,21 @@ def set(key, dir: nil, value: nil, ttl: nil, refresh: nil, prevExist: nil, prevI
end

prev_node = node.serialize
value = node.value if refresh

if refresh
# TODO: refresh TTL
# Do not log!
else
update node, value
log! action, node
end
update node, value, ttl: ttl

log! action, node unless refresh
else
raise Error.new(404, 100, key), "Key not found" if refresh || prevExist == true || prevIndex || prevValue

action = prevExist == false ? :create : :set
prev_node = nil

node = if dir
write key, nodes: {}
write key, nodes: {}, ttl: ttl
else
write key, value: value
write key, value: value, ttl: ttl
end

log! action, node
Expand Down
46 changes: 46 additions & 0 deletions spec/kontena/etcd/test/fake_server_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,50 @@
expect(etcd_server.logs).to eq [[:set, '/kontena/test/quux']]
end
end

describe '#tick' do
it "expires a node" do
etcd.set('/kontena/test/quux', value: 'quux', ttl: 30)

etcd_server.tick! 30

expect{etcd.get('/kontena/test/quux')}.to raise_error(Etcd::KeyNotFound)

expect(etcd_server.nodes).to eq({})
expect(etcd_server.logs).to eq [
[:set, '/kontena/test/quux'],
[:expire, '/kontena/test/quux'],
]
end

it "does not expires a node with a longer TTL" do
etcd.set('/kontena/test/quux', value: 'quux', ttl: 30)

etcd_server.tick! 15

expect{etcd.get('/kontena/test/quux')}.to_not raise_error

expect(etcd_server.nodes).to eq(
'/kontena/test/quux' => 'quux',
)
expect(etcd_server.logs).to eq [
[:set, '/kontena/test/quux'],
]
end

it "does not expires a node without any ttl" do
etcd.set('/kontena/test/quux', value: 'quux')

etcd_server.tick! 15

expect{etcd.get('/kontena/test/quux')}.to_not raise_error

expect(etcd_server.nodes).to eq(
'/kontena/test/quux' => 'quux',
)
expect(etcd_server.logs).to eq [
[:set, '/kontena/test/quux'],
]
end
end
end

0 comments on commit 04b27db

Please sign in to comment.