aboutsummaryrefslogtreecommitdiffstats
path: root/library/go/test/yatest/env.go
blob: d655e4c6daaf1952d6f7d8eba91cf83a96383db1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
// Package yatest provides access to testing context, when running under ya make -t.
package yatest

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"sync"
)

type TestContext struct {
	Build struct {
		BuildType string            `json:"build_type"`
		Flags     map[string]string `json:"flags"`
		Sanitizer string            `json:"sanitizer"`
	} `json:"build"`

	Runtime struct {
		BuildRoot              string            `json:"build_root"`
		OutputPath             string            `json:"output_path"`
		ProjectPath            string            `json:"project_path"`
		PythonBin              string            `json:"python_bin"`
		PythonLibPath          string            `json:"python_lib_path"`
		RAMDrivePath           string            `json:"ram_drive_path"`
		YtHDDPath              string            `json:"yt_hdd_path"`
		TestOutputRAMDrivePath string            `json:"test_output_ram_drive_path"`
		SourceRoot             string            `json:"source_root"`
		WorkPath               string            `json:"work_path"`
		TestToolPath           string            `json:"test_tool_path"`
		TestParameters         map[string]string `json:"test_params"`
	} `json:"runtime"`

	Resources struct {
		Global map[string]string `json:"global"`
	} `json:"resources"`

	Internal struct {
		EnvFile string `json:"env_file"`
	} `json:"internal"`

	Initialized bool
}

var (
	context              TestContext
	isRunningUnderGoTest bool
	initOnce             sync.Once
)

func lazyInit() {
	initOnce.Do(doInit)
}

func verifyContext() {
	if !context.Initialized {
		panic("test context isn't initialized")
	}
}

func initTestContext() {
	data, err := os.ReadFile(getenv("YA_TEST_CONTEXT_FILE"))
	if err != nil {
		panic(err)
	}

	err = json.Unmarshal([]byte(data), &context)
	if err != nil {
		panic(err)
	}
	setupEnv()
	context.Initialized = true
}

func setupEnv() {
	file, err := os.Open(context.Internal.EnvFile)
	if err != nil {
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		var objmap map[string]json.RawMessage
		var val string
		err := json.Unmarshal([]byte(line), &objmap)
		if err != nil {
			panic(err)
		}
		for k, v := range objmap {
			err := json.Unmarshal(v, &val)
			if err != nil {
				panic(err)
			}
			err = os.Setenv(k, val)
			if err != nil {
				panic(err)
			}
		}
	}
}

func HasYaTestContext() bool {
	lazyInit()
	return context.Initialized
}

// GlobalResourcePath returns absolute path to a directory
// containing global build resource.
func GlobalResourcePath(name string) string {
	resource, ok := RelaxedGlobalResourcePath(name)
	if !ok {
		panic(fmt.Sprintf("global resource %s is not defined", name))
	}
	return resource
}

func RelaxedGlobalResourcePath(name string) (string, bool) {
	lazyInit()
	verifyContext()
	resource, ok := context.Resources.Global[name]
	return resource, ok
}

func getenv(name string) string {
	value := os.Getenv(name)
	if value == "" {
		panic(fmt.Sprintf("environment variable %s is not set", name))
	}
	return value
}

func CCompilerPath() string {
	lazyInit()
	return getenv("YA_CC")
}

func CxxCompilerPath() string {
	lazyInit()
	return getenv("YA_CXX")
}

// PythonBinPath returns absolute path to the python
//
// Warn: if you are using build with system python (-DUSE_SYSTEM_PYTHON=X) beware that some python bundles
// are built in a stripped-down form that is needed for building, not running tests.
// See comments in the file below to find out which version of python is compatible with tests.
// https://a.yandex-team.ru/arc/trunk/arcadia/build/platform/python/resources.inc
func PythonBinPath() string {
	lazyInit()
	verifyContext()
	return context.Runtime.PythonBin
}

func PythonLibPath() string {
	lazyInit()
	verifyContext()
	return context.Runtime.PythonLibPath
}

// SourcePath returns absolute path to source directory.
//
// arcadiaPath must be declared using DATA macro inside ya.make.
func SourcePath(arcadiaPath string) string {
	lazyInit()
	if path.IsAbs(arcadiaPath) {
		panic(fmt.Sprintf("relative path expected, but got %q", arcadiaPath))
	}

	// Don't verify context for SourcePath - it can be mined without context
	return filepath.Join(context.Runtime.SourceRoot, arcadiaPath)
}

// BuildPath returns absolute path to the build directory.
func BuildPath(dataPath string) string {
	lazyInit()
	if path.IsAbs(dataPath) {
		panic(fmt.Sprintf("relative path expected, but got %q", dataPath))
	}

	verifyContext()
	return filepath.Join(context.Runtime.BuildRoot, dataPath)
}

// WorkPath returns absolute path to the work directory (initial test cwd).
func WorkPath(dataPath string) string {
	lazyInit()
	if path.IsAbs(dataPath) {
		panic(fmt.Sprintf("relative path expected, but got %q", dataPath))
	}

	verifyContext()
	return filepath.Join(context.Runtime.WorkPath, dataPath)
}

// OutputPath returns absolute path to the output directory (testing_out_stuff).
func OutputPath(dataPath string) string {
	lazyInit()
	verifyContext()
	return filepath.Join(context.Runtime.OutputPath, dataPath)
}

// RAMDrivePath returns absolute path to the ramdrive directory
func RAMDrivePath(dataPath string) string {
	lazyInit()
	if path.IsAbs(dataPath) {
		panic(fmt.Sprintf("relative path expected, but got %q", dataPath))
	}

	verifyContext()
	return filepath.Join(context.Runtime.RAMDrivePath, dataPath)
}

// YtHDDPath returns absolute path to the directory mounted to ext4 fs in YT
func YtHDDPath(dataPath string) string {
	lazyInit()
	if path.IsAbs(dataPath) {
		panic(fmt.Sprintf("relative path expected, but got %q", dataPath))
	}

	verifyContext()
	return filepath.Join(context.Runtime.YtHDDPath, dataPath)
}

// OutputRAMDrivePath returns absolute path to the ramdrive output directory
func OutputRAMDrivePath(dataPath string) string {
	lazyInit()
	if path.IsAbs(dataPath) {
		panic(fmt.Sprintf("relative path expected, but got %q", dataPath))
	}

	verifyContext()
	return filepath.Join(context.Runtime.TestOutputRAMDrivePath, dataPath)
}

// HasRAMDrive returns true if ramdrive is enabled in tests
func HasRAMDrive() bool {
	lazyInit()
	verifyContext()
	return context.Runtime.RAMDrivePath != ""
}

func BinaryPath(dataPath string) (string, error) {
	if runtime.GOOS == "windows" {
		dataPath += ".exe"
	}
	buildPath := BuildPath("")
	binaryPath := filepath.Join(buildPath, dataPath)
	if _, err := os.Stat(binaryPath); os.IsNotExist(err) {
		return "", fmt.Errorf("cannot find binary %s: make sure it was added in the DEPENDS section", dataPath)
	} else {
		return binaryPath, nil
	}
}

// ProjectPath returns arcadia-relative path to the test project
func ProjectPath() string {
	lazyInit()
	verifyContext()
	return context.Runtime.ProjectPath
}

// BuildType returns build type that was used to compile the test
func BuildType() string {
	lazyInit()
	verifyContext()
	return context.Build.BuildType
}

// BuildFlag returns the value of the requested build flag
func BuildFlag(name string) (string, bool) {
	lazyInit()
	verifyContext()
	val, ok := context.Build.Flags[name]
	return val, ok
}

// TestParam returns the value of the requested test parameter
func TestParam(name string) (string, bool) {
	lazyInit()
	verifyContext()
	val, ok := context.Runtime.TestParameters[name]
	return val, ok
}

// Sanitizer returns sanitizer name that was used to compile the test
func Sanitizer() string {
	lazyInit()
	verifyContext()
	return context.Build.Sanitizer
}

func EnvFile() string {
	lazyInit()
	verifyContext()
	return context.Internal.EnvFile
}

func TestToolPath() string {
	lazyInit()
	verifyContext()
	return context.Runtime.TestToolPath
}