test.go 11 KB

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