xref: /aosp_15_r20/build/make/tools/rbcrun/host_test.go (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker// Copyright 2021 Google LLC
2*9e94795aSAndroid Build Coastguard Worker//
3*9e94795aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*9e94795aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*9e94795aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*9e94795aSAndroid Build Coastguard Worker//
7*9e94795aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*9e94795aSAndroid Build Coastguard Worker//
9*9e94795aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*9e94795aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*9e94795aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e94795aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*9e94795aSAndroid Build Coastguard Worker// limitations under the License.
14*9e94795aSAndroid Build Coastguard Worker
15*9e94795aSAndroid Build Coastguard Workerpackage rbcrun
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Workerimport (
18*9e94795aSAndroid Build Coastguard Worker	"fmt"
19*9e94795aSAndroid Build Coastguard Worker	"os"
20*9e94795aSAndroid Build Coastguard Worker	"path/filepath"
21*9e94795aSAndroid Build Coastguard Worker	"runtime"
22*9e94795aSAndroid Build Coastguard Worker	"strings"
23*9e94795aSAndroid Build Coastguard Worker	"testing"
24*9e94795aSAndroid Build Coastguard Worker
25*9e94795aSAndroid Build Coastguard Worker	"go.starlark.net/resolve"
26*9e94795aSAndroid Build Coastguard Worker	"go.starlark.net/starlark"
27*9e94795aSAndroid Build Coastguard Worker	"go.starlark.net/starlarktest"
28*9e94795aSAndroid Build Coastguard Worker)
29*9e94795aSAndroid Build Coastguard Worker
30*9e94795aSAndroid Build Coastguard Worker// In order to use "assert.star" from go/starlark.net/starlarktest in the tests,
31*9e94795aSAndroid Build Coastguard Worker// provide:
32*9e94795aSAndroid Build Coastguard Worker//  * load function that handles "assert.star"
33*9e94795aSAndroid Build Coastguard Worker//  * starlarktest.DataFile function that finds its location
34*9e94795aSAndroid Build Coastguard Worker
35*9e94795aSAndroid Build Coastguard Workerfunc init() {
36*9e94795aSAndroid Build Coastguard Worker	starlarktestSetup()
37*9e94795aSAndroid Build Coastguard Worker}
38*9e94795aSAndroid Build Coastguard Worker
39*9e94795aSAndroid Build Coastguard Workerfunc starlarktestSetup() {
40*9e94795aSAndroid Build Coastguard Worker	resolve.AllowLambda = true
41*9e94795aSAndroid Build Coastguard Worker	starlarktest.DataFile = func(pkgdir, filename string) string {
42*9e94795aSAndroid Build Coastguard Worker		// The caller expects this function to return the path to the
43*9e94795aSAndroid Build Coastguard Worker		// data file. The implementation assumes that the source file
44*9e94795aSAndroid Build Coastguard Worker		// containing the caller and the data file are in the same
45*9e94795aSAndroid Build Coastguard Worker		// directory. It's ugly. Not sure what's the better way.
46*9e94795aSAndroid Build Coastguard Worker		// TODO(asmundak): handle Bazel case
47*9e94795aSAndroid Build Coastguard Worker		_, starlarktestSrcFile, _, _ := runtime.Caller(1)
48*9e94795aSAndroid Build Coastguard Worker		if filepath.Base(starlarktestSrcFile) != "starlarktest.go" {
49*9e94795aSAndroid Build Coastguard Worker			panic(fmt.Errorf("this function should be called from starlarktest.go, got %s",
50*9e94795aSAndroid Build Coastguard Worker				starlarktestSrcFile))
51*9e94795aSAndroid Build Coastguard Worker		}
52*9e94795aSAndroid Build Coastguard Worker		return filepath.Join(filepath.Dir(starlarktestSrcFile), filename)
53*9e94795aSAndroid Build Coastguard Worker	}
54*9e94795aSAndroid Build Coastguard Worker}
55*9e94795aSAndroid Build Coastguard Worker
56*9e94795aSAndroid Build Coastguard Worker// Common setup for the tests: create thread, change to the test directory
57*9e94795aSAndroid Build Coastguard Workerfunc testSetup(t *testing.T) *starlark.Thread {
58*9e94795aSAndroid Build Coastguard Worker	thread := &starlark.Thread{
59*9e94795aSAndroid Build Coastguard Worker		Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
60*9e94795aSAndroid Build Coastguard Worker			if module == "assert.star" {
61*9e94795aSAndroid Build Coastguard Worker				return starlarktest.LoadAssertModule()
62*9e94795aSAndroid Build Coastguard Worker			}
63*9e94795aSAndroid Build Coastguard Worker			return nil, fmt.Errorf("load not implemented")
64*9e94795aSAndroid Build Coastguard Worker		}}
65*9e94795aSAndroid Build Coastguard Worker	starlarktest.SetReporter(thread, t)
66*9e94795aSAndroid Build Coastguard Worker	if err := os.Chdir(dataDir()); err != nil {
67*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
68*9e94795aSAndroid Build Coastguard Worker	}
69*9e94795aSAndroid Build Coastguard Worker	return thread
70*9e94795aSAndroid Build Coastguard Worker}
71*9e94795aSAndroid Build Coastguard Worker
72*9e94795aSAndroid Build Coastguard Workerfunc dataDir() string {
73*9e94795aSAndroid Build Coastguard Worker	_, thisSrcFile, _, _ := runtime.Caller(0)
74*9e94795aSAndroid Build Coastguard Worker	return filepath.Join(filepath.Dir(thisSrcFile), "testdata")
75*9e94795aSAndroid Build Coastguard Worker}
76*9e94795aSAndroid Build Coastguard Worker
77*9e94795aSAndroid Build Coastguard Workerfunc exerciseStarlarkTestFile(t *testing.T, starFile string) {
78*9e94795aSAndroid Build Coastguard Worker	// In order to use "assert.star" from go/starlark.net/starlarktest in the tests, provide:
79*9e94795aSAndroid Build Coastguard Worker	//  * load function that handles "assert.star"
80*9e94795aSAndroid Build Coastguard Worker	//  * starlarktest.DataFile function that finds its location
81*9e94795aSAndroid Build Coastguard Worker	if err := os.Chdir(dataDir()); err != nil {
82*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
83*9e94795aSAndroid Build Coastguard Worker	}
84*9e94795aSAndroid Build Coastguard Worker	thread := &starlark.Thread{
85*9e94795aSAndroid Build Coastguard Worker		Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
86*9e94795aSAndroid Build Coastguard Worker			if module == "assert.star" {
87*9e94795aSAndroid Build Coastguard Worker				return starlarktest.LoadAssertModule()
88*9e94795aSAndroid Build Coastguard Worker			}
89*9e94795aSAndroid Build Coastguard Worker			return nil, fmt.Errorf("load not implemented")
90*9e94795aSAndroid Build Coastguard Worker		}}
91*9e94795aSAndroid Build Coastguard Worker	starlarktest.SetReporter(thread, t)
92*9e94795aSAndroid Build Coastguard Worker	_, thisSrcFile, _, _ := runtime.Caller(0)
93*9e94795aSAndroid Build Coastguard Worker	filename := filepath.Join(filepath.Dir(thisSrcFile), starFile)
94*9e94795aSAndroid Build Coastguard Worker	thread.SetLocal(executionModeKey, ExecutionModeRbc)
95*9e94795aSAndroid Build Coastguard Worker	thread.SetLocal(shellKey, "/bin/sh")
96*9e94795aSAndroid Build Coastguard Worker	if _, err := starlark.ExecFile(thread, filename, nil, rbcBuiltins); err != nil {
97*9e94795aSAndroid Build Coastguard Worker		if err, ok := err.(*starlark.EvalError); ok {
98*9e94795aSAndroid Build Coastguard Worker			t.Fatal(err.Backtrace())
99*9e94795aSAndroid Build Coastguard Worker		}
100*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
101*9e94795aSAndroid Build Coastguard Worker	}
102*9e94795aSAndroid Build Coastguard Worker}
103*9e94795aSAndroid Build Coastguard Worker
104*9e94795aSAndroid Build Coastguard Workerfunc TestFileOps(t *testing.T) {
105*9e94795aSAndroid Build Coastguard Worker	// TODO(asmundak): convert this to use exerciseStarlarkTestFile
106*9e94795aSAndroid Build Coastguard Worker	thread := testSetup(t)
107*9e94795aSAndroid Build Coastguard Worker	if _, err := starlark.ExecFile(thread, "file_ops.star", nil, rbcBuiltins); err != nil {
108*9e94795aSAndroid Build Coastguard Worker		if err, ok := err.(*starlark.EvalError); ok {
109*9e94795aSAndroid Build Coastguard Worker			t.Fatal(err.Backtrace())
110*9e94795aSAndroid Build Coastguard Worker		}
111*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
112*9e94795aSAndroid Build Coastguard Worker	}
113*9e94795aSAndroid Build Coastguard Worker}
114*9e94795aSAndroid Build Coastguard Worker
115*9e94795aSAndroid Build Coastguard Workerfunc TestLoad(t *testing.T) {
116*9e94795aSAndroid Build Coastguard Worker	// TODO(asmundak): convert this to use exerciseStarlarkTestFile
117*9e94795aSAndroid Build Coastguard Worker	thread := testSetup(t)
118*9e94795aSAndroid Build Coastguard Worker	thread.Load = func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
119*9e94795aSAndroid Build Coastguard Worker		if module == "assert.star" {
120*9e94795aSAndroid Build Coastguard Worker			return starlarktest.LoadAssertModule()
121*9e94795aSAndroid Build Coastguard Worker		} else {
122*9e94795aSAndroid Build Coastguard Worker			return loader(thread, module)
123*9e94795aSAndroid Build Coastguard Worker		}
124*9e94795aSAndroid Build Coastguard Worker	}
125*9e94795aSAndroid Build Coastguard Worker	dir := dataDir()
126*9e94795aSAndroid Build Coastguard Worker	if err := os.Chdir(filepath.Dir(dir)); err != nil {
127*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
128*9e94795aSAndroid Build Coastguard Worker	}
129*9e94795aSAndroid Build Coastguard Worker	thread.SetLocal(allowExternalEntrypointKey, false)
130*9e94795aSAndroid Build Coastguard Worker	thread.SetLocal(callingFileKey, "testdata/load.star")
131*9e94795aSAndroid Build Coastguard Worker	thread.SetLocal(executionModeKey, ExecutionModeRbc)
132*9e94795aSAndroid Build Coastguard Worker	if _, err := starlark.ExecFile(thread, "testdata/load.star", nil, rbcBuiltins); err != nil {
133*9e94795aSAndroid Build Coastguard Worker		if err, ok := err.(*starlark.EvalError); ok {
134*9e94795aSAndroid Build Coastguard Worker			t.Fatal(err.Backtrace())
135*9e94795aSAndroid Build Coastguard Worker		}
136*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
137*9e94795aSAndroid Build Coastguard Worker	}
138*9e94795aSAndroid Build Coastguard Worker}
139*9e94795aSAndroid Build Coastguard Worker
140*9e94795aSAndroid Build Coastguard Workerfunc TestBzlLoadsScl(t *testing.T) {
141*9e94795aSAndroid Build Coastguard Worker	moduleCache = make(map[string]*modentry)
142*9e94795aSAndroid Build Coastguard Worker	dir := dataDir()
143*9e94795aSAndroid Build Coastguard Worker	if err := os.Chdir(filepath.Dir(dir)); err != nil {
144*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
145*9e94795aSAndroid Build Coastguard Worker	}
146*9e94795aSAndroid Build Coastguard Worker	vars, _, err := Run("testdata/bzl_loads_scl.bzl", nil, ExecutionModeRbc, false)
147*9e94795aSAndroid Build Coastguard Worker	if err != nil {
148*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
149*9e94795aSAndroid Build Coastguard Worker	}
150*9e94795aSAndroid Build Coastguard Worker	if val, ok := vars["foo"]; !ok {
151*9e94795aSAndroid Build Coastguard Worker		t.Fatalf("Failed to load foo variable")
152*9e94795aSAndroid Build Coastguard Worker	} else if val.(starlark.String) != "bar" {
153*9e94795aSAndroid Build Coastguard Worker		t.Fatalf("Expected \"bar\", got %q", val)
154*9e94795aSAndroid Build Coastguard Worker	}
155*9e94795aSAndroid Build Coastguard Worker}
156*9e94795aSAndroid Build Coastguard Worker
157*9e94795aSAndroid Build Coastguard Workerfunc TestNonEntrypointBzlLoadsScl(t *testing.T) {
158*9e94795aSAndroid Build Coastguard Worker	moduleCache = make(map[string]*modentry)
159*9e94795aSAndroid Build Coastguard Worker	dir := dataDir()
160*9e94795aSAndroid Build Coastguard Worker	if err := os.Chdir(filepath.Dir(dir)); err != nil {
161*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
162*9e94795aSAndroid Build Coastguard Worker	}
163*9e94795aSAndroid Build Coastguard Worker	vars, _, err := Run("testdata/bzl_loads_scl_2.bzl", nil, ExecutionModeRbc, false)
164*9e94795aSAndroid Build Coastguard Worker	if err != nil {
165*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
166*9e94795aSAndroid Build Coastguard Worker	}
167*9e94795aSAndroid Build Coastguard Worker	if val, ok := vars["foo"]; !ok {
168*9e94795aSAndroid Build Coastguard Worker		t.Fatalf("Failed to load foo variable")
169*9e94795aSAndroid Build Coastguard Worker	} else if val.(starlark.String) != "bar" {
170*9e94795aSAndroid Build Coastguard Worker		t.Fatalf("Expected \"bar\", got %q", val)
171*9e94795aSAndroid Build Coastguard Worker	}
172*9e94795aSAndroid Build Coastguard Worker}
173*9e94795aSAndroid Build Coastguard Worker
174*9e94795aSAndroid Build Coastguard Workerfunc TestSclLoadsBzl(t *testing.T) {
175*9e94795aSAndroid Build Coastguard Worker	moduleCache = make(map[string]*modentry)
176*9e94795aSAndroid Build Coastguard Worker	dir := dataDir()
177*9e94795aSAndroid Build Coastguard Worker	if err := os.Chdir(filepath.Dir(dir)); err != nil {
178*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
179*9e94795aSAndroid Build Coastguard Worker	}
180*9e94795aSAndroid Build Coastguard Worker	_, _, err := Run("testdata/scl_incorrectly_loads_bzl.scl", nil, ExecutionModeScl, false)
181*9e94795aSAndroid Build Coastguard Worker	if err == nil {
182*9e94795aSAndroid Build Coastguard Worker		t.Fatal("Expected failure")
183*9e94795aSAndroid Build Coastguard Worker	}
184*9e94795aSAndroid Build Coastguard Worker	if !strings.Contains(err.Error(), ".scl files can only load other .scl files") {
185*9e94795aSAndroid Build Coastguard Worker		t.Fatalf("Expected error to contain \".scl files can only load other .scl files\": %q", err.Error())
186*9e94795aSAndroid Build Coastguard Worker	}
187*9e94795aSAndroid Build Coastguard Worker}
188*9e94795aSAndroid Build Coastguard Worker
189*9e94795aSAndroid Build Coastguard Workerfunc TestCantLoadSymlink(t *testing.T) {
190*9e94795aSAndroid Build Coastguard Worker	moduleCache = make(map[string]*modentry)
191*9e94795aSAndroid Build Coastguard Worker	dir := dataDir()
192*9e94795aSAndroid Build Coastguard Worker	if err := os.Chdir(filepath.Dir(dir)); err != nil {
193*9e94795aSAndroid Build Coastguard Worker		t.Fatal(err)
194*9e94795aSAndroid Build Coastguard Worker	}
195*9e94795aSAndroid Build Coastguard Worker	_, _, err := Run("testdata/test_scl_symlink.scl", nil, ExecutionModeScl, false)
196*9e94795aSAndroid Build Coastguard Worker	if err == nil {
197*9e94795aSAndroid Build Coastguard Worker		t.Fatal("Expected failure")
198*9e94795aSAndroid Build Coastguard Worker	}
199*9e94795aSAndroid Build Coastguard Worker	if !strings.Contains(err.Error(), "symlinks to starlark files are not allowed") {
200*9e94795aSAndroid Build Coastguard Worker		t.Fatalf("Expected error to contain \"symlinks to starlark files are not allowed\": %q", err.Error())
201*9e94795aSAndroid Build Coastguard Worker	}
202*9e94795aSAndroid Build Coastguard Worker}
203*9e94795aSAndroid Build Coastguard Worker
204*9e94795aSAndroid Build Coastguard Workerfunc TestShell(t *testing.T) {
205*9e94795aSAndroid Build Coastguard Worker	exerciseStarlarkTestFile(t, "testdata/shell.star")
206*9e94795aSAndroid Build Coastguard Worker}
207