1
+ #include " nix/store/filetransfer.hh"
2
+ #include " nix/store/config.hh"
3
+ #include " nix/store/http-binary-cache-store.hh"
4
+ #include " nix/store/s3-binary-cache-store.hh"
5
+ #include " nix/store/store-api.hh"
6
+ #include " nix/util/types.hh"
7
+
8
+ #if NIX_WITH_S3_SUPPORT
9
+
10
+ # include < gtest/gtest.h>
11
+ # include < gmock/gmock.h>
12
+
13
+ namespace nix {
14
+
15
+ class S3FileTransferTest : public ::testing::Test
16
+ {
17
+ protected:
18
+ void SetUp () override
19
+ {
20
+ // Clean environment for predictable tests
21
+ unsetenv (" AWS_ACCESS_KEY_ID" );
22
+ unsetenv (" AWS_SECRET_ACCESS_KEY" );
23
+ unsetenv (" AWS_SESSION_TOKEN" );
24
+ unsetenv (" AWS_PROFILE" );
25
+ }
26
+ };
27
+
28
+ // Note: Basic S3 URL parsing tests are covered by ParsedS3URL tests in s3.cc
29
+ // These tests focus on FileTransfer-specific S3 functionality
30
+
31
+ TEST_F (S3FileTransferTest, s3RequestWithMockCredentials)
32
+ {
33
+ // Set up mock credentials for testing
34
+ setenv (" AWS_ACCESS_KEY_ID" , " AKIAIOSFODNN7EXAMPLE" , 1 );
35
+ setenv (" AWS_SECRET_ACCESS_KEY" , " wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" , 1 );
36
+
37
+ std::string s3Uri = " s3://test-bucket/test-key.txt?region=us-east-1" ;
38
+ FileTransferRequest request (s3Uri);
39
+
40
+ // Test that request setup works with credentials
41
+ EXPECT_TRUE (hasPrefix (request.uri , " s3://" ));
42
+
43
+ // Clean up
44
+ unsetenv (" AWS_ACCESS_KEY_ID" );
45
+ unsetenv (" AWS_SECRET_ACCESS_KEY" );
46
+ }
47
+
48
+ TEST_F (S3FileTransferTest, s3RequestWithSessionToken)
49
+ {
50
+ // Test session token handling
51
+ setenv (" AWS_ACCESS_KEY_ID" , " ASIAIOSFODNN7EXAMPLE" , 1 );
52
+ setenv (" AWS_SECRET_ACCESS_KEY" , " wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" , 1 );
53
+ setenv (" AWS_SESSION_TOKEN" , " AQoDYXdzEJr1K...example-session-token" , 1 );
54
+
55
+ std::string s3Uri = " s3://test-bucket/test-key.txt" ;
56
+ FileTransferRequest request (s3Uri);
57
+
58
+ EXPECT_TRUE (hasPrefix (request.uri , " s3://" ));
59
+
60
+ // Clean up
61
+ unsetenv (" AWS_ACCESS_KEY_ID" );
62
+ unsetenv (" AWS_SECRET_ACCESS_KEY" );
63
+ unsetenv (" AWS_SESSION_TOKEN" );
64
+ }
65
+
66
+ /* *
67
+ * Regression test for commit 7a2f2891e
68
+ * Test that S3 store URLs are properly recognized and handled
69
+ */
70
+ TEST_F (S3FileTransferTest, s3StoreRegistration)
71
+ {
72
+ // Test that S3 URI scheme is in the supported schemes (now in S3BinaryCacheStoreConfig)
73
+ auto s3Schemes = S3BinaryCacheStoreConfig::uriSchemes ();
74
+ EXPECT_TRUE (s3Schemes.count (" s3" ) > 0 ) << " S3 scheme should be in S3BinaryCacheStoreConfig URI schemes" ;
75
+
76
+ // Verify that HttpBinaryCacheStoreConfig does NOT include S3
77
+ auto httpSchemes = HttpBinaryCacheStoreConfig::uriSchemes ();
78
+ EXPECT_FALSE (httpSchemes.count (" s3" ) > 0 ) << " S3 scheme should NOT be in HttpBinaryCacheStoreConfig URI schemes" ;
79
+
80
+ // Test that S3 store can be opened without error
81
+ try {
82
+ auto storeUrl = " s3://test-bucket" ;
83
+ auto parsedUrl = parseURL (storeUrl);
84
+ EXPECT_EQ (parsedUrl.scheme , " s3" );
85
+
86
+ // Verify that S3BinaryCacheStoreConfig accepts S3 URLs
87
+ S3BinaryCacheStoreConfig config (" s3" , " test-bucket" , {});
88
+ EXPECT_EQ (config.cacheUri .scheme , " s3" );
89
+ EXPECT_EQ (config.cacheUri .authority ->host , " test-bucket" );
90
+ } catch (const std::exception & e) {
91
+ FAIL () << " Should be able to create S3 store config: " << e.what ();
92
+ }
93
+ }
94
+
95
+ /* *
96
+ * Regression test for commit c0164e087
97
+ * Test that S3 uploads are not rejected with "not supported" error
98
+ */
99
+ TEST_F (S3FileTransferTest, s3UploadsNotRejected)
100
+ {
101
+ auto ft = makeFileTransfer ();
102
+
103
+ // Create a mock upload request
104
+ FileTransferRequest uploadReq (" s3://test-bucket/test-file" );
105
+ uploadReq.data = std::string (" test data" );
106
+
107
+ // This should not throw "uploading to 's3://...' is not supported"
108
+ // We're testing that S3 uploads aren't immediately rejected
109
+ bool gotNotSupportedError = false ;
110
+ try {
111
+ ft->upload (uploadReq);
112
+ } catch (const Error & e) {
113
+ std::string msg = e.what ();
114
+ if (msg.find (" is not supported" ) != std::string::npos) {
115
+ gotNotSupportedError = true ;
116
+ }
117
+ } catch (...) {
118
+ // Other errors are expected (no credentials, network issues, etc.)
119
+ }
120
+
121
+ EXPECT_FALSE (gotNotSupportedError) << " S3 uploads should not be rejected with 'not supported' error" ;
122
+ }
123
+
124
+ /* *
125
+ * Regression test for commit e618ac7e0
126
+ * Test that S3 URLs with region query parameters are handled correctly
127
+ */
128
+ TEST_F (S3FileTransferTest, s3RegionQueryParameters)
129
+ {
130
+ // Test that query parameters are preserved in S3 URLs
131
+ StringMap params;
132
+ params[" region" ] = " us-west-2" ;
133
+
134
+ S3BinaryCacheStoreConfig config (" s3" , " test-bucket" , params);
135
+
136
+ // For S3 stores, query parameters should be preserved
137
+ EXPECT_FALSE (config.cacheUri .query .empty ()) << " S3 store should preserve query parameters" ;
138
+ EXPECT_EQ (config.cacheUri .query [" region" ], " us-west-2" ) << " Region parameter should be preserved" ;
139
+
140
+ // Test with different regions
141
+ StringMap params2;
142
+ params2[" region" ] = " eu-central-1" ;
143
+
144
+ S3BinaryCacheStoreConfig config2 (" s3" , " another-bucket" , params2);
145
+ EXPECT_EQ (config2.cacheUri .query [" region" ], " eu-central-1" ) << " Different region parameter should be preserved" ;
146
+ }
147
+
148
+ } // namespace nix
149
+
150
+ #endif // NIX_WITH_S3_SUPPORT
0 commit comments