<commit_before>package radius_test

import (
	"context"
	"fmt"
	"net"
	"sync/atomic"
	"testing"
	"time"

	"layeh.com/radius"
	. "layeh.com/radius/rfc2865"
)

func TestPacketServer_basic(t *testing.T) {
	addr, err := net.ResolveUDPAddr("udp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	pc, err := net.ListenUDP("udp", addr)
	if err != nil {
		t.Fatal(err)
	}

	secret := []byte("123456790")

	server := radius.PacketServer{
		SecretSource: radius.StaticSecretSource(secret),
		Handler: radius.HandlerFunc(func(w radius.ResponseWriter, r *radius.Request) {
			username := UserName_GetString(r.Packet)
			if username == "tim" {
				w.Write(r.Response(radius.CodeAccessAccept))
			} else {
				w.Write(r.Response(radius.CodeAccessReject))
			}
		}),
	}

	var clientErr error
	go func() {
		defer server.Shutdown(context.Background())

		packet := radius.New(radius.CodeAccessRequest, secret)
		UserName_SetString(packet, "tim")
		client := radius.Client{
			Retry: time.Millisecond * 50,
		}
		response, err := client.Exchange(context.Background(), packet, pc.LocalAddr().String())
		if err != nil {
			clientErr = err
			return
		}
		if response.Code != radius.CodeAccessAccept {
			clientErr = fmt.Errorf("expected CodeAccessAccept, got %s\n", response.Code)
		}
	}()

	if err := server.Serve(pc); err != nil {
		t.Fatal(err)
	}

	server.Shutdown(context.Background())

	if clientErr != nil {
		t.Fatal(err)
	}
}

func TestPacketServer_shutdown(t *testing.T) {
	secret := []byte(`12345`)

	var handlerState int32

	handlerCalled := make(chan struct{})

	var server *radius.TestServer
	handler := radius.HandlerFunc(func(w radius.ResponseWriter, r *radius.Request) {
		close(handlerCalled)
		atomic.AddInt32(&handlerState, 1)
		<-r.Context().Done()
		atomic.AddInt32(&handlerState, 1)
		time.Sleep(time.Millisecond * 15)
		atomic.AddInt32(&handlerState, 1)
	})
	server = radius.NewTestServer(handler, radius.StaticSecretSource(secret))
	defer server.Close()

	req := radius.New(radius.CodeAccessRequest, secret)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		client := radius.Client{
			Retry:           time.Millisecond * 5,
			MaxPacketErrors: 2,
		}
		client.Exchange(ctx, req, server.Addr)
	}()

	<-handlerCalled
	if err := server.Server.Shutdown(context.Background()); err != nil {
		t.Fatalf("got ShutDown error %v; expecting nil", err)
	}
	if state := atomic.LoadInt32(&handlerState); state != 3 {
		t.Fatalf("handlerState = %d; expecting 3", state)
	}
}

func TestRequest_context(t *testing.T) {
	req := &radius.Request{
		Packet: &radius.Packet{},
	}
	if req.Context() != context.Background() {
		t.Fatalf("req.Context() = %v; expecting context.Background()", req.Context())
	}

	req2 := req.WithContext(context.Background())
	if req == req2 {
		t.Fatal("expected WithContext requests to differ")
	}
	if req.Packet != req2.Packet {
		t.Fatalf("expected WithContext request packets to be the same")
	}

	func() {
		defer func() {
			err := recover()
			if err == nil {
				t.Fatal("expected recover() to be non-nil")
			}
			errStr, ok := err.(string)
			if !ok || errStr != "nil ctx" {
				t.Fatalf("got recover() = %v; expected nil ctx", err)
			}
		}()
		req.WithContext(nil)<commit_msg>move server_test.go out of radius_test package<commit_after>package radius

import (
	"context"
	"fmt"
	"net"
	"sync/atomic"
	"testing"
	"time"
)

func TestPacketServer_basic(t *testing.T) {
	addr, err := net.ResolveUDPAddr("udp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	pc, err := net.ListenUDP("udp", addr)
	if err != nil {
		t.Fatal(err)
	}

	secret := []byte("123456790")
	const UserNameType = 1

	server := PacketServer{
		SecretSource: StaticSecretSource(secret),
		Handler: HandlerFunc(func(w ResponseWriter, r *Request) {
			username := String(r.Get(UserNameType))
			if username == "tim" {
				w.Write(r.Response(CodeAccessAccept))
			} else {
				w.Write(r.Response(CodeAccessReject))
			}
		}),
	}

	var clientErr error
	go func() {
		defer server.Shutdown(context.Background())

		packet := New(CodeAccessRequest, secret)
		username, _ := NewString("tim")
		packet.Set(UserNameType, username)
		client := Client{
			Retry: time.Millisecond * 50,
		}
		response, err := client.Exchange(context.Background(), packet, pc.LocalAddr().String())
		if err != nil {
			clientErr = err
			return
		}
		if response.Code != CodeAccessAccept {
			clientErr = fmt.Errorf("expected CodeAccessAccept, got %s", response.Code)
		}
	}()

	if err := server.Serve(pc); err != nil {
		t.Fatal(err)
	}

	server.Shutdown(context.Background())

	if clientErr != nil {
		t.Fatal(err)
	}
}

func TestPacketServer_shutdown(t *testing.T) {
	secret := []byte(`12345`)

	var handlerState int32

	handlerCalled := make(chan struct{})

	var server *TestServer
	handler := HandlerFunc(func(w ResponseWriter, r *Request) {
		close(handlerCalled)
		atomic.AddInt32(&handlerState, 1)
		<-r.Context().Done()
		atomic.AddInt32(&handlerState, 1)
		time.Sleep(time.Millisecond * 15)
		atomic.AddInt32(&handlerState, 1)
	})
	server = NewTestServer(handler, StaticSecretSource(secret))
	defer server.Close()

	req := New(CodeAccessRequest, secret)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func() {
		client := Client{
			Retry:           time.Millisecond * 5,
			MaxPacketErrors: 2,
		}
		client.Exchange(ctx, req, server.Addr)
	}()

	<-handlerCalled
	if err := server.Server.Shutdown(context.Background()); err != nil {
		t.Fatalf("got ShutDown error %v; expecting nil", err)
	}
	if state := atomic.LoadInt32(&handlerState); state != 3 {
		t.Fatalf("handlerState = %d; expecting 3", state)
	}
}

func TestRequest_context(t *testing.T) {
	req := &Request{
		Packet: &Packet{},
	}
	if req.Context() != context.Background() {
		t.Fatalf("req.Context() = %v; expecting context.Background()", req.Context())
	}

	req2 := req.WithContext(context.Background())
	if req == req2 {
		t.Fatal("expected WithContext requests to differ")
	}
	if req.Packet != req2.Packet {
		t.Fatalf("expected WithContext request packets to be the same")
	}

	func() {
		defer func() {
			err := recover()
			if err == nil {
				t.Fatal("expected recover() to be non-nil")
			}
			errStr, ok := err.(string)
			if !ok || errStr != "nil ctx" {
				t.Fatalf("got recover() = %v; expected nil ctx", err)
			}
		}()
		req.WithContext(nil)
{'fraction_non_alphanumeric': 0.15743211426777587, 'fraction_numerical': 0.01302778213781196, 'mean_word_length': 3.9703588143525743, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5781520', 'n_tokens_mistral': 2453, 'n_tokens_neox': 2198, 'n_words': 485}