test.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. package storage
  2. import (
  3. "fmt"
  4. "path"
  5. "strings"
  6. "testing"
  7. "github.com/opencost/opencost/core/pkg/util/json"
  8. )
  9. type testFileContent struct {
  10. Field1 int `json:"field_1"`
  11. Field2 string `json:"field_2"`
  12. }
  13. var tfc = testFileContent{
  14. Field1: 101,
  15. Field2: "TEST_FILE_CONTENT",
  16. }
  17. const testpath = "opencost/storage/"
  18. func createFiles(files []string, testName string, store Storage) error {
  19. b, err := json.Marshal(tfc)
  20. if err != nil {
  21. return fmt.Errorf("failed to marshal file content: %w", err)
  22. }
  23. for _, fileName := range files {
  24. filePath := path.Join(testpath, testName, fileName)
  25. err = store.Write(filePath, b)
  26. if err != nil {
  27. return fmt.Errorf("failed to write file '%s': %w ", filePath, err)
  28. }
  29. }
  30. return nil
  31. }
  32. func cleanupFiles(files []string, testName string, store Storage) error {
  33. for _, fileName := range files {
  34. filePath := path.Join(testpath, testName, fileName)
  35. err := store.Remove(filePath)
  36. if err != nil {
  37. return fmt.Errorf("failed to remove file '%s': %w ", filePath, err)
  38. }
  39. }
  40. return nil
  41. }
  42. func TestStorageList(t *testing.T, store Storage) {
  43. testName := "list"
  44. fileNames := []string{
  45. "/file0.json",
  46. "/file1.json",
  47. "/dir0/file2.json",
  48. "/dir0/file3.json",
  49. }
  50. err := createFiles(fileNames, testName, store)
  51. if err != nil {
  52. t.Errorf("failed to create files: %s", err)
  53. }
  54. defer func() {
  55. err = cleanupFiles(fileNames, testName, store)
  56. if err != nil {
  57. t.Errorf("failed to clean up files: %s", err)
  58. }
  59. }()
  60. testCases := map[string]struct {
  61. path string
  62. expected []string
  63. expectErr bool
  64. }{
  65. "base dir files": {
  66. path: path.Join(testpath, testName),
  67. expected: []string{
  68. "file0.json",
  69. "file1.json",
  70. },
  71. expectErr: false,
  72. },
  73. "single nested dir files": {
  74. path: path.Join(testpath, testName, "dir0"),
  75. expected: []string{
  76. "file2.json",
  77. "file3.json",
  78. },
  79. expectErr: false,
  80. },
  81. "nonexistent dir files": {
  82. path: path.Join(testpath, testName, "dir1"),
  83. expected: []string{},
  84. expectErr: false,
  85. },
  86. }
  87. for name, tc := range testCases {
  88. t.Run(name, func(t *testing.T) {
  89. fileList, err := store.List(tc.path)
  90. if tc.expectErr == (err == nil) {
  91. if tc.expectErr {
  92. t.Errorf("expected error was not thrown")
  93. return
  94. }
  95. t.Errorf("unexpected error: %s", err.Error())
  96. return
  97. }
  98. if len(fileList) != len(tc.expected) {
  99. t.Errorf("file list length does not match expected length, actual: %d, expected: %d", len(fileList), len(tc.expected))
  100. }
  101. expectedSet := map[string]struct{}{}
  102. for _, expName := range tc.expected {
  103. expectedSet[expName] = struct{}{}
  104. }
  105. for _, file := range fileList {
  106. _, ok := expectedSet[file.Name]
  107. if !ok {
  108. t.Errorf("unexpect file in list %s", file.Name)
  109. }
  110. if file.Size == 0 {
  111. t.Errorf("file size is not set")
  112. }
  113. if file.ModTime.IsZero() {
  114. t.Errorf("file mod time is not set")
  115. }
  116. }
  117. })
  118. }
  119. }
  120. func TestStorageListDirectories(t *testing.T, store Storage) {
  121. testName := "list_directories"
  122. fileNames := []string{
  123. "/file0.json",
  124. "/dir0/file2.json",
  125. "/dir0/file3.json",
  126. "/dir0/dir1/file4.json",
  127. "/dir0/dir2/file5.json",
  128. }
  129. err := createFiles(fileNames, testName, store)
  130. if err != nil {
  131. t.Errorf("failed to create files: %s", err)
  132. }
  133. defer func() {
  134. err = cleanupFiles(fileNames, testName, store)
  135. if err != nil {
  136. t.Errorf("failed to clean up files: %s", err)
  137. }
  138. }()
  139. testCases := map[string]struct {
  140. path string
  141. expected []string
  142. expectErr bool
  143. }{
  144. "root dir dir": {
  145. path: "",
  146. expected: []string{
  147. strings.Split(testpath, "/")[0] + "/",
  148. },
  149. expectErr: false,
  150. },
  151. "base dir dir": {
  152. path: path.Join(testpath, testName),
  153. expected: []string{
  154. path.Join(testpath, testName, "dir0") + "/",
  155. },
  156. expectErr: false,
  157. },
  158. "single nested dir files": {
  159. path: path.Join(testpath, testName, "dir0"),
  160. expected: []string{
  161. path.Join(testpath, testName, "dir0", "dir1") + "/",
  162. path.Join(testpath, testName, "dir0", "dir2") + "/",
  163. },
  164. expectErr: false,
  165. },
  166. "dir with no sub dirs": {
  167. path: path.Join(testpath, testName, "dir0/dir1"),
  168. expected: []string{},
  169. expectErr: false,
  170. },
  171. "non-existent dir": {
  172. path: path.Join(testpath, testName, "dir1"),
  173. expected: []string{},
  174. expectErr: false,
  175. },
  176. }
  177. for name, tc := range testCases {
  178. t.Run(name, func(t *testing.T) {
  179. dirList, err := store.ListDirectories(tc.path)
  180. if tc.expectErr == (err == nil) {
  181. if tc.expectErr {
  182. t.Errorf("expected error was not thrown")
  183. return
  184. }
  185. t.Errorf("unexpected error: %s", err.Error())
  186. return
  187. }
  188. if len(dirList) != len(tc.expected) {
  189. t.Errorf("dir list length does not match expected length, actual: %d, expected: %d", len(dirList), len(tc.expected))
  190. }
  191. expectedSet := map[string]struct{}{}
  192. for _, expName := range tc.expected {
  193. expectedSet[expName] = struct{}{}
  194. }
  195. for _, dir := range dirList {
  196. _, ok := expectedSet[dir.Name]
  197. if !ok {
  198. t.Errorf("unexpect dir in list %s", dir.Name)
  199. }
  200. }
  201. })
  202. }
  203. }
  204. func TestStorageExists(t *testing.T, store Storage) {
  205. testName := "exists"
  206. fileNames := []string{
  207. "/file0.json",
  208. }
  209. err := createFiles(fileNames, testName, store)
  210. if err != nil {
  211. t.Errorf("failed to create files: %s", err)
  212. }
  213. defer func() {
  214. err = cleanupFiles(fileNames, testName, store)
  215. if err != nil {
  216. t.Errorf("failed to clean up files: %s", err)
  217. }
  218. }()
  219. testCases := map[string]struct {
  220. path string
  221. expected bool
  222. expectErr bool
  223. }{
  224. "file exists": {
  225. path: path.Join(testpath, testName, "file0.json"),
  226. expected: true,
  227. expectErr: false,
  228. },
  229. "file does not exist": {
  230. path: path.Join(testpath, testName, "file1.json"),
  231. expected: false,
  232. expectErr: false,
  233. },
  234. "dir does not exist": {
  235. path: path.Join(testpath, testName, "dir0/file.json"),
  236. expected: false,
  237. expectErr: false,
  238. },
  239. }
  240. for name, tc := range testCases {
  241. t.Run(name, func(t *testing.T) {
  242. exists, err := store.Exists(tc.path)
  243. if tc.expectErr == (err == nil) {
  244. if tc.expectErr {
  245. t.Errorf("expected error was not thrown")
  246. return
  247. }
  248. t.Errorf("unexpected error: %s", err.Error())
  249. return
  250. }
  251. if exists != tc.expected {
  252. t.Errorf("file exists output did not match expected")
  253. }
  254. })
  255. }
  256. }
  257. func TestStorageRead(t *testing.T, store Storage) {
  258. testName := "read"
  259. fileNames := []string{
  260. "/file0.json",
  261. }
  262. err := createFiles(fileNames, testName, store)
  263. if err != nil {
  264. t.Errorf("failed to create files: %s", err)
  265. }
  266. defer func() {
  267. err = cleanupFiles(fileNames, testName, store)
  268. if err != nil {
  269. t.Errorf("failed to clean up files: %s", err)
  270. }
  271. }()
  272. testCases := map[string]struct {
  273. path string
  274. expectErr bool
  275. }{
  276. "file exists": {
  277. path: path.Join(testpath, testName, "file0.json"),
  278. expectErr: false,
  279. },
  280. "file does not exist": {
  281. path: path.Join(testpath, testName, "file1.json"),
  282. expectErr: true,
  283. },
  284. "dir does not exist": {
  285. path: path.Join(testpath, testName, "dir0/file.json"),
  286. expectErr: true,
  287. },
  288. }
  289. for name, tc := range testCases {
  290. t.Run(name, func(t *testing.T) {
  291. b, err := store.Read(tc.path)
  292. if tc.expectErr && err != nil {
  293. return
  294. }
  295. if tc.expectErr == (err == nil) {
  296. if tc.expectErr {
  297. t.Errorf("expected error was not thrown")
  298. return
  299. }
  300. t.Errorf("unexpected error: %s", err.Error())
  301. return
  302. }
  303. var content testFileContent
  304. err = json.Unmarshal(b, &content)
  305. if err != nil {
  306. t.Errorf("could not unmarshal file content")
  307. return
  308. }
  309. if content != tfc {
  310. t.Errorf("file content did not match writen value")
  311. }
  312. })
  313. }
  314. }
  315. func TestStorageStat(t *testing.T, store Storage) {
  316. testName := "stat"
  317. fileNames := []string{
  318. "/file0.json",
  319. }
  320. err := createFiles(fileNames, testName, store)
  321. if err != nil {
  322. t.Errorf("failed to create files: %s", err)
  323. }
  324. defer func() {
  325. err = cleanupFiles(fileNames, testName, store)
  326. if err != nil {
  327. t.Errorf("failed to clean up files: %s", err)
  328. }
  329. }()
  330. testCases := map[string]struct {
  331. path string
  332. expected *StorageInfo
  333. expectErr bool
  334. }{
  335. "base dir": {
  336. path: path.Join(testpath, testName, "file0.json"),
  337. expected: &StorageInfo{
  338. Name: "file0.json",
  339. Size: 45,
  340. },
  341. expectErr: false,
  342. },
  343. "file does not exist": {
  344. path: path.Join(testpath, testName, "file1.json"),
  345. expected: nil,
  346. expectErr: true,
  347. },
  348. }
  349. for name, tc := range testCases {
  350. t.Run(name, func(t *testing.T) {
  351. status, err := store.Stat(tc.path)
  352. if tc.expectErr && err != nil {
  353. return
  354. }
  355. if tc.expectErr == (err == nil) {
  356. if tc.expectErr {
  357. t.Errorf("expected error was not thrown")
  358. return
  359. }
  360. t.Errorf("unexpected error: %s", err.Error())
  361. return
  362. }
  363. if status.Name != tc.expected.Name {
  364. t.Errorf("status name did name match expected, actual: %s, expected: %s", status.Name, tc.expected.Name)
  365. }
  366. if status.Size != tc.expected.Size {
  367. t.Errorf("status name did size match expected, actual: %d, expected: %d", status.Size, tc.expected.Size)
  368. }
  369. if status.ModTime.IsZero() {
  370. t.Errorf("status mod time is not set")
  371. }
  372. })
  373. }
  374. }