github.com/bazelbuild/rules_webtesting@v0.2.0/go/wtl/environment/environment.go (about) 1 // Copyright 2016 Google Inc. 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 environment provides an interface for defining how browser environments 16 // are managed. 17 package environment 18 19 import ( 20 "context" 21 "sync" 22 23 "github.com/bazelbuild/rules_webtesting/go/errors" 24 "github.com/bazelbuild/rules_webtesting/go/healthreporter" 25 "github.com/bazelbuild/rules_webtesting/go/metadata" 26 "github.com/bazelbuild/rules_webtesting/go/metadata/capabilities" 27 "github.com/bazelbuild/rules_webtesting/go/wtl/diagnostics" 28 ) 29 30 // Env allows web_test environments to be started for controlling a browser 31 // using Selenium WebDriver. 32 type Env interface { 33 healthreporter.HealthReporter 34 // SetUp is called once at the beginning of the test run, and should start a 35 // WebDriver server. It is not necessary that the environment be healthy when 36 // this returns. 37 SetUp(ctx context.Context) error 38 // StartSession is called for each new WebDriver session, before the new 39 // session command is sent to the WebDriver server. caps is the capabilities 40 // sent to the proxy from the client, and the return value is the capabilities 41 // that should be actually sent to the WebDriver server new session command. 42 StartSession(ctx context.Context, id int, caps *capabilities.Capabilities) (*capabilities.Capabilities, error) 43 // StopSession is called for each new WebDriver session, before the delete 44 // session command is sent to the WebDriver server. 45 StopSession(ctx context.Context, id int) error 46 // TearDown is called at the end of the test run. 47 TearDown(ctx context.Context) error 48 // WDAddress returns the address of the WebDriver server. 49 WDAddress(context.Context) string 50 } 51 52 // Base is a partial implementation of Env useful as the base struct for 53 // implementations of Env. 54 type Base struct { 55 *metadata.Metadata 56 diagnostics.Diagnostics 57 name string 58 59 mu sync.RWMutex 60 started bool 61 stopped bool 62 } 63 64 // NewBase creates a new Base environment with the given component name. 65 func NewBase(name string, m *metadata.Metadata, d diagnostics.Diagnostics) (*Base, error) { 66 return &Base{ 67 name: name, 68 Metadata: m, 69 Diagnostics: d, 70 }, nil 71 } 72 73 // SetUp starts the Environment. 74 func (b *Base) SetUp(ctx context.Context) error { 75 b.mu.Lock() 76 defer b.mu.Unlock() 77 if b.started { 78 return errors.NewPermanent(b.Name(), "cannot be started; it has already been started once") 79 } 80 b.started = true 81 return nil 82 } 83 84 // StartSession merges the passed in caps with b.Metadata.Capabilities and returns the merged 85 // capabilities that should be used when calling new session on the WebDriver 86 // server. 87 func (b *Base) StartSession(ctx context.Context, id int, caps *capabilities.Capabilities) (*capabilities.Capabilities, error) { 88 if err := b.Healthy(ctx); err != nil { 89 return nil, err 90 } 91 return caps.MergeOver(b.Metadata.Capabilities).Resolve(b.Metadata.Resolver()) 92 } 93 94 // StopSession is a no-op implementation of Env.StopSession. 95 func (b *Base) StopSession(ctx context.Context, _ int) error { 96 return b.Healthy(ctx) 97 } 98 99 // TearDown is a no-op implementation of Env.TearDown. 100 func (b *Base) TearDown(ctx context.Context) error { 101 b.mu.Lock() 102 defer b.mu.Unlock() 103 if !b.started { 104 return errors.NewPermanent(b.Name(), "cannot be stopped; it was never started") 105 } 106 if b.stopped { 107 return errors.NewPermanent(b.Name(), "cannot be stopped; it was already stopped once") 108 } 109 b.stopped = true 110 return nil 111 } 112 113 // Healthy returns nil (i.e., healthy) iff the environment has been started and 114 // has not yet been stopped. 115 func (b *Base) Healthy(context.Context) error { 116 b.mu.RLock() 117 defer b.mu.RUnlock() 118 if !b.started { 119 return errors.New(b.Name(), "has not been started") 120 } 121 if b.stopped { 122 return errors.NewPermanent(b.Name(), "has been stopped") 123 } 124 return nil 125 } 126 127 // WDAddress returns the empty string. 128 func (*Base) WDAddress(context.Context) string { 129 return "" 130 } 131 132 // Name returns the name of this environment to be used in error messages. 133 func (b *Base) Name() string { 134 return b.name 135 }