github.com/lzy4123/fabric@v2.1.1+incompatible/core/scc/qscc/query_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package qscc
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"testing"
    14  
    15  	"github.com/hyperledger/fabric-chaincode-go/shim"
    16  	"github.com/hyperledger/fabric-chaincode-go/shimtest"
    17  	"github.com/hyperledger/fabric-protos-go/common"
    18  	peer2 "github.com/hyperledger/fabric-protos-go/peer"
    19  	"github.com/hyperledger/fabric/bccsp/sw"
    20  	"github.com/hyperledger/fabric/common/ledger/testutil"
    21  	"github.com/hyperledger/fabric/common/util"
    22  	"github.com/hyperledger/fabric/core/aclmgmt/mocks"
    23  	"github.com/hyperledger/fabric/core/aclmgmt/resources"
    24  	ledger2 "github.com/hyperledger/fabric/core/ledger"
    25  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    26  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt/ledgermgmttest"
    27  	"github.com/hyperledger/fabric/core/peer"
    28  	"github.com/hyperledger/fabric/protoutil"
    29  	"github.com/pkg/errors"
    30  	"github.com/spf13/viper"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  func setupTestLedger(chainid string, path string) (*shimtest.MockStub, *peer.Peer, func(), error) {
    36  	mockAclProvider.Reset()
    37  
    38  	viper.Set("peer.fileSystemPath", path)
    39  	testDir, err := ioutil.TempDir("", "qscc_test")
    40  	if err != nil {
    41  		return nil, nil, nil, err
    42  	}
    43  
    44  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    45  	if err != nil {
    46  		return nil, nil, nil, err
    47  	}
    48  
    49  	initializer := ledgermgmttest.NewInitializer(testDir)
    50  
    51  	ledgerMgr := ledgermgmt.NewLedgerMgr(initializer)
    52  
    53  	cleanup := func() {
    54  		ledgerMgr.Close()
    55  		os.RemoveAll(testDir)
    56  	}
    57  	peerInstance := &peer.Peer{
    58  		LedgerMgr:      ledgerMgr,
    59  		CryptoProvider: cryptoProvider,
    60  	}
    61  	peer.CreateMockChannel(peerInstance, chainid, nil)
    62  
    63  	lq := &LedgerQuerier{
    64  		aclProvider: mockAclProvider,
    65  		ledgers:     peerInstance,
    66  	}
    67  	stub := shimtest.NewMockStub("LedgerQuerier", lq)
    68  	if res := stub.MockInit("1", nil); res.Status != shim.OK {
    69  		return nil, peerInstance, cleanup, fmt.Errorf("Init failed for test ledger [%s] with message: %s", chainid, string(res.Message))
    70  	}
    71  	return stub, peerInstance, cleanup, nil
    72  }
    73  
    74  //pass the prop so we can conveniently inline it in the call and get it back
    75  func resetProvider(res, chainid string, prop *peer2.SignedProposal, retErr error) *peer2.SignedProposal {
    76  	if prop == nil {
    77  		prop, _ = protoutil.MockSignedEndorserProposalOrPanic(
    78  			chainid,
    79  			&peer2.ChaincodeSpec{
    80  				ChaincodeId: &peer2.ChaincodeID{
    81  					Name: "qscc",
    82  				},
    83  			},
    84  			[]byte("Alice"),
    85  			[]byte("msg1"),
    86  		)
    87  	}
    88  	mockAclProvider.Reset()
    89  	mockAclProvider.On("CheckACL", res, chainid, prop).Return(retErr)
    90  	return prop
    91  }
    92  
    93  func tempDir(t *testing.T, stem string) string {
    94  	path, err := ioutil.TempDir("", "qscc-"+stem)
    95  	require.NoError(t, err)
    96  	return path
    97  }
    98  
    99  func TestQueryGetChainInfo(t *testing.T) {
   100  	chainid := "mytestchainid1"
   101  	path := tempDir(t, "test1")
   102  	defer os.RemoveAll(path)
   103  
   104  	stub, _, cleanup, err := setupTestLedger(chainid, path)
   105  	if err != nil {
   106  		t.Fatalf(err.Error())
   107  	}
   108  	defer cleanup()
   109  
   110  	args := [][]byte{[]byte(GetChainInfo), []byte(chainid)}
   111  	prop := resetProvider(resources.Qscc_GetChainInfo, chainid, nil, nil)
   112  	res := stub.MockInvokeWithSignedProposal("1", args, prop)
   113  	assert.Equal(t, int32(shim.OK), res.Status, "GetChainInfo failed with err: %s", res.Message)
   114  
   115  	args = [][]byte{[]byte(GetChainInfo)}
   116  	res = stub.MockInvoke("2", args)
   117  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetChainInfo should have failed because no channel id was provided")
   118  
   119  	args = [][]byte{[]byte(GetChainInfo), []byte("fakechainid")}
   120  	res = stub.MockInvoke("3", args)
   121  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetChainInfo should have failed because the channel id does not exist")
   122  }
   123  
   124  func TestQueryGetTransactionByID(t *testing.T) {
   125  	chainid := "mytestchainid2"
   126  	path := tempDir(t, "test2")
   127  	defer os.RemoveAll(path)
   128  
   129  	stub, _, cleanup, err := setupTestLedger(chainid, path)
   130  	if err != nil {
   131  		t.Fatalf(err.Error())
   132  	}
   133  	defer cleanup()
   134  
   135  	args := [][]byte{[]byte(GetTransactionByID), []byte(chainid), []byte("1")}
   136  	prop := resetProvider(resources.Qscc_GetTransactionByID, chainid, &peer2.SignedProposal{}, nil)
   137  	res := stub.MockInvokeWithSignedProposal("1", args, prop)
   138  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetTransactionByID should have failed with invalid txid: 1")
   139  
   140  	args = [][]byte{[]byte(GetTransactionByID), []byte(chainid), []byte(nil)}
   141  	res = stub.MockInvoke("2", args)
   142  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetTransactionByID should have failed with invalid txid: nil")
   143  
   144  	// Test with wrong number of parameters
   145  	args = [][]byte{[]byte(GetTransactionByID), []byte(chainid)}
   146  	res = stub.MockInvoke("3", args)
   147  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetTransactionByID should have failed due to incorrect number of arguments")
   148  }
   149  
   150  func TestQueryGetBlockByNumber(t *testing.T) {
   151  	chainid := "mytestchainid3"
   152  	path := tempDir(t, "test3")
   153  	defer os.RemoveAll(path)
   154  
   155  	stub, _, cleanup, err := setupTestLedger(chainid, path)
   156  	if err != nil {
   157  		t.Fatalf(err.Error())
   158  	}
   159  	defer cleanup()
   160  
   161  	// block number 0 (genesis block) would already be present in the ledger
   162  	args := [][]byte{[]byte(GetBlockByNumber), []byte(chainid), []byte("0")}
   163  	prop := resetProvider(resources.Qscc_GetBlockByNumber, chainid, nil, nil)
   164  	res := stub.MockInvokeWithSignedProposal("1", args, prop)
   165  	assert.Equal(t, int32(shim.OK), res.Status, "GetBlockByNumber should have succeeded for block number: 0")
   166  
   167  	// block number 1 should not be present in the ledger
   168  	args = [][]byte{[]byte(GetBlockByNumber), []byte(chainid), []byte("1")}
   169  	res = stub.MockInvoke("2", args)
   170  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByNumber should have failed with invalid number: 1")
   171  
   172  	// block number cannot be nil
   173  	args = [][]byte{[]byte(GetBlockByNumber), []byte(chainid), []byte(nil)}
   174  	res = stub.MockInvoke("3", args)
   175  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByNumber should have failed with nil block number")
   176  }
   177  
   178  func TestQueryGetBlockByHash(t *testing.T) {
   179  	chainid := "mytestchainid4"
   180  	path := tempDir(t, "test4")
   181  	defer os.RemoveAll(path)
   182  
   183  	stub, _, cleanup, err := setupTestLedger(chainid, path)
   184  	if err != nil {
   185  		t.Fatalf(err.Error())
   186  	}
   187  	defer cleanup()
   188  
   189  	args := [][]byte{[]byte(GetBlockByHash), []byte(chainid), []byte("0")}
   190  	prop := resetProvider(resources.Qscc_GetBlockByHash, chainid, &peer2.SignedProposal{}, nil)
   191  	res := stub.MockInvokeWithSignedProposal("1", args, prop)
   192  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByHash should have failed with invalid hash: 0")
   193  
   194  	args = [][]byte{[]byte(GetBlockByHash), []byte(chainid), []byte(nil)}
   195  	res = stub.MockInvoke("2", args)
   196  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByHash should have failed with nil hash")
   197  }
   198  
   199  func TestQueryGetBlockByTxID(t *testing.T) {
   200  	chainid := "mytestchainid5"
   201  	path := tempDir(t, "test5")
   202  	defer os.RemoveAll(path)
   203  
   204  	stub, _, cleanup, err := setupTestLedger(chainid, path)
   205  	if err != nil {
   206  		t.Fatalf(err.Error())
   207  	}
   208  	defer cleanup()
   209  
   210  	args := [][]byte{[]byte(GetBlockByTxID), []byte(chainid), []byte("")}
   211  	prop := resetProvider(resources.Qscc_GetBlockByTxID, chainid, &peer2.SignedProposal{}, nil)
   212  	res := stub.MockInvokeWithSignedProposal("1", args, prop)
   213  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByTxID should have failed with blank txId.")
   214  }
   215  
   216  func TestFailingCC2CC(t *testing.T) {
   217  	t.Run("BadProposal", func(t *testing.T) {
   218  		stub := shimtest.NewMockStub("testchannel", &LedgerQuerier{})
   219  		args := [][]byte{[]byte("funcname"), []byte("testchannel")}
   220  		sProp := &peer2.SignedProposal{
   221  			ProposalBytes: []byte("garbage"),
   222  		}
   223  		sProp.Signature = sProp.ProposalBytes
   224  		// Set the ACLProvider to have a failure
   225  		resetProvider(resources.Qscc_GetChainInfo, "testchannel", sProp, nil)
   226  		res := stub.MockInvokeWithSignedProposal("2", args, sProp)
   227  		assert.Equal(t, int32(shim.ERROR), res.Status, "GetChainInfo must fail: %s", res.Message)
   228  		assert.Contains(t, res.Message, "Failed to identify the called chaincode: could not unmarshal proposal: proto: can't skip unknown wire type 7")
   229  	})
   230  
   231  	t.Run("DifferentInvokedCC", func(t *testing.T) {
   232  		stub := shimtest.NewMockStub("testchannel", &LedgerQuerier{})
   233  		args := [][]byte{[]byte("funcname"), []byte("testchannel")}
   234  		sProp, _ := protoutil.MockSignedEndorserProposalOrPanic(
   235  			"testchannel",
   236  			&peer2.ChaincodeSpec{
   237  				ChaincodeId: &peer2.ChaincodeID{
   238  					Name: "usercc",
   239  				},
   240  			},
   241  			[]byte("Alice"),
   242  			[]byte("msg1"),
   243  		)
   244  		sProp.Signature = sProp.ProposalBytes
   245  		// Set the ACLProvider to have a failure
   246  		resetProvider(resources.Qscc_GetChainInfo, "testchannel", sProp, nil)
   247  		res := stub.MockInvokeWithSignedProposal("2", args, sProp)
   248  		assert.Equal(t, int32(shim.ERROR), res.Status, "GetChainInfo must fail: %s", res.Message)
   249  		assert.Contains(t, res.Message, "Rejecting invoke of QSCC from another chaincode because of potential for deadlocks, original invocation for 'usercc'")
   250  	})
   251  }
   252  
   253  func TestFailingAccessControl(t *testing.T) {
   254  	chainid := "mytestchainid6"
   255  	path := tempDir(t, "test6")
   256  	defer os.RemoveAll(path)
   257  
   258  	_, p, cleanup, err := setupTestLedger(chainid, path)
   259  	if err != nil {
   260  		t.Fatalf(err.Error())
   261  	}
   262  	defer cleanup()
   263  	e := &LedgerQuerier{
   264  		aclProvider: mockAclProvider,
   265  		ledgers:     p,
   266  	}
   267  	stub := shimtest.NewMockStub("LedgerQuerier", e)
   268  
   269  	// GetChainInfo
   270  	args := [][]byte{[]byte(GetChainInfo), []byte(chainid)}
   271  	sProp, _ := protoutil.MockSignedEndorserProposalOrPanic(chainid,
   272  		&peer2.ChaincodeSpec{
   273  			ChaincodeId: &peer2.ChaincodeID{
   274  				Name: "qscc"},
   275  		},
   276  		[]byte("Alice"),
   277  		[]byte("msg1"),
   278  	)
   279  	sProp.Signature = sProp.ProposalBytes
   280  	// Set the ACLProvider to have a failure
   281  	resetProvider(resources.Qscc_GetChainInfo, chainid, sProp, errors.New("Failed access control"))
   282  	res := stub.MockInvokeWithSignedProposal("2", args, sProp)
   283  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetChainInfo must fail: %s", res.Message)
   284  	assert.Contains(t, res.Message, "Failed access control")
   285  	// assert that the expectations were met
   286  	mockAclProvider.AssertExpectations(t)
   287  
   288  	// GetBlockByNumber
   289  	args = [][]byte{[]byte(GetBlockByNumber), []byte(chainid), []byte("1")}
   290  	sProp, _ = protoutil.MockSignedEndorserProposalOrPanic(
   291  		chainid,
   292  		&peer2.ChaincodeSpec{
   293  			ChaincodeId: &peer2.ChaincodeID{
   294  				Name: "qscc",
   295  			},
   296  		},
   297  		[]byte("Alice"),
   298  		[]byte("msg1"),
   299  	)
   300  	sProp.Signature = sProp.ProposalBytes
   301  	// Set the ACLProvider to have a failure
   302  	resetProvider(resources.Qscc_GetBlockByNumber, chainid, sProp, errors.New("Failed access control"))
   303  	res = stub.MockInvokeWithSignedProposal("2", args, sProp)
   304  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByNumber must fail: %s", res.Message)
   305  	assert.Contains(t, res.Message, "Failed access control")
   306  	// assert that the expectations were met
   307  	mockAclProvider.AssertExpectations(t)
   308  
   309  	// GetBlockByHash
   310  	args = [][]byte{[]byte(GetBlockByHash), []byte(chainid), []byte("1")}
   311  	sProp, _ = protoutil.MockSignedEndorserProposalOrPanic(
   312  		chainid,
   313  		&peer2.ChaincodeSpec{
   314  			ChaincodeId: &peer2.ChaincodeID{
   315  				Name: "qscc",
   316  			},
   317  		},
   318  		[]byte("Alice"),
   319  		[]byte("msg1"),
   320  	)
   321  	sProp.Signature = sProp.ProposalBytes
   322  	// Set the ACLProvider to have a failure
   323  	resetProvider(resources.Qscc_GetBlockByHash, chainid, sProp, errors.New("Failed access control"))
   324  	res = stub.MockInvokeWithSignedProposal("2", args, sProp)
   325  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByHash must fail: %s", res.Message)
   326  	assert.Contains(t, res.Message, "Failed access control")
   327  	// assert that the expectations were met
   328  	mockAclProvider.AssertExpectations(t)
   329  
   330  	// GetBlockByTxID
   331  	args = [][]byte{[]byte(GetBlockByTxID), []byte(chainid), []byte("1")}
   332  	sProp, _ = protoutil.MockSignedEndorserProposalOrPanic(
   333  		chainid,
   334  		&peer2.ChaincodeSpec{
   335  			ChaincodeId: &peer2.ChaincodeID{
   336  				Name: "qscc",
   337  			},
   338  		},
   339  		[]byte("Alice"),
   340  		[]byte("msg1"),
   341  	)
   342  	sProp.Signature = sProp.ProposalBytes
   343  	// Set the ACLProvider to have a failure
   344  	resetProvider(resources.Qscc_GetBlockByTxID, chainid, sProp, errors.New("Failed access control"))
   345  	res = stub.MockInvokeWithSignedProposal("2", args, sProp)
   346  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlockByTxID must fail: %s", res.Message)
   347  	assert.Contains(t, res.Message, "Failed access control")
   348  	// assert that the expectations were met
   349  	mockAclProvider.AssertExpectations(t)
   350  
   351  	// GetTransactionByID
   352  	args = [][]byte{[]byte(GetTransactionByID), []byte(chainid), []byte("1")}
   353  	sProp, _ = protoutil.MockSignedEndorserProposalOrPanic(
   354  		chainid,
   355  		&peer2.ChaincodeSpec{
   356  			ChaincodeId: &peer2.ChaincodeID{
   357  				Name: "qscc",
   358  			},
   359  		},
   360  		[]byte("Alice"),
   361  		[]byte("msg1"),
   362  	)
   363  	sProp.Signature = sProp.ProposalBytes
   364  	// Set the ACLProvider to have a failure
   365  	resetProvider(resources.Qscc_GetTransactionByID, chainid, sProp, errors.New("Failed access control"))
   366  	res = stub.MockInvokeWithSignedProposal("2", args, sProp)
   367  	assert.Equal(t, int32(shim.ERROR), res.Status, "Qscc_GetTransactionByID must fail: %s", res.Message)
   368  	assert.Contains(t, res.Message, "Failed access control")
   369  	// assert that the expectations were met
   370  	mockAclProvider.AssertExpectations(t)
   371  }
   372  
   373  func TestQueryNonexistentFunction(t *testing.T) {
   374  	chainid := "mytestchainid7"
   375  	path := tempDir(t, "test7")
   376  	defer os.RemoveAll(path)
   377  
   378  	stub, _, cleanup, err := setupTestLedger(chainid, path)
   379  	if err != nil {
   380  		t.Fatalf(err.Error())
   381  	}
   382  	defer cleanup()
   383  
   384  	args := [][]byte{[]byte("GetBlocks"), []byte(chainid), []byte("arg1")}
   385  	prop := resetProvider("qscc/GetBlocks", chainid, &peer2.SignedProposal{}, nil)
   386  	res := stub.MockInvokeWithSignedProposal("1", args, prop)
   387  	assert.Equal(t, int32(shim.ERROR), res.Status, "GetBlocks should have failed because the function does not exist")
   388  }
   389  
   390  // TestQueryGeneratedBlock tests various queries for a newly generated block
   391  // that contains two transactions
   392  func TestQueryGeneratedBlock(t *testing.T) {
   393  	chainid := "mytestchainid8"
   394  	path := tempDir(t, "test8")
   395  	defer os.RemoveAll(path)
   396  
   397  	stub, p, cleanup, err := setupTestLedger(chainid, path)
   398  	if err != nil {
   399  		t.Fatalf(err.Error())
   400  	}
   401  	defer cleanup()
   402  
   403  	block1 := addBlockForTesting(t, chainid, p)
   404  
   405  	// block number 1 should now exist
   406  	args := [][]byte{[]byte(GetBlockByNumber), []byte(chainid), []byte("1")}
   407  	prop := resetProvider(resources.Qscc_GetBlockByNumber, chainid, nil, nil)
   408  	res := stub.MockInvokeWithSignedProposal("1", args, prop)
   409  	assert.Equal(t, int32(shim.OK), res.Status, "GetBlockByNumber should have succeeded for block number 1")
   410  
   411  	// block number 1
   412  	args = [][]byte{[]byte(GetBlockByHash), []byte(chainid), protoutil.BlockHeaderHash(block1.Header)}
   413  	prop = resetProvider(resources.Qscc_GetBlockByHash, chainid, nil, nil)
   414  	res = stub.MockInvokeWithSignedProposal("2", args, prop)
   415  	assert.Equal(t, int32(shim.OK), res.Status, "GetBlockByHash should have succeeded for block 1 hash")
   416  
   417  	// drill into the block to find the transaction ids it contains
   418  	for _, d := range block1.Data.Data {
   419  		ebytes := d
   420  		if ebytes != nil {
   421  			if env, err := protoutil.GetEnvelopeFromBlock(ebytes); err != nil {
   422  				t.Fatalf("error getting envelope from block: %s", err)
   423  			} else if env != nil {
   424  				payload, err := protoutil.UnmarshalPayload(env.Payload)
   425  				if err != nil {
   426  					t.Fatalf("error extracting payload from envelope: %s", err)
   427  				}
   428  				chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   429  				if err != nil {
   430  					t.Fatalf(err.Error())
   431  				}
   432  				if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
   433  					args = [][]byte{[]byte(GetBlockByTxID), []byte(chainid), []byte(chdr.TxId)}
   434  					mockAclProvider.Reset()
   435  					prop = resetProvider(resources.Qscc_GetBlockByTxID, chainid, nil, nil)
   436  					res = stub.MockInvokeWithSignedProposal("3", args, prop)
   437  					assert.Equal(t, int32(shim.OK), res.Status, "GetBlockByTxId should have succeeded for txid: %s", chdr.TxId)
   438  
   439  					args = [][]byte{[]byte(GetTransactionByID), []byte(chainid), []byte(chdr.TxId)}
   440  					prop = resetProvider(resources.Qscc_GetTransactionByID, chainid, nil, nil)
   441  					res = stub.MockInvokeWithSignedProposal("4", args, prop)
   442  					assert.Equal(t, int32(shim.OK), res.Status, "GetTransactionById should have succeeded for txid: %s", chdr.TxId)
   443  				}
   444  			}
   445  		}
   446  	}
   447  }
   448  
   449  func addBlockForTesting(t *testing.T, chainid string, p *peer.Peer) *common.Block {
   450  	ledger := p.GetLedger(chainid)
   451  	defer ledger.Close()
   452  
   453  	txid1 := util.GenerateUUID()
   454  	simulator, _ := ledger.NewTxSimulator(txid1)
   455  	simulator.SetState("ns1", "key1", []byte("value1"))
   456  	simulator.SetState("ns1", "key2", []byte("value2"))
   457  	simulator.SetState("ns1", "key3", []byte("value3"))
   458  	simulator.Done()
   459  	simRes1, _ := simulator.GetTxSimulationResults()
   460  	pubSimResBytes1, _ := simRes1.GetPubSimulationBytes()
   461  
   462  	txid2 := util.GenerateUUID()
   463  	simulator, _ = ledger.NewTxSimulator(txid2)
   464  	simulator.SetState("ns2", "key4", []byte("value4"))
   465  	simulator.SetState("ns2", "key5", []byte("value5"))
   466  	simulator.SetState("ns2", "key6", []byte("value6"))
   467  	simulator.Done()
   468  	simRes2, _ := simulator.GetTxSimulationResults()
   469  	pubSimResBytes2, _ := simRes2.GetPubSimulationBytes()
   470  
   471  	bcInfo, err := ledger.GetBlockchainInfo()
   472  	assert.NoError(t, err)
   473  	block1 := testutil.ConstructBlock(t, 1, bcInfo.CurrentBlockHash, [][]byte{pubSimResBytes1, pubSimResBytes2}, false)
   474  	ledger.CommitLegacy(&ledger2.BlockAndPvtData{Block: block1}, &ledger2.CommitOptions{})
   475  	return block1
   476  }
   477  
   478  var mockAclProvider *mocks.MockACLProvider
   479  
   480  func TestMain(m *testing.M) {
   481  	mockAclProvider = &mocks.MockACLProvider{}
   482  	mockAclProvider.Reset()
   483  
   484  	os.Exit(m.Run())
   485  }