<commit_before>package core

import (
	"os"
	"os/signal"
	//	"runtime"
	//	"syscall"
	"testing"
	"time"

	"github.com/joyent/containerpilot/discovery"
	//	"github.com/joyent/containerpilot/discovery/consul"
	"github.com/joyent/containerpilot/services"
)

// ------------------------------------------
// Test setup with mock services

// Mock Discovery
type NoopServiceBackend struct{}

func (c *NoopServiceBackend) SendHeartbeat(service *discovery.ServiceDefinition)      { return }
func (c *NoopServiceBackend) CheckForUpstreamChanges(backend, tag string) bool        { return false }
func (c *NoopServiceBackend) MarkForMaintenance(service *discovery.ServiceDefinition) {}
func (c *NoopServiceBackend) Deregister(service *discovery.ServiceDefinition)         {}

func getSignalTestConfig(t *testing.T) *App {

	cfg := &services.ServiceConfig{
		ID:         "test-service",
		Name:       "test-service",
		Heartbeat:  1,
		Port:       1,
		TTL:        1,
		Interfaces: []string{"inet"},
		Exec:       []string{"./testdata/test.sh", "interruptSleep"},
	}
	cfg.AddDiscoveryConfig(&NoopServiceBackend{})
	service := services.NewService(cfg)
	app := EmptyApp()
	app.StopTimeout = 5
	app.Services = []*services.Service{service}
	return app
}

// ------------------------------------------

// TODO

// Test handler for SIGUSR1
// func TestMaintenanceSignal(t *testing.T) {
// 	app := getSignalTestConfig(t)
// 	if app.InMaintenanceMode() {
// 		t.Fatal("Should not be in maintenance mode by default")
// 	}

// 	app.ToggleMaintenanceMode()
// 	if !app.InMaintenanceMode() {
// 		t.Fatal("Should be in maintenance mode after receiving SIGUSR1")
// 	}

// 	app.ToggleMaintenanceMode()
// 	if app.InMaintenanceMode() {
// 		t.Fatal("Should not be in maintenance mode after receiving second SIGUSR1")
// 	}
// }

// TODO

// Test handler for SIGTERM. Note that the SIGCHLD handler is fired
// by this same test, but that we don't have a separate unit test
// because they'll interfere with each other's state.
// func TestTerminateSignal(t *testing.T) {

// 	app := getSignalTestConfig(t)
// 	startTime := time.Now()
// 	go func() {
// 		if exitCode, _ := commands.RunAndWait(app.Command, nil); exitCode != 2 {
// 			t.Fatalf("Expected exit code 2 but got %d", exitCode)
// 		}
// 	}()
// 	// we need time for the forked process to start up and this is async
// 	runtime.Gosched()
// 	time.Sleep(10 * time.Millisecond)

// 	app.Terminate()
// 	elapsed := time.Since(startTime)
// 	if elapsed.Seconds() > float64(app.StopTimeout) {
// 		t.Fatalf("Expected elapsed time <= %d seconds, but was %.2f",
// 			app.StopTimeout, elapsed.Seconds())
// 	}
// }

// TODO

// Test handler for SIGHUP
// func TestReloadSignal(t *testing.T) {
// 	app := getSignalTestConfig(t)
// 	app.ConfigFlag = "invalid"
// 	err := app.Reload()
// 	if err == nil {
// 		t.Errorf("Invalid configuration did not return error")
// 	}
// 	app.ConfigFlag = `{ "consul": "newconsul:8500" }`
// 	err = app.Reload()
// 	if err != nil {
// 		t.Errorf("Valid configuration returned error: %v", err)
// 	}
// 	discSvc := app.Discovery
// 	if svc, ok := discSvc.(*consul.Consul); !ok || svc == nil {
// 		t.Errorf("Configuration was not reloaded: %v", discSvc)
// 	}
// }

// TODO

// Test that only ensures that we cover a straight-line run through
// the handleSignals setup code
// func TestSignalWiring(t *testing.T) {
// 	app := EmptyApp()
// 	app.handleSignals()
// 	sendAndWaitForSignal(t, syscall.SIGUSR1)
// 	sendAndWaitForSignal(t, syscall.SIGTERM)
// 	sendAndWaitForSignal(t, syscall.SIGCHLD)
// 	sendAndWaitForSignal(t, syscall.SIGHUP)
// }

// Helper to ensure the signal that we send has been received so that
// we don't muddy subsequent tests of the signal handler.
func sendAndWaitForSignal(t *testing.T, s os.Signal) {
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, s)
	me, _ := os.FindProcess(os.Getpid())
	if err := me.Signal(s); err != nil {
		t.Fatalf("Got error on %s: %v\n", s.String(), err)
	}
	select {
	case recv := <-sig:
		if recv != s {
			t.Fatalf("Expected %v but got %v\n", s, recv)
		}
	case <-time.After(1 * time.Second):
		t.Fatalf("timeout waiting for %v\n", s)
	}
}<commit_msg>got most of signal unit tests working again<commit_after>package core

import (
	"os"
	"os/signal"
	//	"runtime"
	"syscall"
	"testing"
	"time"

	"github.com/joyent/containerpilot/discovery"
	"github.com/joyent/containerpilot/discovery/consul"
	"github.com/joyent/containerpilot/events"
	"github.com/joyent/containerpilot/services"
)

// ------------------------------------------
// Test setup with mock services

// Mock Discovery
type NoopServiceBackend struct{}

func (c *NoopServiceBackend) SendHeartbeat(service *discovery.ServiceDefinition)      { return }
func (c *NoopServiceBackend) CheckForUpstreamChanges(backend, tag string) bool        { return false }
func (c *NoopServiceBackend) MarkForMaintenance(service *discovery.ServiceDefinition) {}
func (c *NoopServiceBackend) Deregister(service *discovery.ServiceDefinition)         {}

func getSignalTestConfig(t *testing.T) *App {

	cfg := &services.ServiceConfig{
		ID:         "test-service",
		Name:       "test-service",
		Heartbeat:  1,
		Port:       1,
		TTL:        1,
		Interfaces: []string{"inet"},
		Exec:       []string{"./testdata/test.sh", "interruptSleep"},
	}
	cfg.AddDiscoveryConfig(&NoopServiceBackend{})
	service := services.NewService(cfg)
	app := EmptyApp()
	app.StopTimeout = 5
	app.Services = []*services.Service{service}
	app.Bus = events.NewEventBus()
	return app
}

// ------------------------------------------

// Test handler for SIGUSR1
func TestMaintenanceSignal(t *testing.T) {
	app := getSignalTestConfig(t)
	if app.InMaintenanceMode() {
		t.Fatal("Should not be in maintenance mode by default")
	}

	app.ToggleMaintenanceMode()
	if !app.InMaintenanceMode() {
		t.Fatal("Should be in maintenance mode after receiving SIGUSR1")
	}

	app.ToggleMaintenanceMode()
	if app.InMaintenanceMode() {
		t.Fatal("Should not be in maintenance mode after receiving second SIGUSR1")
	}
}

// TODO

// Test handler for SIGTERM. Note that the SIGCHLD handler is fired
// by this same test, but that we don't have a separate unit test
// because they'll interfere with each other's state.
// func TestTerminateSignal(t *testing.T) {

// 	app := getSignalTestConfig(t)
// 	startTime := time.Now()
// 	go func() {
// 		if exitCode, _ := commands.RunAndWait(app.Command, nil); exitCode != 2 {
// 			t.Fatalf("Expected exit code 2 but got %d", exitCode)
// 		}
// 	}()
// 	// we need time for the forked process to start up and this is async
// 	runtime.Gosched()
// 	time.Sleep(10 * time.Millisecond)

// 	app.Terminate()
// 	elapsed := time.Since(startTime)
// 	if elapsed.Seconds() > float64(app.StopTimeout) {
// 		t.Fatalf("Expected elapsed time <= %d seconds, but was %.2f",
// 			app.StopTimeout, elapsed.Seconds())
// 	}
// }

// Test handler for SIGHUP
func TestReloadSignal(t *testing.T) {
	app := getSignalTestConfig(t)
	app.ConfigFlag = "invalid"
	err := app.Reload()
	if err == nil {
		t.Errorf("Invalid configuration did not return error")
	}
	app.ConfigFlag = `{ "consul": "newconsul:8500" }`
	err = app.Reload()
	if err != nil {
		t.Errorf("Valid configuration returned error: %v", err)
	}
	discSvc := app.Discovery
	if svc, ok := discSvc.(*consul.Consul); !ok || svc == nil {
		t.Errorf("Configuration was not reloaded: %v", discSvc)
	}
}

// Test that only ensures that we cover a straight-line run through
// the handleSignals setup code
func TestSignalWiring(t *testing.T) {
	app := EmptyApp()
	app.Bus = events.NewEventBus()
	app.handleSignals()
	sendAndWaitForSignal(t, syscall.SIGUSR1)
	sendAndWaitForSignal(t, syscall.SIGTERM)
	sendAndWaitForSignal(t, syscall.SIGCHLD)
	sendAndWaitForSignal(t, syscall.SIGHUP)
}

// Helper to ensure the signal that we send has been received so that
// we don't muddy subsequent tests of the signal handler.
func sendAndWaitForSignal(t *testing.T, s os.Signal) {
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, s)
	me, _ := os.FindProcess(os.Getpid())
	if err := me.Signal(s); err != nil {
		t.Fatalf("Got error on %s: %v\n", s.String(), err)
	}
	select {
	case recv := <-sig:
		if recv != s {
			t.Fatalf("Expected %v but got %v\n", s, recv)
		}
	case <-time.After(1 * time.Second):
		t.Fatalf("timeout waiting for %v\n", s)
	}
}
{'fraction_non_alphanumeric': 0.1665266946610678, 'fraction_numerical': 0.005038992201559688, 'mean_word_length': 3.2143579373104147, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 5, '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': '3583328', 'n_tokens_mistral': 3011, 'n_tokens_neox': 2874, 'n_words': 733}