| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. |
| 4 |
| 5 package venv |
| 6 |
| 7 import ( |
| 8 "encoding/json" |
| 9 "fmt" |
| 10 "io/ioutil" |
| 11 "path/filepath" |
| 12 "testing" |
| 13 |
| 14 "github.com/luci/luci-go/vpython/api/vpython" |
| 15 "github.com/luci/luci-go/vpython/filesystem" |
| 16 "github.com/luci/luci-go/vpython/filesystem/testfs" |
| 17 "github.com/luci/luci-go/vpython/python" |
| 18 |
| 19 "github.com/luci/luci-go/common/errors" |
| 20 |
| 21 "golang.org/x/net/context" |
| 22 |
| 23 . "github.com/luci/luci-go/common/testing/assertions" |
| 24 . "github.com/smartystreets/goconvey/convey" |
| 25 ) |
| 26 |
| 27 type resolvedInterpreter struct { |
| 28 i *python.Interpreter |
| 29 version python.Version |
| 30 } |
| 31 |
| 32 func resolveFromPath(vers python.Version) *resolvedInterpreter { |
| 33 c := context.Background() |
| 34 i, err := python.Find(c, vers) |
| 35 if err != nil { |
| 36 return nil |
| 37 } |
| 38 if err := filesystem.AbsPath(&i.Python); err != nil { |
| 39 panic(err) |
| 40 } |
| 41 |
| 42 ri := resolvedInterpreter{ |
| 43 i: i, |
| 44 } |
| 45 if ri.version, err = ri.i.GetVersion(c); err != nil { |
| 46 panic(err) |
| 47 } |
| 48 return &ri |
| 49 } |
| 50 |
| 51 var ( |
| 52 pythonGeneric = resolveFromPath(python.Version{}) |
| 53 python27 = resolveFromPath(python.Version{2, 7, 0}) |
| 54 python3 = resolveFromPath(python.Version{3, 0, 0}) |
| 55 ) |
| 56 |
| 57 func TestResolvePythonInterpreter(t *testing.T) { |
| 58 t.Parallel() |
| 59 |
| 60 Convey(`Resolving a Python interpreter`, t, func() { |
| 61 c := context.Background() |
| 62 cfg := Config{ |
| 63 Spec: &vpython.Spec{}, |
| 64 } |
| 65 |
| 66 // Tests to run if we have Python 2.7 installed. |
| 67 if python27 != nil { |
| 68 Convey(`When Python 2.7 is requested, it gets resolved.`
, func() { |
| 69 cfg.Spec.PythonVersion = "2.7" |
| 70 So(cfg.resolvePythonInterpreter(c), ShouldBeNil) |
| 71 So(cfg.Python, ShouldEqual, python27.i.Python) |
| 72 |
| 73 vers, err := python.ParseVersion(cfg.Spec.Python
Version) |
| 74 So(err, ShouldBeNil) |
| 75 So(vers.IsSatisfiedBy(python27.version), ShouldB
eTrue) |
| 76 }) |
| 77 |
| 78 Convey(`Fails when Python 9999 is requested, but a Pytho
n 2 interpreter is forced.`, func() { |
| 79 cfg.Python = python27.i.Python |
| 80 cfg.Spec.PythonVersion = "9999" |
| 81 So(cfg.resolvePythonInterpreter(c), ShouldErrLik
e, "doesn't match specification") |
| 82 }) |
| 83 } |
| 84 |
| 85 // Tests to run if we have Python 2.7 and a generic Python insta
lled. |
| 86 if pythonGeneric != nil && python27 != nil { |
| 87 // Our generic Python resolves to a known version, so we
can proceed. |
| 88 Convey(`When no Python version is specified, spec resolv
es to generic.`, func() { |
| 89 So(cfg.resolvePythonInterpreter(c), ShouldBeNil) |
| 90 So(cfg.Python, ShouldEqual, pythonGeneric.i.Pyth
on) |
| 91 |
| 92 vers, err := python.ParseVersion(cfg.Spec.Python
Version) |
| 93 So(err, ShouldBeNil) |
| 94 So(vers.IsSatisfiedBy(pythonGeneric.version), Sh
ouldBeTrue) |
| 95 }) |
| 96 } |
| 97 |
| 98 // Tests to run if we have Python 3 installed. |
| 99 if python3 != nil { |
| 100 Convey(`When Python 3 is requested, it gets resolved.`,
func() { |
| 101 cfg.Spec.PythonVersion = "3" |
| 102 So(cfg.resolvePythonInterpreter(c), ShouldBeNil) |
| 103 So(cfg.Python, ShouldEqual, python3.i.Python) |
| 104 |
| 105 vers, err := python.ParseVersion(cfg.Spec.Python
Version) |
| 106 So(err, ShouldBeNil) |
| 107 So(vers.IsSatisfiedBy(python3.version), ShouldBe
True) |
| 108 }) |
| 109 |
| 110 Convey(`Fails when Python 9999 is requested, but a Pytho
n 3 interpreter is forced.`, func() { |
| 111 cfg.Python = python3.i.Python |
| 112 cfg.Spec.PythonVersion = "9999" |
| 113 So(cfg.resolvePythonInterpreter(c), ShouldErrLik
e, "doesn't match specification") |
| 114 }) |
| 115 } |
| 116 }) |
| 117 } |
| 118 |
| 119 type setupCheckManifest struct { |
| 120 Interpreter string `json:"interpreter"` |
| 121 Pants string `json:"pants"` |
| 122 Shirt string `json:"shirt"` |
| 123 } |
| 124 |
| 125 func testVirtualEnvWith(t *testing.T, py *python.Interpreter) { |
| 126 t.Parallel() |
| 127 |
| 128 if py == nil { |
| 129 t.Skipf("No python interpreter found.") |
| 130 } |
| 131 |
| 132 tl, err := loadTestEnvironment(context.Background(), t) |
| 133 if err != nil { |
| 134 t.Fatalf("could not set up test loader for %q: %s", py.Python, e
rr) |
| 135 } |
| 136 |
| 137 Convey(`Testing Setup`, t, testfs.MustWithTempDir(t, "TestVirtualEnv", f
unc(tdir string) { |
| 138 c := context.Background() |
| 139 config := Config{ |
| 140 BaseDir: tdir, |
| 141 MaxHashLen: 4, |
| 142 Package: vpython.Spec_Package{ |
| 143 Path: "foo/bar/virtualenv", |
| 144 Version: "unresolved", |
| 145 }, |
| 146 Python: py.Python, |
| 147 Spec: &vpython.Spec{ |
| 148 Wheel: []*vpython.Spec_Package{ |
| 149 {Path: "foo/bar/shirt", Version: "unreso
lved"}, |
| 150 {Path: "foo/bar/pants", Version: "unreso
lved"}, |
| 151 }, |
| 152 }, |
| 153 Loader: tl, |
| 154 } |
| 155 |
| 156 // Load the bootstrap wheels for the next part of the test. |
| 157 So(tl.ensureWheels(c, t, py, tdir), ShouldBeNil) |
| 158 |
| 159 err := With(c, config, false, func(c context.Context, v *Env) er
ror { |
| 160 testScriptPath := filepath.Join(testDataDir, "setup_chec
k.py") |
| 161 checkOut := filepath.Join(tdir, "output.json") |
| 162 i := v.InterpreterCommand() |
| 163 So(i.Run(c, testScriptPath, "--json-output", checkOut),
ShouldBeNil) |
| 164 |
| 165 var m setupCheckManifest |
| 166 So(loadJSON(checkOut, &m), ShouldBeNil) |
| 167 So(m.Interpreter, ShouldStartWith, v.Root) |
| 168 So(m.Pants, ShouldStartWith, v.Root) |
| 169 So(m.Shirt, ShouldStartWith, v.Root) |
| 170 |
| 171 // We should be able to delete it. |
| 172 So(v.Delete(c), ShouldBeNil) |
| 173 return nil |
| 174 }) |
| 175 So(err, ShouldBeNil) |
| 176 })) |
| 177 } |
| 178 |
| 179 func TestVirtualEnv(t *testing.T) { |
| 180 t.Parallel() |
| 181 |
| 182 for _, tc := range []struct { |
| 183 name string |
| 184 ri *resolvedInterpreter |
| 185 }{ |
| 186 {"python27", python27}, |
| 187 {"python3", python3}, |
| 188 } { |
| 189 tc := tc |
| 190 |
| 191 t.Run(fmt.Sprintf(`Testing Virtualenv for: %s`, tc.name), func(t
*testing.T) { |
| 192 testVirtualEnvWith(t, tc.ri.i) |
| 193 }) |
| 194 } |
| 195 } |
| 196 |
| 197 func loadJSON(path string, dst interface{}) error { |
| 198 content, err := ioutil.ReadFile(path) |
| 199 if err != nil { |
| 200 return errors.Annotate(err).Reason("failed to open file").Err() |
| 201 } |
| 202 if err := json.Unmarshal(content, dst); err != nil { |
| 203 return errors.Annotate(err).Reason("failed to unmarshal JSON").E
rr() |
| 204 } |
| 205 return nil |
| 206 } |
| OLD | NEW |