require 'test_helper'
require 'vcr'

# creation of google's example of guest book
class CreateGuestbookGo < MiniTest::Test
  def test_create_guestbook_entities
    VCR.configure do |c|
      c.cassette_library_dir = 'test/cassettes'
      c.hook_into :webmock
    end

    # WebMock.allow_net_connect!
    VCR.use_cassette('kubernetes_guestbook') do # , record: :new_episodes) do
      client = Kubeclient::Client.new 'http://10.35.0.23:8080/api/', 'v1'

      testing_ns = Kubeclient::Resource.new
      testing_ns.metadata = {}
      testing_ns.metadata.name = 'kubeclient-ns'

      # delete in case they existed before so creation can be tested
      delete_namespace(client, testing_ns.metadata.name)
      delete_services(client, testing_ns.metadata.name,
                      ['guestbook', 'redis-master', 'redis-slave'])
      delete_replication_controllers(client, testing_ns.metadata.name,
                                     ['guestbook', 'redis-master', 'redis-slave'])

      client.create_namespace testing_ns
      services = create_services(client, testing_ns.metadata.name)
      replicators = create_replication_controllers(client, testing_ns.metadata.name)

      get_namespaces(client)
      get_services(client, testing_ns.metadata.name)
      get_replication_controllers(client, testing_ns.metadata.name)

      delete_services(client, testing_ns.metadata.name, services)
      delete_replication_controllers(client, testing_ns.metadata.name, replicators)

      client.delete_namespace testing_ns.metadata.name
    end
  end

  def delete_namespace(client, namespace_name)
    client.delete_namespace namespace_name
    rescue KubeException => exception
      assert_instance_of(KubeException, exception)
      assert_equal(404, exception.error_code)
  end

  def get_namespaces(client)
    namespaces = client.get_namespaces
    assert(true, namespaces.size > 2)
  end

  def get_services(client, ns)
    retrieved_services = client.get_services(namespace: ns)
    assert_equal(3, retrieved_services.size)
  end

  def get_replication_controllers(client, ns)
    retrieved_replicators = client.get_replication_controllers(namespace: ns)
    assert_equal(3, retrieved_replicators.size)
  end

  def create_services(client, ns)
    guestbook_service = client.create_service guestbook_service(ns)
    redis_service = client.create_service redis_service(ns)
    redis_slave_service = client.create_service redis_slave_service(ns)
    [guestbook_service, redis_service, redis_slave_service]
  end

  def create_replication_controllers(client, namespace)
    rc = client.create_replication_controller guestbook_rc(namespace)
    rc2 = client.create_replication_controller redis_master_rc(namespace)
    rc3 = client.create_replication_controller redis_slave_rc(namespace)
    [rc, rc2, rc3]
  end

  def delete_services(client, namespace, services)
    # if the entity is not found, no need to fail the test
    services.each do |service|
      begin
        if service.instance_of?(Kubeclient::Service)
          client.delete_service service.metadata.name, namespace
        else
          # it's just a string - service name
          client.delete_service service, namespace
        end
      rescue KubeException => exception
        assert_instance_of(KubeException, exception)
        assert_equal(404, exception.error_code)
      end
    end
  end

  def delete_replication_controllers(client, namespace, replication_controllers)
    # if the entity is not found, no need to fail the test
    replication_controllers.each do |rc|
      begin
        if rc.instance_of?(Kubeclient::ReplicationController)
          client.delete_replication_controller rc.metadata.name, namespace
        else
          # it's just a string - rc name
          client.delete_replication_controller rc, namespace
        end
      rescue KubeException => exception
        assert_instance_of(KubeException, exception)
        assert_equal(404, exception.error_code)
      end
    end
  end

  private

  def construct_base_rc(namespace)
    rc = Kubeclient::ReplicationController.new
    rc.metadata = {}
    rc.metadata.namespace = namespace
    rc.metadata.labels = {}
    rc.spec = {}
    rc.spec.selector = {}
    rc.spec.template = {}
    rc.spec.template.metadata = {}
    rc.spec.template.spec = {}
    rc.spec.template.metadata.labels = {}
    rc
  end

  def redis_master_rc(namespace)
    rc = construct_base_rc(namespace)
    rc.metadata.name = 'redis-master'
    rc.metadata.labels.app = 'redis'
    rc.metadata.labels.role = 'master'
    rc.spec.replicas = 1
    rc.spec.selector.app = 'redis'
    rc.spec.selector.role = 'master'
    rc.spec.template.metadata.labels.app = 'redis'
    rc.spec.template.metadata.labels.role = 'master'
    rc.spec.template.spec.containers = [{ 'name' => 'redis-master',
                                          'image' => 'redis',
                                          'ports' => [{ 'name' => 'redis-server',
                                                        'containerPort' => 6379 }] }]
    rc
  end

  def redis_slave_rc(namespace)
    rc = construct_base_rc(namespace)
    rc.metadata.name = 'redis-slave'
    rc.metadata.labels.app = 'redis'
    rc.metadata.labels.role = 'slave'
    rc.spec.replicas = 2
    rc.spec.selector.app = 'redis'
    rc.spec.selector.role = 'slave'
    rc.spec.template.metadata.labels.app = 'redis'
    rc.spec.template.metadata.labels.role = 'slave'
    rc.spec.template.spec.containers = [{ 'name'          => 'redis-slave',
                                          'image'         => 'kubernetes/redis-slave:v2',
                                          'ports'         => [{ 'name'          => 'redis-server',
                                                                'containerPort' => 6379 }
                                                             ] }]
    rc
  end

  def guestbook_rc(namespace)
    rc = construct_base_rc(namespace)
    rc.metadata.name = 'guestbook'
    rc.metadata.labels.app = 'guestbook'
    rc.metadata.labels.role = 'slave'
    rc.spec.replicas = 3
    rc.spec.selector.app = 'guestbook'
    rc.spec.template.metadata.labels.app = 'guestbook'
    rc.spec.template.spec.containers = [{ 'name'     => 'guestbook',
                                          'image'    => 'kubernetes/guestbook:v2',
                                          'ports'    => [{ 'name'          => 'http-server',
                                                           'containerPort' => 3000 }]
                                        }]

    rc
  end

  def base_service(namespace)
    our_service = Kubeclient::Service.new
    our_service.metadata = {}
    our_service.metadata.namespace = namespace
    our_service.metadata.labels = {}
    our_service.spec = {}
    our_service.spec.selector = {}
    our_service
  end

  def redis_slave_service(namespace)
    our_service = base_service(namespace)
    our_service.metadata.name = 'redis-slave'
    our_service.metadata.labels.app = 'redis'
    our_service.metadata.labels.role = 'slave'

    our_service.spec.ports = [{ 'port' => 6379,
                                'targetPort' => 'redis-server'
                              }]

    our_service.spec.selector.app = 'redis'
    our_service.spec.selector.role = 'slave'
    our_service
  end

  def redis_service(namespace)
    our_service = base_service(namespace)
    our_service.metadata.name = 'redis-master'
    our_service.metadata.labels.app = 'redis'
    our_service.metadata.labels.role = 'master'

    our_service.spec.ports = [{ 'port' => 6379,
                                'targetPort' => 'redis-server'
                              }]

    our_service.spec.selector.app = 'redis'
    our_service.spec.selector.role = 'master'
    our_service
  end

  def guestbook_service(namespace)
    our_service = base_service(namespace)
    our_service.metadata.name = 'guestbook'
    our_service.metadata.labels.name = 'guestbook'

    our_service.spec.ports = [{ 'port' => 3000,
                                'targetPort' => 'http-server'
                              }]

    our_service.spec.selector.app = 'guestbook'
    our_service.type = 'LoadBalancer'
    our_service
  end
end
