parse_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. package test
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "testing"
  7. "google.golang.org/protobuf/encoding/protojson"
  8. "k8s.io/utils/pointer"
  9. porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
  10. "github.com/porter-dev/porter/internal/porter_app"
  11. "github.com/sergi/go-diff/diffmatchpatch"
  12. "github.com/matryer/is"
  13. )
  14. func TestParseYAML(t *testing.T) {
  15. tests := []struct {
  16. porterYamlFileName string
  17. want *porterv1.PorterApp
  18. }{
  19. {"v2_input_nobuild", result_nobuild},
  20. {"v1_input_no_build_no_image", v1_result_nobuild_no_image},
  21. }
  22. for _, tt := range tests {
  23. t.Run(tt.porterYamlFileName, func(t *testing.T) {
  24. is := is.New(t)
  25. want, err := os.ReadFile(fmt.Sprintf("../testdata/%s.yaml", tt.porterYamlFileName))
  26. is.NoErr(err) // no error expected reading test file
  27. got, err := porter_app.ParseYAML(context.Background(), want, "test-app")
  28. is.NoErr(err) // umbrella chart values should convert to map[string]any without issues
  29. diffProtoWithFailTest(t, is, tt.want, got.AppProto)
  30. is.Equal(got.EnvVariables, map[string]string{
  31. "PORT": "8080",
  32. "NODE_ENV": "production",
  33. })
  34. })
  35. }
  36. }
  37. var result_nobuild = &porterv1.PorterApp{
  38. Name: "test-app",
  39. Services: map[string]*porterv1.Service{
  40. "example-web": {
  41. Name: "example-web",
  42. RunOptional: pointer.String("node index.js"),
  43. Port: 8080,
  44. CpuCores: 0.1,
  45. RamMegabytes: 256,
  46. Gpu: &porterv1.GPU{
  47. Enabled: false,
  48. GpuCoresNvidia: 0,
  49. },
  50. Config: &porterv1.Service_WebConfig{
  51. WebConfig: &porterv1.WebServiceConfig{
  52. Autoscaling: &porterv1.Autoscaling{
  53. Enabled: true,
  54. MinInstances: 1,
  55. MaxInstances: 3,
  56. CpuThresholdPercent: 60,
  57. MemoryThresholdPercent: 60,
  58. },
  59. Domains: []*porterv1.Domain{
  60. {
  61. Name: "test1.example.com",
  62. },
  63. {
  64. Name: "test2.example.com",
  65. },
  66. },
  67. HealthCheck: &porterv1.HealthCheck{
  68. Enabled: true,
  69. HttpPath: "/healthz",
  70. },
  71. },
  72. },
  73. Type: 1,
  74. },
  75. "example-wkr": {
  76. Name: "example-wkr",
  77. RunOptional: pointer.String("echo 'work'"),
  78. InstancesOptional: pointer.Int32(1),
  79. Port: 80,
  80. CpuCores: 0.1,
  81. RamMegabytes: 256,
  82. GpuCoresNvidia: 0,
  83. Gpu: &porterv1.GPU{
  84. Enabled: false,
  85. GpuCoresNvidia: 0,
  86. },
  87. Config: &porterv1.Service_WorkerConfig{
  88. WorkerConfig: &porterv1.WorkerServiceConfig{
  89. Autoscaling: nil,
  90. },
  91. },
  92. Type: 2,
  93. },
  94. "example-job": {
  95. Name: "example-job",
  96. RunOptional: pointer.String("echo 'hello world'"),
  97. CpuCores: 0.1,
  98. RamMegabytes: 256,
  99. GpuCoresNvidia: 0,
  100. Gpu: &porterv1.GPU{
  101. Enabled: false,
  102. GpuCoresNvidia: 0,
  103. },
  104. Config: &porterv1.Service_JobConfig{
  105. JobConfig: &porterv1.JobServiceConfig{
  106. AllowConcurrentOptional: pointer.Bool(true),
  107. Cron: "*/10 * * * *",
  108. SuspendCron: pointer.Bool(false),
  109. TimeoutSeconds: 60,
  110. },
  111. },
  112. Type: 3,
  113. },
  114. },
  115. ServiceList: []*porterv1.Service{
  116. {
  117. Name: "example-web",
  118. RunOptional: pointer.String("node index.js"),
  119. Port: 8080,
  120. CpuCores: 0.1,
  121. RamMegabytes: 256,
  122. GpuCoresNvidia: 0,
  123. Gpu: &porterv1.GPU{
  124. Enabled: false,
  125. GpuCoresNvidia: 0,
  126. },
  127. Config: &porterv1.Service_WebConfig{
  128. WebConfig: &porterv1.WebServiceConfig{
  129. Autoscaling: &porterv1.Autoscaling{
  130. Enabled: true,
  131. MinInstances: 1,
  132. MaxInstances: 3,
  133. CpuThresholdPercent: 60,
  134. MemoryThresholdPercent: 60,
  135. },
  136. Domains: []*porterv1.Domain{
  137. {
  138. Name: "test1.example.com",
  139. },
  140. {
  141. Name: "test2.example.com",
  142. },
  143. },
  144. HealthCheck: &porterv1.HealthCheck{
  145. Enabled: true,
  146. HttpPath: "/healthz",
  147. },
  148. },
  149. },
  150. Type: 1,
  151. },
  152. {
  153. Name: "example-wkr",
  154. RunOptional: pointer.String("echo 'work'"),
  155. InstancesOptional: pointer.Int32(1),
  156. Port: 80,
  157. CpuCores: 0.1,
  158. RamMegabytes: 256,
  159. GpuCoresNvidia: 0,
  160. Gpu: &porterv1.GPU{
  161. Enabled: false,
  162. GpuCoresNvidia: 0,
  163. },
  164. Config: &porterv1.Service_WorkerConfig{
  165. WorkerConfig: &porterv1.WorkerServiceConfig{
  166. Autoscaling: nil,
  167. },
  168. },
  169. Type: 2,
  170. },
  171. {
  172. Name: "example-job",
  173. RunOptional: pointer.String("echo 'hello world'"),
  174. CpuCores: 0.1,
  175. RamMegabytes: 256,
  176. GpuCoresNvidia: 0,
  177. Gpu: &porterv1.GPU{
  178. Enabled: false,
  179. GpuCoresNvidia: 0,
  180. },
  181. Config: &porterv1.Service_JobConfig{
  182. JobConfig: &porterv1.JobServiceConfig{
  183. AllowConcurrentOptional: pointer.Bool(true),
  184. Cron: "*/10 * * * *",
  185. SuspendCron: pointer.Bool(false),
  186. TimeoutSeconds: 60,
  187. },
  188. },
  189. Type: 3,
  190. },
  191. },
  192. Predeploy: &porterv1.Service{
  193. RunOptional: pointer.String("ls"),
  194. Port: 0,
  195. CpuCores: 0,
  196. RamMegabytes: 0,
  197. GpuCoresNvidia: 0,
  198. Gpu: &porterv1.GPU{
  199. Enabled: false,
  200. GpuCoresNvidia: 0,
  201. },
  202. Config: &porterv1.Service_JobConfig{},
  203. Type: 3,
  204. },
  205. Image: &porterv1.AppImage{
  206. Repository: "nginx",
  207. Tag: "latest",
  208. },
  209. }
  210. var (
  211. trueBool = true
  212. zeroInt32 = int32(0)
  213. oneInt32 = int32(1)
  214. )
  215. var v1_result_nobuild_no_image = &porterv1.PorterApp{
  216. Name: "test-app",
  217. Services: map[string]*porterv1.Service{
  218. "example-job": {
  219. Name: "example-job",
  220. RunOptional: pointer.String("echo 'hello world'"),
  221. CpuCores: 0.1,
  222. RamMegabytes: 256,
  223. GpuCoresNvidia: 0,
  224. Config: &porterv1.Service_JobConfig{
  225. JobConfig: &porterv1.JobServiceConfig{
  226. AllowConcurrentOptional: &trueBool,
  227. Cron: "*/10 * * * *",
  228. },
  229. },
  230. Type: 3,
  231. },
  232. "example-wkr": {
  233. Name: "example-wkr",
  234. RunOptional: pointer.String("echo 'work'"),
  235. InstancesOptional: &oneInt32,
  236. Port: 80,
  237. CpuCores: 0.1,
  238. RamMegabytes: 256,
  239. GpuCoresNvidia: 0,
  240. Config: &porterv1.Service_WorkerConfig{
  241. WorkerConfig: &porterv1.WorkerServiceConfig{
  242. Autoscaling: nil,
  243. },
  244. },
  245. Type: 2,
  246. },
  247. "example-web": {
  248. Name: "example-web",
  249. RunOptional: pointer.String("node index.js"),
  250. InstancesOptional: &zeroInt32,
  251. Port: 8080,
  252. CpuCores: 0.1,
  253. GpuCoresNvidia: 0,
  254. RamMegabytes: 256,
  255. Config: &porterv1.Service_WebConfig{
  256. WebConfig: &porterv1.WebServiceConfig{
  257. Autoscaling: &porterv1.Autoscaling{
  258. Enabled: true,
  259. MinInstances: 1,
  260. MaxInstances: 3,
  261. CpuThresholdPercent: 60,
  262. MemoryThresholdPercent: 60,
  263. },
  264. Domains: []*porterv1.Domain{
  265. {
  266. Name: "test1.example.com",
  267. },
  268. {
  269. Name: "test2.example.com",
  270. },
  271. },
  272. HealthCheck: &porterv1.HealthCheck{
  273. Enabled: true,
  274. HttpPath: "/healthz",
  275. },
  276. Private: pointer.Bool(false),
  277. },
  278. },
  279. Type: 1,
  280. },
  281. },
  282. ServiceList: []*porterv1.Service{
  283. {
  284. Name: "example-job",
  285. RunOptional: pointer.String("echo 'hello world'"),
  286. CpuCores: 0.1,
  287. RamMegabytes: 256,
  288. GpuCoresNvidia: 0,
  289. Config: &porterv1.Service_JobConfig{
  290. JobConfig: &porterv1.JobServiceConfig{
  291. AllowConcurrentOptional: &trueBool,
  292. Cron: "*/10 * * * *",
  293. },
  294. },
  295. Type: 3,
  296. },
  297. {
  298. Name: "example-wkr",
  299. RunOptional: pointer.String("echo 'work'"),
  300. InstancesOptional: &oneInt32,
  301. Port: 80,
  302. CpuCores: 0.1,
  303. RamMegabytes: 256,
  304. GpuCoresNvidia: 0,
  305. Config: &porterv1.Service_WorkerConfig{
  306. WorkerConfig: &porterv1.WorkerServiceConfig{
  307. Autoscaling: nil,
  308. },
  309. },
  310. Type: 2,
  311. },
  312. {
  313. Name: "example-web",
  314. RunOptional: pointer.String("node index.js"),
  315. InstancesOptional: &zeroInt32,
  316. Port: 8080,
  317. CpuCores: 0.1,
  318. RamMegabytes: 256,
  319. GpuCoresNvidia: 0,
  320. Config: &porterv1.Service_WebConfig{
  321. WebConfig: &porterv1.WebServiceConfig{
  322. Autoscaling: &porterv1.Autoscaling{
  323. Enabled: true,
  324. MinInstances: 1,
  325. MaxInstances: 3,
  326. CpuThresholdPercent: 60,
  327. MemoryThresholdPercent: 60,
  328. },
  329. Domains: []*porterv1.Domain{
  330. {
  331. Name: "test1.example.com",
  332. },
  333. {
  334. Name: "test2.example.com",
  335. },
  336. },
  337. HealthCheck: &porterv1.HealthCheck{
  338. Enabled: true,
  339. HttpPath: "/healthz",
  340. },
  341. Private: pointer.Bool(false),
  342. },
  343. },
  344. Type: 1,
  345. },
  346. },
  347. Predeploy: &porterv1.Service{
  348. RunOptional: pointer.String("ls"),
  349. Instances: 0,
  350. Port: 0,
  351. CpuCores: 0,
  352. RamMegabytes: 0,
  353. GpuCoresNvidia: 0,
  354. Config: &porterv1.Service_JobConfig{},
  355. Type: 3,
  356. },
  357. }
  358. func diffProtoWithFailTest(t *testing.T, is *is.I, want, got *porterv1.PorterApp) {
  359. t.Helper()
  360. opts := protojson.MarshalOptions{Multiline: true}
  361. wantJson, err := opts.Marshal(want)
  362. is.NoErr(err) // no error expected marshalling want
  363. gotJson, err := opts.Marshal(got)
  364. is.NoErr(err) // no error expected marshalling got
  365. if string(wantJson) != string(gotJson) {
  366. dmp := diffmatchpatch.New()
  367. diffs := dmp.DiffMain(string(wantJson), string(gotJson), false)
  368. t.Errorf("diff between want and got: %s", dmp.DiffPrettyText(diffs))
  369. }
  370. }