xref: /aosp_15_r20/external/sandboxed-api/contrib/jsonnet/jsonnet_tests.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1*ec63e07aSXin Li // Copyright 2020 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li //     https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li 
15*ec63e07aSXin Li #include <unistd.h>
16*ec63e07aSXin Li 
17*ec63e07aSXin Li #include <fstream>
18*ec63e07aSXin Li #include <iostream>
19*ec63e07aSXin Li #include <memory>
20*ec63e07aSXin Li #include <streambuf>
21*ec63e07aSXin Li #include <string>
22*ec63e07aSXin Li 
23*ec63e07aSXin Li #include "gtest/gtest.h"
24*ec63e07aSXin Li #include "contrib/jsonnet/jsonnet_base_sandbox.h"
25*ec63e07aSXin Li #include "sandboxed_api/util/path.h"
26*ec63e07aSXin Li #include "sandboxed_api/util/status_matchers.h"
27*ec63e07aSXin Li 
28*ec63e07aSXin Li namespace {
29*ec63e07aSXin Li 
30*ec63e07aSXin Li class JsonnetTest : public ::testing::Test {
31*ec63e07aSXin Li  protected:
32*ec63e07aSXin Li   enum Evaluation { kBase, kMultipleFiles, kYamlStream };
33*ec63e07aSXin Li 
SetUp()34*ec63e07aSXin Li   void SetUp() override {
35*ec63e07aSXin Li     // Get paths to where input and output is stored.
36*ec63e07aSXin Li     char buffer[256];
37*ec63e07aSXin Li     int error = readlink("/proc/self/exe", buffer, 256);
38*ec63e07aSXin Li     ASSERT_GE(error, 0);
39*ec63e07aSXin Li 
40*ec63e07aSXin Li     std::pair<absl::string_view, absl::string_view> parts_of_path =
41*ec63e07aSXin Li         sapi::file::SplitPath(buffer);
42*ec63e07aSXin Li     absl::string_view binary_path = parts_of_path.first;
43*ec63e07aSXin Li 
44*ec63e07aSXin Li     std::string input_path =
45*ec63e07aSXin Li         sapi::file::JoinPath(binary_path, "tests_input", "dummy_input");
46*ec63e07aSXin Li     std::string output_path =
47*ec63e07aSXin Li         sapi::file::JoinPath(binary_path, "tests_output", "dummy_input");
48*ec63e07aSXin Li 
49*ec63e07aSXin Li     // Set up sandbox and api.
50*ec63e07aSXin Li     sandbox_ = std::make_unique<JsonnetBaseSandbox>(input_path, output_path);
51*ec63e07aSXin Li     ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
52*ec63e07aSXin Li     api_ = std::make_unique<JsonnetApi>(sandbox_.get());
53*ec63e07aSXin Li 
54*ec63e07aSXin Li     // Initialize library's main structure.
55*ec63e07aSXin Li     SAPI_ASSERT_OK_AND_ASSIGN(JsonnetVm * vm_ptr, api_->c_jsonnet_make());
56*ec63e07aSXin Li     vm_ = std::make_unique<sapi::v::RemotePtr>(vm_ptr);
57*ec63e07aSXin Li   }
58*ec63e07aSXin Li 
TearDown()59*ec63e07aSXin Li   void TearDown() override {
60*ec63e07aSXin Li     if (jsonnet_vm_was_used_) {
61*ec63e07aSXin Li       SAPI_ASSERT_OK_AND_ASSIGN(
62*ec63e07aSXin Li           char* result, api_->c_jsonnet_realloc(vm_.get(), output_.get(), 0));
63*ec63e07aSXin Li     }
64*ec63e07aSXin Li     ASSERT_THAT(api_->c_jsonnet_destroy(vm_.get()), sapi::IsOk());
65*ec63e07aSXin Li     if (input_was_read_) {
66*ec63e07aSXin Li       ASSERT_THAT(api_->c_free_input(input_.get()), sapi::IsOk());
67*ec63e07aSXin Li     }
68*ec63e07aSXin Li   }
69*ec63e07aSXin Li 
70*ec63e07aSXin Li   // Reads input from file.
71*ec63e07aSXin Li   void ReadInput(const char* filename);
72*ec63e07aSXin Li 
73*ec63e07aSXin Li   // Evaluates jsonnet code.
74*ec63e07aSXin Li   void EvaluateJsonnetCode(Evaluation type, bool expected_correct);
75*ec63e07aSXin Li 
76*ec63e07aSXin Li   // Writes output to file.
77*ec63e07aSXin Li   void WriteOutput(const char* filename_or_directory, Evaluation type);
78*ec63e07aSXin Li 
79*ec63e07aSXin Li   // Reads the output written to a file by library function / expected output.
80*ec63e07aSXin Li   std::string ReadOutput(const char* filename);
81*ec63e07aSXin Li 
82*ec63e07aSXin Li   std::unique_ptr<JsonnetBaseSandbox> sandbox_;
83*ec63e07aSXin Li   std::unique_ptr<JsonnetApi> api_;
84*ec63e07aSXin Li   std::unique_ptr<sapi::v::RemotePtr> input_;
85*ec63e07aSXin Li   std::unique_ptr<sapi::v::RemotePtr> output_;
86*ec63e07aSXin Li   std::unique_ptr<sapi::v::RemotePtr> vm_;
87*ec63e07aSXin Li 
88*ec63e07aSXin Li   std::string input_filename_in_sandboxee_;
89*ec63e07aSXin Li   bool jsonnet_vm_was_used_ = false;
90*ec63e07aSXin Li   bool input_was_read_ = false;
91*ec63e07aSXin Li };
92*ec63e07aSXin Li 
ReadInput(const char * filename)93*ec63e07aSXin Li void JsonnetTest::ReadInput(const char* filename) {
94*ec63e07aSXin Li   std::string in_file_in_sandboxee(std::string("/input/") +
95*ec63e07aSXin Li                                    basename(const_cast<char*>(&filename[0])));
96*ec63e07aSXin Li   input_filename_in_sandboxee_ = std::move(in_file_in_sandboxee);
97*ec63e07aSXin Li   sapi::v::ConstCStr in_file_var(input_filename_in_sandboxee_.c_str());
98*ec63e07aSXin Li 
99*ec63e07aSXin Li   SAPI_ASSERT_OK_AND_ASSIGN(char* input_ptr,
100*ec63e07aSXin Li                             api_->c_read_input(0, in_file_var.PtrBefore()));
101*ec63e07aSXin Li   input_ = std::make_unique<sapi::v::RemotePtr>(input_ptr);
102*ec63e07aSXin Li 
103*ec63e07aSXin Li   input_was_read_ = true;
104*ec63e07aSXin Li }
105*ec63e07aSXin Li 
EvaluateJsonnetCode(Evaluation type,bool expected_correct)106*ec63e07aSXin Li void JsonnetTest::EvaluateJsonnetCode(Evaluation type, bool expected_correct) {
107*ec63e07aSXin Li   sapi::v::ConstCStr in_file_var(input_filename_in_sandboxee_.c_str());
108*ec63e07aSXin Li   sapi::v::Int error;
109*ec63e07aSXin Li   char* output_ptr;
110*ec63e07aSXin Li 
111*ec63e07aSXin Li   switch (type) {
112*ec63e07aSXin Li     case kBase: {
113*ec63e07aSXin Li       SAPI_ASSERT_OK_AND_ASSIGN(
114*ec63e07aSXin Li           output_ptr,
115*ec63e07aSXin Li           api_->c_jsonnet_evaluate_snippet(vm_.get(), in_file_var.PtrBefore(),
116*ec63e07aSXin Li                                            input_.get(), error.PtrAfter()));
117*ec63e07aSXin Li       break;
118*ec63e07aSXin Li     }
119*ec63e07aSXin Li 
120*ec63e07aSXin Li     case kMultipleFiles: {
121*ec63e07aSXin Li       SAPI_ASSERT_OK_AND_ASSIGN(
122*ec63e07aSXin Li           output_ptr, api_->c_jsonnet_evaluate_snippet_multi(
123*ec63e07aSXin Li                           vm_.get(), in_file_var.PtrBefore(), input_.get(),
124*ec63e07aSXin Li                           error.PtrAfter()));
125*ec63e07aSXin Li       break;
126*ec63e07aSXin Li     }
127*ec63e07aSXin Li 
128*ec63e07aSXin Li     case kYamlStream: {
129*ec63e07aSXin Li       SAPI_ASSERT_OK_AND_ASSIGN(
130*ec63e07aSXin Li           output_ptr, api_->c_jsonnet_evaluate_snippet_stream(
131*ec63e07aSXin Li                           vm_.get(), in_file_var.PtrBefore(), input_.get(),
132*ec63e07aSXin Li                           error.PtrAfter()));
133*ec63e07aSXin Li       break;
134*ec63e07aSXin Li     }
135*ec63e07aSXin Li   }
136*ec63e07aSXin Li 
137*ec63e07aSXin Li   if (expected_correct) {
138*ec63e07aSXin Li     ASSERT_THAT(error.GetValue(), testing::Eq(0));
139*ec63e07aSXin Li   } else {
140*ec63e07aSXin Li     ASSERT_THAT(error.GetValue(), testing::Eq(1));
141*ec63e07aSXin Li   }
142*ec63e07aSXin Li 
143*ec63e07aSXin Li   output_ = std::make_unique<sapi::v::RemotePtr>(output_ptr);
144*ec63e07aSXin Li 
145*ec63e07aSXin Li   jsonnet_vm_was_used_ = true;
146*ec63e07aSXin Li }
147*ec63e07aSXin Li 
WriteOutput(const char * filename_or_directory,Evaluation type)148*ec63e07aSXin Li void JsonnetTest::WriteOutput(const char* filename_or_directory,
149*ec63e07aSXin Li                               Evaluation type) {
150*ec63e07aSXin Li   bool success;
151*ec63e07aSXin Li 
152*ec63e07aSXin Li   switch (type) {
153*ec63e07aSXin Li     case kBase: {
154*ec63e07aSXin Li       std::string out_file_in_sandboxee(
155*ec63e07aSXin Li           std::string("/output/") +
156*ec63e07aSXin Li           basename(const_cast<char*>(&filename_or_directory[0])));
157*ec63e07aSXin Li       sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
158*ec63e07aSXin Li 
159*ec63e07aSXin Li       SAPI_ASSERT_OK_AND_ASSIGN(
160*ec63e07aSXin Li           success,
161*ec63e07aSXin Li           api_->c_write_output_file(output_.get(), out_file_var.PtrBefore()));
162*ec63e07aSXin Li       break;
163*ec63e07aSXin Li     }
164*ec63e07aSXin Li     case kMultipleFiles: {
165*ec63e07aSXin Li       std::string out_file_in_sandboxee(std::string("/output/"));
166*ec63e07aSXin Li       sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
167*ec63e07aSXin Li       SAPI_ASSERT_OK_AND_ASSIGN(
168*ec63e07aSXin Li           success, api_->c_write_multi_output_files(
169*ec63e07aSXin Li                        output_.get(), out_file_var.PtrBefore(), false));
170*ec63e07aSXin Li       break;
171*ec63e07aSXin Li     }
172*ec63e07aSXin Li 
173*ec63e07aSXin Li     case kYamlStream: {
174*ec63e07aSXin Li       std::string out_file_in_sandboxee(
175*ec63e07aSXin Li           std::string("/output/") +
176*ec63e07aSXin Li           basename(const_cast<char*>(&filename_or_directory[0])));
177*ec63e07aSXin Li       sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
178*ec63e07aSXin Li       SAPI_ASSERT_OK_AND_ASSIGN(
179*ec63e07aSXin Li           success,
180*ec63e07aSXin Li           api_->c_write_output_stream(output_.get(), out_file_var.PtrBefore()));
181*ec63e07aSXin Li       break;
182*ec63e07aSXin Li     }
183*ec63e07aSXin Li   }
184*ec63e07aSXin Li 
185*ec63e07aSXin Li   ASSERT_THAT(success, testing::Eq(true));
186*ec63e07aSXin Li }
187*ec63e07aSXin Li 
ReadOutput(const char * filename)188*ec63e07aSXin Li std::string JsonnetTest::ReadOutput(const char* filename) {
189*ec63e07aSXin Li   std::ifstream input_stream(filename);
190*ec63e07aSXin Li   std::string contents((std::istreambuf_iterator<char>(input_stream)),
191*ec63e07aSXin Li                        std::istreambuf_iterator<char>());
192*ec63e07aSXin Li   return contents;
193*ec63e07aSXin Li }
194*ec63e07aSXin Li 
195*ec63e07aSXin Li // One file evaluation to one file
TEST_F(JsonnetTest,OneFileNoDependencies)196*ec63e07aSXin Li TEST_F(JsonnetTest, OneFileNoDependencies) {
197*ec63e07aSXin Li   constexpr char kInputFile[] = "arith.jsonnet";
198*ec63e07aSXin Li   constexpr char kOutputFile[] = "arith_output";
199*ec63e07aSXin Li   constexpr char kOutputToRead[] = "tests_output/arith_output";
200*ec63e07aSXin Li   constexpr char kOutputToExpect[] = "tests_expected_output/arith.golden";
201*ec63e07aSXin Li 
202*ec63e07aSXin Li   ReadInput(kInputFile);
203*ec63e07aSXin Li   EvaluateJsonnetCode(kBase, true);
204*ec63e07aSXin Li   WriteOutput(kOutputFile, kBase);
205*ec63e07aSXin Li 
206*ec63e07aSXin Li   std::string produced_output = ReadOutput(kOutputToRead);
207*ec63e07aSXin Li   std::string expected_output = ReadOutput(kOutputToExpect);
208*ec63e07aSXin Li 
209*ec63e07aSXin Li   ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
210*ec63e07aSXin Li }
211*ec63e07aSXin Li 
212*ec63e07aSXin Li // One file evaluating to one file, dependent on some other files
TEST_F(JsonnetTest,OneFileSomeDependencies)213*ec63e07aSXin Li TEST_F(JsonnetTest, OneFileSomeDependencies) {
214*ec63e07aSXin Li   constexpr char kInputFile[] = "negroni.jsonnet";
215*ec63e07aSXin Li   constexpr char kOutputFile[] = "negroni_output";
216*ec63e07aSXin Li   constexpr char kOutputToRead[] = "tests_output/negroni_output";
217*ec63e07aSXin Li   constexpr char kOutputToExpect[] = "tests_expected_output/negroni.golden";
218*ec63e07aSXin Li 
219*ec63e07aSXin Li   ReadInput(kInputFile);
220*ec63e07aSXin Li   EvaluateJsonnetCode(kBase, true);
221*ec63e07aSXin Li   WriteOutput(kOutputFile, kBase);
222*ec63e07aSXin Li 
223*ec63e07aSXin Li   const std::string produced_output = ReadOutput(kOutputToRead);
224*ec63e07aSXin Li   const std::string expected_output = ReadOutput(kOutputToExpect);
225*ec63e07aSXin Li 
226*ec63e07aSXin Li   ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
227*ec63e07aSXin Li }
228*ec63e07aSXin Li 
229*ec63e07aSXin Li // One file evaluating to two files
TEST_F(JsonnetTest,MultipleFiles)230*ec63e07aSXin Li TEST_F(JsonnetTest, MultipleFiles) {
231*ec63e07aSXin Li   constexpr char kInputFile[] = "multiple_files_example.jsonnet";
232*ec63e07aSXin Li   constexpr char kOutputFile[] = "";
233*ec63e07aSXin Li   constexpr char kOutputToRead1[] = "tests_output/first_file.json";
234*ec63e07aSXin Li   constexpr char kOutputToRead2[] = "tests_output/second_file.json";
235*ec63e07aSXin Li   constexpr char kOutputToExpect1[] = "tests_expected_output/first_file.json";
236*ec63e07aSXin Li   constexpr char kOutputToExpect2[] = "tests_expected_output/second_file.json";
237*ec63e07aSXin Li 
238*ec63e07aSXin Li   ReadInput(kInputFile);
239*ec63e07aSXin Li   EvaluateJsonnetCode(kMultipleFiles, true);
240*ec63e07aSXin Li   WriteOutput(kOutputFile, kMultipleFiles);
241*ec63e07aSXin Li 
242*ec63e07aSXin Li   const std::string produced_output_1 = ReadOutput(kOutputToRead1);
243*ec63e07aSXin Li   const std::string produced_output_2 = ReadOutput(kOutputToRead2);
244*ec63e07aSXin Li   const std::string expected_output_1 = ReadOutput(kOutputToExpect1);
245*ec63e07aSXin Li   const std::string expected_output_2 = ReadOutput(kOutputToExpect2);
246*ec63e07aSXin Li 
247*ec63e07aSXin Li   ASSERT_STREQ(produced_output_1.c_str(), expected_output_1.c_str());
248*ec63e07aSXin Li   ASSERT_STREQ(produced_output_2.c_str(), expected_output_2.c_str());
249*ec63e07aSXin Li }
250*ec63e07aSXin Li 
251*ec63e07aSXin Li // One file evaluating to yaml stream format
TEST_F(JsonnetTest,YamlStream)252*ec63e07aSXin Li TEST_F(JsonnetTest, YamlStream) {
253*ec63e07aSXin Li   constexpr char kInputFile[] = "yaml_stream_example.jsonnet";
254*ec63e07aSXin Li   constexpr char kOutputFile[] = "yaml_stream_example.yaml";
255*ec63e07aSXin Li   constexpr char kOutputToRead[] = "tests_output/yaml_stream_example.yaml";
256*ec63e07aSXin Li   constexpr char kOutputToExpect[] =
257*ec63e07aSXin Li       "tests_expected_output/yaml_stream_example.yaml";
258*ec63e07aSXin Li 
259*ec63e07aSXin Li   ReadInput(kInputFile);
260*ec63e07aSXin Li   EvaluateJsonnetCode(kYamlStream, true);
261*ec63e07aSXin Li   WriteOutput(kOutputFile, kYamlStream);
262*ec63e07aSXin Li 
263*ec63e07aSXin Li   const std::string produced_output = ReadOutput(kOutputToRead);
264*ec63e07aSXin Li   const std::string expected_output = ReadOutput(kOutputToExpect);
265*ec63e07aSXin Li 
266*ec63e07aSXin Li   ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
267*ec63e07aSXin Li }
268*ec63e07aSXin Li 
269*ec63e07aSXin Li // One file depended on some other files not accessible by the sandbox
TEST_F(JsonnetTest,BadEvaluation)270*ec63e07aSXin Li TEST_F(JsonnetTest, BadEvaluation) {
271*ec63e07aSXin Li   constexpr char kInputFile[] = "imports.jsonnet";
272*ec63e07aSXin Li 
273*ec63e07aSXin Li   ReadInput(kInputFile);
274*ec63e07aSXin Li   EvaluateJsonnetCode(kBase, false);
275*ec63e07aSXin Li }
276*ec63e07aSXin Li 
277*ec63e07aSXin Li }  // namespace
278