#include <balancer/kernel/net/address.h>

#include <library/cpp/testing/unittest/registar.h>

#include <util/digest/city.h>
#include <netinet/in.h>

Y_UNIT_TEST_SUITE(TTestBalancerNetAddress) {

    auto DoGetIp4(TString ip4) {
        sockaddr_in in;
        Zero(in);
        in.sin_family = AF_INET;
        UNIT_ASSERT(inet_pton(in.sin_family, ip4.c_str(), &in.sin_addr) == 1);
        return in;
    }

    auto DoGetIp6(TString ip6) {
        sockaddr_in6 in;
        Zero(in);
        in.sin6_family = AF_INET6;
        UNIT_ASSERT(inet_pton(in.sin6_family, ip6.c_str(), &in.sin6_addr) == 1);
        return in;
    }

    Y_UNIT_TEST(TestAddr4Hash) {
        {
            auto addr = DoGetIp4("127.0.0.1");

            UNIT_ASSERT_VALUES_EQUAL(
                NSrvKernel::IpHash(NAddr::TOpaqueAddr((const sockaddr*) &addr)),
                CityHash64((const char*)&addr.sin_addr, sizeof(addr.sin_addr))
            );
        }
        {
            auto addr = DoGetIp4("88.86.202.88");

            UNIT_ASSERT_VALUES_EQUAL(
                NSrvKernel::IpHash(NAddr::TOpaqueAddr((const sockaddr*) &addr)),
                CityHash64((const char*)&addr.sin_addr, sizeof(addr.sin_addr))
            );

            UNIT_ASSERT(NSrvKernel::IpHash(NAddr::TOpaqueAddr((const sockaddr*) &addr)) > 0.01 * Max<ui64>());
        }
    }

    Y_UNIT_TEST(TestAddr6Hash) {
        auto addr = DoGetIp6("::1");

        UNIT_ASSERT_VALUES_EQUAL(
            NSrvKernel::IpHash(NAddr::TOpaqueAddr((const sockaddr*)&addr)),
            CityHash64((const char*)&addr.sin6_addr, sizeof(addr.sin6_addr))
        );

        UNIT_ASSERT(NSrvKernel::IpHash(NAddr::TOpaqueAddr((const sockaddr*) &addr)) > 0.2031 * Max<ui64>());
        UNIT_ASSERT(NSrvKernel::IpHash(NAddr::TOpaqueAddr((const sockaddr*) &addr)) < 0.2032 * Max<ui64>());
    }
}


Y_UNIT_TEST_SUITE(TestConflictingAddressses) {
    Y_UNIT_TEST(InAddrAnyDifferentPorts) {
        TVector<TNetworkAddress> a = { {"*", 8080} };
        TVector<TNetworkAddress> b = { {"*", 8081} };

        UNIT_ASSERT(!NSrvKernel::HasConflictingAddresses(a, b));
    }

    Y_UNIT_TEST(InAddrAnySamePorts) {
        TVector<TNetworkAddress> a = { {"*", 8080} };
        TVector<TNetworkAddress> b = { {"*", 8080} };

        UNIT_ASSERT(NSrvKernel::HasConflictingAddresses(a, b));
    }

    Y_UNIT_TEST(InAddrAnyAndIpDifferentPorts) {
        TVector<TNetworkAddress> a = { {"*", 8080} };
        TVector<TNetworkAddress> b = { {"::1", 8081} };

        UNIT_ASSERT(!NSrvKernel::HasConflictingAddresses(a, b));
    }

    Y_UNIT_TEST(InAddrAnyAndIpSamePorts) {
        TVector<TNetworkAddress> a = { {"*", 8080} };
        TVector<TNetworkAddress> b = { {"::1", 8080} };

        UNIT_ASSERT(NSrvKernel::HasConflictingAddresses(a, b));
    }

    Y_UNIT_TEST(DifferentIpDifferentPorts) {
        TVector<TNetworkAddress> a = { {"::1", 8080} };
        TVector<TNetworkAddress> b = { {"2a02:6b8:f000:7247:1e1b:dff:fe8b:abcd", 8081} };

        UNIT_ASSERT(!NSrvKernel::HasConflictingAddresses(a, b));
    }

    Y_UNIT_TEST(SameIpDifferentPorts) {
        TVector<TNetworkAddress> a = { {"::1", 8080} };
        TVector<TNetworkAddress> b = { {"::1", 8081} };

        UNIT_ASSERT(!NSrvKernel::HasConflictingAddresses(a, b));
    }

    Y_UNIT_TEST(SameIpSamePorts) {
        TVector<TNetworkAddress> a = { {"::1", 8080} };
        TVector<TNetworkAddress> b = { {"::1", 8080} };

        UNIT_ASSERT(NSrvKernel::HasConflictingAddresses(a, b));
    }
}
