You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
8.2 KiB

  1. package config_test
  2. import (
  3. "reflect"
  4. "testing"
  5. "github.com/stretchr/testify/assert"
  6. "gerrit.wikimedia.org/r/blubber/build"
  7. "gerrit.wikimedia.org/r/blubber/config"
  8. )
  9. func TestPythonConfigYAMLMerge(t *testing.T) {
  10. cfg, err := config.ReadYAMLConfig([]byte(`---
  11. version: v4
  12. base: foo
  13. python:
  14. version: python2.7
  15. requirements: [requirements.txt]
  16. variants:
  17. test:
  18. python:
  19. version: python3
  20. requirements: [other-requirements.txt, requirements-test.txt]
  21. use-system-flag: true`))
  22. if assert.NoError(t, err) {
  23. assert.Equal(t, []string{"requirements.txt"}, cfg.Python.Requirements)
  24. assert.Equal(t, "python2.7", cfg.Python.Version)
  25. variant, err := config.ExpandVariant(cfg, "test")
  26. if assert.NoError(t, err) {
  27. assert.Equal(t, []string{"other-requirements.txt", "requirements-test.txt"}, variant.Python.Requirements)
  28. assert.Equal(t, "python3", variant.Python.Version)
  29. assert.Equal(t, true, variant.Python.UseSystemFlag)
  30. }
  31. }
  32. }
  33. func TestPythonConfigYAMLMergeEmpty(t *testing.T) {
  34. cfg, err := config.ReadYAMLConfig([]byte(`---
  35. version: v4
  36. base: foo
  37. python:
  38. requirements: [requirements.txt]
  39. variants:
  40. test:
  41. python:
  42. requirements: []`))
  43. if assert.NoError(t, err) {
  44. assert.Equal(t, []string{"requirements.txt"}, cfg.Python.Requirements)
  45. variant, err := config.ExpandVariant(cfg, "test")
  46. if assert.NoError(t, err) {
  47. assert.Equal(t, []string{}, variant.Python.Requirements)
  48. }
  49. }
  50. }
  51. func TestPythonConfigYAMLDoNotMergeNil(t *testing.T) {
  52. cfg, err := config.ReadYAMLConfig([]byte(`---
  53. version: v4
  54. base: foo
  55. python:
  56. requirements: [requirements.txt]
  57. variants:
  58. test:
  59. python:
  60. requirements: ~`))
  61. if assert.NoError(t, err) {
  62. assert.Equal(t, []string{"requirements.txt"}, cfg.Python.Requirements)
  63. variant, err := config.ExpandVariant(cfg, "test")
  64. if assert.NoError(t, err) {
  65. assert.Equal(t, []string{"requirements.txt"}, variant.Python.Requirements)
  66. }
  67. }
  68. }
  69. func TestPythonConfigInstructionsNoRequirementsWithVersion(t *testing.T) {
  70. cfg := config.PythonConfig{
  71. Version: "python2.7",
  72. }
  73. t.Run("PhasePrivileged", func(t *testing.T) {
  74. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePrivileged))
  75. })
  76. t.Run("PhasePrivilegeDropped", func(t *testing.T) {
  77. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePrivilegeDropped))
  78. })
  79. t.Run("PhasePreInstall", func(t *testing.T) {
  80. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePreInstall))
  81. })
  82. t.Run("PhasePostInstall", func(t *testing.T) {
  83. assert.Equal(t,
  84. []build.Instruction{
  85. build.Env{map[string]string{
  86. "PYTHONPATH": "/opt/lib/python/site-packages",
  87. "PATH": "/opt/lib/python/site-packages/bin:${PATH}",
  88. }},
  89. },
  90. cfg.InstructionsForPhase(build.PhasePostInstall),
  91. )
  92. })
  93. }
  94. func TestPythonConfigInstructionsNoRequirementsNoVersion(t *testing.T) {
  95. cfg := config.PythonConfig{}
  96. t.Run("PhasePrivileged", func(t *testing.T) {
  97. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePrivileged))
  98. })
  99. t.Run("PhasePrivilegeDropped", func(t *testing.T) {
  100. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePrivilegeDropped))
  101. })
  102. t.Run("PhasePreInstall", func(t *testing.T) {
  103. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePreInstall))
  104. })
  105. t.Run("PhasePostInstall", func(t *testing.T) {
  106. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePostInstall))
  107. })
  108. }
  109. func TestPythonConfigInstructionsWithRequirements(t *testing.T) {
  110. cfg := config.PythonConfig{
  111. Version: "python2.7",
  112. Requirements: []string{"requirements.txt", "requirements-test.txt", "docs/requirements.txt"},
  113. }
  114. t.Run("PhasePrivileged", func(t *testing.T) {
  115. assert.Equal(t,
  116. []build.Instruction{
  117. build.RunAll{[]build.Run{
  118. {"python2.7", []string{"-m", "easy_install", "pip"}},
  119. {"python2.7", []string{"-m", "pip", "install", "-U", "setuptools", "wheel", "tox"}},
  120. }},
  121. },
  122. cfg.InstructionsForPhase(build.PhasePrivileged),
  123. )
  124. })
  125. t.Run("PhasePrivilegeDropped", func(t *testing.T) {
  126. assert.Empty(t, cfg.InstructionsForPhase(build.PhasePrivilegeDropped))
  127. })
  128. t.Run("PhasePreInstall", func(t *testing.T) {
  129. assert.Equal(t,
  130. []build.Instruction{
  131. build.Env{map[string]string{
  132. "PIP_WHEEL_DIR": "/opt/lib/python",
  133. "PIP_FIND_LINKS": "file:///opt/lib/python",
  134. }},
  135. build.Run{"mkdir -p", []string{"/opt/lib/python"}},
  136. build.Run{"mkdir -p", []string{"docs/"}},
  137. build.Copy{[]string{"requirements.txt", "requirements-test.txt"}, "./"},
  138. build.Copy{[]string{"docs/requirements.txt"}, "docs/"},
  139. build.RunAll{[]build.Run{
  140. {"python2.7", []string{"-m", "pip", "wheel",
  141. "-r", "requirements.txt",
  142. "-r", "requirements-test.txt",
  143. "-r", "docs/requirements.txt",
  144. }},
  145. {"python2.7", []string{"-m", "pip", "install",
  146. "--target", "/opt/lib/python/site-packages",
  147. "-r", "requirements.txt",
  148. "-r", "requirements-test.txt",
  149. "-r", "docs/requirements.txt",
  150. }},
  151. }},
  152. },
  153. cfg.InstructionsForPhase(build.PhasePreInstall),
  154. )
  155. })
  156. t.Run("PhasePostInstall", func(t *testing.T) {
  157. assert.Equal(t,
  158. []build.Instruction{
  159. build.Env{map[string]string{
  160. "PIP_NO_INDEX": "1",
  161. "PYTHONPATH": "/opt/lib/python/site-packages",
  162. "PATH": "/opt/lib/python/site-packages/bin:${PATH}",
  163. }},
  164. },
  165. cfg.InstructionsForPhase(build.PhasePostInstall),
  166. )
  167. })
  168. }
  169. func TestPythonConfigUseSystemFlag(t *testing.T) {
  170. cfg := config.PythonConfig{
  171. Version: "python2.7",
  172. Requirements: []string{"requirements.txt", "requirements-test.txt", "docs/requirements.txt"},
  173. UseSystemFlag: true,
  174. }
  175. t.Run("PhasePreInstall", func(t *testing.T) {
  176. assert.Equal(t,
  177. []build.Instruction{
  178. build.Env{map[string]string{
  179. "PIP_WHEEL_DIR": "/opt/lib/python",
  180. "PIP_FIND_LINKS": "file:///opt/lib/python",
  181. }},
  182. build.Run{"mkdir -p", []string{"/opt/lib/python"}},
  183. build.Run{"mkdir -p", []string{"docs/"}},
  184. build.Copy{[]string{"requirements.txt", "requirements-test.txt"}, "./"},
  185. build.Copy{[]string{"docs/requirements.txt"}, "docs/"},
  186. build.RunAll{[]build.Run{
  187. {"python2.7", []string{"-m", "pip", "wheel",
  188. "-r", "requirements.txt",
  189. "-r", "requirements-test.txt",
  190. "-r", "docs/requirements.txt",
  191. }},
  192. {"python2.7", []string{"-m", "pip", "install", "--system",
  193. "--target", "/opt/lib/python/site-packages",
  194. "-r", "requirements.txt",
  195. "-r", "requirements-test.txt",
  196. "-r", "docs/requirements.txt",
  197. }},
  198. }},
  199. },
  200. cfg.InstructionsForPhase(build.PhasePreInstall),
  201. )
  202. })
  203. }
  204. func TestPythonConfigRequirementsArgs(t *testing.T) {
  205. cfg := config.PythonConfig{
  206. Requirements: []string{"foo", "bar", "baz/qux"},
  207. }
  208. assert.Equal(t,
  209. []string{
  210. "-r", "foo",
  211. "-r", "bar",
  212. "-r", "baz/qux",
  213. },
  214. cfg.RequirementsArgs(),
  215. )
  216. }
  217. func TestSliceInsert(t *testing.T) {
  218. t.Run("test inserting an element", func(t *testing.T) {
  219. got := config.InsertElement([]string{"Hello", "World"}, "Beautiful", 1)
  220. expected := []string{"Hello", "Beautiful", "World"}
  221. if ! reflect.DeepEqual(got, expected) {
  222. t.Errorf("Expected '%v'; got '%v'", expected, got)
  223. }
  224. })
  225. t.Run("test inserting an element at the end", func(t *testing.T) {
  226. orig := []string{"Foo", "Bar", "Baz"}
  227. got := config.InsertElement(orig, "Beautiful", len(orig))
  228. expected := []string{"Foo", "Bar", "Baz", "Beautiful"}
  229. if ! reflect.DeepEqual(got, expected) {
  230. t.Errorf("Expected '%v'; got '%v'", expected, got)
  231. }
  232. })
  233. t.Run("test inserting an element at the beginning", func(t *testing.T) {
  234. orig := []string{"Foo", "Bar", "Baz"}
  235. got := config.InsertElement(orig, "Beautiful", 0)
  236. expected := []string{"Beautiful", "Foo", "Bar", "Baz"}
  237. if ! reflect.DeepEqual(got, expected) {
  238. t.Errorf("Expected '%v'; got '%v'", expected, got)
  239. }
  240. })
  241. }
  242. func TestPosFinding(t *testing.T) {
  243. t.Run("test finding string in slice", func(t *testing.T) {
  244. got := config.PosOf([]string{"foo", "bar"}, "foo")
  245. expected := 0
  246. if got != expected {
  247. t.Errorf("Expected '%v'; got '%v'", expected, got)
  248. }
  249. })
  250. t.Run("test finding string NOT in slice", func(t *testing.T) {
  251. got := config.PosOf([]string{"foo", "bar"}, "baz")
  252. expected := -1
  253. if got != expected {
  254. t.Errorf("Expected '%v'; got '%v'", expected, got)
  255. }
  256. })
  257. }