|
1 | 1 | import * as fs from "node:fs"; |
| 2 | +import { writeFileSync } from "node:fs"; |
2 | 3 | import { http, HttpResponse } from "msw"; |
3 | 4 | import { MAX_UPLOAD_SIZE } from "../r2/constants"; |
4 | 5 | import { actionsForEventCategories } from "../r2/helpers"; |
@@ -100,6 +101,7 @@ describe("r2", () => { |
100 | 101 | wrangler r2 bucket notification Manage event notification rules for an R2 bucket |
101 | 102 | wrangler r2 bucket domain Manage custom domains for an R2 bucket |
102 | 103 | wrangler r2 bucket dev-url Manage public access via the r2.dev URL for an R2 bucket |
| 104 | + wrangler r2 bucket lifecycle Manage lifecycle rules for an R2 bucket |
103 | 105 |
|
104 | 106 | GLOBAL FLAGS |
105 | 107 | -j, --experimental-json-config Experimental: support wrangler.json [boolean] |
@@ -137,6 +139,7 @@ describe("r2", () => { |
137 | 139 | wrangler r2 bucket notification Manage event notification rules for an R2 bucket |
138 | 140 | wrangler r2 bucket domain Manage custom domains for an R2 bucket |
139 | 141 | wrangler r2 bucket dev-url Manage public access via the r2.dev URL for an R2 bucket |
| 142 | + wrangler r2 bucket lifecycle Manage lifecycle rules for an R2 bucket |
140 | 143 |
|
141 | 144 | GLOBAL FLAGS |
142 | 145 | -j, --experimental-json-config Experimental: support wrangler.json [boolean] |
@@ -1000,7 +1003,7 @@ binding = \\"testBucket\\"" |
1000 | 1003 | " |
1001 | 1004 | wrangler r2 bucket notification list <bucket> |
1002 | 1005 |
|
1003 | | - List event notification rules for a bucket |
| 1006 | + List event notification rules for an R2 bucket |
1004 | 1007 |
|
1005 | 1008 | POSITIONALS |
1006 | 1009 | bucket The name of the R2 bucket to get event notification rules for [string] [required] |
@@ -1869,6 +1872,240 @@ binding = \\"testBucket\\"" |
1869 | 1872 | }); |
1870 | 1873 | }); |
1871 | 1874 | }); |
| 1875 | + describe("lifecycle", () => { |
| 1876 | + const { setIsTTY } = useMockIsTTY(); |
| 1877 | + mockAccountId(); |
| 1878 | + mockApiToken(); |
| 1879 | + describe("list", () => { |
| 1880 | + it("should list lifecycle rules when they exist", async () => { |
| 1881 | + const bucketName = "my-bucket"; |
| 1882 | + const lifecycleRules = [ |
| 1883 | + { |
| 1884 | + id: "rule-1", |
| 1885 | + enabled: true, |
| 1886 | + conditions: { prefix: "images/" }, |
| 1887 | + deleteObjectsTransition: { |
| 1888 | + condition: { |
| 1889 | + type: "Age", |
| 1890 | + maxAge: 2592000, |
| 1891 | + }, |
| 1892 | + }, |
| 1893 | + }, |
| 1894 | + ]; |
| 1895 | + msw.use( |
| 1896 | + http.get( |
| 1897 | + "*/accounts/:accountId/r2/buckets/:bucketName/lifecycle", |
| 1898 | + async ({ params }) => { |
| 1899 | + const { accountId, bucketName: bucketParam } = params; |
| 1900 | + expect(accountId).toEqual("some-account-id"); |
| 1901 | + expect(bucketParam).toEqual(bucketName); |
| 1902 | + return HttpResponse.json( |
| 1903 | + createFetchResult({ |
| 1904 | + rules: lifecycleRules, |
| 1905 | + }) |
| 1906 | + ); |
| 1907 | + }, |
| 1908 | + { once: true } |
| 1909 | + ) |
| 1910 | + ); |
| 1911 | + await runWrangler(`r2 bucket lifecycle list ${bucketName}`); |
| 1912 | + expect(std.out).toMatchInlineSnapshot(` |
| 1913 | + "Listing lifecycle rules for bucket 'my-bucket'... |
| 1914 | + id: rule-1 |
| 1915 | + enabled: Yes |
| 1916 | + prefix: images/ |
| 1917 | + action: Expire objects after 30 days" |
| 1918 | + `); |
| 1919 | + }); |
| 1920 | + }); |
| 1921 | + describe("add", () => { |
| 1922 | + it("it should add a lifecycle rule using command-line arguments", async () => { |
| 1923 | + const bucketName = "my-bucket"; |
| 1924 | + const ruleId = "my-rule"; |
| 1925 | + const prefix = "images/"; |
| 1926 | + const conditionType = "Age"; |
| 1927 | + const conditionValue = "30"; |
| 1928 | + |
| 1929 | + msw.use( |
| 1930 | + http.get( |
| 1931 | + "*/accounts/:accountId/r2/buckets/:bucketName/lifecycle", |
| 1932 | + async ({ params }) => { |
| 1933 | + const { accountId, bucketName: bucketParam } = params; |
| 1934 | + expect(accountId).toEqual("some-account-id"); |
| 1935 | + expect(bucketParam).toEqual(bucketName); |
| 1936 | + return HttpResponse.json( |
| 1937 | + createFetchResult({ |
| 1938 | + rules: [], |
| 1939 | + }) |
| 1940 | + ); |
| 1941 | + }, |
| 1942 | + { once: true } |
| 1943 | + ), |
| 1944 | + http.put( |
| 1945 | + "*/accounts/:accountId/r2/buckets/:bucketName/lifecycle", |
| 1946 | + async ({ request, params }) => { |
| 1947 | + const { accountId, bucketName: bucketParam } = params; |
| 1948 | + expect(accountId).toEqual("some-account-id"); |
| 1949 | + expect(bucketName).toEqual(bucketParam); |
| 1950 | + const requestBody = await request.json(); |
| 1951 | + expect(requestBody).toEqual({ |
| 1952 | + rules: [ |
| 1953 | + { |
| 1954 | + id: ruleId, |
| 1955 | + enabled: true, |
| 1956 | + conditions: { prefix: prefix }, |
| 1957 | + deleteObjectsTransition: { |
| 1958 | + condition: { |
| 1959 | + type: conditionType, |
| 1960 | + maxAge: 2592000, |
| 1961 | + }, |
| 1962 | + }, |
| 1963 | + }, |
| 1964 | + ], |
| 1965 | + }); |
| 1966 | + return HttpResponse.json(createFetchResult({})); |
| 1967 | + }, |
| 1968 | + { once: true } |
| 1969 | + ) |
| 1970 | + ); |
| 1971 | + await runWrangler( |
| 1972 | + `r2 bucket lifecycle add ${bucketName} --id ${ruleId} --prefix ${prefix} --expire-days ${conditionValue}` |
| 1973 | + ); |
| 1974 | + expect(std.out).toMatchInlineSnapshot(` |
| 1975 | + "Adding lifecycle rule 'my-rule' to bucket 'my-bucket'... |
| 1976 | + ✨ Added lifecycle rule 'my-rule' to bucket 'my-bucket'." |
| 1977 | + `); |
| 1978 | + }); |
| 1979 | + }); |
| 1980 | + describe("remove", () => { |
| 1981 | + it("should remove a lifecycle rule as expected", async () => { |
| 1982 | + const bucketName = "my-bucket"; |
| 1983 | + const ruleId = "my-rule"; |
| 1984 | + const lifecycleRules = { |
| 1985 | + rules: [ |
| 1986 | + { |
| 1987 | + id: ruleId, |
| 1988 | + enabled: true, |
| 1989 | + conditions: {}, |
| 1990 | + }, |
| 1991 | + ], |
| 1992 | + }; |
| 1993 | + msw.use( |
| 1994 | + http.get( |
| 1995 | + "*/accounts/:accountId/r2/buckets/:bucketName/lifecycle", |
| 1996 | + async ({ params }) => { |
| 1997 | + const { accountId, bucketName: bucketParam } = params; |
| 1998 | + expect(accountId).toEqual("some-account-id"); |
| 1999 | + expect(bucketParam).toEqual(bucketName); |
| 2000 | + return HttpResponse.json(createFetchResult(lifecycleRules)); |
| 2001 | + }, |
| 2002 | + { once: true } |
| 2003 | + ), |
| 2004 | + http.put( |
| 2005 | + "*/accounts/:accountId/r2/buckets/:bucketName/lifecycle", |
| 2006 | + async ({ request, params }) => { |
| 2007 | + const { accountId, bucketName: bucketParam } = params; |
| 2008 | + expect(accountId).toEqual("some-account-id"); |
| 2009 | + expect(bucketName).toEqual(bucketParam); |
| 2010 | + const requestBody = await request.json(); |
| 2011 | + expect(requestBody).toEqual({ |
| 2012 | + rules: [], |
| 2013 | + }); |
| 2014 | + return HttpResponse.json(createFetchResult({})); |
| 2015 | + }, |
| 2016 | + { once: true } |
| 2017 | + ) |
| 2018 | + ); |
| 2019 | + await runWrangler( |
| 2020 | + `r2 bucket lifecycle remove ${bucketName} --id ${ruleId}` |
| 2021 | + ); |
| 2022 | + expect(std.out).toMatchInlineSnapshot(` |
| 2023 | + "Removing lifecycle rule 'my-rule' from bucket 'my-bucket'... |
| 2024 | + Lifecycle rule 'my-rule' removed from bucket 'my-bucket'." |
| 2025 | + `); |
| 2026 | + }); |
| 2027 | + it("should handle removing non-existant rule ID as expected", async () => { |
| 2028 | + const bucketName = "my-bucket"; |
| 2029 | + const ruleId = "my-rule"; |
| 2030 | + const lifecycleRules = { |
| 2031 | + rules: [], |
| 2032 | + }; |
| 2033 | + msw.use( |
| 2034 | + http.get( |
| 2035 | + "*/accounts/:accountId/r2/buckets/:bucketName/lifecycle", |
| 2036 | + async ({ params }) => { |
| 2037 | + const { accountId, bucketName: bucketParam } = params; |
| 2038 | + expect(accountId).toEqual("some-account-id"); |
| 2039 | + expect(bucketParam).toEqual(bucketName); |
| 2040 | + return HttpResponse.json(createFetchResult(lifecycleRules)); |
| 2041 | + }, |
| 2042 | + { once: true } |
| 2043 | + ) |
| 2044 | + ); |
| 2045 | + await expect(() => |
| 2046 | + runWrangler( |
| 2047 | + `r2 bucket lifecycle remove ${bucketName} --id ${ruleId}` |
| 2048 | + ) |
| 2049 | + ).rejects.toThrowErrorMatchingInlineSnapshot( |
| 2050 | + "[Error: Lifecycle rule with ID 'my-rule' not found in configuration for 'my-bucket'.]" |
| 2051 | + ); |
| 2052 | + }); |
| 2053 | + }); |
| 2054 | + describe("set", () => { |
| 2055 | + it("should set lifecycle configuration from a JSON file", async () => { |
| 2056 | + const bucketName = "my-bucket"; |
| 2057 | + const filePath = "lifecycle-configuration.json"; |
| 2058 | + const lifecycleRules = { |
| 2059 | + rules: [ |
| 2060 | + { |
| 2061 | + id: "rule-1", |
| 2062 | + enabled: true, |
| 2063 | + conditions: {}, |
| 2064 | + deleteObjectsTransition: { |
| 2065 | + condition: { |
| 2066 | + type: "Age", |
| 2067 | + maxAge: 2592000, |
| 2068 | + }, |
| 2069 | + }, |
| 2070 | + }, |
| 2071 | + ], |
| 2072 | + }; |
| 2073 | + |
| 2074 | + writeFileSync(filePath, JSON.stringify(lifecycleRules)); |
| 2075 | + |
| 2076 | + setIsTTY(true); |
| 2077 | + mockConfirm({ |
| 2078 | + text: `Are you sure you want to overwrite all existing lifecycle rules for bucket '${bucketName}'?`, |
| 2079 | + result: true, |
| 2080 | + }); |
| 2081 | + |
| 2082 | + msw.use( |
| 2083 | + http.put( |
| 2084 | + "*/accounts/:accountId/r2/buckets/:bucketName/lifecycle", |
| 2085 | + async ({ request, params }) => { |
| 2086 | + const { accountId, bucketName: bucketParam } = params; |
| 2087 | + expect(accountId).toEqual("some-account-id"); |
| 2088 | + expect(bucketName).toEqual(bucketParam); |
| 2089 | + const requestBody = await request.json(); |
| 2090 | + expect(requestBody).toEqual({ |
| 2091 | + ...lifecycleRules, |
| 2092 | + }); |
| 2093 | + return HttpResponse.json(createFetchResult({})); |
| 2094 | + }, |
| 2095 | + { once: true } |
| 2096 | + ) |
| 2097 | + ); |
| 2098 | + |
| 2099 | + await runWrangler( |
| 2100 | + `r2 bucket lifecycle set ${bucketName} --file ${filePath}` |
| 2101 | + ); |
| 2102 | + expect(std.out).toMatchInlineSnapshot(` |
| 2103 | + "Setting lifecycle configuration (1 rules) for bucket 'my-bucket'... |
| 2104 | + ✨ Set lifecycle configuration for bucket 'my-bucket'." |
| 2105 | + `); |
| 2106 | + }); |
| 2107 | + }); |
| 2108 | + }); |
1872 | 2109 | }); |
1873 | 2110 |
|
1874 | 2111 | describe("r2 object", () => { |
|
0 commit comments