// +build go1.10,linux,!appengine

/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// The test in this file should be run in an environment that has go1.10 or later,
// as the function SyscallConn() (required to get socket option) was
// introduced to net.TCPListener in go1.10.

package test

import (
	"testing"
	"time"

	"google.golang.org/grpc/internal/channelz"
	"google.golang.org/grpc/internal/leakcheck"
	testpb "google.golang.org/grpc/test/grpc_testing"
)

func TestCZSocketMetricsSocketOption(t *testing.T) {
	envs := []env{tcpClearRREnv, tcpTLSRREnv}
	for _, e := range envs {
		testCZSocketMetricsSocketOption(t, e)
	}
}

func testCZSocketMetricsSocketOption(t *testing.T, e env) {
	defer leakcheck.Check(t)
	channelz.NewChannelzStorage()
	te := newTest(t, e)
	te.startServer(&testServer{security: e.security})
	defer te.tearDown()
	cc := te.clientConn()
	tc := testpb.NewTestServiceClient(cc)
	doSuccessfulUnaryCall(tc, t)

	time.Sleep(10 * time.Millisecond)
	ss, _ := channelz.GetServers(0)
	if len(ss) != 1 {
		t.Fatalf("There should be one server, not %d", len(ss))
	}
	if len(ss[0].ListenSockets) != 1 {
		t.Fatalf("There should be one listen socket, not %d", len(ss[0].ListenSockets))
	}
	for id := range ss[0].ListenSockets {
		sm := channelz.GetSocket(id)
		if sm == nil || sm.SocketData == nil || sm.SocketData.SocketOptions == nil {
			t.Fatalf("Unable to get server listen socket options")
		}
	}
	ns, _ := channelz.GetServerSockets(ss[0].ID, 0)
	if len(ns) != 1 {
		t.Fatalf("There should be one server normal socket, not %d", len(ns))
	}
	if ns[0] == nil || ns[0].SocketData == nil || ns[0].SocketData.SocketOptions == nil {
		t.Fatalf("Unable to get server normal socket options")
	}

	tchan, _ := channelz.GetTopChannels(0)
	if len(tchan) != 1 {
		t.Fatalf("There should only be one top channel, not %d", len(tchan))
	}
	if len(tchan[0].SubChans) != 1 {
		t.Fatalf("There should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans))
	}
	var id int64
	for id = range tchan[0].SubChans {
		break
	}
	sc := channelz.GetSubChannel(id)
	if sc == nil {
		t.Fatalf("There should only be one socket under subchannel %d, not 0", id)
	}
	if len(sc.Sockets) != 1 {
		t.Fatalf("There should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets))
	}
	for id = range sc.Sockets {
		break
	}
	skt := channelz.GetSocket(id)
	if skt == nil || skt.SocketData == nil || skt.SocketData.SocketOptions == nil {
		t.Fatalf("Unable to get client normal socket options")
	}
}
