github.com/bartle-stripe/trillian@v1.2.1/testonly/integration/logenv.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package integration provides test-only code for performing integrated 16 // tests of Trillian functionality. 17 package integration 18 19 import ( 20 "context" 21 "database/sql" 22 "net" 23 "sync" 24 "time" 25 26 "github.com/golang/glog" 27 "github.com/golang/protobuf/proto" 28 "google.golang.org/grpc" 29 30 "github.com/google/trillian" 31 "github.com/google/trillian/crypto/keys/der" 32 "github.com/google/trillian/crypto/keyspb" 33 "github.com/google/trillian/extension" 34 "github.com/google/trillian/quota" 35 "github.com/google/trillian/server" 36 "github.com/google/trillian/server/admin" 37 "github.com/google/trillian/server/interceptor" 38 "github.com/google/trillian/storage/mysql" 39 "github.com/google/trillian/storage/testdb" 40 "github.com/google/trillian/util" 41 42 _ "github.com/go-sql-driver/mysql" // Load MySQL driver 43 _ "github.com/google/trillian/crypto/keys/der/proto" // Register PrivateKey ProtoHandler 44 ) 45 46 var ( 47 sequencerWindow = time.Duration(0) 48 batchSize = 50 49 // SequencerInterval is the time between runs of the sequencer. 50 SequencerInterval = 500 * time.Millisecond 51 timeSource = util.SystemTimeSource{} 52 ) 53 54 // LogEnv is a test environment that contains both a log server and a connection to it. 55 type LogEnv struct { 56 registry extension.Registry 57 pendingTasks *sync.WaitGroup 58 grpcServer *grpc.Server 59 adminServer *admin.Server 60 logServer *server.TrillianLogRPCServer 61 LogOperation server.LogOperation 62 Sequencer *server.LogOperationManager 63 sequencerCancel context.CancelFunc 64 ClientConn *grpc.ClientConn // TODO(gbelvin): Deprecate. 65 66 Address string 67 Log trillian.TrillianLogClient 68 Admin trillian.TrillianAdminClient 69 DB *sql.DB 70 } 71 72 // NewLogEnv creates a fresh DB, log server, and client. The numSequencers parameter 73 // indicates how many sequencers to run in parallel; if numSequencers is zero a 74 // manually-controlled test sequencer is used. 75 // TODO(codingllama): Remove 3rd parameter (need to coordinate with 76 // github.com/google/certificate-transparency-go) 77 func NewLogEnv(ctx context.Context, numSequencers int, _ string) (*LogEnv, error) { 78 return NewLogEnvWithGRPCOptions(ctx, numSequencers, nil, nil) 79 } 80 81 // NewLogEnvWithGRPCOptions works the same way as NewLogEnv, but allows callers to also set additional grpc.ServerOption and grpc.DialOption values. 82 func NewLogEnvWithGRPCOptions(ctx context.Context, numSequencers int, serverOpts []grpc.ServerOption, clientOpts []grpc.DialOption) (*LogEnv, error) { 83 db, err := testdb.NewTrillianDB(ctx) 84 if err != nil { 85 return nil, err 86 } 87 88 registry := extension.Registry{ 89 AdminStorage: mysql.NewAdminStorage(db), 90 LogStorage: mysql.NewLogStorage(db, nil), 91 QuotaManager: quota.Noop(), 92 NewKeyProto: func(ctx context.Context, spec *keyspb.Specification) (proto.Message, error) { 93 return der.NewProtoFromSpec(spec) 94 }, 95 } 96 97 ret, err := NewLogEnvWithRegistryAndGRPCOptions(ctx, numSequencers, registry, serverOpts, clientOpts) 98 if err != nil { 99 db.Close() 100 return nil, err 101 } 102 ret.DB = db 103 return ret, nil 104 } 105 106 // NewLogEnvWithRegistry uses the passed in Registry to create a log server, 107 // and client. The numSequencers parameter indicates how many sequencers to 108 // run in parallel; if numSequencers is zero a manually-controlled test 109 // sequencer is used. 110 func NewLogEnvWithRegistry(ctx context.Context, numSequencers int, registry extension.Registry) (*LogEnv, error) { 111 return NewLogEnvWithRegistryAndGRPCOptions(ctx, numSequencers, registry, nil, nil) 112 } 113 114 // NewLogEnvWithRegistryAndGRPCOptions works the same way as NewLogEnv, but allows callers to also set additional grpc.ServerOption and grpc.DialOption values. 115 func NewLogEnvWithRegistryAndGRPCOptions(ctx context.Context, numSequencers int, registry extension.Registry, serverOpts []grpc.ServerOption, clientOpts []grpc.DialOption) (*LogEnv, error) { 116 // Create the GRPC Server. 117 serverOpts = append(serverOpts, grpc.UnaryInterceptor(interceptor.ErrorWrapper)) 118 grpcServer := grpc.NewServer(serverOpts...) 119 120 // Setup the Admin Server. 121 adminServer := admin.New(registry, nil) 122 trillian.RegisterTrillianAdminServer(grpcServer, adminServer) 123 124 // Setup the Log Server. 125 logServer := server.NewTrillianLogRPCServer(registry, timeSource) 126 trillian.RegisterTrillianLogServer(grpcServer, logServer) 127 128 // Create Sequencer. 129 sequencerManager := server.NewSequencerManager(registry, sequencerWindow) 130 var wg sync.WaitGroup 131 var sequencerTask *server.LogOperationManager 132 ctx, cancel := context.WithCancel(ctx) 133 info := server.LogOperationInfo{ 134 Registry: registry, 135 BatchSize: batchSize, 136 NumWorkers: numSequencers, 137 RunInterval: SequencerInterval, 138 TimeSource: timeSource, 139 } 140 // Start a live sequencer in a goroutine. 141 sequencerTask = server.NewLogOperationManager(info, sequencerManager) 142 wg.Add(1) 143 go func(wg *sync.WaitGroup, om *server.LogOperationManager) { 144 defer wg.Done() 145 om.OperationLoop(ctx) 146 }(&wg, sequencerTask) 147 148 // Listen and start server. 149 addr, lis, err := listen() 150 if err != nil { 151 cancel() 152 return nil, err 153 } 154 wg.Add(1) 155 go func(wg *sync.WaitGroup, grpcServer *grpc.Server, lis net.Listener) { 156 defer wg.Done() 157 if err := grpcServer.Serve(lis); err != nil { 158 glog.Errorf("gRPC server stopped: %v", err) 159 glog.Flush() 160 } 161 }(&wg, grpcServer, lis) 162 163 // Connect to the server. 164 if clientOpts == nil { 165 clientOpts = []grpc.DialOption{grpc.WithInsecure()} 166 } 167 168 cc, err := grpc.Dial(addr, clientOpts...) 169 if err != nil { 170 cancel() 171 return nil, err 172 } 173 174 return &LogEnv{ 175 registry: registry, 176 pendingTasks: &wg, 177 grpcServer: grpcServer, 178 adminServer: adminServer, 179 logServer: logServer, 180 Address: addr, 181 ClientConn: cc, 182 Log: trillian.NewTrillianLogClient(cc), 183 Admin: trillian.NewTrillianAdminClient(cc), 184 LogOperation: sequencerManager, 185 Sequencer: sequencerTask, 186 sequencerCancel: cancel, 187 }, nil 188 } 189 190 // Close shuts down the server. 191 func (env *LogEnv) Close() { 192 if env.sequencerCancel != nil { 193 env.sequencerCancel() 194 } 195 env.ClientConn.Close() 196 env.grpcServer.GracefulStop() 197 env.pendingTasks.Wait() 198 if env.DB != nil { 199 env.DB.Close() 200 } 201 }