github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/observer/recorder_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package observer_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock/testclock"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/apiserver/observer"
    15  	"github.com/juju/juju/apiserver/observer/fakeobserver"
    16  	apitesting "github.com/juju/juju/apiserver/testing"
    17  	"github.com/juju/juju/core/auditlog"
    18  	"github.com/juju/juju/rpc"
    19  	"github.com/juju/juju/rpc/params"
    20  )
    21  
    22  type recorderSuite struct {
    23  	testing.IsolationSuite
    24  }
    25  
    26  var _ = gc.Suite(&recorderSuite{})
    27  
    28  func (s *recorderSuite) TestServerRequest(c *gc.C) {
    29  	fake := &fakeobserver.Instance{}
    30  	log := &apitesting.FakeAuditLog{}
    31  	clock := testclock.NewClock(time.Now())
    32  	auditRecorder, err := auditlog.NewRecorder(log, clock, auditlog.ConversationArgs{
    33  		ConnectionID: 4567,
    34  	})
    35  	c.Assert(err, jc.ErrorIsNil)
    36  	factory := observer.NewRecorderFactory(fake, auditRecorder, observer.CaptureArgs)
    37  	recorder := factory()
    38  	hdr := &rpc.Header{
    39  		RequestId: 123,
    40  		Request:   rpc.Request{"Type", 5, "", "Action"},
    41  	}
    42  	err = recorder.HandleRequest(hdr, "the args")
    43  	c.Assert(err, jc.ErrorIsNil)
    44  
    45  	fake.CheckCallNames(c, "RPCObserver")
    46  	fakeOb := fake.Calls()[0].Args[0].(*fakeobserver.RPCInstance)
    47  	fakeOb.CheckCallNames(c, "ServerRequest")
    48  	fakeOb.CheckCall(c, 0, "ServerRequest", hdr, "the args")
    49  
    50  	log.CheckCallNames(c, "AddConversation", "AddRequest")
    51  
    52  	request := log.Calls()[1].Args[0].(auditlog.Request)
    53  	c.Assert(request.ConversationID, gc.HasLen, 16)
    54  	request.ConversationID = "abcdef0123456789"
    55  	c.Assert(request, gc.Equals, auditlog.Request{
    56  		ConversationID: "abcdef0123456789",
    57  		ConnectionID:   "11D7",
    58  		RequestID:      123,
    59  		When:           clock.Now().Format(time.RFC3339),
    60  		Facade:         "Type",
    61  		Method:         "Action",
    62  		Version:        5,
    63  		Args:           `"the args"`,
    64  	})
    65  }
    66  
    67  func (s *recorderSuite) TestServerRequestNoArgs(c *gc.C) {
    68  	fake := &fakeobserver.Instance{}
    69  	log := &apitesting.FakeAuditLog{}
    70  	clock := testclock.NewClock(time.Now())
    71  	auditRecorder, err := auditlog.NewRecorder(log, clock, auditlog.ConversationArgs{
    72  		ConnectionID: 4567,
    73  	})
    74  	c.Assert(err, jc.ErrorIsNil)
    75  	factory := observer.NewRecorderFactory(fake, auditRecorder, observer.NoCaptureArgs)
    76  	recorder := factory()
    77  	hdr := &rpc.Header{
    78  		RequestId: 123,
    79  		Request:   rpc.Request{"Type", 5, "", "Action"},
    80  	}
    81  	err = recorder.HandleRequest(hdr, "the args")
    82  	c.Assert(err, jc.ErrorIsNil)
    83  
    84  	log.CheckCallNames(c, "AddConversation", "AddRequest")
    85  
    86  	request := log.Calls()[1].Args[0].(auditlog.Request)
    87  	c.Assert(request.ConversationID, gc.HasLen, 16)
    88  	request.ConversationID = "abcdef0123456789"
    89  	c.Assert(request, gc.Equals, auditlog.Request{
    90  		ConversationID: "abcdef0123456789",
    91  		ConnectionID:   "11D7",
    92  		RequestID:      123,
    93  		When:           clock.Now().Format(time.RFC3339),
    94  		Facade:         "Type",
    95  		Method:         "Action",
    96  		Version:        5,
    97  	})
    98  }
    99  
   100  func (s *recorderSuite) TestServerReply(c *gc.C) {
   101  	fake := &fakeobserver.Instance{}
   102  	log := &apitesting.FakeAuditLog{}
   103  	clock := testclock.NewClock(time.Now())
   104  	auditRecorder, err := auditlog.NewRecorder(log, clock, auditlog.ConversationArgs{
   105  		ConnectionID: 4567,
   106  	})
   107  	c.Assert(err, jc.ErrorIsNil)
   108  	factory := observer.NewRecorderFactory(fake, auditRecorder, observer.CaptureArgs)
   109  	recorder := factory()
   110  
   111  	req := rpc.Request{"Type", 5, "", "Action"}
   112  	hdr := &rpc.Header{RequestId: 123}
   113  	err = recorder.HandleReply(req, hdr, "the response")
   114  	c.Assert(err, jc.ErrorIsNil)
   115  
   116  	fake.CheckCallNames(c, "RPCObserver")
   117  	fakeOb := fake.Calls()[0].Args[0].(*fakeobserver.RPCInstance)
   118  	fakeOb.CheckCallNames(c, "ServerReply")
   119  	fakeOb.CheckCall(c, 0, "ServerReply", req, hdr, "the response")
   120  
   121  	log.CheckCallNames(c, "AddConversation", "AddResponse")
   122  
   123  	respErrors := log.Calls()[1].Args[0].(auditlog.ResponseErrors)
   124  	c.Assert(respErrors.ConversationID, gc.HasLen, 16)
   125  	respErrors.ConversationID = "abcdef0123456789"
   126  	c.Assert(respErrors, gc.DeepEquals, auditlog.ResponseErrors{
   127  		ConversationID: "abcdef0123456789",
   128  		ConnectionID:   "11D7",
   129  		RequestID:      123,
   130  		When:           clock.Now().Format(time.RFC3339),
   131  		Errors:         nil,
   132  	})
   133  }
   134  
   135  func (s *recorderSuite) TestReplyResultNotAStruct(c *gc.C) {
   136  	s.checkServerReplyErrors(c, 12345, nil)
   137  }
   138  
   139  func (s *recorderSuite) TestReplyResultNoErrorAttrs(c *gc.C) {
   140  	s.checkServerReplyErrors(c,
   141  		params.ApplicationCharmRelationsResults{
   142  			CharmRelations: []string{"abc", "123"},
   143  		},
   144  		nil,
   145  	)
   146  }
   147  
   148  func (s *recorderSuite) TestReplyResultErrorSlice(c *gc.C) {
   149  	s.checkServerReplyErrors(c,
   150  		params.ErrorResults{
   151  			Results: []params.ErrorResult{{
   152  				Error: &params.Error{
   153  					Message: "antiphon",
   154  					Code:    "midlake",
   155  				},
   156  			}, {
   157  				Error: nil,
   158  			}},
   159  		},
   160  		[]*auditlog.Error{{
   161  			Message: "antiphon",
   162  			Code:    "midlake",
   163  		}, nil},
   164  	)
   165  }
   166  
   167  func (s *recorderSuite) TestReplyResultError(c *gc.C) {
   168  	s.checkServerReplyErrors(c,
   169  		params.ErrorResult{
   170  			Error: &params.Error{
   171  				Message: "antiphon",
   172  				Code:    "midlake",
   173  			},
   174  		},
   175  		[]*auditlog.Error{{
   176  			Message: "antiphon",
   177  			Code:    "midlake",
   178  		}},
   179  	)
   180  }
   181  
   182  func (s *recorderSuite) TestReplyResultSlice(c *gc.C) {
   183  	s.checkServerReplyErrors(c,
   184  		params.AddMachinesResults{
   185  			Machines: []params.AddMachinesResult{{
   186  				Machine: "some-machine",
   187  			}, {
   188  				Error: &params.Error{
   189  					Message: "something bad",
   190  					Code:    "fall-down-go-boom",
   191  					Info: params.DischargeRequiredErrorInfo{
   192  						MacaroonPath: "somewhere",
   193  					}.AsMap(),
   194  				},
   195  			}},
   196  		},
   197  		[]*auditlog.Error{nil, {
   198  			Message: "something bad",
   199  			Code:    "fall-down-go-boom",
   200  		}},
   201  	)
   202  }
   203  
   204  func (s *recorderSuite) checkServerReplyErrors(c *gc.C, result interface{}, expected []*auditlog.Error) {
   205  	fake := &fakeobserver.Instance{}
   206  	log := &apitesting.FakeAuditLog{}
   207  	clock := testclock.NewClock(time.Now())
   208  	auditRecorder, err := auditlog.NewRecorder(log, clock, auditlog.ConversationArgs{
   209  		ConnectionID: 4567,
   210  	})
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	factory := observer.NewRecorderFactory(fake, auditRecorder, observer.CaptureArgs)
   213  	recorder := factory()
   214  
   215  	req := rpc.Request{"Type", 5, "", "Action"}
   216  	hdr := &rpc.Header{RequestId: 123}
   217  	err = recorder.HandleReply(req, hdr, result)
   218  	c.Assert(err, jc.ErrorIsNil)
   219  
   220  	log.CheckCallNames(c, "AddConversation", "AddResponse")
   221  
   222  	respErrors := log.Calls()[1].Args[0].(auditlog.ResponseErrors)
   223  	c.Assert(respErrors.ConversationID, gc.HasLen, 16)
   224  	respErrors.ConversationID = ""
   225  	c.Assert(respErrors, gc.DeepEquals, auditlog.ResponseErrors{
   226  		ConnectionID: "11D7",
   227  		RequestID:    123,
   228  		When:         clock.Now().Format(time.RFC3339),
   229  		Errors:       expected,
   230  	})
   231  }
   232  
   233  func (s *recorderSuite) TestNoAuditRequest(c *gc.C) {
   234  	fake := &fakeobserver.Instance{}
   235  	factory := observer.NewRecorderFactory(fake, nil, observer.NoCaptureArgs)
   236  	recorder := factory()
   237  	hdr := &rpc.Header{
   238  		RequestId: 123,
   239  		Request:   rpc.Request{"Type", 0, "", "Action"},
   240  	}
   241  	err := recorder.HandleRequest(hdr, "the body")
   242  	c.Assert(err, jc.ErrorIsNil)
   243  }
   244  
   245  func (s *recorderSuite) TestNoAuditReply(c *gc.C) {
   246  	fake := &fakeobserver.Instance{}
   247  	factory := observer.NewRecorderFactory(fake, nil, observer.NoCaptureArgs)
   248  	recorder := factory()
   249  	req := rpc.Request{"Type", 0, "", "Action"}
   250  	hdr := &rpc.Header{RequestId: 123}
   251  	err := recorder.HandleReply(req, hdr, "the body")
   252  	c.Assert(err, jc.ErrorIsNil)
   253  }