require 'minitest/autorun' # Problem # https://softwareengineering.stackexchange.com/questions/153806/conflict-resolution-for-two-way-sync # interface DB { # String Get(String) # void Set(String, String) # []String Keys() # # // we can add extra methods as we sit fit # } # # We want to implement the replicate method # # db1.set("a", "a") # db2.set("b", "b") # replicate(db1, db2) # assert db2.get("a") == "a" # assert db1.get("b") == "b" class Database attr_accessor :records attr_reader :logs def initialize @records = {} @logs = {} # key, last_set end def get(key) @records[key] end def set(key, value) @records[key] = value @logs[key] = Time.now end def size @records.count end def keys @records.keys end end def replicate(db1, db2) db = Database.new db1_records = db1.records db2_records = db2.records db1_keys = db1.records.keys db2_keys = db2.records.keys db1_records.each do |k, v| if db2_records.keys.include?(k) value = db1.logs[k] > db2.logs[k] ? v : db2.get(k) db.set(k, value) else db.set(k, v) end end db2_records.each do |k, v| unless db1_records.keys.include?(k) db.set(k, v) end end db1.records = db.records db2.records = db.records end # Test Database class class TestDatabase < Minitest::Test def setup @db = Database.new end def test_that_database_start_with_empty_records assert_equal 0, @db.size, "Database size is not 0" end def test_that_database_can_set_and_get_key @db.set("foo", "bar") assert_equal "bar", @db.records["foo"], "Value wasn't stored" assert_equal "bar", @db.get("foo"), "Value wasn't fetched" assert_equal 1, @db.size, "Database size is incorrect" end def test_that_database_returns_nil_for_non_existing_key assert_nil @db.get("foo"), "Not nil value returned for non existing key" end def test_that_database_keys_return_keys @db.set("hi", "bye") @db.set("salt", "sugar") @db.set("black", "white") assert_equal ["hi", "salt", "black"], @db.keys, "Wrong existing keys returned" end end # Test replicate method class TestReplicate < Minitest::Test def setup @db1 = Database.new @db2 = Database.new @db1.set("a", "a") @db2.set("b", "b") end def test_that_database_are_replicated_without_conflicts replicate(@db1, @db2) assert_equal "b", @db1.get("b"), "Database one is not replicated correctly" assert_equal "a", @db2.get("a"), "Database two is not replicated correctly" end def test_that_database_are_replicated_with_conflicts @db1.set("c", "d") @db2.set("c", "f") replicate(@db1, @db2) assert_equal "f", @db1.get("c"), "Database one is not consistent" assert_equal "f", @db2.get("c"), "Database two is not consistent" end def test_that_database_are_replicated_with_conflicts_and_time_stamp_checking @db1.set("c", "d") @db2.set("c", "f") @db1.set("c", "x") replicate(@db1, @db2) assert_equal "x", @db1.get("c"), "Database one is not consistent" assert_equal "x", @db2.get("c"), "Database two is not consistent" end end