github.com/web-platform-tests/wpt.fyi@v0.0.0-20240530210107-70cf978996f1/webdriver/webapp_server.go (about)

     1  package webdriver
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"os"
     9  	"os/exec"
    10  
    11  	"github.com/web-platform-tests/wpt.fyi/shared/sharedtest"
    12  )
    13  
    14  var (
    15  	staging    = flag.Bool("staging", false, "Use the app's deployed staging instance")
    16  	remoteHost = flag.String("remote_host", "staging.wpt.fyi", "Remote host of the staging webapp")
    17  )
    18  
    19  // StaticTestDataRevision is the SHA for the local (static) test run summaries.
    20  const StaticTestDataRevision = "24278ab61781de72ed363b866ae6b50b86822b27"
    21  
    22  // AppServer is an abstraction for navigating an instance of the webapp.
    23  type AppServer interface {
    24  	// Hook for closing the process that runs the webserver.
    25  	io.Closer
    26  
    27  	// GetWebappURL returns the URL for the given path on the running webapp.
    28  	GetWebappURL(path string) string
    29  }
    30  
    31  type remoteAppServer struct {
    32  	host string
    33  }
    34  
    35  func (i *remoteAppServer) GetWebappURL(path string) string {
    36  	// Remote (staging) server has HTTPS.
    37  	return fmt.Sprintf("https://%s%s", i.host, path)
    38  }
    39  
    40  func (i *remoteAppServer) Close() error {
    41  	return nil // Nothing needed here :)
    42  }
    43  
    44  type devAppServerInstance struct {
    45  	gcd  sharedtest.Instance
    46  	app  *exec.Cmd
    47  	port int
    48  }
    49  
    50  func (i *devAppServerInstance) GetWebappURL(path string) string {
    51  	// Local dev server doesn't have HTTPS.
    52  	return fmt.Sprintf("http://localhost:%d%s", i.port, path)
    53  }
    54  
    55  func (i *devAppServerInstance) Close() error {
    56  	i.app.Process.Kill()
    57  	return i.gcd.Close()
    58  }
    59  
    60  // newDevAppServer creates a dev appserve instance.
    61  func newDevAppServer() (*devAppServerInstance, error) {
    62  	gcd, err := sharedtest.NewAEInstance(true)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	port := pickUnusedPort()
    67  	os.Setenv("PORT", fmt.Sprint(port))
    68  	// Start the webapp server at last to pick up env vars (including those
    69  	// set by NewAEInstance).
    70  	// When running a test, CWD is the directory where the test file is;
    71  	// reset it to the root of the repo to run the server.
    72  	app := exec.Command("./web")
    73  	app.Dir = ".."
    74  	if err = app.Start(); err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	s := &devAppServerInstance{
    79  		gcd:  gcd,
    80  		app:  app,
    81  		port: port,
    82  	}
    83  	return s, nil
    84  }
    85  
    86  // NewWebserver creates an AppServer instance, which may be backed by local or
    87  // remote (staging) servers.
    88  func NewWebserver() (s AppServer, err error) {
    89  	if *staging {
    90  		return &remoteAppServer{
    91  			host: *remoteHost,
    92  		}, nil
    93  	}
    94  
    95  	app, err := newDevAppServer()
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	if err = addStaticData(app); err != nil {
   100  		// dev_appserver has started.
   101  		app.Close()
   102  		return nil, err
   103  	}
   104  	return app, err
   105  }
   106  
   107  func addStaticData(i *devAppServerInstance) (err error) {
   108  	cmd := exec.Command(
   109  		"go",
   110  		"run",
   111  		"../util/populate_dev_data.go",
   112  		fmt.Sprintf("--local_host=localhost:%d", i.port),
   113  		"--remote_runs=false",
   114  		"--static_runs=true",
   115  	)
   116  	output, err := cmd.CombinedOutput()
   117  	if err != nil {
   118  		log.Printf("%s", output)
   119  		return err
   120  	}
   121  	return nil
   122  }