...

Source file src/github.com/letsencrypt/boulder/test/integration/akamai_purger_drain_queue_test.go

Documentation: github.com/letsencrypt/boulder/test/integration

     1  //go:build integration
     2  
     3  package integration
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"fmt"
     9  	"os"
    10  	"os/exec"
    11  	"syscall"
    12  	"testing"
    13  	"time"
    14  
    15  	akamaipb "github.com/letsencrypt/boulder/akamai/proto"
    16  	"github.com/letsencrypt/boulder/cmd"
    17  	bcreds "github.com/letsencrypt/boulder/grpc/creds"
    18  	"github.com/letsencrypt/boulder/metrics"
    19  	"github.com/letsencrypt/boulder/test"
    20  	"google.golang.org/grpc"
    21  	"google.golang.org/grpc/balancer/roundrobin"
    22  	"google.golang.org/grpc/connectivity"
    23  )
    24  
    25  func setup() (*exec.Cmd, *bytes.Buffer, akamaipb.AkamaiPurgerClient, error) {
    26  	purgerCmd := exec.Command("./bin/boulder", "akamai-purger", "--config", "test/integration/testdata/akamai-purger-queue-drain-config.json")
    27  	var outputBuffer bytes.Buffer
    28  	purgerCmd.Stdout = &outputBuffer
    29  	purgerCmd.Stderr = &outputBuffer
    30  	purgerCmd.Start()
    31  
    32  	// If we error, we need to kill the process we started or the test command
    33  	// will never exit.
    34  	sigterm := func() {
    35  		purgerCmd.Process.Signal(syscall.SIGTERM)
    36  		purgerCmd.Wait()
    37  	}
    38  
    39  	tlsConfig, err := (&cmd.TLSConfig{
    40  		CACertFile: "test/grpc-creds/minica.pem",
    41  		CertFile:   "test/grpc-creds/ra.boulder/cert.pem",
    42  		KeyFile:    "test/grpc-creds/ra.boulder/key.pem",
    43  	}).Load(metrics.NoopRegisterer)
    44  	if err != nil {
    45  		sigterm()
    46  		return nil, nil, nil, err
    47  	}
    48  	creds := bcreds.NewClientCredentials(tlsConfig.RootCAs, tlsConfig.Certificates, "akamai-purger.boulder")
    49  	conn, err := grpc.Dial(
    50  		"dns:///akamai-purger.service.consul:9199",
    51  		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingConfig": [{"%s":{}}]}`, roundrobin.Name)),
    52  		grpc.WithTransportCredentials(creds),
    53  	)
    54  	if err != nil {
    55  		sigterm()
    56  		return nil, nil, nil, err
    57  	}
    58  	for i := 0; ; i++ {
    59  		if conn.GetState() == connectivity.Ready {
    60  			break
    61  		}
    62  		if i > 40 {
    63  			sigterm()
    64  			return nil, nil, nil, fmt.Errorf("timed out waiting for akamai-purger to come up: %s", outputBuffer.String())
    65  		}
    66  		time.Sleep(50 * time.Millisecond)
    67  	}
    68  	purgerClient := akamaipb.NewAkamaiPurgerClient(conn)
    69  	return purgerCmd, &outputBuffer, purgerClient, nil
    70  }
    71  
    72  func TestAkamaiPurgerDrainQueueFails(t *testing.T) {
    73  	purgerCmd, outputBuffer, purgerClient, err := setup()
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  
    78  	// We know that the purger is configured to only process two items per batch,
    79  	// so submitting 10 items should give it enough of a backlog to guarantee
    80  	// that our SIGTERM reaches the process before it's fully cleared the queue.
    81  	for i := 0; i < 10; i++ {
    82  		_, err = purgerClient.Purge(context.Background(), &akamaipb.PurgeRequest{
    83  			Urls: []string{fmt.Sprintf("http://example%d.com/", i)},
    84  		})
    85  		if err != nil {
    86  			// Don't use t.Fatal here because we need to get as far as the SIGTERM or
    87  			// we'll hang on exit.
    88  			t.Error(err)
    89  		}
    90  	}
    91  
    92  	purgerCmd.Process.Signal(syscall.SIGTERM)
    93  	err = purgerCmd.Wait()
    94  	if err == nil {
    95  		t.Error("expected error shutting down akamai-purger that could not reach backend")
    96  	}
    97  
    98  	// Use two asserts because we're not sure what integer (10? 8?) will come in
    99  	// the middle of the error message.
   100  	test.AssertContains(t, outputBuffer.String(), "failed to purge OCSP responses for")
   101  	test.AssertContains(t, outputBuffer.String(), "certificates before exit: all attempts to submit purge request failed")
   102  }
   103  
   104  func TestAkamaiPurgerDrainQueueSucceeds(t *testing.T) {
   105  	purgerCmd, outputBuffer, purgerClient, err := setup()
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	for i := 0; i < 10; i++ {
   110  		_, err := purgerClient.Purge(context.Background(), &akamaipb.PurgeRequest{
   111  			Urls: []string{"http://example.com/"},
   112  		})
   113  		if err != nil {
   114  			t.Error(err)
   115  		}
   116  	}
   117  	time.Sleep(200 * time.Millisecond)
   118  	purgerCmd.Process.Signal(syscall.SIGTERM)
   119  
   120  	akamaiTestSrvCmd := exec.Command("./bin/akamai-test-srv", "--listen", "localhost:6889",
   121  		"--secret", "its-a-secret")
   122  	akamaiTestSrvCmd.Stdout = os.Stdout
   123  	akamaiTestSrvCmd.Stderr = os.Stderr
   124  	akamaiTestSrvCmd.Start()
   125  
   126  	err = purgerCmd.Wait()
   127  	if err != nil {
   128  		t.Errorf("unexpected error shutting down akamai-purger: %s. Output was:\n%s", err, outputBuffer.String())
   129  	}
   130  	test.AssertContains(t, outputBuffer.String(), "Shutting down; finished purging OCSP responses")
   131  	akamaiTestSrvCmd.Process.Signal(syscall.SIGTERM)
   132  	_ = akamaiTestSrvCmd.Wait()
   133  }
   134  

View as plain text