From 932108f489715b37a5d38192b79155c1f5638364 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Sun, 25 Feb 2018 08:52:52 +0000 Subject: [PATCH] Document and cleanup --- example.go | 27 ++++++++++++++++++++------- example_test.go | 14 ++++++++++---- setup.go | 11 ++++++++++- setup_test.go | 4 +++- 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/example.go b/example.go index e910996..e49f99e 100644 --- a/example.go +++ b/example.go @@ -16,31 +16,44 @@ type Example struct { Next plugin.Handler } -// ServeDNS implements the plugin.Handler interface. +// ServeDNS implements the plugin.Handler interface. This method gets called when example is used +// in a Server. func (e Example) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { - // Somewhat convoluted, as we could have printed "example" here and just call - // the next plugin - but as an example, show how to wrap a ResponseWriter might be - // educational. + // This function could be simpler. I.e. just fmt.Println("example") here, but we want to show + // a slightly more complex example as to make this more interesting. + // Here we wrap the dns.ResponseWriter in a new ResponseWriter and call the next plugin, when the + // answer comes back, it will print "example". + + // Wrap. pw := NewResponsePrinter(w) + + // Call next plugin (if any). return plugin.NextOrFailure(e.Name(), e.Next, ctx, pw, r) } // Name implements the Handler interface. func (e Example) Name() string { return "example" } +// ResponsePrinter wrap a dns.ResponseWriter and will write example to standard output when +// WriteMsg is called. type ResponsePrinter struct { dns.ResponseWriter } -// NewResponsePrinter returns a dns.Msg modifier that print example when a query is received. +// NewResponsePrinter returns ResponseWriter. func NewResponsePrinter(w dns.ResponseWriter) *ResponsePrinter { return &ResponsePrinter{ResponseWriter: w} } -// WriteMsg records the status code and calls the underlying ResponseWriter's WriteMsg method. +// WriteMsg calls the underlying ResponseWriter's WriteMsg method and prints "example" to standard +// output. func (r *ResponsePrinter) WriteMsg(res *dns.Msg) error { - fmt.Fprintf(out, "example") + fmt.Fprintln(out, ex) return r.ResponseWriter.WriteMsg(res) } +// Make out a reference to os.Stdout so we can easily overwrite it for testing. var out io.Writer = os.Stdout + +// What we will print. +const ex = "example" diff --git a/example_test.go b/example_test.go index fa9c834..9fa213e 100644 --- a/example_test.go +++ b/example_test.go @@ -12,18 +12,24 @@ import ( ) func TestExample(t *testing.T) { - ex := Example{Next: test.ErrorHandler()} + // Create a new Example Plugin. Use the test.ErrorHandler as the next plugin. + x := Example{Next: test.ErrorHandler()} + // Setup a new output buffer that is *not* standard output, so we can check if + // example is really being printed. b := &bytes.Buffer{} out = b ctx := context.TODO() r := new(dns.Msg) r.SetQuestion("example.org.", dns.TypeA) + // Create a new Recorder that captures the result, this isn't actually used in this test + // as it just serves as something that implements the dns.ResponseWriter interface. rec := dnstest.NewRecorder(&test.ResponseWriter{}) - ex.ServeDNS(ctx, rec, r) - if x := b.String(); x != "example" { - t.Errorf("Failed to print 'example', got %s", x) + // Call our plugin directly, and check the result. + x.ServeDNS(ctx, rec, r) + if a := b.String(); a != ex+"\n" { + t.Errorf("Failed to print '%s', got %s", ex, a) } } diff --git a/setup.go b/setup.go index fe862d2..09ca01f 100644 --- a/setup.go +++ b/setup.go @@ -7,6 +7,8 @@ import ( "github.com/mholt/caddy" ) +// init registers this plugin within the Caddy plugin framework. It uses "example" as the +// name, and couples it to the Action "setup". func init() { caddy.RegisterPlugin("example", caddy.Plugin{ ServerType: "dns", @@ -14,15 +16,22 @@ func init() { }) } +// setup is the function that gets called when the config parser see the token "example". Setup is responsible +// for parsing any extra options the example plugin may have. The first token this function sees is "example". func setup(c *caddy.Controller) error { - c.Next() + c.Next() // Ignore "example" and give us the next token. if c.NextArg() { + // If there was another token, return an error, because we don't have any configuration. + // Any errors returned from this setup function should be wrapped with plugin.Error, so we + // can present a slightly nicer error message to the user. return plugin.Error("example", c.ArgErr()) } + // Add the Plugin to CoreDNS, so Servers can use it in their plugin chain. dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { return Example{Next: next} }) + // All OK, return a nil error. return nil } diff --git a/setup_test.go b/setup_test.go index 4e87130..40c8291 100644 --- a/setup_test.go +++ b/setup_test.go @@ -6,7 +6,9 @@ import ( "github.com/mholt/caddy" ) -func TestSetupWhoami(t *testing.T) { +// TestSetup tests the various things that should be parsed by setup. +// Make sure you also test for parse errors. +func TestSetup(t *testing.T) { c := caddy.NewTestController("dns", `example`) if err := setup(c); err != nil { t.Fatalf("Expected no errors, but got: %v", err)