github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/core/auditlog/auditlog_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  package auditlog_test
     4  
     5  import (
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/juju/clock/testclock"
    12  	"github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/core/auditlog"
    17  )
    18  
    19  type AuditLogSuite struct {
    20  	testing.IsolationSuite
    21  }
    22  
    23  var _ = gc.Suite(&AuditLogSuite{})
    24  
    25  func (s *AuditLogSuite) TestAuditLogFile(c *gc.C) {
    26  	dir := c.MkDir()
    27  	logFile := auditlog.NewLogFile(dir, 300, 10)
    28  	err := logFile.AddConversation(auditlog.Conversation{
    29  		Who:            "deerhoof",
    30  		What:           "gojira",
    31  		When:           "2017-11-27T13:21:24Z",
    32  		ModelName:      "admin/default",
    33  		ConversationID: "0123456789abcdef",
    34  		ConnectionID:   "AC1",
    35  	})
    36  	c.Assert(err, jc.ErrorIsNil)
    37  	err = logFile.AddRequest(auditlog.Request{
    38  		ConversationID: "0123456789abcdef",
    39  		ConnectionID:   "AC1",
    40  		RequestID:      25,
    41  		When:           "2017-12-12T11:34:56Z",
    42  		Facade:         "Application",
    43  		Method:         "Deploy",
    44  		Version:        4,
    45  		Args:           `{"applications": [{"application": "prometheus"}]}`,
    46  	})
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	err = logFile.AddResponse(auditlog.ResponseErrors{
    49  		ConversationID: "0123456789abcdef",
    50  		ConnectionID:   "AC1",
    51  		RequestID:      25,
    52  		When:           "2017-12-12T11:35:11Z",
    53  		Errors: []*auditlog.Error{
    54  			{Message: "oops", Code: "unauthorized access"},
    55  		},
    56  	})
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	err = logFile.Close()
    59  	c.Assert(err, jc.ErrorIsNil)
    60  
    61  	bytes, err := ioutil.ReadFile(filepath.Join(dir, "audit.log"))
    62  	c.Assert(string(bytes), gc.Equals, expectedLogContents)
    63  }
    64  
    65  func (s *AuditLogSuite) TestAuditLogFilePriming(c *gc.C) {
    66  	dir := c.MkDir()
    67  	logFile := auditlog.NewLogFile(dir, 300, 10)
    68  	err := logFile.Close()
    69  	c.Assert(err, jc.ErrorIsNil)
    70  
    71  	info, err := os.Stat(filepath.Join(dir, "audit.log"))
    72  	c.Assert(err, jc.ErrorIsNil)
    73  	c.Assert(info.Mode(), gc.Equals, os.FileMode(0600))
    74  	// The chown will only work when run as root.
    75  }
    76  
    77  func (s *AuditLogSuite) TestRecorder(c *gc.C) {
    78  	var log fakeLog
    79  	logTime, err := time.Parse(time.RFC3339, "2017-11-27T15:45:23Z")
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	clock := testclock.NewClock(logTime)
    82  	rec, err := auditlog.NewRecorder(&log, clock, auditlog.ConversationArgs{
    83  		Who:          "wildbirds and peacedrums",
    84  		What:         "Doubt/Hope",
    85  		ModelName:    "admin/default",
    86  		ConnectionID: 687,
    87  	})
    88  	c.Assert(err, jc.ErrorIsNil)
    89  	clock.Advance(time.Second)
    90  	err = rec.AddRequest(auditlog.RequestArgs{
    91  		RequestID: 246,
    92  		Facade:    "Death Vessel",
    93  		Method:    "Horchata",
    94  		Version:   5,
    95  		Args:      `{"a": "something"}`,
    96  	})
    97  	c.Assert(err, jc.ErrorIsNil)
    98  	clock.Advance(time.Second)
    99  	err = rec.AddResponse(auditlog.ResponseErrorsArgs{
   100  		RequestID: 246,
   101  		Errors: []*auditlog.Error{{
   102  			Message: "something bad",
   103  			Code:    "bad request",
   104  		}},
   105  	})
   106  
   107  	log.stub.CheckCallNames(c, "AddConversation", "AddRequest", "AddResponse")
   108  	calls := log.stub.Calls()
   109  	rec0 := calls[0].Args[0].(auditlog.Conversation)
   110  	callID := rec0.ConversationID
   111  	c.Assert(rec0, gc.DeepEquals, auditlog.Conversation{
   112  		Who:            "wildbirds and peacedrums",
   113  		What:           "Doubt/Hope",
   114  		When:           "2017-11-27T15:45:23Z",
   115  		ModelName:      "admin/default",
   116  		ConnectionID:   "2AF",
   117  		ConversationID: callID,
   118  	})
   119  	c.Assert(calls[1].Args[0], gc.DeepEquals, auditlog.Request{
   120  		ConversationID: callID,
   121  		ConnectionID:   "2AF",
   122  		RequestID:      246,
   123  		When:           "2017-11-27T15:45:24Z",
   124  		Facade:         "Death Vessel",
   125  		Method:         "Horchata",
   126  		Version:        5,
   127  		Args:           `{"a": "something"}`,
   128  	})
   129  	c.Assert(calls[2].Args[0], gc.DeepEquals, auditlog.ResponseErrors{
   130  		ConversationID: callID,
   131  		ConnectionID:   "2AF",
   132  		RequestID:      246,
   133  		When:           "2017-11-27T15:45:25Z",
   134  		Errors: []*auditlog.Error{{
   135  			Message: "something bad",
   136  			Code:    "bad request",
   137  		}},
   138  	})
   139  }
   140  
   141  type fakeLog struct {
   142  	stub testing.Stub
   143  }
   144  
   145  func (l *fakeLog) AddConversation(m auditlog.Conversation) error {
   146  	l.stub.AddCall("AddConversation", m)
   147  	return l.stub.NextErr()
   148  }
   149  
   150  func (l *fakeLog) AddRequest(m auditlog.Request) error {
   151  	l.stub.AddCall("AddRequest", m)
   152  	return l.stub.NextErr()
   153  }
   154  
   155  func (l *fakeLog) AddResponse(m auditlog.ResponseErrors) error {
   156  	l.stub.AddCall("AddResponse", m)
   157  	return l.stub.NextErr()
   158  }
   159  
   160  func (l *fakeLog) Close() error {
   161  	l.stub.AddCall("Close")
   162  	return l.stub.NextErr()
   163  }
   164  
   165  var (
   166  	expectedLogContents = `
   167  {"conversation":{"who":"deerhoof","what":"gojira","when":"2017-11-27T13:21:24Z","model-name":"admin/default","model-uuid":"","conversation-id":"0123456789abcdef","connection-id":"AC1"}}
   168  {"request":{"conversation-id":"0123456789abcdef","connection-id":"AC1","request-id":25,"when":"2017-12-12T11:34:56Z","facade":"Application","method":"Deploy","version":4,"args":"{\"applications\": [{\"application\": \"prometheus\"}]}"}}
   169  {"errors":{"conversation-id":"0123456789abcdef","connection-id":"AC1","request-id":25,"when":"2017-12-12T11:35:11Z","errors":[{"message":"oops","code":"unauthorized access"}]}}
   170  `[1:]
   171  )