Compare commits
2096 Commits
v2.5.0
...
v3.0-beta2
| Author | SHA1 | Date | |
|---|---|---|---|
| 43ebc172cb | |||
| 892e79a982 | |||
| 542e080f0a | |||
| f35eb0f148 | |||
| c764e7fd97 | |||
| 1c97f10d8a | |||
| d8499e6941 | |||
| 105a678d64 | |||
| a12de09533 | |||
| 431a610f00 | |||
| 6e6ebc5947 | |||
| b30b78e442 | |||
| cab859a0e4 | |||
| a2c6469d41 | |||
| 55d95f9009 | |||
| ab1048b7ee | |||
| 38a10f8be4 | |||
| f165ba6480 | |||
| bcc875a39c | |||
| 2f2029a5c1 | |||
| 8dd509c31b | |||
| 171f6422b1 | |||
| 5e6c3f314c | |||
| efc97d177a | |||
| 601e90f5fe | |||
| decede394a | |||
| eb850ddd36 | |||
| 2bf305b177 | |||
| d3a4b7a799 | |||
| b85b5e00d4 | |||
| 45b90972dc | |||
| 4a807b6373 | |||
| 6ed9164c9d | |||
| 7180d6aa07 | |||
| 9d6445d4ce | |||
| 953f9da3b5 | |||
| 97b304abc9 | |||
| 49a1d4417d | |||
| 8451de8752 | |||
| 32bed83a17 | |||
| 92edce8fa1 | |||
| 545d3208c8 | |||
| b745726462 | |||
| 3dbfd49414 | |||
| 2ee9376df2 | |||
| aa62c2eff6 | |||
| 04d142cd62 | |||
| 2f3627e74b | |||
| d545902acc | |||
| 4871a8f43e | |||
| 32c8f495ab | |||
| 0c21d2c047 | |||
| 0964a06ab5 | |||
| 3e50ee6193 | |||
| da98f47502 | |||
| 036f407d6a | |||
| 2c60dbd4fb | |||
| b12ca1da88 | |||
| d4ada51fad | |||
| ef89dabb61 | |||
| 9be1ffd633 | |||
| f0ae6a0bb1 | |||
| 1e44ee9e9b | |||
| b3bda2aa64 | |||
| 82ad5a632d | |||
| 21213a2587 | |||
| 776af45c09 | |||
| 70b66382eb | |||
| 14326b626e | |||
| 1dabd68327 | |||
| f27ce7e1e4 | |||
| 91c5515d5b | |||
| 6ab1937ff5 | |||
| 576a490435 | |||
| 0afa545b06 | |||
| 937cefe824 | |||
| 896605f838 | |||
| 250e98837f | |||
| 2cb3505dce | |||
| 73f11fae2e | |||
| 4ced5bbbc0 | |||
| 4421fda877 | |||
| 5407052e0c | |||
| 90c7943242 | |||
| 70d536c6c4 | |||
| 319b934967 | |||
| 61017fc204 | |||
| 1ff90b713f | |||
| 7045d06221 | |||
| 05cc370c55 | |||
| 963e202745 | |||
| 82b1a11820 | |||
| 694c6e8fd2 | |||
| 45186255cf | |||
| a531a1709e | |||
| f85a3ad44d | |||
| ee7afcbe9e | |||
| b3b63f836a | |||
| c2ef2ef287 | |||
| e65fd45c65 | |||
| 32a1d1445c | |||
| 35c853e906 | |||
| 481139772b | |||
| 5dfac9a765 | |||
| ee92fee212 | |||
| b06d809364 | |||
| f8fb97d912 | |||
| 5f2f4a0897 | |||
| b7d198793f | |||
| 991b6eafca | |||
| 5b75eea8cf | |||
| ba48f40d21 | |||
| 6fafc8dba1 | |||
| 53312852e9 | |||
| 2d59112c1b | |||
| 637db29fad | |||
| 87aca5bf1b | |||
| 585503f9fb | |||
| 19e07a610a | |||
| 4058c85e2a | |||
| b3c073ab6c | |||
| 6a42b95d39 | |||
| 30b2a7169f | |||
| cb49e11eca | |||
| 5b5cf9f006 | |||
| 2bf94d8db4 | |||
| 7366cef1fe | |||
| 1854381456 | |||
| 8dee54bf5d | |||
| bbc4c361bb | |||
| 83b7397398 | |||
| 04a887dafa | |||
| 4c5291f941 | |||
| b73d196c6b | |||
| d0564933a2 | |||
| 03f91e8d85 | |||
| c711fb67c8 | |||
| 7e6314dcac | |||
| 10df9dc8c3 | |||
| 4110c7ffb0 | |||
| 7f79024e6a | |||
| f6cbbe1e64 | |||
| 64312ceded | |||
| 98206ab49f | |||
| 56622ee2c6 | |||
| 65c0937741 | |||
| 8498bfd2c2 | |||
| 7403b94b9d | |||
| d40cc32393 | |||
| fc983f9751 | |||
| ae255a7adf | |||
| 90c6b04361 | |||
| 86a274a7ee | |||
| 530b6a5088 | |||
| 5e52aaac6f | |||
| 3ea441d1a0 | |||
| 14df3c6249 | |||
| 7f8643efde | |||
| 273311eed2 | |||
| 5e431149cd | |||
| 7023dedc05 | |||
| 9e98c86ae1 | |||
| 071237d322 | |||
| 06468d6f43 | |||
| 4377e95c99 | |||
| f4feb38089 | |||
| 82232e2530 | |||
| 9c2809a1a4 | |||
| dd5b4a25d1 | |||
| 73e5c70d80 | |||
| 6d36641080 | |||
| 662dbaf8b2 | |||
| e63ff1c762 | |||
| 084ad69c53 | |||
| 1ccde201be | |||
| 48a721e259 | |||
| 4c7f638f3c | |||
| 35e53ee511 | |||
| b1881e5f54 | |||
| 3c39a935f8 | |||
| 2b0499c968 | |||
| 504d800a0d | |||
| 9d4fa87914 | |||
| 6016033b8b | |||
| 5af54c57ba | |||
| cb42cfc6af | |||
| 9ddf22ea93 | |||
| b2fe7e518f | |||
| 4fbe954a79 | |||
| 66621d762e | |||
| 9dd6aefcec | |||
| 749fd618a9 | |||
| 6bf05a8154 | |||
| a08809f8fe | |||
| 57ecb276c8 | |||
| 79a803ea8f | |||
| 0f6579801d | |||
| fcaf2bfdba | |||
| 4144f71e23 | |||
| 852ecd71f7 | |||
| aadc6e0bbd | |||
| a738945a88 | |||
| 9d3cbfe896 | |||
| 1a11f1e8c6 | |||
| a12f5376b5 | |||
| fd531e84fc | |||
| d26d7162a5 | |||
| a9cdf580a7 | |||
| 990acb3fd3 | |||
| 3486bf92eb | |||
| ed1864e076 | |||
| 0998ce81f3 | |||
| 99e068643b | |||
| 0d7eb18d7b | |||
| 81c11ebb53 | |||
| 2e73c58338 | |||
| 381a48f21d | |||
| a88176e060 | |||
| e06756bcab | |||
| 9c222a445f | |||
| 51bde36dee | |||
| e4c0c39fbf | |||
| 1abdd170d3 | |||
| dddd155afa | |||
| c411714546 | |||
| cba7c1726f | |||
| be8ec24106 | |||
| 0b3ccaff27 | |||
| b273cd1339 | |||
| 82eb32a71e | |||
| e905c2c6b5 | |||
| 13376d89cc | |||
| 2e1f26096f | |||
| 8f97e8d5ed | |||
| 92f20b9b7d | |||
| 3d5251d9a5 | |||
| 195be2742c | |||
| 2adc4d12be | |||
| 8d7b7009c3 | |||
| ca5a34ad1e | |||
| fbd94fc6ce | |||
| 953a07252a | |||
| f77bd59e1d | |||
| e371e03696 | |||
| 5b6754ce6c | |||
| 4aba3bc62b | |||
| fc6ad2059a | |||
| 69c8bb1eb3 | |||
| 0bf721a74c | |||
| c504abb84d | |||
| 2527289e3e | |||
| 581ffb862c | |||
| 8e70e9c1c3 | |||
| 4a3c19c666 | |||
| d575a5ce12 | |||
| 53dc145ce7 | |||
| 0398face05 | |||
| ef7d8ab90b | |||
| 28f4f3a8c8 | |||
| 3fb0b71822 | |||
| 40b2f00dc5 | |||
| 749da42ffc | |||
| 1f9f439acb | |||
| c5a817194a | |||
| c1e4d0590c | |||
| 85466c7ee1 | |||
| 43b474143c | |||
| 740478344b | |||
| 5094c1db2a | |||
| f5bb2b11e5 | |||
| 8da702c2e7 | |||
| d2b0bad1cf | |||
| ece8a925a6 | |||
| fc54c01f01 | |||
| 3fd420c901 | |||
| 01788e86e5 | |||
| 4f52bc138f | |||
| 2de439bd1e | |||
| b989e2ce37 | |||
| 25f08ddd39 | |||
| a16c799da9 | |||
| 0052e9d136 | |||
| b72cf90ed4 | |||
| 69013ef8ad | |||
| 16132e86a3 | |||
| 047191abf0 | |||
| 11372ac9ff | |||
| 336c1b7b6e | |||
| 2c5abed2f1 | |||
| 8c6890c95f | |||
| 60adcedebe | |||
| 95de5f6fe1 | |||
| 788aafff3c | |||
| c09d506245 | |||
| 18c5e90076 | |||
| fee0745e98 | |||
| 43073da7eb | |||
| 0b6fee138a | |||
| 78b9c3004a | |||
| c99aa74140 | |||
| 4fbff99186 | |||
| 8afd56575c | |||
| 1951f3856f | |||
| 8357cdf591 | |||
| 499bad5f53 | |||
| df2a23d1a7 | |||
| d6ecf74db4 | |||
| 6670e6cd29 | |||
| d8b11adfd5 | |||
| 4a5b753fd8 | |||
| d9231eb805 | |||
| bb1e7f62a0 | |||
| e5ffb2bfd2 | |||
| 6fff0b3e2a | |||
| f0d1853a66 | |||
| 7224728ab8 | |||
| ca7c3cc27d | |||
| ac439d83fe | |||
| c0b92eb5d0 | |||
| 5599bdf1bc | |||
| de41536046 | |||
| 30d321998c | |||
| 59a02ce76a | |||
| 2c396d4922 | |||
| 3191678b14 | |||
| 7ecf057901 | |||
| 091726b374 | |||
| dfaa6d8eb9 | |||
| aff4bf8f6c | |||
| ba1e1532ac | |||
| ae3bda81c5 | |||
| 0ec747630d | |||
| 945131ccab | |||
| f11b4cb481 | |||
| 92c6025390 | |||
| 138c738db9 | |||
| 4fae1958fa | |||
| fb450385d7 | |||
| 7b1d827460 | |||
| 74ebc2d3b0 | |||
| 95f3e52064 | |||
| da2b65cd7c | |||
| 2fcb8b849e | |||
| d7a72e30c0 | |||
| f397d0ddd7 | |||
| db98632078 | |||
| 1509b4cb6e | |||
| f20f4d130b | |||
| 3af4b1ff98 | |||
| f80c2406a8 | |||
| 17006b4539 | |||
| e5d400ebb9 | |||
| f824004e4f | |||
| 453eebbac8 | |||
| 1a39d93b4e | |||
| 6fac471415 | |||
| 252568c91b | |||
| 8e11f8dc21 | |||
| 2475ca8f9a | |||
| 2a18430a45 | |||
| dc4743a392 | |||
| 0cb57f52de | |||
| d2aaa2211e | |||
| f4666df7da | |||
| 4cd4ce504d | |||
| fadfa7cc42 | |||
| b912edbbef | |||
| a6c6b00d7e | |||
| 2a557f67d2 | |||
| 1a6af064b0 | |||
| 7ef62d28a5 | |||
| b8fb8cdce6 | |||
| 135679096b | |||
| 1ff428087e | |||
| f6c5242a93 | |||
| 3d2d8f2d86 | |||
| aef8dab4d9 | |||
| bcb7eff6fa | |||
| e16f45e494 | |||
| 435d0f22f5 | |||
| dc2738afad | |||
| 08a45e9a3b | |||
| 02221c993e | |||
| 9c8d508247 | |||
| 8f42bec270 | |||
| 00c70307ad | |||
| 883435336c | |||
| 2c8e35a933 | |||
| 660d3fa1e9 | |||
| 7df18678a4 | |||
| 260c731f6b | |||
| 00b1908f3c | |||
| 1ef332e82c | |||
| cf926134ef | |||
| e73e7aea56 | |||
| a72d73294c | |||
| 0f546a4692 | |||
| dd7e215e78 | |||
| fcd75422d5 | |||
| ad6837ee47 | |||
| 01d5bc73cc | |||
| f3b915c43a | |||
| 73a49c463d | |||
| d86cb92a94 | |||
| 09c29cdda5 | |||
| 67dec6a665 | |||
| b673bc1386 | |||
| 4b08f3909d | |||
| 35fc5007c8 | |||
| ac499b3aff | |||
| 31c317f5f7 | |||
| a6623357ad | |||
| c6a1076e3a | |||
| d318c84434 | |||
| c21a210198 | |||
| fc877ae0f4 | |||
| 1049824014 | |||
| 1d8222ef6a | |||
| ee635be441 | |||
| 01d3282838 | |||
| 35a502f309 | |||
| 662579e9a9 | |||
| 00dd0e8a9d | |||
| 430c312263 | |||
| 8ed8bfb8bc | |||
| 0939371e2e | |||
| f2dabd0731 | |||
| e7ef79e0d3 | |||
| ffda5bc0f7 | |||
| 737896695c | |||
| ae69244ac7 | |||
| 8232552152 | |||
| f7b481fc28 | |||
| 8bc1af9d1a | |||
| fd1a0edf7f | |||
| 4c83dba183 | |||
| b641720575 | |||
| 950455bd93 | |||
| eb79436ab7 | |||
| 10db47bf4c | |||
| 4d454f8914 | |||
| eb4a46b40f | |||
| 7df326083d | |||
| 48f5a61564 | |||
| 19f0f7535f | |||
| e3e0b72b43 | |||
| 3435df8b9c | |||
| 7e12460303 | |||
| 9d3d0912e5 | |||
| 1ed4f64e60 | |||
| 8b64b2113e | |||
| 5bf2b6c382 | |||
| fa0b06ac60 | |||
| ef22a87fcf | |||
| bfce379471 | |||
| 4872f6d2dc | |||
| 3c30870dc2 | |||
| 4317e4c4a2 | |||
| 7da57e0aa5 | |||
| 0da4168836 | |||
| df67d57bca | |||
| 82e7f1a212 | |||
| 289521b4b7 | |||
| d557beb5f1 | |||
| 2cf1193b56 | |||
| 57315f1e27 | |||
| 56bef637bd | |||
| d1bac6cde0 | |||
| 23a136d9ef | |||
| d8f7bce9d4 | |||
| 39354249e9 | |||
| 98e756e278 | |||
| 91ca5b6f2a | |||
| b6ac0860c6 | |||
| 00dc078311 | |||
| 2d9a2506b4 | |||
| fa73b1ce80 | |||
| f4b97979c4 | |||
| 62b21c586d | |||
| 606c75162f | |||
| a8c10dbc08 | |||
| c6768a93c8 | |||
| 74949d306f | |||
| 77f93886da | |||
| 8f5a7f1764 | |||
| f78f7d6b37 | |||
| 75541b9cf0 | |||
| 922b7c44ce | |||
| 8bc63e9029 | |||
| 2647f59df1 | |||
| 77f6449db9 | |||
| f3ad71d751 | |||
| 2db62a211a | |||
| 4e6c1335d5 | |||
| f185528f1c | |||
| 2b668e628a | |||
| 0688d7ca9f | |||
| 0135dff001 | |||
| efe25db40f | |||
| 773a5631c5 | |||
| 5d5f5cd9a6 | |||
| ad9b2ab617 | |||
| cb8b038795 | |||
| 078e69d06d | |||
| df8e56ddf8 | |||
| f44d6e063c | |||
| 113509a4e9 | |||
| 839c675cb9 | |||
| 854c360def | |||
| 0cbb95ed1e | |||
| d8929b1d3e | |||
| fa99a6745d | |||
| b79217be1e | |||
| d27a0f5b0c | |||
| 97c27668bc | |||
| e5970e83ff | |||
| d3c022f89e | |||
| 3624587f08 | |||
| 56c080417a | |||
| da4e3784e9 | |||
| 35f7a71f9a | |||
| bf22b4cbfe | |||
| 4741152f05 | |||
| fb33cf4576 | |||
| 1fb38abf6b | |||
| 4299feee37 | |||
| 86b1906798 | |||
| 18a0a85df6 | |||
| 05ba32b552 | |||
| c30c12d369 | |||
| 09dfaf9875 | |||
| ae604b6289 | |||
| fc8146b53d | |||
| 641845519d | |||
| b32809d03f | |||
| 02b2c7482a | |||
| 6fd0d5e267 | |||
| a4ecacb9b5 | |||
| b9e0fcdf85 | |||
| 4ef79d250d | |||
| 18c57ea230 | |||
| a883424d25 | |||
| 7fa170cee9 | |||
| 8925329950 | |||
| 4aa5dab62d | |||
| 936dd2eaaa | |||
| 09e80f0390 | |||
| 63dfa303e5 | |||
| 599b1eb689 | |||
| 4a636b6da7 | |||
| d92172f50c | |||
| 2623240635 | |||
| 908e8577bb | |||
| f90fda8e6f | |||
| f4037667fa | |||
| a1fd12ef42 | |||
| 517721eaa4 | |||
| b56a2c14bb | |||
| 62d703fdf7 | |||
| f29899e566 | |||
| 9cebcc45c1 | |||
| 3125177e5c | |||
| 7810413699 | |||
| 261db14c4b | |||
| 16783bff16 | |||
| 352cdc137d | |||
| bd2e1ef67e | |||
| 7f970bbc7b | |||
| 35609fe3d1 | |||
| 4fcca7c61b | |||
| d55dc92502 | |||
| c148d89004 | |||
| 8e7a127792 | |||
| 6afe2c4e9f | |||
| be69e2c02c | |||
| e3be9f7fe9 | |||
| ca3cb07fcb | |||
| b98e5690eb | |||
| 45e6187c1a | |||
| c521182ceb | |||
| 83662b5195 | |||
| 8db7cf49a6 | |||
| 30f3b55baf | |||
| 8750ba94c8 | |||
| b5beac879e | |||
| e8b6995cc7 | |||
| 7ca8db15d9 | |||
| 9d96382ecc | |||
| b86b8965f1 | |||
| f6c49daaa6 | |||
| a129a6192a | |||
| 22ae259cf5 | |||
| e627820d3d | |||
| 65711f4bfe | |||
| 4531f39c30 | |||
| 3db1188444 | |||
| be3d38ac92 | |||
| b490bdfe33 | |||
| 95725e407e | |||
| f6457a2023 | |||
| 7dcb85010a | |||
| 0525bf5d4e | |||
| 7207068181 | |||
| 59d2fe8aa4 | |||
| be92c8bde1 | |||
| a3e22091be | |||
| 17b7dfb27b | |||
| 06173b9194 | |||
| 2a45e879bb | |||
| ce6c67f9bc | |||
| 87cb0c2aec | |||
| d0b191af18 | |||
| b607adadcf | |||
| e7828c1e5e | |||
| c051cb8be1 | |||
| 6f51fc34c3 | |||
| 02b02c51e8 | |||
| a414dd028c | |||
| c2439b04c9 | |||
| ed550a894f | |||
| 8b51f58fe7 | |||
| 310b0e888d | |||
| c189c20164 | |||
| 0811338370 | |||
| ecc22757b8 | |||
| 5e553e40fa | |||
| 26c5029256 | |||
| 75454b02c0 | |||
| bbc079e57b | |||
| 83bbffd491 | |||
| fc5e1d97af | |||
| 85041d297c | |||
| 17c7ce9b40 | |||
| 6506161107 | |||
| 590da0cab3 | |||
| 44b6a3a054 | |||
| a11396c901 | |||
| cd52c24e87 | |||
| 2e52008542 | |||
| a6a5f393cc | |||
| b3f2f0fa1e | |||
| f788c8cb37 | |||
| deaeec0bc7 | |||
| 16656af847 | |||
| 3b279983e6 | |||
| 55d4392d90 | |||
| acfc119409 | |||
| 18fcb23371 | |||
| 1ae2fc648d | |||
| 2215095be8 | |||
| 28d2966819 | |||
| 92efd17952 | |||
| 3a7ec2a26e | |||
| 56a05d78bd | |||
| fa5cf602f5 | |||
| c94659f552 | |||
| 1164510004 | |||
| f24867029c | |||
| 680ff95b8e | |||
| 31ea5f550f | |||
| fc62af6b3a | |||
| f8533e6641 | |||
| 87fec9d434 | |||
| b1e9327a2b | |||
| 0aa4b47d59 | |||
| b9d50fa144 | |||
| 3231d767d5 | |||
| 3f05b4bb1e | |||
| 9eabd956b7 | |||
| eb58414600 | |||
| cb83c237f4 | |||
| 773a13dc26 | |||
| 8c2f7ac083 | |||
| f375c3000d | |||
| ea4ce0ce1f | |||
| c9fe2bab60 | |||
| 6c617ba28c | |||
| b98c826e95 | |||
| 2034d4b971 | |||
| f225bb0032 | |||
| 69b87fdb9a | |||
| 6f70445654 | |||
| 145c14ed57 | |||
| b9843fe6d1 | |||
| ab9757082e | |||
| d6e4fb46cf | |||
| a93fe5b2b2 | |||
| 8f9c3c8381 | |||
| 363f36dfae | |||
| 7328f4d3fd | |||
| 8f3b6a23f6 | |||
| cc4fdd6d0c | |||
| 3781a099dd | |||
| e4d52b2851 | |||
| ac45ccbad7 | |||
| 1a412378db | |||
| 17904a6e8b | |||
| 9c47fdeb2f | |||
| 808ac2cefc | |||
| aaf6dd2cd6 | |||
| 08f7ccff38 | |||
| 13720759a5 | |||
| a2731da987 | |||
| a8e1572955 | |||
| 3ca8e8a6d2 | |||
| bf4a00b663 | |||
| 4ab041f79e | |||
| f3fe1a5320 | |||
| f808baafa7 | |||
| 1f28ff6890 | |||
| 640c9a49d8 | |||
| 5d51b439d2 | |||
| 9ae050f0e5 | |||
| c77f91213c | |||
| 0f7d6a780a | |||
| ab4957684f | |||
| 1dbaabffbc | |||
| d42bfc2570 | |||
| 9ed45ba761 | |||
| 9d893eec01 | |||
| 52241b8e0b | |||
| 701a2fdcf3 | |||
| 995f17493e | |||
| eb787adccd | |||
| 57e6e0092d | |||
| a685e46fb6 | |||
| 1144988443 | |||
| 27dc32e2e8 | |||
| 6721cec73f | |||
| 18bbefee1c | |||
| bd0357b637 | |||
| 49507ea377 | |||
| 2c0b191ef5 | |||
| 02ac7a4001 | |||
| fbe422008a | |||
| d0d21ba9a6 | |||
| c78669353f | |||
| afb62638a8 | |||
| 4a062b6d00 | |||
| 6590e6fae8 | |||
| ab7bbd5a44 | |||
| 317f2d043f | |||
| c21b353042 | |||
| a73ef353f0 | |||
| d769f6c084 | |||
| ed58474c37 | |||
| 4c3048964d | |||
| cacf14a41e | |||
| e24e34619a | |||
| ac1648c946 | |||
| 65f9cc986a | |||
| 252cd4901b | |||
| a2b69e96b9 | |||
| 3a0a8810d1 | |||
| b9c60125e8 | |||
| cae975cb39 | |||
| 2f2326006d | |||
| d183c11e69 | |||
| 653d4b1d6a | |||
| d1f6bbf32f | |||
| 22fac87473 | |||
| 3003a8cb6e | |||
| f4908b6315 | |||
| 63ca9f6f5a | |||
| b9059181fd | |||
| 25ca751ab8 | |||
| 08c1def8b7 | |||
| 71210dd624 | |||
| fee9df4c2b | |||
| 5d7d165be5 | |||
| b5d4a678d4 | |||
| 8193d50da7 | |||
| ffc9a8322b | |||
| f28eec8be3 | |||
| 807c052fea | |||
| 45e232ef62 | |||
| 9accb962aa | |||
| 4ab3542c88 | |||
| 5a67ca255f | |||
| c97dbf390e | |||
| 008a031493 | |||
| b05939ec9a | |||
| 84e50f9003 | |||
| 7c917156ee | |||
| 6a7e9134a5 | |||
| 86ef33f84f | |||
| 6f794b7d11 | |||
| febad7b1d7 | |||
| 48c5e26acd | |||
| 3f0679896b | |||
| 96e98f6d4c | |||
| b067317595 | |||
| 1febd578a4 | |||
| 4131d8b57a | |||
| 36f4f1d0f3 | |||
| 1cd3985913 | |||
| 058c905432 | |||
| 41b775561a | |||
| 0ee7ac2c5e | |||
| 3fd6ae597d | |||
| 14312d225c | |||
| 262a03667e | |||
| 422decde3b | |||
| 6fc2b69697 | |||
| 594ab0e2b5 | |||
| ea9ac0d2d2 | |||
| 9045be0c12 | |||
| bc4c71a7c6 | |||
| 18079aaced | |||
| 47644f2755 | |||
| 43b91ea0d6 | |||
| 83bf63641c | |||
| 1e891f434d | |||
| 746257710b | |||
| 30ddfc7a28 | |||
| 5447bd007a | |||
| f8e233e400 | |||
| 9c50b89d64 | |||
| 063b54aefe | |||
| c961d6218d | |||
| 1176b68c6a | |||
| 5adac86b43 | |||
| 580cd510d5 | |||
| d59beec354 | |||
| c11322a016 | |||
| fe4cdc59be | |||
| 35a1a04f50 | |||
| 6e7813f2f8 | |||
| 7c9728df47 | |||
| da8782a9d0 | |||
| d523d45124 | |||
| c4d6051477 | |||
| cd060c64d5 | |||
| f881ada45c | |||
| b9b3b75c0c | |||
| 37b031afcf | |||
| fcc3a7f6e4 | |||
| 5836a6ec4b | |||
| 9e0ed7bc8e | |||
| 50c79df70f | |||
| f888716d81 | |||
| 5274f93db7 | |||
| e32ee9f02e | |||
| 48c936e9a9 | |||
| b77bce1961 | |||
| f3d277cbab | |||
| afa4ee9a28 | |||
| 92f4442356 | |||
| 47b6f01c8b | |||
| 68225d64aa | |||
| fa06040ed2 | |||
| eae4bb74dd | |||
| caa765ec32 | |||
| e00f9611f4 | |||
| 1004515bda | |||
| 7d75e0e53c | |||
| f7e3297a0f | |||
| 14952de2ee | |||
| f98dbd249e | |||
| b369b7e495 | |||
| 23167a0bb3 | |||
| 8c1195b277 | |||
| 6cdc1e4d37 | |||
| e7a202fe4d | |||
| b5dc1727d2 | |||
| 53f5cb6553 | |||
| f797b19825 | |||
| 814ca99e3d | |||
| c483b2ff98 | |||
| 2496202417 | |||
| 3c6fadb6f8 | |||
| 055e5aff2a | |||
| 692878b0c0 | |||
| a6061ce555 | |||
| 2ea548850e | |||
| 87fc83678c | |||
| d8b43a3d76 | |||
| 6189208fa5 | |||
| daf8db71a8 | |||
| c186d8b2be | |||
| cd40362d47 | |||
| 81ad469533 | |||
| bb77070aab | |||
| c051ff3eac | |||
| ff913333a2 | |||
| ac5f7ecdea | |||
| 4e33e80957 | |||
| bf1b60564e | |||
| 50ddf7913a | |||
| 39bb9ce118 | |||
| 2d8180fc9c | |||
| fac51d92c5 | |||
| c3fc340c09 | |||
| 581fb8ebfd | |||
| 0fa0b3b256 | |||
| 3b21e9fcf0 | |||
| 4c35c83b84 | |||
| 37c6a1ddf0 | |||
| 9c0b89b9b0 | |||
| ae39ec8585 | |||
| e37817285a | |||
| dfe0e258cd | |||
| eda23252e1 | |||
| 257b824d4f | |||
| b469904c7f | |||
| 509b37eb91 | |||
| 9dac382fbf | |||
| ddbdb54c04 | |||
| 181a671bfb | |||
| 1ce34ed907 | |||
| f9e7b14f2c | |||
| dad394523f | |||
| 1c50eb345c | |||
| 5c7689388d | |||
| baff9b0267 | |||
| fe2e6b8a80 | |||
| fb74ebb4ea | |||
| 8784be9a14 | |||
| fba3d7cb0f | |||
| f953033ba7 | |||
| 72415be2db | |||
| 9653f43466 | |||
| 1acbd5b7d8 | |||
| f0ecbd3878 | |||
| 9dcfe6dc39 | |||
| 397e4e4766 | |||
| 5b9ed82d29 | |||
| 0def04ad34 | |||
| e9982bb27e | |||
| 18eb9d6076 | |||
| e7ff018487 | |||
| 6ba5471bd4 | |||
| ddb1d0c684 | |||
| 7d89cf228c | |||
| 5775c0a341 | |||
| d750908e36 | |||
| b1a648608b | |||
| b7147a8bd2 | |||
| 82d5d1b003 | |||
| f4e90df406 | |||
| 2cce057df1 | |||
| dea2234b14 | |||
| 99a053bbdd | |||
| b7fd6bcf7d | |||
| a3b6efdbfa | |||
| 3a1dff6636 | |||
| cf92011fb9 | |||
| 0106033293 | |||
| 4a43cc1df6 | |||
| 0f52b4397f | |||
| 9c0da733e8 | |||
| de90ad8967 | |||
| 2f3d1ec2ef | |||
| 73bed3880f | |||
| edebdb166e | |||
| 7f83be3d0d | |||
| 50920b1423 | |||
| 42b1c8c80d | |||
| a5d1e9ee43 | |||
| ff4dbea19d | |||
| 1bd58bc1c0 | |||
| 21b0945d08 | |||
| 89ef019b7c | |||
| 801129530e | |||
| 23fa5fa1c7 | |||
| 020277c045 | |||
| f8b3c0a64c | |||
| d03ae3bfe5 | |||
| 6f9896c2fe | |||
| 853cd16336 | |||
| 0fab210ad2 | |||
| 9fc0a83b83 | |||
| aa8bd044c5 | |||
| 0201b9769c | |||
| 4ff6748eb4 | |||
| 59cb429d2d | |||
| 454ccb451b | |||
| 273fbaac68 | |||
| 8ff997594f | |||
| 616a6bec38 | |||
| a6c736b8a2 | |||
| 5b02d63c89 | |||
| c1fc8995ce | |||
| 34f261588f | |||
| f188900379 | |||
| f80d5f8c03 | |||
| fcc960e9a2 | |||
| db27bbb162 | |||
| 1bce8f6669 | |||
| 15fb56e607 | |||
| 714129c8e3 | |||
| 59a384b453 | |||
| b5a5b7b912 | |||
| a167eb4fa1 | |||
| 660ce3a61d | |||
| edf5868c38 | |||
| 5588e7597c | |||
| 68a5fb66ff | |||
| 33dc9fdd76 | |||
| 316e1aac67 | |||
| 2ed3cd7f1a | |||
| 14cc771cbe | |||
| 2a8b96b680 | |||
| 6f923ecd17 | |||
| 501f21b16c | |||
| f4ad673b6d | |||
| 37ff432f9d | |||
| 20283a46f9 | |||
| 634699c8e2 | |||
| 7d97f381cf | |||
| 7a1326ff14 | |||
| ee84d4371b | |||
| f8b05e0f42 | |||
| a4e5b7ea37 | |||
| a20443b577 | |||
| e96d72d669 | |||
| defb15bea1 | |||
| 10016d9d38 | |||
| 73ec486434 | |||
| ccb063df06 | |||
| b90a078be0 | |||
| 80e15dd754 | |||
| de394311e0 | |||
| 908765e0e7 | |||
| c465e594d7 | |||
| 0da733de9c | |||
| 2fc8da7a87 | |||
| 0bea6aba63 | |||
| fe2c096166 | |||
| c90619c665 | |||
| 952e4dab3e | |||
| eecf844ca2 | |||
| 8952c7c9d1 | |||
| c6ab63ec47 | |||
| 05dfccbb74 | |||
| fc829b32d9 | |||
| f2700822e9 | |||
| 21f6c07686 | |||
| 4bafb88720 | |||
| 7c61ed99ae | |||
| 356f7b9db6 | |||
| 822c8f1575 | |||
| efdd4a6682 | |||
| eaaf9246b7 | |||
| 00a6efa15e | |||
| c5377fb429 | |||
| 0583ec0f93 | |||
| 12f487e223 | |||
| 30a8a434a1 | |||
| 79db997e8c | |||
| 137ef1f781 | |||
| 338afc80d5 | |||
| 78598df96e | |||
| e737dab5ca | |||
| 84609a4a3b | |||
| 0b25a29a9c | |||
| b1bfd35968 | |||
| a053552fee | |||
| 6886faa944 | |||
| c843637a6a | |||
| 2f78584cdb | |||
| 6b7491e111 | |||
| 2e20c680cb | |||
| f33de8e911 | |||
| fbc90e038c | |||
| bf943ddba3 | |||
| 3f945e886b | |||
| 931d7cd039 | |||
| 3f5b33b060 | |||
| fa63d26485 | |||
| d617d029d2 | |||
| 98082a940c | |||
| 12460af0ec | |||
| 34eb5acee7 | |||
| 9ec3216ab0 | |||
| 92c2f8d556 | |||
| eef506d8c4 | |||
| 7f15e2c167 | |||
| 03aea09ce9 | |||
| 2897f618a6 | |||
| 5f2aba6c5b | |||
| 21632d22ab | |||
| f59f6a5486 | |||
| 32989f4cca | |||
| b5ef793ae4 | |||
| d405176367 | |||
| 74cb4b6590 | |||
| 15087251fb | |||
| 73d6b95339 | |||
| c3032f7ba3 | |||
| 339e73ee3d | |||
| a2c00f1cc5 | |||
| 6da3f87736 | |||
| 6ae464f33a | |||
| 74decb4bdc | |||
| 2e9272c778 | |||
| 6fe850e2c1 | |||
| bb3360e92a | |||
| f46eee96a9 | |||
| 3ed8870362 | |||
| 605f0fa24a | |||
| 5a4e48fa99 | |||
| 79e7ae4424 | |||
| 35071649e0 | |||
| d27bb4d3fb | |||
| 64a18874e1 | |||
| 05e8c576a2 | |||
| ea7c2e73ad | |||
| b6f276265d | |||
| 3c3d3c9ec6 | |||
| d66932a8a2 | |||
| 34141363ae | |||
| 3ccf7c8006 | |||
| 56c76f380b | |||
| f36ade2959 | |||
| 85ad5f1d37 | |||
| 64fa9a6394 | |||
| a00231a1c2 | |||
| 9914714eeb | |||
| 600ffa727e | |||
| a7de2ceae4 | |||
| 972ac99b7c | |||
| 9bd3b417c4 | |||
| a985f21d44 | |||
| 7c005e8f0b | |||
| 6e886735a3 | |||
| b30dcce4bc | |||
| 58121d89fc | |||
| 6a1192172d | |||
| 8bd07287f8 | |||
| 753fd164d7 | |||
| 307c86fc28 | |||
| 72a64388b5 | |||
| 1210fca8e5 | |||
| 97ac81aa9c | |||
| c8727db03b | |||
| 57d22fb93f | |||
| f0f7da9ff0 | |||
| 6c4791b48d | |||
| 9c1217cd2c | |||
| 448437c342 | |||
| 251bf7a2b4 | |||
| f1efce56aa | |||
| 34b82caaa8 | |||
| a1b5aae958 | |||
| 70c42ddcff | |||
| 75ab2e026d | |||
| f43e1ab2ff | |||
| 12dfee544f | |||
| 0ea651f1df | |||
| 8ed9e2e5cc | |||
| a352af5b9f | |||
| 51a32a2bfa | |||
| e6013353d2 | |||
| aac190eaa9 | |||
| ebba7a0327 | |||
| 13d993a836 | |||
| f384538959 | |||
| 269583a6a1 | |||
| 0b05d39804 | |||
| 2ca7da06a3 | |||
| 4b59cee17a | |||
| bf817281a5 | |||
| 98982b7a74 | |||
| 2114cbcf0b | |||
| 979807feee | |||
| add7078f66 | |||
| ab4d020212 | |||
| aa251fc9ce | |||
| c105a07bab | |||
| 09de46e5ac | |||
| cc375f48c7 | |||
| e59b0c0694 | |||
| 07fee0a810 | |||
| 29185eeef7 | |||
| 53dc21c69b | |||
| b0dd79cbfd | |||
| 442db7fee1 | |||
| be2e2577b8 | |||
| c8c337cead | |||
| 92cba94031 | |||
| c30b1b126d | |||
| 52403ca17e | |||
| 05868bc1df | |||
| 092bb69c41 | |||
| 40d946a6e3 | |||
| 5f1fe13530 | |||
| d8bb7c3094 | |||
| 9c6698e87b | |||
| 1cac6ecedb | |||
| 40088cd4fe | |||
| b939a27a8d | |||
| 73af4df96d | |||
| 70cd9265bf | |||
| cd1b2e2841 | |||
| b0a24ae4aa | |||
| 11e35f7b68 | |||
| 8f4cf6c797 | |||
| 2190392e05 | |||
| a621c0d273 | |||
| 4c12703e0c | |||
| da67afa51e | |||
| 3e14f8a0e5 | |||
| a950ff9795 | |||
| 4132cf12e3 | |||
| 4f7fb40d9b | |||
| c7fae5386d | |||
| 42802ac710 | |||
| a85bda13db | |||
| ecdc730de7 | |||
| 8927042421 | |||
| 32f78d465b | |||
| ab3b586838 | |||
| 94a7e9b185 | |||
| 1a708da155 | |||
| f94599cd29 | |||
| d9d4e6c82f | |||
| 0796b2c0e3 | |||
| bbfdbaf952 | |||
| 7b4fe824ec | |||
| 28fabadeae | |||
| 37495dd1c6 | |||
| e5e8e2021f | |||
| dfd4fbc566 | |||
| 08f02397b6 | |||
| d3f90dcfcc | |||
| ba65b89bbb | |||
| 3d353c7d6d | |||
| bc05cc4977 | |||
| cbb5811d8b | |||
| 6461981aa4 | |||
| c260c319ee | |||
| d13957cb72 | |||
| 4a8f82ca9b | |||
| cdcc7a7172 | |||
| f2ce8f266b | |||
| dcde1422b7 | |||
| 423eca6e7d | |||
| fd52320460 | |||
| 462608517b | |||
| 9586493632 | |||
| b150452db3 | |||
| 1bca28ad12 | |||
| 9e121ef0c8 | |||
| 5f5fcc0e04 | |||
| a854f0c4d4 | |||
| 1979143e7c | |||
| 32ffedccda | |||
| 4f7f03a28c | |||
| d0074b25db | |||
| 8dd118bd86 | |||
| fb82425d3e | |||
| aa1d28835d | |||
| f30df8bb57 | |||
| 281ec60085 | |||
| 09f5e6f4dc | |||
| e26cd21048 | |||
| 1c5be92259 | |||
| 6e99eed417 | |||
| 92a085550e | |||
| c4a0ec844c | |||
| 3e3b996963 | |||
| 36e99ac531 | |||
| 7a26d309b1 | |||
| ca55d1f315 | |||
| 41fd0ed467 | |||
| bcb44b7b31 | |||
| 1ab1154010 | |||
| 6b85a6fd78 | |||
| 8f067a5ed2 | |||
| db1ba30df7 | |||
| 1952ebf7c4 | |||
| 70481953fd | |||
| 870775e863 | |||
| 54383a9a0c | |||
| 510a21195a | |||
| 3b5a583903 | |||
| a9e05c77d1 | |||
| 3418db1dcd | |||
| d94896cf10 | |||
| eb8871a4bd | |||
| 389dd12ab4 | |||
| 4a54edd8bb | |||
| 1d4803cff0 | |||
| 6fc972ab1e | |||
| 66eebd1ac3 | |||
| 568832c5af | |||
| 4ff7b0f49b | |||
| c12aa0e8ce | |||
| 61a655f199 | |||
| 88e9161e57 | |||
| 10adc57b3f | |||
| 62ae02bdd1 | |||
| dca503bcbd | |||
| bc21862661 | |||
| 1e06f3f5f4 | |||
| 00802d035a | |||
| edcef7d078 | |||
| 899a44a735 | |||
| 6a95963c89 | |||
| a35bf497be | |||
| 9b42b33648 | |||
| 053868f593 | |||
| 1adb7b286c | |||
| 30c19d525e | |||
| 8161a0943d | |||
| a8e3f731b7 | |||
| 0cb68b86fc | |||
| 723be4f612 | |||
| 070af40487 | |||
| 0a58404584 | |||
| c201f4c63e | |||
| 317b5e6d86 | |||
| 38ddc88b20 | |||
| 7ad72ba905 | |||
| 36e8af05a2 | |||
| 2bfded3c5f | |||
| 842a59535d | |||
| d4e1a715eb | |||
| 954c0e9fae | |||
| f6a3b53fb5 | |||
| 01d47fb280 | |||
| dfcb82d233 | |||
| 83346a29aa | |||
| 317c5ba88d | |||
| caa26f594e | |||
| aa9a92d2e0 | |||
| 4f227ae92e | |||
| cd0256d40d | |||
| 2ccc19185c | |||
| b4d595e561 | |||
| 88a132b878 | |||
| b5726a8d5a | |||
| b7f4a5c198 | |||
| 1d9ad9be33 | |||
| 2b7a26dabd | |||
| a233570777 | |||
| 6fae264222 | |||
| 8699d49f93 | |||
| c4ce3293a2 | |||
| dbafc8c9db | |||
| 6c6c3a5081 | |||
| d420cb38d1 | |||
| b55f8215ec | |||
| 08caf4bbde | |||
| 59c928acc2 | |||
| e38e8c740f | |||
| 4ceab4abc7 | |||
| 8ff48c126a | |||
| 6da3af5e89 | |||
| 77c362af8d | |||
| 2cf0dc2cb2 | |||
| bdb67d4909 | |||
| 4fe72ebf69 | |||
| 49fdf8427a | |||
| 534bc83173 | |||
| 87f6d7da11 | |||
| cdd341af64 | |||
| f70252f013 | |||
| ed989ecc8d | |||
| a147015e96 | |||
| 8cf7fb7f80 | |||
| c317149a08 | |||
| ff8b25a50a | |||
| afa539368f | |||
| dc427d5a2c | |||
| a87b5f757d | |||
| 4db57cc0bb | |||
| 44f0242157 | |||
| e5b3f27a30 | |||
| a15984b663 | |||
| f7fecdc6de | |||
| cabefa4fff | |||
| 1ec97e5199 | |||
| 458d15063d | |||
| e8786b0747 | |||
| d0bcd1d87c | |||
| c8bd9fd6cc | |||
| 4c59e48cc2 | |||
| 85a463faab | |||
| feca2871eb | |||
| 144c703c7b | |||
| ae6cae0771 | |||
| 2b99b64ec5 | |||
| ffe1407217 | |||
| 7d8519f5f0 | |||
| b79f04493d | |||
| 7e7d9457ea | |||
| 07fdf6491c | |||
| fb4bb7f53e | |||
| 1da1849de6 | |||
| 98dccb8641 | |||
| 8a38991270 | |||
| 2fe58461d5 | |||
| 16cd27282f | |||
| e081a5c5a0 | |||
| 0ea01f24a8 | |||
| 882980ada7 | |||
| 66f7a2be15 | |||
| 908b2d151f | |||
| d3bc52278d | |||
| 012d1378d4 | |||
| 4da31291d2 | |||
| c1e94e61d0 | |||
| ab79348af5 | |||
| d83e24572a | |||
| 1ffcea1952 | |||
| 35f40b7312 | |||
| b76449d151 | |||
| 15546dd84e | |||
| ca3405afc5 | |||
| 36ebfc747a | |||
| bc328cbed7 | |||
| 7ae81a2195 | |||
| cf98a16db0 | |||
| f813b4c58f | |||
| c5635f9c89 | |||
| d932653c7f | |||
| 39aca0f038 | |||
| 9943b9a226 | |||
| 3bb20dbf2e | |||
| 7a8b3c419b | |||
| 60e7c6d150 | |||
| a9aaa5ad73 | |||
| 6c1fee736b | |||
| f81d2595f9 | |||
| 1896bd0920 | |||
| 183f32390c | |||
| 455948ad14 | |||
| 0918063c55 | |||
| 22c001c8a6 | |||
| d15b0bf4c4 | |||
| 01a910fedc | |||
| 8c05067f88 | |||
| f67563e9ee | |||
| d0841919ea | |||
| a23e60ab69 | |||
| ab30297d02 | |||
| 3362d6bc56 | |||
| e5f391ab53 | |||
| 19a5e425cf | |||
| 69d0e82453 | |||
| f84737d7d4 | |||
| 0ee0ea554d | |||
| 40845578c6 | |||
| f4e22e49b6 | |||
| 8a2af9b818 | |||
| 255901ca7c | |||
| 52644bb28a | |||
| 7cad3c89d3 | |||
| bcdddfe4e8 | |||
| c4ca1444f9 | |||
| f5565d4814 | |||
| f20ee6b482 | |||
| 6c8d084664 | |||
| 412e7bcdae | |||
| 3b65fc0107 | |||
| 5792a16222 | |||
| 6a9f451091 | |||
| a559d59d80 | |||
| de20a8930e | |||
| 9343b0378d | |||
| 3fabd2ea1b | |||
| 5de69b288f | |||
| 5eea02b17a | |||
| 5c0812ab6f | |||
| 5af3fe93f2 | |||
| ee400df930 | |||
| 09b8401324 | |||
| be1fb13162 | |||
| aa83dc15e2 | |||
| 7c482064df | |||
| c93a3ce227 | |||
| 03c10ef885 | |||
| cc1ed98fc4 | |||
| ebf0bd5fc9 | |||
| be48caf59f | |||
| c0cf0cb802 | |||
| 3d60d0dfa5 | |||
| b68df56b03 | |||
| 6fbba13ab3 | |||
| 311624beaa | |||
| ca5099f53b | |||
| 5877e5e11a | |||
| 69eb62c09f | |||
| ec36e28368 | |||
| 4da56b65ab | |||
| 71febeb71f | |||
| a292aedd9c | |||
| b58e605b99 | |||
| 7776803890 | |||
| cd23ab9955 | |||
| aa32459bc2 | |||
| 41a0995db7 | |||
| 3f9f0679ec | |||
| d1145ed3fb | |||
| f074c1eaff | |||
| ea566fff24 | |||
| b8cb5e0367 | |||
| 7a87c900ee | |||
| e95170e9fd | |||
| d0dead0a08 | |||
| 71d718a6e2 | |||
| ad94f99d57 | |||
| bcaaedf2ff | |||
| 3dc3d363fd | |||
| 690a6e1a59 | |||
| eacc46da6d | |||
| 0903d5541b | |||
| c19a2e5b45 | |||
| 10a764c4f2 | |||
| 0a9f705308 | |||
| dabd680d6b | |||
| 4522b02925 | |||
| fabaf5cc04 | |||
| f7888886e9 | |||
| dfd5413b10 | |||
| 1b341f8000 | |||
| af9b864b83 | |||
| 93e424de4c | |||
| e7a0ab76c3 | |||
| d8b90721b3 | |||
| cb5c1bd24d | |||
| af371249f9 | |||
| 0dd7fb7361 | |||
| 22fd2aed02 | |||
| c433167950 | |||
| e0ffcda32e | |||
| d34ba416a6 | |||
| 3d15ee6d74 | |||
| 48cf56b69a | |||
| 406ee43ae5 | |||
| 488165ec73 | |||
| 545c39356a | |||
| 42db1378e0 | |||
| c35b51a268 | |||
| df1e52e394 | |||
| 246b04f904 | |||
| 333f9101a0 | |||
| 24acea7261 | |||
| 08ca72399b | |||
| e29e3416db | |||
| 83ce40191c | |||
| 7c06b5cc22 | |||
| 3b8e478a6a | |||
| 9498c78576 | |||
| 746e203f7b | |||
| a7d7f31e76 | |||
| 16847fdb41 | |||
| 28e7f0f74f | |||
| 80d757b371 | |||
| 5bdf0cd136 | |||
| e498503428 | |||
| 26f70a5fd7 | |||
| ef46b23250 | |||
| 39ccf1526f | |||
| 12889a9509 | |||
| c24935b519 | |||
| 3693473f40 | |||
| 2cb83cf19d | |||
| 8c02a7bd6b | |||
| 8ee0e5d11f | |||
| c87b425639 | |||
| e320bd025f | |||
| d465c445fc | |||
| dc30b9d37b | |||
| 37cfe2a3cb | |||
| 26abce647d | |||
| ca84ef38f8 | |||
| 78fe588330 | |||
| ddf72fa53f | |||
| 3a6e8a535c | |||
| d882af9f94 | |||
| 48539c851e | |||
| a701bba839 | |||
| c7ba60162b | |||
| d4e98cd9bc | |||
| 05ec24e7b8 | |||
| e44ef7f823 | |||
| 04ff97cd72 | |||
| 8e6fdf62fb | |||
| 74d7a946a7 | |||
| 2b58b6b5d7 | |||
| 7ee290cc57 | |||
| 3868a796a4 | |||
| b99ea80b58 | |||
| ce2ae31950 | |||
| f355f36d09 | |||
| 5aa11b4578 | |||
| c48da9b5cf | |||
| 12d65bfdfa | |||
| cba471b09b | |||
| f1b897b3de | |||
| 0589134006 | |||
| 6ed36e01ac | |||
| 25d93d1041 | |||
| e28c9b3309 | |||
| 5335a6b636 | |||
| f83d5f4280 | |||
| 28ec6b4d60 | |||
| 27a0ef7ee8 | |||
| 5eab5dc47b | |||
| 2ec5bc77d7 | |||
| 2f3587ee8a | |||
| 9ece45caa5 | |||
| f163ceffd0 | |||
| 31de9faaf2 | |||
| d302c82c82 | |||
| 6fa5e681aa | |||
| e631940d9e | |||
| e22e20fa9d | |||
| 79c8556927 | |||
| 7d16307db4 | |||
| 1626982a3a | |||
| 6beb9be42c | |||
| bf41eb824d | |||
| 38f4cfb7a2 | |||
| aca9d3965d | |||
| 4cc06ad779 | |||
| 79d56f779d | |||
| 280f9befae | |||
| 201f50b121 | |||
| 1cfa523f49 | |||
| 548ee47aa7 | |||
| 55448de92a | |||
| b63471ebe9 | |||
| 33395d530d | |||
| fcd3af30ec | |||
| e334107c7d | |||
| f5eb54e595 | |||
| 56c3dd3652 | |||
| 6ddd458402 | |||
| ee328667d0 | |||
| bc2bc1f2ac | |||
| 3dee75603c | |||
| c7e3ed096f | |||
| 62fe5cdbaa | |||
| 10f66fa78f | |||
| 0cbc493113 | |||
| c30c9fbca9 | |||
| f4fd3f48f0 | |||
| 4ee9e48e7c | |||
| 55fab0493d | |||
| 22c4e605cf | |||
| 67737b1556 | |||
| cdfd3449ed | |||
| fab1062c0b | |||
| 766b9d5270 | |||
| 023fa2b2cc | |||
| 8910351f5c | |||
| 1b42e3015e | |||
| 4e9e18d4c0 | |||
| ba5b127684 | |||
| 225e7a6a32 | |||
| 7e9963ae05 | |||
| b7c0f3ea95 | |||
| a8e2610d7d | |||
| b934ace1fc | |||
| 82cbfc9905 | |||
| 9f294e3565 | |||
| 68775182f0 | |||
| dc3e172eb4 | |||
| 5bd128ba85 | |||
| 1a8579cd6d | |||
| 5921bb0589 | |||
| c8e894e8f8 | |||
| 141f22bedf | |||
| d9844350fe | |||
| 2d9d11a89c | |||
| 4fa92198a0 | |||
| 662430d5db | |||
| 139b19f9ac | |||
| 6e50e2412e | |||
| 005e14a060 | |||
| c8c9e0a7e7 | |||
| 0f65cb2b79 | |||
| 85094fc74d | |||
| 5227dc679d | |||
| 77c510c364 | |||
| 2d2ad8b237 | |||
| 6ea00a4f7c | |||
| 1bb0530c69 | |||
| b36f644628 | |||
| 2dee9c8d74 | |||
| 9c6eb7736f | |||
| e86dfcf55c | |||
| d6311aefb7 | |||
| 8e18f2c5d2 | |||
| 0644bfe27c | |||
| 0b285845d1 | |||
| d3ff4bf75e | |||
| aa4ac9fa05 | |||
| 0339a5ad01 | |||
| bffb217d37 | |||
| 40f85e5ca3 | |||
| 2dba2f4a95 | |||
| 70542fb730 | |||
| cd742979b1 | |||
| 736d58e35f | |||
| 64138bd424 | |||
| f51d74fa68 | |||
| 78c6ce842e | |||
| ad79df9b74 | |||
| b4763290de | |||
| 8264c76642 | |||
| 6edd6c8f03 | |||
| f1bc87133d | |||
| dd7a13930f | |||
| 8ad10149ab | |||
| 0731064375 | |||
| e194461420 | |||
| b97b23647e | |||
| 7bdeceff36 | |||
| 45c69fa638 | |||
| d7f3869959 | |||
| cdc36dd171 | |||
| ed16914715 | |||
| a1d66d98dc | |||
| dd3295da60 | |||
| 282aaa5cf0 | |||
| 462a939438 | |||
| 030f902ca5 | |||
| 58093941c0 | |||
| 005271d24b | |||
| 2b263bcb5d | |||
| 79d0f47ee7 | |||
| 1ebb18ae57 | |||
| fad4875f11 | |||
| 42d1205260 | |||
| 3d90340446 | |||
| d68e1fd308 | |||
| 217d5df276 | |||
| d1ccf83236 | |||
| 28968144d6 | |||
| 4c5cfd51d7 | |||
| b6044910ec | |||
| 5aa90eb086 | |||
| ce58486850 | |||
| 7e63978a3f | |||
| c9674f84e8 | |||
| 0697274695 | |||
| 654d1f939e | |||
| 477b876a1f | |||
| 523cf21b4a | |||
| df0a5cf52f | |||
| caa6337952 | |||
| 700a3f9f84 | |||
| f9b13791de | |||
| 7886318341 | |||
| 3c13901695 | |||
| 573632012e | |||
| 002455da07 | |||
| e9e6ac64bd | |||
| 36ab8ae19c | |||
| df366da721 | |||
| 67dc761344 | |||
| 0b4552a8e7 | |||
| 2345b41a74 | |||
| 141e395489 | |||
| 91139672cc | |||
| 3d178c8eb6 | |||
| c9bd45ba13 | |||
| db9c288050 | |||
| f1cb8f2f25 | |||
| 7ec2c09249 | |||
| 354bfcea15 | |||
| 891d7c134c | |||
| eb5822bc7c | |||
| 154d70e4e2 | |||
| c4a0fe0234 | |||
| 0011beb654 | |||
| 419251ed35 | |||
| bd850d8158 | |||
| d7c7f27207 | |||
| 0fb95297a2 | |||
| cf1f43dc9d | |||
| d6935847b4 | |||
| 0715ba3e5e | |||
| efbbb31370 | |||
| 207c1a20ee | |||
| 579bc1c2c8 | |||
| bd4cb549d6 | |||
| fd392a2422 | |||
| 13864853a8 | |||
| d86b2c4fb4 | |||
| a1f103576a | |||
| aa766e3e18 | |||
| ee0e4d2b69 | |||
| 8eb3e48bc7 | |||
| 384292b647 | |||
| 1bb1ddcd29 | |||
| 24324939e1 | |||
| 2436cda7ac | |||
| 75b83af08f | |||
| 82d8e3c2b6 | |||
| c351f46e47 | |||
| fb9e8d2166 | |||
| 3668cb6dd4 | |||
| 93f3e30cac | |||
| 52af346ec8 | |||
| 8e0bba4f99 | |||
| 4cc61d10ff | |||
| 8deb6d9246 | |||
| 20eb6df9e8 | |||
| a921eeb5e2 | |||
| f3f34e1835 | |||
| 4a29d459da | |||
| 0f867a3484 | |||
| 6eeddaa564 | |||
| d80458ef81 | |||
| ad15df7222 | |||
| 98f7febed1 | |||
| 4f04eaec3a | |||
| 5a2b9b1f44 | |||
| 721b37a08e | |||
| b3d494d4c8 | |||
| 85ec70e92b | |||
| e2f0ff9e88 | |||
| 0dbd7d0e17 | |||
| 8cdaa044e1 | |||
| 712a420217 | |||
| b38dc70c71 | |||
| 72d9fcdcb4 | |||
| 5a6981e7af | |||
| 79d29db18b | |||
| 4f6a52503d | |||
| 1b5c40dd1f | |||
| 700b77c450 | |||
| 8449017592 | |||
| 5cf3425b93 | |||
| aa13a80d83 | |||
| 9e2ef543ed | |||
| 2aabb387b1 | |||
| f972863f49 | |||
| f00320c8b9 | |||
| 1f57cf08a7 | |||
| 0ff5ff5dbe | |||
| 5ba19144d5 | |||
| c9ba856c52 | |||
| a30ceefa6b | |||
| 31e2a8b8e9 | |||
| 9b4150509c | |||
| c68cd7d19a | |||
| 85382dc2e0 | |||
| 7315a0ecec | |||
| 411bd55cd4 | |||
| 9c0141e84e | |||
| ca5d0496ee | |||
| 24b9bc1e55 | |||
| cf1e167430 | |||
| a1afd2328d | |||
| ada9bfcae8 | |||
| f88588db90 | |||
| 5930dc6354 | |||
| 9c64da4323 | |||
| c863ea4aa1 | |||
| e1432f4339 | |||
| 890c527ae5 | |||
| 1fa8b74595 | |||
| 5559ad1238 | |||
| bd8f5e9bfd | |||
| 29f6283eab | |||
| 396f53d20e | |||
| 4a69de1f30 | |||
| bd6e2d6ca4 | |||
| fc78e42a78 | |||
| 9d1906d333 | |||
| 4a3f50cef7 | |||
| 4751e4b94e | |||
| 1b7f4f31ca | |||
| ca01604b43 | |||
| 93f9a0c39c | |||
| 93977316ce | |||
| 7e49bdf5a8 | |||
| df0bc7bbc4 | |||
| 63b50ab9b1 | |||
| c0beef7572 | |||
| 5ec448861d | |||
| 7d4326a397 | |||
| cc43b94864 | |||
| 57a31828f8 | |||
| 0c7fccdcbe | |||
| a1fcd3c5b6 | |||
| c4048f8f22 | |||
| 15dc30edf6 | |||
| 4254aa5f5a | |||
| 09ff042986 | |||
| 924ecce2c3 | |||
| 69daede583 | |||
| a6e8d61e8e | |||
| 65a7fa320a | |||
| be5e6d55fc | |||
| b0c01369c5 | |||
| f6772bb896 | |||
| b21fa2daa0 | |||
| 730d4857ba | |||
| 0e1c12e65f | |||
| 37b125ca98 | |||
| 2e9303cb6c | |||
| 7db38c80fc | |||
| aad824a562 | |||
| f0087c93b8 | |||
| ae7e7e9656 | |||
| e008473e47 | |||
| 79313aa268 | |||
| 1c35d4b26b | |||
| a56f657fb1 | |||
| f5db9950f8 | |||
| e5931e264b | |||
| 9485e8cfee | |||
| 22b139d9f8 | |||
| 2a600b25e7 | |||
| 393891d6ea | |||
| 1bbd056797 | |||
| add5bb47d5 | |||
| 305f8d6982 | |||
| 93851a9a0f | |||
| 8a184e9d30 | |||
| 3a66d7c453 | |||
| 00a479de6f | |||
| 32f9f8fcce | |||
| e4208441b3 | |||
| ee5ebe2e81 | |||
| a71b681e80 | |||
| 2cbc62d6c0 | |||
| cc125f5fd7 | |||
| 7f9c8a1935 | |||
| 3c54d14460 | |||
| c5b39a5100 | |||
| 7888c1c614 | |||
| b43315c36d | |||
| fbd6417c8a | |||
| 850ad1c0fb | |||
| dbe35bfed1 | |||
| f1caae126e | |||
| bad6a40a12 | |||
| 5bc194e1f0 | |||
| d315ff2b96 | |||
| 163b45cf37 | |||
| 87c718f549 | |||
| e04678f33c | |||
| bbdf75bdfa | |||
| 5c0cf9f5d7 | |||
| 8a61ec4b4e | |||
| 874a6e86fd | |||
| ef4bec1c6d | |||
| 4da99d14e6 | |||
| cc80191cd1 | |||
| 3cdb3f0d54 | |||
| 437b957be1 | |||
| 9f17e4ee2c | |||
| 509c3dc715 | |||
| 4051f04e66 | |||
| d503c5d83d | |||
| 02a37d670c | |||
| a7deca1df5 | |||
| 1bec6c2aae | |||
| a66825c71f | |||
| 0fb110a4af | |||
| 167c02d773 | |||
| 0c50a7437b | |||
| 5339ec66b7 | |||
| 2371dcf694 | |||
| 65bc194c42 | |||
| 99ee38cea3 | |||
| 5d8a51c307 | |||
| 6325635fce | |||
| 7612e47aee | |||
| d06b9401ea | |||
| ecb1552c10 | |||
| 9f066d01b1 | |||
| 673ae1edc0 | |||
| b25b31e4a0 | |||
| f65fde8bb7 | |||
| 0a04b135ca | |||
| 88d27fe649 | |||
| 5d166dc8cb | |||
| 8f81c97aaa | |||
| b5f35261a0 | |||
| f55e24cd12 | |||
| efc0b60d41 | |||
| f3bc726001 | |||
| 60e797ccc4 | |||
| 20b553461b | |||
| 0bff097afb | |||
| b0cb6d6d4c | |||
| b345c7cf46 | |||
| 56e2082205 | |||
| fe2d8f1ea0 | |||
| e16bbc660d | |||
| 2676f24e0a | |||
| b8e6fcfeae | |||
| b5f18561ab | |||
| 22c3ec2d63 | |||
| b678daa744 | |||
| e1433ebb41 | |||
| 1b83742e3e | |||
| 90cca93951 | |||
| 4e37290a7f | |||
| 7d3146ed8d | |||
| 0a1af65a4c | |||
| 4de9ac133a | |||
| 60c7bfe9a7 | |||
| 9bafc4fea1 | |||
| 7387f2e490 | |||
| 93b4f3fac8 | |||
| fdeeb73587 | |||
| 6062930f9a | |||
| 867b838053 | |||
| 58dc282ca0 | |||
| d7ee7cb88f | |||
| da9c792ca2 | |||
| 8171cd51c4 | |||
| 74b10a42ee | |||
| f14ef22bb6 | |||
| e8c9b0806a | |||
| 36c4d01ef8 | |||
| e51d403420 | |||
| f54615ed46 | |||
| 4c1b6f3059 | |||
| ada641090f | |||
| eb6c8a3521 | |||
| 3a021a87a1 | |||
| 5100339604 | |||
| 8448e3970b | |||
| dbed679904 | |||
| acb5340ffb | |||
| 6a01cd56ca | |||
| ae38705bed | |||
| db083c43dd | |||
| c5435596ad | |||
| 03130e1217 | |||
| 2ca6acc1e9 | |||
| d8f68eb118 | |||
| 97697b93ed | |||
| 152b484eb5 | |||
| 97de8c1cc2 | |||
| 6cf46b1635 | |||
| 1665cb4282 | |||
| 1113081aab | |||
| 39bc3cb532 | |||
| 0a0a0776e4 | |||
| 59d199a148 | |||
| 8b9d13491f | |||
| 4dcd2ceb01 | |||
| 6004ba6554 | |||
| f1847d4501 | |||
| e63ff167a7 | |||
| a27186e34f | |||
| 2a8904f844 | |||
| 59fc72d37e | |||
| 34e3683ded | |||
| 13760b1bdd | |||
| 8a252774ce | |||
| 963f9fdf40 | |||
| b4a2b96e32 | |||
| 299a2457cd | |||
| 3de4707c98 | |||
| 603ec65e91 | |||
| cdcffcd31e | |||
| f8a1c7c8a1 | |||
| 5d64568f3e | |||
| 374fbad06d | |||
| aa31336c64 | |||
| 135ba68ff5 | |||
| d3ee81bb5a | |||
| e0b585779d | |||
| 4729bea1a2 | |||
| e1393f9780 | |||
| ad7e66cdae | |||
| 2f09ef2970 | |||
| 6ea2c08ecb | |||
| b82f1edd63 | |||
| 1685e7cea4 | |||
| 287d8ca367 | |||
| af65a81d5b | |||
| 03e2f25adb | |||
| aa9093bcf6 | |||
| dc4f347ae1 | |||
| 23599814a3 | |||
| 2b6df412b7 | |||
| e4fecb48e3 | |||
| cf89b565a6 | |||
| 23404decea | |||
| 7e2f653bc7 | |||
| 4bb656b704 | |||
| 0dc0e03c4c | |||
| ef2094f817 | |||
| 83052352dc | |||
| f053b41645 | |||
| 2dc8fcd3be | |||
| e70b99a706 | |||
| 9cdf0601eb | |||
| 28ef972c9f | |||
| 74ea266157 | |||
| 235bbc9c7e |
@@ -1,6 +1,6 @@
|
||||
[run]
|
||||
init_cmds = [
|
||||
["go", "build", "-o", "./bin/grafana-server"],
|
||||
["go", "build", "-o", "./bin/grafana-server", "./pkg/cmd/grafana-server"],
|
||||
["./bin/grafana-server"]
|
||||
]
|
||||
watch_all = true
|
||||
@@ -12,6 +12,6 @@ watch_dirs = [
|
||||
watch_exts = [".go", ".ini", ".toml", ".html"]
|
||||
build_delay = 1500
|
||||
cmds = [
|
||||
["go", "build", "-o", "./bin/grafana-server"],
|
||||
["go", "build", "-o", "./bin/grafana-server", "./pkg/cmd/grafana-server"],
|
||||
["./bin/grafana-server"]
|
||||
]
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*.go]
|
||||
indent_style = tabs
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
Follow the setup guide in README.md
|
||||
|
||||
### Rebuild frontend assets on source change
|
||||
```
|
||||
grunt && grunt watch
|
||||
```
|
||||
|
||||
### Rerun tests on source change
|
||||
```
|
||||
grunt karma:dev
|
||||
```
|
||||
|
||||
### Run tests for backend assets before commit
|
||||
```
|
||||
test -z "$(gofmt -s -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
|
||||
```
|
||||
|
||||
### Run tests for frontend assets before commit
|
||||
```
|
||||
grunt test
|
||||
godep go test -v ./pkg/...
|
||||
```
|
||||
@@ -0,0 +1,12 @@
|
||||
Thank you! For helping us make Grafana even better.
|
||||
|
||||
To help us respond to your issues faster, please make sure to add as much information as possible.
|
||||
|
||||
If this issue is about a plugin, please open the issue in that repository.
|
||||
|
||||
Start your issues title with [Feature Request] / [Bug] / [Question] or no tag if your unsure.
|
||||
|
||||
Ex
|
||||
* What grafana version are you using?
|
||||
* What datasource are you using?
|
||||
* What OS are you running grafana on?
|
||||
@@ -0,0 +1,2 @@
|
||||
* Link the PR to an issue for new features
|
||||
* Rebase your PR if it gets out of sync with master
|
||||
+7
-1
@@ -1,10 +1,12 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
coverage/
|
||||
.aws-config.json
|
||||
awsconfig
|
||||
/dist
|
||||
/emails/dist
|
||||
/public_gen
|
||||
/public/vendor/npm
|
||||
/tmp
|
||||
vendor/phantomjs/phantomjs
|
||||
|
||||
@@ -29,6 +31,10 @@ public/css/*.min.css
|
||||
|
||||
conf/custom.ini
|
||||
fig.yml
|
||||
docker-compose.yml
|
||||
profile.cov
|
||||
grafana
|
||||
/grafana
|
||||
.notouch
|
||||
/pkg/cmd/grafana-cli/grafana-cli
|
||||
/pkg/cmd/grafana-server/grafana-server
|
||||
/examples/*/dist
|
||||
@@ -5,3 +5,6 @@ if [ $? -gt 0 ]; then
|
||||
echo "Some files aren't formatted, please run 'go fmt ./pkg/...' to format your source code before committing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
grunt test
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"bitwise":false,
|
||||
"curly": true,
|
||||
"eqnull": true,
|
||||
"globalstrict": true,
|
||||
"strict": true,
|
||||
"devel": true,
|
||||
"eqeqeq": true,
|
||||
"forin": false,
|
||||
@@ -12,7 +12,7 @@
|
||||
"supernew": true,
|
||||
"expr": true,
|
||||
"indent": 2,
|
||||
"latedef": true,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": true,
|
||||
@@ -27,6 +27,8 @@
|
||||
"maxlen": 140,
|
||||
|
||||
"globals": {
|
||||
"System": true,
|
||||
"Promise": true,
|
||||
"define": true,
|
||||
"require": true,
|
||||
"Chromath": false,
|
||||
|
||||
+98
-2
@@ -1,4 +1,100 @@
|
||||
# 2.5 (unreleased)
|
||||
# 3.0.0-beta2 (unreleased)
|
||||
|
||||
### New Features (introduces since 3.0-beta1)
|
||||
* **Preferences**: Set home dashboard on user and org level, closes [#1678](https://github.com/grafana/grafana/issues/1678)
|
||||
* **Preferences**: Set timezone on user and org level, closes [#3214](https://github.com/grafana/grafana/issues/3214), [#1200](https://github.com/grafana/grafana/issues/1200)
|
||||
* **Preferences**: Set theme on user and org level, closes [#3214](https://github.com/grafana/grafana/issues/3214), [#1917](https://github.com/grafana/grafana/issues/1917)
|
||||
|
||||
### Bug fixes
|
||||
* **Dashboard**: Fixed dashboard panel layout for mobile devices, fixes [#4529](https://github.com/grafana/grafana/issues/4529)
|
||||
* **Table Panel**: Fixed issue with table panel sort, fixes [#4532](https://github.com/grafana/grafana/issues/4532)
|
||||
* **Page Load Crash**: A Datasource with null jsonData would make Grafana fail to load page, fixes [#4536](https://github.com/grafana/grafana/issues/4536)
|
||||
* **Metrics tab**: Fix for missing datasource name in datasource selector, fixes [#4540](https://github.com/grafana/grafana/issues/4540)
|
||||
* **Graph**: Fix legend in table mode with series on right-y axis, fixes [#4551](https://github.com/grafana/grafana/issues/4551), [#1145](https://github.com/grafana/grafana/issues/1145)
|
||||
* **Password**: Password reset link/page did not work, fixes [#4542](https://github.com/grafana/grafana/issues/4542)
|
||||
|
||||
# 3.0.0-beta1 (2016-03-31)
|
||||
|
||||
### New Features
|
||||
* **Playlists**: Playlists can now be persisted and started from urls, closes [#3655](https://github.com/grafana/grafana/issues/3655)
|
||||
* **Metadata**: Settings panel now shows dashboard metadata, closes [#3304](https://github.com/grafana/grafana/issues/3304)
|
||||
* **InfluxDB**: Support for policy selection in query editor, closes [#2018](https://github.com/grafana/grafana/issues/2018)
|
||||
* **Snapshots UI**: Dashboard snapshots list can be managed through UI, closes[#1984](https://github.com/grafana/grafana/issues/1984)
|
||||
* **Prometheus**: Prometheus annotation support, closes[#2883](https://github.com/grafana/grafana/pull/2883)
|
||||
* **Cli**: New cli tool for downloading and updating plugins
|
||||
* **Annotations**: Annotations can now contain links that can be clicked (you can navigate on to annotation popovers), closes [#1588](https://github.com/grafana/grafana/issues/1588)
|
||||
* **Opentsdb**: Opentsdb 2.2 filters support, closes[#3077](https://github.com/grafana/grafana/issues/3077)
|
||||
|
||||
### Breaking changes
|
||||
* **Plugin API**: Both datasource and panel plugin api (and plugin.json schema) have been updated, requiring an update to plugins. See [plugin api](https://github.com/grafana/grafana/blob/master/public/app/plugins/plugin_api.md) for more info.
|
||||
* **InfluxDB 0.8.x** The data source for the old version of influxdb (0.8.x) is no longer included in default builds, but can easily be installed via improved plugin system, closes [#3523](https://github.com/grafana/grafana/issues/3523)
|
||||
* **KairosDB** The data source is no longer included in default builds, but can easily be installed via improved plugin system, closes [#3524](https://github.com/grafana/grafana/issues/3524)
|
||||
* **Templating**: Templating value formats (glob/regex/pipe etc) are now handled automatically and not specified by the user, this makes variable values possible to reuse in many contexts. It can in some edge cases break existing dashboards that have template variables that do not reload on dashboard load. To fix any issue just go into template variable options and update the variable (so it's values are reloaded.).
|
||||
|
||||
### Enhancements
|
||||
* **LDAP**: Support for nested LDAP Groups, closes [#4401](https://github.com/grafana/grafana/issues/4401), [#3808](https://github.com/grafana/grafana/issues/3808)
|
||||
* **Sessions**: Support for memcached as session storage, closes [#3458](https://github.com/grafana/grafana/issues/3458)
|
||||
* **mysql**: Grafana now supports ssl for mysql, closes [#3584](https://github.com/grafana/grafana/issues/3584)
|
||||
* **snapshot**: Annotations are now included in snapshots, closes [#3635](https://github.com/grafana/grafana/issues/3635)
|
||||
* **Admin**: Admin can now have global overview of Grafana setup, closes [#3812](https://github.com/grafana/grafana/issues/3812)
|
||||
* **graph**: Right side legend height is now fixed at row height, closes [#1277](https://github.com/grafana/grafana/issues/1277)
|
||||
* **Table**: All content in table panel is now html escaped, closes [#3673](https://github.com/grafana/grafana/issues/3673)
|
||||
* **graph**: Template variables can now be used in TimeShift and TimeFrom, closes[#1960](https://github.com/grafana/grafana/issues/1960)
|
||||
* **Tooltip**: Optionally add milliseconds to timestamp in tool tip, closes[#2248](https://github.com/grafana/grafana/issues/2248)
|
||||
* **Opentsdb**: Support milliseconds when using openTSDB datasource, closes [#2865](https://github.com/grafana/grafana/issues/2865)
|
||||
* **Opentsdb**: Add support for annotations, closes[#664](https://github.com/grafana/grafana/issues/664)
|
||||
|
||||
### Bug fixes
|
||||
* **Playlist**: Fix for memory leak when running a playlist, closes [#3794](https://github.com/grafana/grafana/pull/3794)
|
||||
* **InfluxDB**: Fix for InfluxDB and table panel when using Format As Table and having group by time, fixes [#3928](https://github.com/grafana/grafana/issues/3928)
|
||||
* **Panel Time shift**: Fix for panel time range and using dashboard times liek `Today` and `This Week`, fixes [#3941](https://github.com/grafana/grafana/issues/3941)
|
||||
* **Row repeat**: Repeated rows will now appear next to each other and not by the bottom of the dashboard, fixes [#3942](https://github.com/grafana/grafana/issues/3942)
|
||||
* **Png renderer**: Fix for phantomjs path on windows, fixes [#3657](https://github.com/grafana/grafana/issues/3657)
|
||||
|
||||
# 2.6.1 (unrelased, 2.6.x branch)
|
||||
|
||||
### New Features
|
||||
* **Elasticsearch**: Support for derivative unit option, closes [#3512](https://github.com/grafana/grafana/issues/3512)
|
||||
|
||||
### Bug fixes
|
||||
* **Graph Panel**: Fixed typehead when adding series style override, closes [#3554](https://github.com/grafana/grafana/issues/3554)
|
||||
|
||||
# 2.6.0 (2015-12-14)
|
||||
|
||||
### New Features
|
||||
* **Elasticsearch**: Support for pipeline aggregations Moving average and derivative, closes [#2715](https://github.com/grafana/grafana/issues/2715)
|
||||
* **Elasticsearch**: Support for inline script and missing options for metrics, closes [#3500](https://github.com/grafana/grafana/issues/3500)
|
||||
* **Syslog**: Support for syslog logging, closes [#3161](https://github.com/grafana/grafana/pull/3161)
|
||||
* **Timepicker**: Always show refresh button even with refresh rate, closes [#3498](https://github.com/grafana/grafana/pull/3498)
|
||||
* **Login**: Make it possible to change the login hint on the login page, closes [#2571](https://github.com/grafana/grafana/pull/2571)
|
||||
|
||||
### Bug Fixes
|
||||
* **metric editors**: Fix for clicking typeahead auto dropdown option, fixes [#3428](https://github.com/grafana/grafana/issues/3428)
|
||||
* **influxdb**: Fixed issue showing Group By label only on first query, fixes [#3453](https://github.com/grafana/grafana/issues/3453)
|
||||
* **logging**: Add more verbose info logging for http reqeusts, closes [#3405](https://github.com/grafana/grafana/pull/3405)
|
||||
|
||||
# 2.6.0-Beta1 (2015-12-04)
|
||||
|
||||
### New Table Panel
|
||||
* **table**: New powerful and flexible table panel, closes [#215](https://github.com/grafana/grafana/issues/215)
|
||||
|
||||
### Enhancements
|
||||
* **CloudWatch**: Support for multiple AWS Credentials, closes [#3053](https://github.com/grafana/grafana/issues/3053), [#3080](https://github.com/grafana/grafana/issues/3080)
|
||||
* **Elasticsearch**: Support for dynamic daily indices for annotations, closes [#3061](https://github.com/grafana/grafana/issues/3061)
|
||||
* **Elasticsearch**: Support for setting min_doc_count for date histogram, closes [#3416](https://github.com/grafana/grafana/issues/3416)
|
||||
* **Graph Panel**: Option to hide series with all zeroes from legend and tooltip, closes [#1381](https://github.com/grafana/grafana/issues/1381), [#3336](https://github.com/grafana/grafana/issues/3336)
|
||||
|
||||
### Bug Fixes
|
||||
* **cloudwatch**: fix for handling of period for long time ranges, fixes [#3086](https://github.com/grafana/grafana/issues/3086)
|
||||
* **dashboard**: fix for collapse row by clicking on row title, fixes [#3065](https://github.com/grafana/grafana/issues/3065)
|
||||
* **influxdb**: fix for relative time ranges `last x months` and `last x years`, fixes [#3067](https://github.com/grafana/grafana/issues/3067)
|
||||
* **graph**: layout fix for color picker when right side legend was enabled, fixes [#3093](https://github.com/grafana/grafana/issues/3093)
|
||||
* **elasticsearch**: disabling elastic query (via eye) caused error, fixes [#3300](https://github.com/grafana/grafana/issues/3300)
|
||||
|
||||
### Breaking changes
|
||||
* **elasticsearch**: Manual json edited queries are not supported any more (They very barely worked in 2.5)
|
||||
|
||||
# 2.5 (2015-10-28)
|
||||
|
||||
**New Feature: Mix data sources**
|
||||
- A built in data source is now available named `-- Mixed --`, When picked in the metrics tab,
|
||||
@@ -11,7 +107,7 @@ it allows you to add queries of differnet data source types & instances to the s
|
||||
|
||||
**New Feature: New and much improved time picker**
|
||||
- Support for quick ranges like `Today`, `This day last week`, `This week`, `The day so far`, etc.
|
||||
- Muck improved UI and improved support for UTC, [Issue #2761](https://github.com/grafana/grafana/issues/2761) for more info.
|
||||
- Improved UI and improved support for UTC, [Issue #2761](https://github.com/grafana/grafana/issues/2761) for more info.
|
||||
|
||||
**User Onboarding**
|
||||
- Org admin can now send email invites (or invite links) to people who are not yet Grafana users
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
If you have any idea for an improvement or found a bug do not hesitate to open an issue.
|
||||
And if you have time clone this repo and submit a pull request and help me make Grafana the
|
||||
kickass metrics & devops dashboard we all dream about!
|
||||
|
||||
Prerequisites:
|
||||
- Nodejs (for jshint & grunt & development server)
|
||||
|
||||
Clone repository:
|
||||
|
||||
npm install
|
||||
grunt server (starts development web server in src folder)
|
||||
grunt (runs jshint and less -> css compilation)
|
||||
|
||||
Please remember to run grunt before doing pull request to verify that your code passes all the jshint validations.
|
||||
Generated
+228
-37
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"ImportPath": "github.com/grafana/grafana",
|
||||
"GoVersion": "go1.5",
|
||||
"GoVersion": "go1.5.1",
|
||||
"GodepVersion": "v60",
|
||||
"Packages": [
|
||||
"./pkg/..."
|
||||
],
|
||||
@@ -15,97 +16,263 @@
|
||||
"Rev": "d9bcf409c8a368d06c9b347705c381e7c12d54df"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/Unknwon/macaron",
|
||||
"Rev": "93de4f3fad97bf246b838f828e2348f46f21f20a"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/awserr",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/awsutil",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/client",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/client/metadata",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/corehandlers",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/credentials",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/defaults",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/ec2metadata",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/request",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/aws/session",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/endpoints",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/ec2query",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/rest",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/signer/v4",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/private/waiter",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/cloudwatch",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/aws/aws-sdk-go/service/ec2",
|
||||
"Comment": "v0.9.16-3-g4944a94",
|
||||
"Rev": "4944a94a3b092d1dad8a964415700a70f55e580a"
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/bmizerany/assert",
|
||||
"Comment": "release.r60-6-ge17e998",
|
||||
"Rev": "e17e99893cb6509f428e1728281c2ad60a6b31e3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/bradfitz/gomemcache/memcache",
|
||||
"Comment": "release.r60-40-g72a6864",
|
||||
"Rev": "72a68649ba712ee7c4b5b4a943a626bcd7d90eb8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codegangsta/cli",
|
||||
"Comment": "1.2.0-187-gc31a797",
|
||||
"Rev": "c31a7975863e7810c92e2e288a9ab074f9a88f29"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/davecgh/go-spew/spew",
|
||||
"Rev": "2df174808ee097f90d259e432cc04442cf60be21"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/fatih/color",
|
||||
"Comment": "v0.1-16-g4f7bcef",
|
||||
"Rev": "4f7bcef27eec7925456d0c30c5e7b0408b3339be"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/franela/goreq",
|
||||
"Rev": "3ddeded65be21dacb5a2e2d0b95af9ff6862a2b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-ini/ini",
|
||||
"Comment": "v0-48-g060d7da",
|
||||
"Rev": "060d7da055ba6ec5ea7a31f116332fe5efa04ce0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-ldap/ldap",
|
||||
"Comment": "v1-19-g83e6542",
|
||||
"Rev": "83e65426fd1c06626e88aa8a085e5bfed0208e29"
|
||||
"Comment": "v2.2.1",
|
||||
"Rev": "07a7330929b9ee80495c88a4439657d89c7dbd87"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/binding",
|
||||
"Rev": "2502aaf4bce3a4e6451b4610847bfb8dffdb6266"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/gzip",
|
||||
"Rev": "4938e9be6b279d8426cb1c89a6bcf7af70b0c21d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/inject",
|
||||
"Rev": "c5ab7bf3a307593cd44cb272d1a5beea473dd072"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/session",
|
||||
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/session/memcache",
|
||||
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/session/mysql",
|
||||
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/session/postgres",
|
||||
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-macaron/session/redis",
|
||||
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-sql-driver/mysql",
|
||||
"Comment": "v1.2-26-g9543750",
|
||||
"Rev": "9543750295406ef070f7de8ae9c43ccddd44e15e"
|
||||
"Comment": "v1.2-171-g267b128",
|
||||
"Rev": "267b128680c46286b9ca13475c3cca5de8f79bd7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-xorm/core",
|
||||
"Rev": "be6e7ac47dc57bd0ada25322fa526944f66ccaa6"
|
||||
"Comment": "v0.4.4-7-g9e608f7",
|
||||
"Rev": "9e608f7330b9d16fe2818cfe731128b3f156cb9a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-xorm/xorm",
|
||||
"Comment": "v0.4.2-58-ge2889e5",
|
||||
"Rev": "e2889e5517600b82905f1d2ba8b70deb71823ffe"
|
||||
"Comment": "v0.4.4-44-gf561133",
|
||||
"Rev": "f56113384f2c63dfe4cd8e768e349f1c35122b58"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/websocket",
|
||||
"Rev": "c45a635370221f34fea2d5163fd156fcb4e38e8a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gosimple/slug",
|
||||
"Rev": "8d258463b4459f161f51d6a357edacd3eef9d663"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-version",
|
||||
"Rev": "7e3c02b30806fa5779d3bdfc152ce4c6f40e7b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jmespath/go-jmespath",
|
||||
"Comment": "0.2.2",
|
||||
"Rev": "3433f3ea46d9f8019119e7dd41274e112a2359a9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jtolds/gls",
|
||||
"Rev": "f1ac7f4f24f50328e6bc838ca4437d1612a0243c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/klauspost/compress/flate",
|
||||
"Rev": "7b02889a2005228347aef0e76beeaee564d82f8c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/klauspost/compress/gzip",
|
||||
"Rev": "7b02889a2005228347aef0e76beeaee564d82f8c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/klauspost/cpuid",
|
||||
"Rev": "349c675778172472f5e8f3a3e0fe187e302e5a10"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/klauspost/crc32",
|
||||
"Rev": "6834731faf32e62a2dd809d99fb24d1e4ae5a92d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/kr/pretty",
|
||||
"Comment": "go.weekly.2011-12-22-27-ge6ac2fc",
|
||||
"Rev": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/kr/text",
|
||||
"Rev": "bb797dc4fb8320488f47bf11de07a733d7233e1f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/lib/pq",
|
||||
"Comment": "go1.0-cutoff-13-g19eeca3",
|
||||
"Rev": "19eeca3e30d2577b1761db471ec130810e67f532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/macaron-contrib/binding",
|
||||
"Rev": "0fbe4b9707e6eb556ef843e5471592f55ce0a5e7"
|
||||
"ImportPath": "github.com/lib/pq/oid",
|
||||
"Comment": "go1.0-cutoff-13-g19eeca3",
|
||||
"Rev": "19eeca3e30d2577b1761db471ec130810e67f532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/macaron-contrib/session",
|
||||
"Rev": "31e841d95c7302b9ac456c830ea2d6dfcef4f84a"
|
||||
"ImportPath": "github.com/mattn/go-colorable",
|
||||
"Rev": "9cbef7c35391cca05f15f8181dc0b18bc9736dbb"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-isatty",
|
||||
"Rev": "56b76bdf51f7708750eac80fa38b952bb9f32639"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-sqlite3",
|
||||
@@ -121,12 +288,28 @@
|
||||
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/streadway/amqp",
|
||||
"Rev": "150b7f24d6ad507e6026c13d85ce1f1391ac7400"
|
||||
"ImportPath": "github.com/smartystreets/goconvey/convey/assertions",
|
||||
"Comment": "1.5.0-356-gfbc0a1c",
|
||||
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vaughan0/go-ini",
|
||||
"Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"
|
||||
"ImportPath": "github.com/smartystreets/goconvey/convey/assertions/oglematchers",
|
||||
"Comment": "1.5.0-356-gfbc0a1c",
|
||||
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/smartystreets/goconvey/convey/gotest",
|
||||
"Comment": "1.5.0-356-gfbc0a1c",
|
||||
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/smartystreets/goconvey/convey/reporting",
|
||||
"Comment": "1.5.0-356-gfbc0a1c",
|
||||
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/streadway/amqp",
|
||||
"Rev": "150b7f24d6ad507e6026c13d85ce1f1391ac7400"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/context",
|
||||
@@ -136,6 +319,10 @@
|
||||
"ImportPath": "golang.org/x/oauth2",
|
||||
"Rev": "c58fcf0ffc1c772aa2e1ee4894bc19f2649263b2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "7a56174f0086b32866ebd746a794417edbc678a1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/asn1-ber.v1",
|
||||
"Comment": "v1",
|
||||
@@ -151,6 +338,10 @@
|
||||
"Comment": "v0-16-g1772191",
|
||||
"Rev": "177219109c97e7920c933e21c9b25f874357b237"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/macaron.v1",
|
||||
"Rev": "1c6dd87797ae9319b4658cbd48d1d0420b279fd5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/redis.v2",
|
||||
"Comment": "v2.3.2",
|
||||
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
Macaron [](https://drone.io/github.com/Unknwon/macaron/latest) [](http://gocover.io/github.com/Unknwon/macaron)
|
||||
=======================
|
||||
|
||||

|
||||
|
||||
Package macaron is a high productive and modular design web framework in Go.
|
||||
|
||||
##### Current version: 0.5.4
|
||||
|
||||
## Getting Started
|
||||
|
||||
To install Macaron:
|
||||
|
||||
go get github.com/Unknwon/macaron
|
||||
|
||||
The very basic usage of Macaron:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/Unknwon/macaron"
|
||||
|
||||
func main() {
|
||||
m := macaron.Classic()
|
||||
m.Get("/", func() string {
|
||||
return "Hello world!"
|
||||
})
|
||||
m.Run()
|
||||
}
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Powerful routing with suburl.
|
||||
- Flexible routes combinations.
|
||||
- Unlimited nested group routers.
|
||||
- Directly integrate with existing services.
|
||||
- Dynamically change template files at runtime.
|
||||
- Allow to use in-memory template and static files.
|
||||
- Easy to plugin/unplugin features with modular design.
|
||||
- Handy dependency injection powered by [inject](https://github.com/codegangsta/inject).
|
||||
- Better router layer and less reflection make faster speed.
|
||||
|
||||
## Middlewares
|
||||
|
||||
Middlewares allow you easily plugin/unplugin features for your Macaron applications.
|
||||
|
||||
There are already many [middlewares](https://github.com/macaron-contrib) to simplify your work:
|
||||
|
||||
- gzip - Gzip compression to all requests
|
||||
- render - Go template engine
|
||||
- static - Serves static files
|
||||
- [binding](https://github.com/macaron-contrib/binding) - Request data binding and validation
|
||||
- [i18n](https://github.com/macaron-contrib/i18n) - Internationalization and Localization
|
||||
- [cache](https://github.com/macaron-contrib/cache) - Cache manager
|
||||
- [session](https://github.com/macaron-contrib/session) - Session manager
|
||||
- [csrf](https://github.com/macaron-contrib/csrf) - Generates and validates csrf tokens
|
||||
- [captcha](https://github.com/macaron-contrib/captcha) - Captcha service
|
||||
- [pongo2](https://github.com/macaron-contrib/pongo2) - Pongo2 template engine support
|
||||
- [sockets](https://github.com/macaron-contrib/sockets) - WebSockets channels binding
|
||||
- [bindata](https://github.com/macaron-contrib/bindata) - Embed binary data as static and template files
|
||||
- [toolbox](https://github.com/macaron-contrib/toolbox) - Health check, pprof, profile and statistic services
|
||||
- [oauth2](https://github.com/macaron-contrib/oauth2) - OAuth 2.0 backend
|
||||
- [switcher](https://github.com/macaron-contrib/switcher) - Multiple-site support
|
||||
- [method](https://github.com/macaron-contrib/method) - HTTP method override
|
||||
- [permissions2](https://github.com/xyproto/permissions2) - Cookies, users and permissions
|
||||
- [renders](https://github.com/macaron-contrib/renders) - Beego-like render engine(Macaron has built-in template engine, this is another option)
|
||||
|
||||
## Use Cases
|
||||
|
||||
- [Gogs](https://github.com/gogits/gogs): Go Git Service
|
||||
- [Gogs Web](https://github.com/gogits/gogsweb): Gogs official website
|
||||
- [Go Walker](https://gowalker.org): Go online API documentation
|
||||
- [Switch](https://github.com/gpmgo/switch): Gopm registry
|
||||
- [YouGam](http://yougam.com): Online Forum
|
||||
- [Car Girl](http://qcnl.gzsy.com/): Online campaign
|
||||
- [Critical Stack Intel](https://intel.criticalstack.com/): A 100% free intel marketplace from Critical Stack, Inc.
|
||||
|
||||
## Getting Help
|
||||
|
||||
- [API Reference](https://gowalker.org/github.com/Unknwon/macaron)
|
||||
- [Documentation](http://macaron.gogs.io)
|
||||
- [FAQs](http://macaron.gogs.io/docs/faqs)
|
||||
- [](https://gitter.im/Unknwon/macaron?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
## Credits
|
||||
|
||||
- Basic design of [Martini](https://github.com/go-martini/martini).
|
||||
- Router layer of [beego](https://github.com/astaxie/beego).
|
||||
- Logo is modified by [@insionng](https://github.com/insionng) based on [Tribal Dragon](http://xtremeyamazaki.deviantart.com/art/Tribal-Dragon-27005087).
|
||||
|
||||
## License
|
||||
|
||||
This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
|
||||
-370
@@ -1,370 +0,0 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Context(t *testing.T) {
|
||||
Convey("Do advanced encapsulation operations", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderers(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}, "fixtures/basic2"))
|
||||
|
||||
Convey("Get request body", func() {
|
||||
m.Get("/body1", func(ctx *Context) {
|
||||
data, err := ioutil.ReadAll(ctx.Req.Body().ReadCloser())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(data), ShouldEqual, "This is my request body")
|
||||
})
|
||||
m.Get("/body2", func(ctx *Context) {
|
||||
data, err := ctx.Req.Body().Bytes()
|
||||
So(err, ShouldBeNil)
|
||||
So(string(data), ShouldEqual, "This is my request body")
|
||||
})
|
||||
m.Get("/body3", func(ctx *Context) {
|
||||
data, err := ctx.Req.Body().String()
|
||||
So(err, ShouldBeNil)
|
||||
So(data, ShouldEqual, "This is my request body")
|
||||
})
|
||||
|
||||
for i := 1; i <= 3; i++ {
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/body"+com.ToStr(i), nil)
|
||||
req.Body = ioutil.NopCloser(bytes.NewBufferString("This is my request body"))
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Get remote IP address", func() {
|
||||
m.Get("/remoteaddr", func(ctx *Context) string {
|
||||
return ctx.RemoteAddr()
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/remoteaddr", nil)
|
||||
req.RemoteAddr = "127.0.0.1:3333"
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "127.0.0.1")
|
||||
})
|
||||
|
||||
Convey("Render HTML", func() {
|
||||
|
||||
Convey("Normal HTML", func() {
|
||||
m.Get("/html", func(ctx *Context) {
|
||||
ctx.HTML(304, "hello", "Unknwon") // 304 for logger test.
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/html", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
|
||||
})
|
||||
|
||||
Convey("HTML template set", func() {
|
||||
m.Get("/html2", func(ctx *Context) {
|
||||
ctx.Data["Name"] = "Unknwon"
|
||||
ctx.HTMLSet(200, "basic2", "hello2")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/html2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
|
||||
})
|
||||
|
||||
Convey("With layout", func() {
|
||||
m.Get("/layout", func(ctx *Context) {
|
||||
ctx.HTML(200, "hello", "Unknwon", HTMLOptions{"layout"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/layout", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "head<h1>Hello Unknwon</h1>foot")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Parse from and query", func() {
|
||||
m.Get("/query", func(ctx *Context) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(ctx.QueryTrim("name") + " ")
|
||||
buf.WriteString(ctx.QueryEscape("name") + " ")
|
||||
buf.WriteString(com.ToStr(ctx.QueryInt("int")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.QueryInt64("int64")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.QueryFloat64("float64")) + " ")
|
||||
return buf.String()
|
||||
})
|
||||
m.Get("/query2", func(ctx *Context) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(strings.Join(ctx.QueryStrings("list"), ",") + " ")
|
||||
buf.WriteString(strings.Join(ctx.QueryStrings("404"), ",") + " ")
|
||||
return buf.String()
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/query?name=Unknwon&int=12&int64=123&float64=1.25", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Unknwon Unknwon 12 123 1.25 ")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/query2?list=item1&list=item2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "item1,item2 ")
|
||||
})
|
||||
|
||||
Convey("URL parameter", func() {
|
||||
m.Get("/:name/:int/:int64/:float64", func(ctx *Context) string {
|
||||
var buf bytes.Buffer
|
||||
ctx.SetParams("name", ctx.Params("name"))
|
||||
buf.WriteString(ctx.Params(""))
|
||||
buf.WriteString(ctx.Params(":name") + " ")
|
||||
buf.WriteString(ctx.ParamsEscape(":name") + " ")
|
||||
buf.WriteString(com.ToStr(ctx.ParamsInt(":int")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.ParamsInt64(":int64")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.ParamsFloat64(":float64")) + " ")
|
||||
return buf.String()
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/user/1/13/1.24", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "user user 1 13 1.24 ")
|
||||
})
|
||||
|
||||
Convey("Get file", func() {
|
||||
m.Get("/getfile", func(ctx *Context) {
|
||||
ctx.GetFile("hi")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/getfile", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Set and get cookie", func() {
|
||||
m.Get("/set", func(ctx *Context) {
|
||||
ctx.SetCookie("user", "Unknwon", 1, "/", "localhost", true, true)
|
||||
ctx.SetCookie("user", "Unknwon", int32(1), "/", "localhost", 1)
|
||||
ctx.SetCookie("user", "Unknwon", int64(1))
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/set", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Header().Get("Set-Cookie"), ShouldEqual, "user=Unknwon; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure")
|
||||
|
||||
m.Get("/get", func(ctx *Context) string {
|
||||
ctx.GetCookie("404")
|
||||
So(ctx.GetCookieInt("uid"), ShouldEqual, 1)
|
||||
So(ctx.GetCookieInt64("uid"), ShouldEqual, 1)
|
||||
So(ctx.GetCookieFloat64("balance"), ShouldEqual, 1.25)
|
||||
return ctx.GetCookie("user")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "user=Unknwon; uid=1; balance=1.25")
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Unknwon")
|
||||
})
|
||||
|
||||
Convey("Set and get secure cookie", func() {
|
||||
m.SetDefaultCookieSecret("macaron")
|
||||
m.Get("/set", func(ctx *Context) {
|
||||
ctx.SetSecureCookie("user", "Unknwon", 1)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/set", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
cookie := resp.Header().Get("Set-Cookie")
|
||||
|
||||
m.Get("/get", func(ctx *Context) string {
|
||||
name, ok := ctx.GetSecureCookie("user")
|
||||
So(ok, ShouldBeTrue)
|
||||
return name
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", cookie)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Unknwon")
|
||||
})
|
||||
|
||||
Convey("Serve files", func() {
|
||||
m.Get("/file", func(ctx *Context) {
|
||||
ctx.ServeFile("fixtures/custom_funcs/index.tmpl")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/file", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
|
||||
|
||||
m.Get("/file2", func(ctx *Context) {
|
||||
ctx.ServeFile("fixtures/custom_funcs/index.tmpl", "ok.tmpl")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/file2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
|
||||
})
|
||||
|
||||
Convey("Serve file content", func() {
|
||||
m.Get("/file", func(ctx *Context) {
|
||||
ctx.ServeFileContent("fixtures/custom_funcs/index.tmpl")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/file", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
|
||||
|
||||
m.Get("/file2", func(ctx *Context) {
|
||||
ctx.ServeFileContent("fixtures/custom_funcs/index.tmpl", "ok.tmpl")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/file2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
|
||||
|
||||
m.Get("/file3", func(ctx *Context) {
|
||||
ctx.ServeFileContent("404.tmpl")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/file3", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "open 404.tmpl: no such file or directory\n")
|
||||
So(resp.Code, ShouldEqual, 500)
|
||||
})
|
||||
|
||||
Convey("Serve content", func() {
|
||||
m.Get("/content", func(ctx *Context) {
|
||||
ctx.ServeContent("content1", bytes.NewReader([]byte("Hello world!")))
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/content", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Hello world!")
|
||||
|
||||
m.Get("/content2", func(ctx *Context) {
|
||||
ctx.ServeContent("content1", bytes.NewReader([]byte("Hello world!")), time.Now())
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/content2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Hello world!")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Context_Render(t *testing.T) {
|
||||
Convey("Invalid render", t, func() {
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
}()
|
||||
|
||||
m := New()
|
||||
m.Get("/", func(ctx *Context) {
|
||||
ctx.HTML(200, "hey")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Context_Redirect(t *testing.T) {
|
||||
Convey("Context with default redirect", t, func() {
|
||||
url, err := url.Parse("http://localhost/path/one")
|
||||
So(err, ShouldBeNil)
|
||||
resp := httptest.NewRecorder()
|
||||
req := http.Request{
|
||||
Method: "GET",
|
||||
URL: url,
|
||||
}
|
||||
ctx := &Context{
|
||||
Req: Request{&req},
|
||||
Resp: NewResponseWriter(resp),
|
||||
Data: make(map[string]interface{}),
|
||||
}
|
||||
ctx.Redirect("two")
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusFound)
|
||||
So(resp.HeaderMap["Location"][0], ShouldEqual, "/path/two")
|
||||
})
|
||||
|
||||
Convey("Context with custom redirect", t, func() {
|
||||
url, err := url.Parse("http://localhost/path/one")
|
||||
So(err, ShouldBeNil)
|
||||
resp := httptest.NewRecorder()
|
||||
req := http.Request{
|
||||
Method: "GET",
|
||||
URL: url,
|
||||
}
|
||||
ctx := &Context{
|
||||
Req: Request{&req},
|
||||
Resp: NewResponseWriter(resp),
|
||||
Data: make(map[string]interface{}),
|
||||
}
|
||||
ctx.Redirect("two", 307)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusTemporaryRedirect)
|
||||
So(resp.HeaderMap["Location"][0], ShouldEqual, "/path/two")
|
||||
})
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderAcceptEncoding = "Accept-Encoding"
|
||||
HeaderContentEncoding = "Content-Encoding"
|
||||
HeaderContentLength = "Content-Length"
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderVary = "Vary"
|
||||
)
|
||||
|
||||
// Gziper returns a Handler that adds gzip compression to all requests.
|
||||
// Make sure to include the Gzip middleware above other middleware
|
||||
// that alter the response body (like the render middleware).
|
||||
func Gziper() Handler {
|
||||
return func(ctx *Context) {
|
||||
if !strings.Contains(ctx.Req.Header.Get(HeaderAcceptEncoding), "gzip") {
|
||||
return
|
||||
}
|
||||
|
||||
headers := ctx.Resp.Header()
|
||||
headers.Set(HeaderContentEncoding, "gzip")
|
||||
headers.Set(HeaderVary, HeaderAcceptEncoding)
|
||||
|
||||
gz := gzip.NewWriter(ctx.Resp)
|
||||
defer gz.Close()
|
||||
|
||||
gzw := gzipResponseWriter{gz, ctx.Resp}
|
||||
ctx.Resp = gzw
|
||||
ctx.MapTo(gzw, (*http.ResponseWriter)(nil))
|
||||
|
||||
ctx.Next()
|
||||
|
||||
// delete content length after we know we have been written to
|
||||
gzw.Header().Del("Content-Length")
|
||||
}
|
||||
}
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
w *gzip.Writer
|
||||
ResponseWriter
|
||||
}
|
||||
|
||||
func (grw gzipResponseWriter) Write(p []byte) (int, error) {
|
||||
if len(grw.Header().Get(HeaderContentType)) == 0 {
|
||||
grw.Header().Set(HeaderContentType, http.DetectContentType(p))
|
||||
}
|
||||
|
||||
return grw.w.Write(p)
|
||||
}
|
||||
|
||||
func (grw gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
hijacker, ok := grw.ResponseWriter.(http.Hijacker)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
|
||||
}
|
||||
return hijacker.Hijack()
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Gzip(t *testing.T) {
|
||||
Convey("Gzip response content", t, func() {
|
||||
before := false
|
||||
|
||||
m := New()
|
||||
m.Use(Gziper())
|
||||
m.Use(func(r http.ResponseWriter) {
|
||||
r.(ResponseWriter).Before(func(rw ResponseWriter) {
|
||||
before = true
|
||||
})
|
||||
})
|
||||
m.Get("/", func() string { return "hello wolrd!" })
|
||||
|
||||
// Not yet gzip.
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
_, ok := resp.HeaderMap[HeaderContentEncoding]
|
||||
So(ok, ShouldBeFalse)
|
||||
|
||||
ce := resp.Header().Get(HeaderContentEncoding)
|
||||
So(strings.EqualFold(ce, "gzip"), ShouldBeFalse)
|
||||
|
||||
// Gzip now.
|
||||
resp = httptest.NewRecorder()
|
||||
req.Header.Set(HeaderAcceptEncoding, "gzip")
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
_, ok = resp.HeaderMap[HeaderContentEncoding]
|
||||
So(ok, ShouldBeTrue)
|
||||
|
||||
ce = resp.Header().Get(HeaderContentEncoding)
|
||||
So(strings.EqualFold(ce, "gzip"), ShouldBeTrue)
|
||||
|
||||
So(before, ShouldBeTrue)
|
||||
})
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
inject
|
||||
======
|
||||
|
||||
Dependency injection for go
|
||||
-1
@@ -1 +0,0 @@
|
||||
ignore
|
||||
-174
@@ -1,174 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package inject_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/Unknwon/macaron/inject"
|
||||
)
|
||||
|
||||
type SpecialString interface {
|
||||
}
|
||||
|
||||
type TestStruct struct {
|
||||
Dep1 string `inject:"t" json:"-"`
|
||||
Dep2 SpecialString `inject`
|
||||
Dep3 string
|
||||
}
|
||||
|
||||
type Greeter struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (g *Greeter) String() string {
|
||||
return "Hello, My name is" + g.Name
|
||||
}
|
||||
|
||||
/* Test Helpers */
|
||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||
if a != b {
|
||||
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func refute(t *testing.T, a interface{}, b interface{}) {
|
||||
if a == b {
|
||||
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_InjectorInvoke(t *testing.T) {
|
||||
injector := inject.New()
|
||||
expect(t, injector == nil, false)
|
||||
|
||||
dep := "some dependency"
|
||||
injector.Map(dep)
|
||||
dep2 := "another dep"
|
||||
injector.MapTo(dep2, (*SpecialString)(nil))
|
||||
dep3 := make(chan *SpecialString)
|
||||
dep4 := make(chan *SpecialString)
|
||||
typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem())
|
||||
typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem())
|
||||
injector.Set(typRecv, reflect.ValueOf(dep3))
|
||||
injector.Set(typSend, reflect.ValueOf(dep4))
|
||||
|
||||
_, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) {
|
||||
expect(t, d1, dep)
|
||||
expect(t, d2, dep2)
|
||||
expect(t, reflect.TypeOf(d3).Elem(), reflect.TypeOf(dep3).Elem())
|
||||
expect(t, reflect.TypeOf(d4).Elem(), reflect.TypeOf(dep4).Elem())
|
||||
expect(t, reflect.TypeOf(d3).ChanDir(), reflect.RecvDir)
|
||||
expect(t, reflect.TypeOf(d4).ChanDir(), reflect.SendDir)
|
||||
})
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func Test_InjectorInvokeReturnValues(t *testing.T) {
|
||||
injector := inject.New()
|
||||
expect(t, injector == nil, false)
|
||||
|
||||
dep := "some dependency"
|
||||
injector.Map(dep)
|
||||
dep2 := "another dep"
|
||||
injector.MapTo(dep2, (*SpecialString)(nil))
|
||||
|
||||
result, err := injector.Invoke(func(d1 string, d2 SpecialString) string {
|
||||
expect(t, d1, dep)
|
||||
expect(t, d2, dep2)
|
||||
return "Hello world"
|
||||
})
|
||||
|
||||
expect(t, result[0].String(), "Hello world")
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func Test_InjectorApply(t *testing.T) {
|
||||
injector := inject.New()
|
||||
|
||||
injector.Map("a dep").MapTo("another dep", (*SpecialString)(nil))
|
||||
|
||||
s := TestStruct{}
|
||||
err := injector.Apply(&s)
|
||||
expect(t, err, nil)
|
||||
|
||||
expect(t, s.Dep1, "a dep")
|
||||
expect(t, s.Dep2, "another dep")
|
||||
}
|
||||
|
||||
func Test_InterfaceOf(t *testing.T) {
|
||||
iType := inject.InterfaceOf((*SpecialString)(nil))
|
||||
expect(t, iType.Kind(), reflect.Interface)
|
||||
|
||||
iType = inject.InterfaceOf((**SpecialString)(nil))
|
||||
expect(t, iType.Kind(), reflect.Interface)
|
||||
|
||||
// Expecting nil
|
||||
defer func() {
|
||||
rec := recover()
|
||||
refute(t, rec, nil)
|
||||
}()
|
||||
iType = inject.InterfaceOf((*testing.T)(nil))
|
||||
}
|
||||
|
||||
func Test_InjectorSet(t *testing.T) {
|
||||
injector := inject.New()
|
||||
typ := reflect.TypeOf("string")
|
||||
typSend := reflect.ChanOf(reflect.SendDir, typ)
|
||||
typRecv := reflect.ChanOf(reflect.RecvDir, typ)
|
||||
|
||||
// instantiating unidirectional channels is not possible using reflect
|
||||
// http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064
|
||||
chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
|
||||
chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
|
||||
|
||||
injector.Set(typSend, chanSend)
|
||||
injector.Set(typRecv, chanRecv)
|
||||
|
||||
expect(t, injector.GetVal(typSend).IsValid(), true)
|
||||
expect(t, injector.GetVal(typRecv).IsValid(), true)
|
||||
expect(t, injector.GetVal(chanSend.Type()).IsValid(), false)
|
||||
}
|
||||
|
||||
func Test_InjectorGet(t *testing.T) {
|
||||
injector := inject.New()
|
||||
|
||||
injector.Map("some dependency")
|
||||
|
||||
expect(t, injector.GetVal(reflect.TypeOf("string")).IsValid(), true)
|
||||
expect(t, injector.GetVal(reflect.TypeOf(11)).IsValid(), false)
|
||||
}
|
||||
|
||||
func Test_InjectorSetParent(t *testing.T) {
|
||||
injector := inject.New()
|
||||
injector.MapTo("another dep", (*SpecialString)(nil))
|
||||
|
||||
injector2 := inject.New()
|
||||
injector2.SetParent(injector)
|
||||
|
||||
expect(t, injector2.GetVal(inject.InterfaceOf((*SpecialString)(nil))).IsValid(), true)
|
||||
}
|
||||
|
||||
func TestInjectImplementors(t *testing.T) {
|
||||
injector := inject.New()
|
||||
g := &Greeter{"Jeremy"}
|
||||
injector.Map(g)
|
||||
|
||||
expect(t, injector.GetVal(inject.InterfaceOf((*fmt.Stringer)(nil))).IsValid(), true)
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Logger(t *testing.T) {
|
||||
Convey("Global logger", t, func() {
|
||||
buf := bytes.NewBufferString("")
|
||||
m := New()
|
||||
m.Map(log.New(buf, "[Macaron] ", 0))
|
||||
m.Use(Logger())
|
||||
m.Use(func(res http.ResponseWriter) {
|
||||
res.WriteHeader(http.StatusNotFound)
|
||||
})
|
||||
m.Get("/", func() {})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, http.StatusNotFound)
|
||||
So(len(buf.String()), ShouldBeGreaterThan, 0)
|
||||
})
|
||||
|
||||
if ColorLog {
|
||||
Convey("Color console output", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/:code:int", func(ctx *Context) (int, string) {
|
||||
return ctx.ParamsInt(":code"), ""
|
||||
})
|
||||
|
||||
// Just for testing if logger would capture.
|
||||
codes := []int{200, 201, 202, 301, 302, 304, 401, 403, 404, 500}
|
||||
for _, code := range codes {
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/"+com.ToStr(code), nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
-218
@@ -1,218 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Version(t *testing.T) {
|
||||
Convey("Get version", t, func() {
|
||||
So(Version(), ShouldEqual, _VERSION)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_New(t *testing.T) {
|
||||
Convey("Initialize a new instance", t, func() {
|
||||
So(New(), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Just test that Run doesn't bomb", t, func() {
|
||||
go New().Run()
|
||||
time.Sleep(1 * time.Second)
|
||||
os.Setenv("PORT", "4001")
|
||||
go New().Run("0.0.0.0")
|
||||
go New().Run(4002)
|
||||
go New().Run("0.0.0.0", 4003)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Macaron_Before(t *testing.T) {
|
||||
Convey("Register before handlers", t, func() {
|
||||
m := New()
|
||||
m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
|
||||
return false
|
||||
})
|
||||
m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
|
||||
return true
|
||||
})
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Macaron_ServeHTTP(t *testing.T) {
|
||||
Convey("Serve HTTP requests", t, func() {
|
||||
result := ""
|
||||
m := New()
|
||||
m.Use(func(c *Context) {
|
||||
result += "foo"
|
||||
c.Next()
|
||||
result += "ban"
|
||||
})
|
||||
m.Use(func(c *Context) {
|
||||
result += "bar"
|
||||
c.Next()
|
||||
result += "baz"
|
||||
})
|
||||
m.Get("/", func() {})
|
||||
m.Action(func(res http.ResponseWriter, req *http.Request) {
|
||||
result += "bat"
|
||||
res.WriteHeader(http.StatusBadRequest)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(result, ShouldEqual, "foobarbatbazban")
|
||||
So(resp.Code, ShouldEqual, http.StatusBadRequest)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Macaron_Handlers(t *testing.T) {
|
||||
Convey("Add custom handlers", t, func() {
|
||||
result := ""
|
||||
batman := func(c *Context) {
|
||||
result += "batman!"
|
||||
}
|
||||
|
||||
m := New()
|
||||
m.Use(func(c *Context) {
|
||||
result += "foo"
|
||||
c.Next()
|
||||
result += "ban"
|
||||
})
|
||||
m.Handlers(
|
||||
batman,
|
||||
batman,
|
||||
batman,
|
||||
)
|
||||
|
||||
Convey("Add not callable function", func() {
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
}()
|
||||
m.Use("shit")
|
||||
})
|
||||
|
||||
m.Get("/", func() {})
|
||||
m.Action(func(res http.ResponseWriter, req *http.Request) {
|
||||
result += "bat"
|
||||
res.WriteHeader(http.StatusBadRequest)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(result, ShouldEqual, "batman!batman!batman!bat")
|
||||
So(resp.Code, ShouldEqual, http.StatusBadRequest)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Macaron_EarlyWrite(t *testing.T) {
|
||||
Convey("Write early content to response", t, func() {
|
||||
result := ""
|
||||
m := New()
|
||||
m.Use(func(res http.ResponseWriter) {
|
||||
result += "foobar"
|
||||
res.Write([]byte("Hello world"))
|
||||
})
|
||||
m.Use(func() {
|
||||
result += "bat"
|
||||
})
|
||||
m.Get("/", func() {})
|
||||
m.Action(func(res http.ResponseWriter) {
|
||||
result += "baz"
|
||||
res.WriteHeader(http.StatusBadRequest)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(result, ShouldEqual, "foobar")
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Macaron_Written(t *testing.T) {
|
||||
Convey("Written sign", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
m := New()
|
||||
m.Handlers(func(res http.ResponseWriter) {
|
||||
res.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
ctx := m.createContext(resp, &http.Request{Method: "GET"})
|
||||
So(ctx.Written(), ShouldBeFalse)
|
||||
|
||||
ctx.run()
|
||||
So(ctx.Written(), ShouldBeTrue)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Macaron_Basic_NoRace(t *testing.T) {
|
||||
Convey("Make sure no race between requests", t, func() {
|
||||
m := New()
|
||||
handlers := []Handler{func() {}, func() {}}
|
||||
// Ensure append will not realloc to trigger the race condition
|
||||
m.handlers = handlers[:1]
|
||||
m.Get("/", func() {})
|
||||
req, _ := http.NewRequest("GET", "/", nil)
|
||||
for i := 0; i < 2; i++ {
|
||||
go func() {
|
||||
resp := httptest.NewRecorder()
|
||||
m.ServeHTTP(resp, req)
|
||||
}()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SetENV(t *testing.T) {
|
||||
Convey("Get and save environment variable", t, func() {
|
||||
tests := []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"", "development"},
|
||||
{"not_development", "not_development"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
setENV(test.in)
|
||||
So(Env, ShouldEqual, test.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Config(t *testing.T) {
|
||||
Convey("Set and get configuration object", t, func() {
|
||||
So(Config(), ShouldNotBeNil)
|
||||
cfg, err := SetConfig([]byte(""))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Recovery(t *testing.T) {
|
||||
Convey("Recovery from panic", t, func() {
|
||||
buf := bytes.NewBufferString("")
|
||||
setENV(DEV)
|
||||
|
||||
m := New()
|
||||
m.Map(log.New(buf, "[Macaron] ", 0))
|
||||
m.Use(func(res http.ResponseWriter, req *http.Request) {
|
||||
res.Header().Set("Content-Type", "unpredictable")
|
||||
})
|
||||
m.Use(Recovery())
|
||||
m.Use(func(res http.ResponseWriter, req *http.Request) {
|
||||
panic("here is a panic!")
|
||||
})
|
||||
m.Get("/", func() {})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, http.StatusInternalServerError)
|
||||
So(resp.HeaderMap.Get("Content-Type"), ShouldEqual, "text/html")
|
||||
So(buf.String(), ShouldNotBeEmpty)
|
||||
})
|
||||
|
||||
Convey("Revocery panic to another response writer", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
resp2 := httptest.NewRecorder()
|
||||
setENV(DEV)
|
||||
|
||||
m := New()
|
||||
m.Use(Recovery())
|
||||
m.Use(func(c *Context) {
|
||||
c.MapTo(resp2, (*http.ResponseWriter)(nil))
|
||||
panic("here is a panic!")
|
||||
})
|
||||
m.Get("/", func() {})
|
||||
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp2.Code, ShouldEqual, http.StatusInternalServerError)
|
||||
So(resp2.HeaderMap.Get("Content-Type"), ShouldEqual, "text/html")
|
||||
So(resp2.Body.Len(), ShouldBeGreaterThan, 0)
|
||||
})
|
||||
}
|
||||
-581
@@ -1,581 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
type Greeting struct {
|
||||
One string `json:"one"`
|
||||
Two string `json:"two"`
|
||||
}
|
||||
|
||||
type GreetingXML struct {
|
||||
XMLName xml.Name `xml:"greeting"`
|
||||
One string `xml:"one,attr"`
|
||||
Two string `xml:"two,attr"`
|
||||
}
|
||||
|
||||
func Test_Render_JSON(t *testing.T) {
|
||||
Convey("Render JSON", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer())
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.JSON(300, Greeting{"hello", "world"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, `{"one":"hello","two":"world"}`)
|
||||
})
|
||||
|
||||
Convey("Render JSON with prefix", t, func() {
|
||||
m := Classic()
|
||||
prefix := ")]}',\n"
|
||||
m.Use(Renderer(RenderOptions{
|
||||
PrefixJSON: []byte(prefix),
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.JSON(300, Greeting{"hello", "world"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, prefix+`{"one":"hello","two":"world"}`)
|
||||
})
|
||||
|
||||
Convey("Render Indented JSON", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
IndentJSON: true,
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.JSON(300, Greeting{"hello", "world"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, `{
|
||||
"one": "hello",
|
||||
"two": "world"
|
||||
}`)
|
||||
})
|
||||
|
||||
Convey("Render JSON and return string", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer())
|
||||
m.Get("/foobar", func(r Render) {
|
||||
result, err := r.JSONString(Greeting{"hello", "world"})
|
||||
So(err, ShouldBeNil)
|
||||
So(result, ShouldEqual, `{"one":"hello","two":"world"}`)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Render with charset JSON", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Charset: "foobar",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.JSON(300, Greeting{"hello", "world"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=foobar")
|
||||
So(resp.Body.String(), ShouldEqual, `{"one":"hello","two":"world"}`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_XML(t *testing.T) {
|
||||
Convey("Render XML", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer())
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.XML(300, GreetingXML{One: "hello", Two: "world"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentXML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, `<greeting one="hello" two="world"></greeting>`)
|
||||
})
|
||||
|
||||
Convey("Render XML with prefix", t, func() {
|
||||
m := Classic()
|
||||
prefix := ")]}',\n"
|
||||
m.Use(Renderer(RenderOptions{
|
||||
PrefixXML: []byte(prefix),
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.XML(300, GreetingXML{One: "hello", Two: "world"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentXML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, prefix+`<greeting one="hello" two="world"></greeting>`)
|
||||
})
|
||||
|
||||
Convey("Render Indented XML", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
IndentXML: true,
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.XML(300, GreetingXML{One: "hello", Two: "world"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentXML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, `<greeting one="hello" two="world"></greeting>`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_HTML(t *testing.T) {
|
||||
Convey("Render HTML", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderers(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}, "fixtures/basic2"))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "hello", "jeremy")
|
||||
r.SetTemplatePath("", "fixtures/basic2")
|
||||
})
|
||||
m.Get("/foobar2", func(r Render) {
|
||||
if r.HasTemplateSet("basic2") {
|
||||
r.HTMLSet(200, "basic2", "hello", "jeremy")
|
||||
}
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello jeremy</h1>")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/foobar2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>What's up, jeremy</h1>")
|
||||
|
||||
Convey("Change render templates path", func() {
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>What's up, jeremy</h1>")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Render HTML and return string", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderers(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}, "basic2:fixtures/basic2"))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
result, err := r.HTMLString("hello", "jeremy")
|
||||
So(err, ShouldBeNil)
|
||||
So(result, ShouldEqual, "<h1>Hello jeremy</h1>")
|
||||
})
|
||||
m.Get("/foobar2", func(r Render) {
|
||||
result, err := r.HTMLSetString("basic2", "hello", "jeremy")
|
||||
So(err, ShouldBeNil)
|
||||
So(result, ShouldEqual, "<h1>What's up, jeremy</h1>")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/foobar2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Render with nested HTML", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "admin/index", "jeremy")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Admin jeremy</h1>")
|
||||
})
|
||||
|
||||
Convey("Render bad HTML", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "nope", nil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusInternalServerError)
|
||||
So(resp.Body.String(), ShouldEqual, "html/template: \"nope\" is undefined\n")
|
||||
})
|
||||
|
||||
Convey("Invalid template set", t, func() {
|
||||
Convey("Empty template set argument", func() {
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
}()
|
||||
m := Classic()
|
||||
m.Use(Renderers(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}, ""))
|
||||
})
|
||||
|
||||
Convey("Bad template set path", func() {
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
}()
|
||||
m := Classic()
|
||||
m.Use(Renderers(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}, "404"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_XHTML(t *testing.T) {
|
||||
Convey("Render XHTML", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
HTMLContentType: ContentXHTML,
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "hello", "jeremy")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentXHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello jeremy</h1>")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_Extensions(t *testing.T) {
|
||||
Convey("Render with extensions", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
Extensions: []string{".tmpl", ".html"},
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "hypertext", nil)
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "Hypertext!")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_Funcs(t *testing.T) {
|
||||
Convey("Render with functions", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/custom_funcs",
|
||||
Funcs: []template.FuncMap{
|
||||
{
|
||||
"myCustomFunc": func() string {
|
||||
return "My custom function"
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "index", "jeremy")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Body.String(), ShouldEqual, "My custom function")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_Layout(t *testing.T) {
|
||||
Convey("Render with layout", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
Layout: "layout",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "content", "jeremy")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Body.String(), ShouldEqual, "head<h1>jeremy</h1>foot")
|
||||
})
|
||||
|
||||
Convey("Render with current layout", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
Layout: "current_layout",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "content", "jeremy")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Body.String(), ShouldEqual, "content head<h1>jeremy</h1>content foot")
|
||||
})
|
||||
|
||||
Convey("Render with override layout", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
Layout: "layout",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "content", "jeremy", HTMLOptions{
|
||||
Layout: "another_layout",
|
||||
})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "another head<h1>jeremy</h1>another foot")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_Delimiters(t *testing.T) {
|
||||
Convey("Render with delimiters", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Delims: Delims{"{[{", "}]}"},
|
||||
Directory: "fixtures/basic",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "delims", "jeremy")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello jeremy</h1>")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_BinaryData(t *testing.T) {
|
||||
Convey("Render binary data", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer())
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.RawData(200, []byte("hello there"))
|
||||
})
|
||||
m.Get("/foobar2", func(r Render) {
|
||||
r.RenderData(200, []byte("hello there"))
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, ContentBinary)
|
||||
So(resp.Body.String(), ShouldEqual, "hello there")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/foobar2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, CONTENT_PLAIN)
|
||||
So(resp.Body.String(), ShouldEqual, "hello there")
|
||||
})
|
||||
|
||||
Convey("Render binary data with mime type", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer())
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.RW().Header().Set(ContentType, "image/jpeg")
|
||||
r.RawData(200, []byte("..jpeg data.."))
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/foobar", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get(ContentType), ShouldEqual, "image/jpeg")
|
||||
So(resp.Body.String(), ShouldEqual, "..jpeg data..")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_Status(t *testing.T) {
|
||||
Convey("Render with status 204", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
r := TplRender{resp, newTemplateSet(), &RenderOptions{}, "", time.Now()}
|
||||
r.Status(204)
|
||||
So(resp.Code, ShouldEqual, http.StatusNoContent)
|
||||
})
|
||||
|
||||
Convey("Render with status 404", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
r := TplRender{resp, newTemplateSet(), &RenderOptions{}, "", time.Now()}
|
||||
r.Error(404)
|
||||
So(resp.Code, ShouldEqual, http.StatusNotFound)
|
||||
})
|
||||
|
||||
Convey("Render with status 500", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
r := TplRender{resp, newTemplateSet(), &RenderOptions{}, "", time.Now()}
|
||||
r.Error(500)
|
||||
So(resp.Code, ShouldEqual, http.StatusInternalServerError)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Render_NoRace(t *testing.T) {
|
||||
Convey("Make sure render has no race", t, func() {
|
||||
m := Classic()
|
||||
m.Use(Renderer(RenderOptions{
|
||||
Directory: "fixtures/basic",
|
||||
}))
|
||||
m.Get("/foobar", func(r Render) {
|
||||
r.HTML(200, "hello", "world")
|
||||
})
|
||||
|
||||
done := make(chan bool)
|
||||
doreq := func() {
|
||||
resp := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/foobar", nil)
|
||||
m.ServeHTTP(resp, req)
|
||||
done <- true
|
||||
}
|
||||
// Run two requests to check there is no race condition
|
||||
go doreq()
|
||||
go doreq()
|
||||
<-done
|
||||
<-done
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetExt(t *testing.T) {
|
||||
Convey("Get extension", t, func() {
|
||||
So(GetExt("test"), ShouldBeBlank)
|
||||
So(GetExt("test.tmpl"), ShouldEqual, ".tmpl")
|
||||
So(GetExt("test.go.tmpl"), ShouldEqual, ".go.tmpl")
|
||||
})
|
||||
}
|
||||
-188
@@ -1,188 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
type closeNotifyingRecorder struct {
|
||||
*httptest.ResponseRecorder
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
|
||||
return &closeNotifyingRecorder{
|
||||
httptest.NewRecorder(),
|
||||
make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *closeNotifyingRecorder) close() {
|
||||
c.closed <- true
|
||||
}
|
||||
|
||||
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
|
||||
return c.closed
|
||||
}
|
||||
|
||||
type hijackableResponse struct {
|
||||
Hijacked bool
|
||||
}
|
||||
|
||||
func newHijackableResponse() *hijackableResponse {
|
||||
return &hijackableResponse{}
|
||||
}
|
||||
|
||||
func (h *hijackableResponse) Header() http.Header { return nil }
|
||||
func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil }
|
||||
func (h *hijackableResponse) WriteHeader(code int) {}
|
||||
func (h *hijackableResponse) Flush() {}
|
||||
func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
h.Hijacked = true
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func Test_ResponseWriter(t *testing.T) {
|
||||
Convey("Write string to response writer", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(resp)
|
||||
rw.Write([]byte("Hello world"))
|
||||
|
||||
So(resp.Code, ShouldEqual, rw.Status())
|
||||
So(resp.Body.String(), ShouldEqual, "Hello world")
|
||||
So(rw.Status(), ShouldEqual, http.StatusOK)
|
||||
So(rw.Size(), ShouldEqual, 11)
|
||||
So(rw.Written(), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Write strings to response writer", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(resp)
|
||||
rw.Write([]byte("Hello world"))
|
||||
rw.Write([]byte("foo bar bat baz"))
|
||||
|
||||
So(resp.Code, ShouldEqual, rw.Status())
|
||||
So(resp.Body.String(), ShouldEqual, "Hello worldfoo bar bat baz")
|
||||
So(rw.Status(), ShouldEqual, http.StatusOK)
|
||||
So(rw.Size(), ShouldEqual, 26)
|
||||
So(rw.Written(), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Write header to response writer", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(resp)
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
|
||||
So(resp.Code, ShouldEqual, rw.Status())
|
||||
So(resp.Body.String(), ShouldBeBlank)
|
||||
So(rw.Status(), ShouldEqual, http.StatusNotFound)
|
||||
So(rw.Size(), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Write before response write", t, func() {
|
||||
result := ""
|
||||
resp := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(resp)
|
||||
rw.Before(func(ResponseWriter) {
|
||||
result += "foo"
|
||||
})
|
||||
rw.Before(func(ResponseWriter) {
|
||||
result += "bar"
|
||||
})
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
|
||||
So(resp.Code, ShouldEqual, rw.Status())
|
||||
So(resp.Body.String(), ShouldBeBlank)
|
||||
So(rw.Status(), ShouldEqual, http.StatusNotFound)
|
||||
So(rw.Size(), ShouldEqual, 0)
|
||||
So(result, ShouldEqual, "barfoo")
|
||||
})
|
||||
|
||||
Convey("Response writer with Hijack", t, func() {
|
||||
hijackable := newHijackableResponse()
|
||||
rw := NewResponseWriter(hijackable)
|
||||
hijacker, ok := rw.(http.Hijacker)
|
||||
So(ok, ShouldBeTrue)
|
||||
_, _, err := hijacker.Hijack()
|
||||
So(err, ShouldBeNil)
|
||||
So(hijackable.Hijacked, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Response writer with bad Hijack", t, func() {
|
||||
hijackable := new(http.ResponseWriter)
|
||||
rw := NewResponseWriter(*hijackable)
|
||||
hijacker, ok := rw.(http.Hijacker)
|
||||
So(ok, ShouldBeTrue)
|
||||
_, _, err := hijacker.Hijack()
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Response writer with close notify", t, func() {
|
||||
resp := newCloseNotifyingRecorder()
|
||||
rw := NewResponseWriter(resp)
|
||||
closed := false
|
||||
notifier := rw.(http.CloseNotifier).CloseNotify()
|
||||
resp.close()
|
||||
select {
|
||||
case <-notifier:
|
||||
closed = true
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
So(closed, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Response writer with flusher", t, func() {
|
||||
resp := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(resp)
|
||||
_, ok := rw.(http.Flusher)
|
||||
So(ok, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Response writer with flusher handler", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
f, ok := w.(http.Flusher)
|
||||
So(ok, ShouldBeTrue)
|
||||
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
w.Header().Set("Connection", "keep-alive")
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
io.WriteString(w, "data: Hello\n\n")
|
||||
f.Flush()
|
||||
}
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/events", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Body.String(), ShouldEqual, "data: Hello\n\ndata: Hello\n\n")
|
||||
})
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Return_Handler(t *testing.T) {
|
||||
Convey("Return with status and body", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/", func() (int, string) {
|
||||
return 418, "i'm a teapot"
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusTeapot)
|
||||
So(resp.Body.String(), ShouldEqual, "i'm a teapot")
|
||||
})
|
||||
|
||||
Convey("Return with pointer", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/", func() *string {
|
||||
str := "hello world"
|
||||
return &str
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Body.String(), ShouldEqual, "hello world")
|
||||
})
|
||||
|
||||
Convey("Return with byte slice", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/", func() []byte {
|
||||
return []byte("hello world")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Body.String(), ShouldEqual, "hello world")
|
||||
})
|
||||
}
|
||||
-199
@@ -1,199 +0,0 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Router_Handle(t *testing.T) {
|
||||
Convey("Register all HTTP methods routes", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/get", func() string {
|
||||
return "GET"
|
||||
})
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "GET")
|
||||
|
||||
m.Patch("/patch", func() string {
|
||||
return "PATCH"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("PATCH", "/patch", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "PATCH")
|
||||
|
||||
m.Post("/post", func() string {
|
||||
return "POST"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("POST", "/post", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "POST")
|
||||
|
||||
m.Put("/put", func() string {
|
||||
return "PUT"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("PUT", "/put", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "PUT")
|
||||
|
||||
m.Delete("/delete", func() string {
|
||||
return "DELETE"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("DELETE", "/delete", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "DELETE")
|
||||
|
||||
m.Options("/options", func() string {
|
||||
return "OPTIONS"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("OPTIONS", "/options", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "OPTIONS")
|
||||
|
||||
m.Head("/head", func() string {
|
||||
return "HEAD"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("HEAD", "/head", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "HEAD")
|
||||
|
||||
m.Any("/any", func() string {
|
||||
return "ANY"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/any", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "ANY")
|
||||
|
||||
m.Route("/route", "GET,POST", func() string {
|
||||
return "ROUTE"
|
||||
})
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("POST", "/route", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "ROUTE")
|
||||
})
|
||||
|
||||
Convey("Register all HTTP methods routes with combo", t, func() {
|
||||
m := Classic()
|
||||
m.SetURLPrefix("/prefix")
|
||||
m.Use(Renderer())
|
||||
m.Combo("/", func(ctx *Context) {
|
||||
ctx.Data["prefix"] = "Prefix_"
|
||||
}).
|
||||
Get(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "GET" }).
|
||||
Patch(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "PATCH" }).
|
||||
Post(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "POST" }).
|
||||
Put(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "PUT" }).
|
||||
Delete(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "DELETE" }).
|
||||
Options(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "OPTIONS" }).
|
||||
Head(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "HEAD" })
|
||||
|
||||
for name := range _HTTP_METHODS {
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest(name, "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Prefix_"+name)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
}()
|
||||
m.Combo("/").Get(func() {}).Get(nil)
|
||||
})
|
||||
|
||||
Convey("Register duplicated routes", t, func() {
|
||||
r := NewRouter()
|
||||
r.Get("/")
|
||||
r.Get("/")
|
||||
})
|
||||
|
||||
Convey("Register invalid HTTP method", t, func() {
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
}()
|
||||
r := NewRouter()
|
||||
r.Handle("404", "/", nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Router_Group(t *testing.T) {
|
||||
Convey("Register route group", t, func() {
|
||||
m := Classic()
|
||||
m.Group("/api", func() {
|
||||
m.Group("/v1", func() {
|
||||
m.Get("/list", func() string {
|
||||
return "Well done!"
|
||||
})
|
||||
})
|
||||
})
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/api/v1/list", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Well done!")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Router_NotFound(t *testing.T) {
|
||||
Convey("Custom not found handler", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/", func() {})
|
||||
m.NotFound(func() string {
|
||||
return "Custom not found"
|
||||
})
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/404", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Custom not found")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Router_splat(t *testing.T) {
|
||||
Convey("Register router with glob", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/*", func(ctx *Context) string {
|
||||
return ctx.Params("*")
|
||||
})
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/hahaha", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "hahaha")
|
||||
})
|
||||
}
|
||||
-246
@@ -1,246 +0,0 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
var currentRoot, _ = os.Getwd()
|
||||
|
||||
func Test_Static(t *testing.T) {
|
||||
Convey("Serve static files", t, func() {
|
||||
m := New()
|
||||
m.Use(Static("./"))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
resp.Body = new(bytes.Buffer)
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get("Expires"), ShouldBeBlank)
|
||||
So(resp.Body.Len(), ShouldBeGreaterThan, 0)
|
||||
|
||||
Convey("Change static path", func() {
|
||||
m.Get("/", func(ctx *Context) {
|
||||
ctx.ChangeStaticPath("./", "inject")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
resp.Body = new(bytes.Buffer)
|
||||
req, err = http.NewRequest("GET", "http://localhost:4000/inject.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get("Expires"), ShouldBeBlank)
|
||||
So(resp.Body.Len(), ShouldBeGreaterThan, 0)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Serve static files with local path", t, func() {
|
||||
Root = os.TempDir()
|
||||
f, err := ioutil.TempFile(Root, "static_content")
|
||||
So(err, ShouldBeNil)
|
||||
f.WriteString("Expected Content")
|
||||
f.Close()
|
||||
|
||||
m := New()
|
||||
m.Use(Static("."))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
resp.Body = new(bytes.Buffer)
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/"+path.Base(strings.Replace(f.Name(), "\\", "/", -1)), nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header().Get("Expires"), ShouldBeBlank)
|
||||
So(resp.Body.String(), ShouldEqual, "Expected Content")
|
||||
})
|
||||
|
||||
Convey("Serve static files with head", t, func() {
|
||||
m := New()
|
||||
m.Use(Static(currentRoot))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
resp.Body = new(bytes.Buffer)
|
||||
req, err := http.NewRequest("HEAD", "http://localhost:4000/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(resp.Body.Len(), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Serve static files as post", t, func() {
|
||||
m := New()
|
||||
m.Use(Static(currentRoot))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("POST", "http://localhost:4000/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldEqual, http.StatusNotFound)
|
||||
})
|
||||
|
||||
Convey("Serve static files with bad directory", t, func() {
|
||||
m := Classic()
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Code, ShouldNotEqual, http.StatusOK)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Static_Options(t *testing.T) {
|
||||
Convey("Serve static files with options logging", t, func() {
|
||||
var buf bytes.Buffer
|
||||
m := NewWithLogger(&buf)
|
||||
opt := StaticOptions{}
|
||||
m.Use(Static(currentRoot, opt))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
|
||||
|
||||
// Not disable logging.
|
||||
m.Handlers()
|
||||
buf.Reset()
|
||||
opt.SkipLogging = true
|
||||
m.Use(Static(currentRoot, opt))
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(buf.Len(), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Serve static files with options serve index", t, func() {
|
||||
var buf bytes.Buffer
|
||||
m := NewWithLogger(&buf)
|
||||
opt := StaticOptions{IndexFile: "macaron.go"}
|
||||
m.Use(Static(currentRoot, opt))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
|
||||
})
|
||||
|
||||
Convey("Serve static files with options prefix", t, func() {
|
||||
var buf bytes.Buffer
|
||||
m := NewWithLogger(&buf)
|
||||
opt := StaticOptions{Prefix: "public"}
|
||||
m.Use(Static(currentRoot, opt))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/public/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
|
||||
})
|
||||
|
||||
Convey("Serve static files with options expires", t, func() {
|
||||
var buf bytes.Buffer
|
||||
m := NewWithLogger(&buf)
|
||||
opt := StaticOptions{Expires: func() string { return "46" }}
|
||||
m.Use(Static(currentRoot, opt))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Header().Get("Expires"), ShouldEqual, "46")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Static_Redirect(t *testing.T) {
|
||||
Convey("Serve static files with redirect", t, func() {
|
||||
m := New()
|
||||
m.Use(Static(currentRoot, StaticOptions{Prefix: "/public"}))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/public", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusFound)
|
||||
So(resp.Header().Get("Location"), ShouldEqual, "/public/")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Statics(t *testing.T) {
|
||||
Convey("Serve multiple static routers", t, func() {
|
||||
Convey("Register empty directory", func() {
|
||||
defer func() {
|
||||
So(recover(), ShouldNotBeNil)
|
||||
}()
|
||||
|
||||
m := New()
|
||||
m.Use(Statics(StaticOptions{}))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
})
|
||||
|
||||
Convey("Serve normally", func() {
|
||||
var buf bytes.Buffer
|
||||
m := NewWithLogger(&buf)
|
||||
m.Use(Statics(StaticOptions{}, currentRoot, currentRoot+"/inject"))
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "http://localhost:4000/inject/inject.go", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
|
||||
So(resp.Code, ShouldEqual, http.StatusOK)
|
||||
So(buf.String(), ShouldEndWith, "[Macaron] [Static] Serving /inject/inject.go\n")
|
||||
})
|
||||
})
|
||||
}
|
||||
-421
@@ -1,421 +0,0 @@
|
||||
// Copyright 2013 Beego Authors
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
// NOTE: last sync 0c93364 on Dec 19, 2014.
|
||||
|
||||
import (
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
)
|
||||
|
||||
type leafInfo struct {
|
||||
// Names of wildcards that lead to this leaf.
|
||||
// eg, ["id" "name"] for the wildcard ":id" and ":name".
|
||||
wildcards []string
|
||||
// Not nil if the leaf is regexp.
|
||||
regexps *regexp.Regexp
|
||||
handle Handle
|
||||
}
|
||||
|
||||
func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params Params) {
|
||||
if leaf.regexps == nil {
|
||||
if len(wildcardValues) == 0 && len(leaf.wildcards) > 0 {
|
||||
if com.IsSliceContainsStr(leaf.wildcards, ":") {
|
||||
params = make(map[string]string)
|
||||
j := 0
|
||||
for _, v := range leaf.wildcards {
|
||||
if v == ":" {
|
||||
continue
|
||||
}
|
||||
params[v] = ""
|
||||
j += 1
|
||||
}
|
||||
return true, params
|
||||
}
|
||||
return false, nil
|
||||
} else if len(wildcardValues) == 0 {
|
||||
return true, nil // Static path.
|
||||
}
|
||||
|
||||
// Match *
|
||||
if len(leaf.wildcards) == 1 && leaf.wildcards[0] == ":splat" {
|
||||
params = make(map[string]string)
|
||||
params[":splat"] = path.Join(wildcardValues...)
|
||||
return true, params
|
||||
}
|
||||
|
||||
// Match *.*
|
||||
if len(leaf.wildcards) == 3 && leaf.wildcards[0] == "." {
|
||||
params = make(map[string]string)
|
||||
lastone := wildcardValues[len(wildcardValues)-1]
|
||||
strs := strings.SplitN(lastone, ".", 2)
|
||||
if len(strs) == 2 {
|
||||
params[":ext"] = strs[1]
|
||||
} else {
|
||||
params[":ext"] = ""
|
||||
}
|
||||
params[":path"] = path.Join(wildcardValues[:len(wildcardValues)-1]...) + "/" + strs[0]
|
||||
return true, params
|
||||
}
|
||||
|
||||
// Match :id
|
||||
params = make(map[string]string)
|
||||
j := 0
|
||||
for _, v := range leaf.wildcards {
|
||||
if v == ":" {
|
||||
continue
|
||||
}
|
||||
if v == "." {
|
||||
lastone := wildcardValues[len(wildcardValues)-1]
|
||||
strs := strings.SplitN(lastone, ".", 2)
|
||||
if len(strs) == 2 {
|
||||
params[":ext"] = strs[1]
|
||||
} else {
|
||||
params[":ext"] = ""
|
||||
}
|
||||
if len(wildcardValues[j:]) == 1 {
|
||||
params[":path"] = strs[0]
|
||||
} else {
|
||||
params[":path"] = path.Join(wildcardValues[j:]...) + "/" + strs[0]
|
||||
}
|
||||
return true, params
|
||||
}
|
||||
if len(wildcardValues) <= j {
|
||||
return false, nil
|
||||
}
|
||||
params[v] = wildcardValues[j]
|
||||
j++
|
||||
}
|
||||
if len(params) != len(wildcardValues) {
|
||||
return false, nil
|
||||
}
|
||||
return true, params
|
||||
}
|
||||
|
||||
if !leaf.regexps.MatchString(path.Join(wildcardValues...)) {
|
||||
return false, nil
|
||||
}
|
||||
params = make(map[string]string)
|
||||
matches := leaf.regexps.FindStringSubmatch(path.Join(wildcardValues...))
|
||||
for i, match := range matches[1:] {
|
||||
params[leaf.wildcards[i]] = match
|
||||
}
|
||||
return true, params
|
||||
}
|
||||
|
||||
// Tree represents a router tree for Macaron instance.
|
||||
type Tree struct {
|
||||
fixroutes map[string]*Tree
|
||||
wildcard *Tree
|
||||
leaves []*leafInfo
|
||||
}
|
||||
|
||||
// NewTree initializes and returns a router tree.
|
||||
func NewTree() *Tree {
|
||||
return &Tree{
|
||||
fixroutes: make(map[string]*Tree),
|
||||
}
|
||||
}
|
||||
|
||||
// splitPath splites patthen into parts.
|
||||
//
|
||||
// Examples:
|
||||
// "/" -> []
|
||||
// "/admin" -> ["admin"]
|
||||
// "/admin/" -> ["admin"]
|
||||
// "/admin/users" -> ["admin", "users"]
|
||||
func splitPath(pattern string) []string {
|
||||
if len(pattern) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
elements := strings.Split(pattern, "/")
|
||||
if elements[0] == "" {
|
||||
elements = elements[1:]
|
||||
}
|
||||
if elements[len(elements)-1] == "" {
|
||||
elements = elements[:len(elements)-1]
|
||||
}
|
||||
return elements
|
||||
}
|
||||
|
||||
// AddRouter adds a new route to router tree.
|
||||
func (t *Tree) AddRouter(pattern string, handle Handle) {
|
||||
t.addSegments(splitPath(pattern), handle, nil, "")
|
||||
}
|
||||
|
||||
// splitSegment splits segment into parts.
|
||||
//
|
||||
// Examples:
|
||||
// "admin" -> false, nil, ""
|
||||
// ":id" -> true, [:id], ""
|
||||
// "?:id" -> true, [: :id], "" : meaning can empty
|
||||
// ":id:int" -> true, [:id], ([0-9]+)
|
||||
// ":name:string" -> true, [:name], ([\w]+)
|
||||
// ":id([0-9]+)" -> true, [:id], ([0-9]+)
|
||||
// ":id([0-9]+)_:name" -> true, [:id :name], ([0-9]+)_(.+)
|
||||
// "cms_:id_:page.html" -> true, [:id :page], cms_(.+)_(.+).html
|
||||
// "*" -> true, [:splat], ""
|
||||
// "*.*" -> true,[. :path :ext], "" . meaning separator
|
||||
func splitSegment(key string) (bool, []string, string) {
|
||||
if strings.HasPrefix(key, "*") {
|
||||
if key == "*.*" {
|
||||
return true, []string{".", ":path", ":ext"}, ""
|
||||
} else {
|
||||
return true, []string{":splat"}, ""
|
||||
}
|
||||
}
|
||||
if strings.ContainsAny(key, ":") {
|
||||
var paramsNum int
|
||||
var out []rune
|
||||
var start bool
|
||||
var startexp bool
|
||||
var param []rune
|
||||
var expt []rune
|
||||
var skipnum int
|
||||
params := []string{}
|
||||
reg := regexp.MustCompile(`[a-zA-Z0-9]+`)
|
||||
for i, v := range key {
|
||||
if skipnum > 0 {
|
||||
skipnum -= 1
|
||||
continue
|
||||
}
|
||||
if start {
|
||||
//:id:int and :name:string
|
||||
if v == ':' {
|
||||
if len(key) >= i+4 {
|
||||
if key[i+1:i+4] == "int" {
|
||||
out = append(out, []rune("([0-9]+)")...)
|
||||
params = append(params, ":"+string(param))
|
||||
start = false
|
||||
startexp = false
|
||||
skipnum = 3
|
||||
param = make([]rune, 0)
|
||||
paramsNum += 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(key) >= i+7 {
|
||||
if key[i+1:i+7] == "string" {
|
||||
out = append(out, []rune(`([\w]+)`)...)
|
||||
params = append(params, ":"+string(param))
|
||||
paramsNum += 1
|
||||
start = false
|
||||
startexp = false
|
||||
skipnum = 6
|
||||
param = make([]rune, 0)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
// params only support a-zA-Z0-9
|
||||
if reg.MatchString(string(v)) {
|
||||
param = append(param, v)
|
||||
continue
|
||||
}
|
||||
if v != '(' {
|
||||
out = append(out, []rune(`(.+)`)...)
|
||||
params = append(params, ":"+string(param))
|
||||
param = make([]rune, 0)
|
||||
paramsNum += 1
|
||||
start = false
|
||||
startexp = false
|
||||
}
|
||||
}
|
||||
if startexp {
|
||||
if v != ')' {
|
||||
expt = append(expt, v)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if v == ':' {
|
||||
param = make([]rune, 0)
|
||||
start = true
|
||||
} else if v == '(' {
|
||||
startexp = true
|
||||
start = false
|
||||
params = append(params, ":"+string(param))
|
||||
paramsNum += 1
|
||||
expt = make([]rune, 0)
|
||||
expt = append(expt, '(')
|
||||
} else if v == ')' {
|
||||
startexp = false
|
||||
expt = append(expt, ')')
|
||||
out = append(out, expt...)
|
||||
param = make([]rune, 0)
|
||||
} else if v == '?' {
|
||||
params = append(params, ":")
|
||||
} else {
|
||||
out = append(out, v)
|
||||
}
|
||||
}
|
||||
if len(param) > 0 {
|
||||
if paramsNum > 0 {
|
||||
out = append(out, []rune(`(.+)`)...)
|
||||
}
|
||||
params = append(params, ":"+string(param))
|
||||
}
|
||||
return true, params, string(out)
|
||||
} else {
|
||||
return false, nil, ""
|
||||
}
|
||||
}
|
||||
|
||||
// addSegments add segments to the router tree.
|
||||
func (t *Tree) addSegments(segments []string, handle Handle, wildcards []string, reg string) {
|
||||
// Fixed root route.
|
||||
if len(segments) == 0 {
|
||||
if reg != "" {
|
||||
filterCards := make([]string, 0, len(wildcards))
|
||||
for _, v := range wildcards {
|
||||
if v == ":" || v == "." {
|
||||
continue
|
||||
}
|
||||
filterCards = append(filterCards, v)
|
||||
}
|
||||
t.leaves = append(t.leaves, &leafInfo{
|
||||
handle: handle,
|
||||
wildcards: filterCards,
|
||||
regexps: regexp.MustCompile("^" + reg + "$"),
|
||||
})
|
||||
} else {
|
||||
t.leaves = append(t.leaves, &leafInfo{
|
||||
handle: handle,
|
||||
wildcards: wildcards,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
seg := segments[0]
|
||||
iswild, params, regexpStr := splitSegment(seg)
|
||||
//for the router /login/*/access match /login/2009/11/access
|
||||
if !iswild && com.IsSliceContainsStr(wildcards, ":splat") {
|
||||
iswild = true
|
||||
regexpStr = seg
|
||||
}
|
||||
if seg == "*" && len(wildcards) > 0 && reg == "" {
|
||||
iswild = true
|
||||
regexpStr = "(.+)"
|
||||
}
|
||||
if iswild {
|
||||
if t.wildcard == nil {
|
||||
t.wildcard = NewTree()
|
||||
}
|
||||
if regexpStr != "" {
|
||||
if reg == "" {
|
||||
rr := ""
|
||||
for _, w := range wildcards {
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
if w == ":splat" {
|
||||
rr = rr + "(.+)/"
|
||||
} else {
|
||||
rr = rr + "([^/]+)/"
|
||||
}
|
||||
}
|
||||
regexpStr = rr + regexpStr
|
||||
} else {
|
||||
regexpStr = "/" + regexpStr
|
||||
}
|
||||
} else if reg != "" {
|
||||
if seg == "*.*" {
|
||||
regexpStr = "/([^.]+).(.+)"
|
||||
} else {
|
||||
for _, w := range params {
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
regexpStr = "/([^/]+)" + regexpStr
|
||||
}
|
||||
}
|
||||
}
|
||||
t.wildcard.addSegments(segments[1:], handle, append(wildcards, params...), reg+regexpStr)
|
||||
} else {
|
||||
subTree, ok := t.fixroutes[seg]
|
||||
if !ok {
|
||||
subTree = NewTree()
|
||||
t.fixroutes[seg] = subTree
|
||||
}
|
||||
subTree.addSegments(segments[1:], handle, wildcards, reg)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree) match(segments []string, wildcardValues []string) (handle Handle, params Params) {
|
||||
// Handle leaf nodes.
|
||||
if len(segments) == 0 {
|
||||
for _, l := range t.leaves {
|
||||
if ok, pa := l.match(wildcardValues); ok {
|
||||
return l.handle, pa
|
||||
}
|
||||
}
|
||||
if t.wildcard != nil {
|
||||
for _, l := range t.wildcard.leaves {
|
||||
if ok, pa := l.match(wildcardValues); ok {
|
||||
return l.handle, pa
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
seg, segs := segments[0], segments[1:]
|
||||
|
||||
subTree, ok := t.fixroutes[seg]
|
||||
if ok {
|
||||
handle, params = subTree.match(segs, wildcardValues)
|
||||
} else if len(segs) == 0 { //.json .xml
|
||||
if subindex := strings.LastIndex(seg, "."); subindex != -1 {
|
||||
subTree, ok = t.fixroutes[seg[:subindex]]
|
||||
if ok {
|
||||
handle, params = subTree.match(segs, wildcardValues)
|
||||
if handle != nil {
|
||||
if params == nil {
|
||||
params = make(map[string]string)
|
||||
}
|
||||
params[":ext"] = seg[subindex+1:]
|
||||
return handle, params
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if handle == nil && t.wildcard != nil {
|
||||
handle, params = t.wildcard.match(segs, append(wildcardValues, seg))
|
||||
}
|
||||
if handle == nil {
|
||||
for _, l := range t.leaves {
|
||||
if ok, pa := l.match(append(wildcardValues, segments...)); ok {
|
||||
return l.handle, pa
|
||||
}
|
||||
}
|
||||
}
|
||||
return handle, params
|
||||
}
|
||||
|
||||
// Match returns Handle and params if any route is matched.
|
||||
func (t *Tree) Match(pattern string) (Handle, Params) {
|
||||
if len(pattern) == 0 || pattern[0] != '/' {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return t.match(splitPath(pattern), nil)
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package macaron
|
||||
|
||||
import (
|
||||
// "net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_splitSegment(t *testing.T) {
|
||||
type result struct {
|
||||
Ok bool
|
||||
Parts []string
|
||||
Regex string
|
||||
}
|
||||
cases := map[string]result{
|
||||
"admin": result{false, nil, ""},
|
||||
":id": result{true, []string{":id"}, ""},
|
||||
"?:id": result{true, []string{":", ":id"}, ""},
|
||||
":id:int": result{true, []string{":id"}, "([0-9]+)"},
|
||||
":name:string": result{true, []string{":name"}, `([\w]+)`},
|
||||
":id([0-9]+)": result{true, []string{":id"}, "([0-9]+)"},
|
||||
":id([0-9]+)_:name": result{true, []string{":id", ":name"}, "([0-9]+)_(.+)"},
|
||||
"cms_:id_:page.html": result{true, []string{":id", ":page"}, "cms_(.+)_(.+).html"},
|
||||
"*": result{true, []string{":splat"}, ""},
|
||||
"*.*": result{true, []string{".", ":path", ":ext"}, ""},
|
||||
}
|
||||
Convey("Splits segment into parts", t, func() {
|
||||
for key, result := range cases {
|
||||
ok, parts, regex := splitSegment(key)
|
||||
So(ok, ShouldEqual, result.Ok)
|
||||
if result.Parts == nil {
|
||||
So(parts, ShouldBeNil)
|
||||
} else {
|
||||
So(parts, ShouldNotBeNil)
|
||||
So(strings.Join(parts, " "), ShouldEqual, strings.Join(result.Parts, " "))
|
||||
}
|
||||
So(regex, ShouldEqual, result.Regex)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Tree_Match(t *testing.T) {
|
||||
type result struct {
|
||||
pattern string
|
||||
reqUrl string
|
||||
params map[string]string
|
||||
}
|
||||
|
||||
cases := []result{
|
||||
{"/:id", "/123", map[string]string{":id": "123"}},
|
||||
{"/hello/?:id", "/hello", map[string]string{":id": ""}},
|
||||
{"/", "/", nil},
|
||||
{"", "", nil},
|
||||
{"/customer/login", "/customer/login", nil},
|
||||
{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}},
|
||||
{"/*", "/customer/123", map[string]string{":splat": "customer/123"}},
|
||||
{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}},
|
||||
{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}},
|
||||
{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}},
|
||||
{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}},
|
||||
{"/thumbnail/:size/uploads/*", "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg",
|
||||
map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}},
|
||||
{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}},
|
||||
{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}},
|
||||
{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}},
|
||||
{"/dl/:width:int/:height:int/*.*", "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg",
|
||||
map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}},
|
||||
{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}},
|
||||
{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}},
|
||||
{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}},
|
||||
{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}},
|
||||
{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}},
|
||||
{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}},
|
||||
{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}},
|
||||
{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}},
|
||||
{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}},
|
||||
{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}},
|
||||
{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}},
|
||||
{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}},
|
||||
}
|
||||
|
||||
Convey("Match routers in tree", t, func() {
|
||||
for _, c := range cases {
|
||||
t := NewTree()
|
||||
t.AddRouter(c.pattern, nil)
|
||||
_, params := t.Match(c.reqUrl)
|
||||
if params != nil {
|
||||
for k, v := range c.params {
|
||||
vv, ok := params[k]
|
||||
So(ok, ShouldBeTrue)
|
||||
So(vv, ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
AWS SDK for Go
|
||||
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Copyright 2014-2015 Stripe, Inc.
|
||||
+4
-7
@@ -57,16 +57,13 @@ func rcopy(dst, src reflect.Value, root bool) {
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
if !root {
|
||||
dst.Set(reflect.New(src.Type()).Elem())
|
||||
}
|
||||
|
||||
t := dst.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
name := t.Field(i).Name
|
||||
srcval := src.FieldByName(name)
|
||||
if srcval.IsValid() {
|
||||
rcopy(dst.FieldByName(name), srcval, false)
|
||||
srcVal := src.FieldByName(name)
|
||||
dstVal := dst.FieldByName(name)
|
||||
if srcVal.IsValid() && dstVal.CanSet() {
|
||||
rcopy(dstVal, srcVal, false)
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
|
||||
+32
@@ -77,6 +77,28 @@ func TestCopy(t *testing.T) {
|
||||
assert.NotEqual(t, f2.C, f1.C)
|
||||
}
|
||||
|
||||
func TestCopyNestedWithUnexported(t *testing.T) {
|
||||
type Bar struct {
|
||||
a int
|
||||
B int
|
||||
}
|
||||
type Foo struct {
|
||||
A string
|
||||
B Bar
|
||||
}
|
||||
|
||||
f1 := &Foo{A: "string", B: Bar{a: 1, B: 2}}
|
||||
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values match
|
||||
assert.Equal(t, f2.A, f1.A)
|
||||
assert.NotEqual(t, f2.B, f1.B)
|
||||
assert.NotEqual(t, f2.B.a, f1.B.a)
|
||||
assert.Equal(t, f2.B.B, f2.B.B)
|
||||
}
|
||||
|
||||
func TestCopyIgnoreNilMembers(t *testing.T) {
|
||||
type Foo struct {
|
||||
A *string
|
||||
@@ -136,6 +158,8 @@ func TestCopyDifferentStructs(t *testing.T) {
|
||||
C map[string]*int
|
||||
SrcUnique string
|
||||
SameNameDiffType int
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
type DstFoo struct {
|
||||
A int
|
||||
@@ -143,6 +167,8 @@ func TestCopyDifferentStructs(t *testing.T) {
|
||||
C map[string]*int
|
||||
DstUnique int
|
||||
SameNameDiffType string
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
@@ -159,6 +185,8 @@ func TestCopyDifferentStructs(t *testing.T) {
|
||||
},
|
||||
SrcUnique: "unique",
|
||||
SameNameDiffType: 1,
|
||||
unexportedPtr: &int1,
|
||||
ExportedPtr: &int2,
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
@@ -173,6 +201,10 @@ func TestCopyDifferentStructs(t *testing.T) {
|
||||
assert.Equal(t, 1, f1.SameNameDiffType)
|
||||
assert.Equal(t, 0, f2.DstUnique)
|
||||
assert.Equal(t, "", f2.SameNameDiffType)
|
||||
assert.Equal(t, int1, *f1.unexportedPtr)
|
||||
assert.Nil(t, f2.unexportedPtr)
|
||||
assert.Equal(t, int2, *f1.ExportedPtr)
|
||||
assert.Equal(t, int2, *f2.ExportedPtr)
|
||||
}
|
||||
|
||||
func ExampleCopyOf() {
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package awsutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// DeepEqual returns if the two values are deeply equal like reflect.DeepEqual.
|
||||
// In addition to this, this method will also dereference the input values if
|
||||
// possible so the DeepEqual performed will not fail if one parameter is a
|
||||
// pointer and the other is not.
|
||||
//
|
||||
// DeepEqual will not perform indirection of nested values of the input parameters.
|
||||
func DeepEqual(a, b interface{}) bool {
|
||||
ra := reflect.Indirect(reflect.ValueOf(a))
|
||||
rb := reflect.Indirect(reflect.ValueOf(b))
|
||||
|
||||
if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid {
|
||||
// If the elements are both nil, and of the same type the are equal
|
||||
// If they are of different types they are not equal
|
||||
return reflect.TypeOf(a) == reflect.TypeOf(b)
|
||||
} else if raValid != rbValid {
|
||||
// Both values must be valid to be equal
|
||||
return false
|
||||
}
|
||||
|
||||
return reflect.DeepEqual(ra.Interface(), rb.Interface())
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package awsutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeepEqual(t *testing.T) {
|
||||
cases := []struct {
|
||||
a, b interface{}
|
||||
equal bool
|
||||
}{
|
||||
{"a", "a", true},
|
||||
{"a", "b", false},
|
||||
{"a", aws.String(""), false},
|
||||
{"a", nil, false},
|
||||
{"a", aws.String("a"), true},
|
||||
{(*bool)(nil), (*bool)(nil), true},
|
||||
{(*bool)(nil), (*string)(nil), false},
|
||||
{nil, nil, true},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
assert.Equal(t, c.equal, awsutil.DeepEqual(c.a, c.b), "%d, a:%v b:%v, %t", i, c.a, c.b, c.equal)
|
||||
}
|
||||
}
|
||||
+74
-39
@@ -5,18 +5,20 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jmespath/go-jmespath"
|
||||
)
|
||||
|
||||
var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
|
||||
|
||||
// rValuesAtPath returns a slice of values found in value v. The values
|
||||
// in v are explored recursively so all nested values are collected.
|
||||
func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool) []reflect.Value {
|
||||
func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value {
|
||||
pathparts := strings.Split(path, "||")
|
||||
if len(pathparts) > 1 {
|
||||
for _, pathpart := range pathparts {
|
||||
vals := rValuesAtPath(v, pathpart, create, caseSensitive)
|
||||
if vals != nil && len(vals) > 0 {
|
||||
vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm)
|
||||
if len(vals) > 0 {
|
||||
return vals
|
||||
}
|
||||
}
|
||||
@@ -74,7 +76,16 @@ func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool)
|
||||
return false
|
||||
})
|
||||
|
||||
if create && value.Kind() == reflect.Ptr && value.IsNil() {
|
||||
if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 {
|
||||
if !value.IsNil() {
|
||||
value.Set(reflect.Zero(value.Type()))
|
||||
}
|
||||
return []reflect.Value{value}
|
||||
}
|
||||
|
||||
if createPath && value.Kind() == reflect.Ptr && value.IsNil() {
|
||||
// TODO if the value is the terminus it should not be created
|
||||
// if the value to be set to its position is nil.
|
||||
value.Set(reflect.New(value.Type().Elem()))
|
||||
value = value.Elem()
|
||||
} else {
|
||||
@@ -82,7 +93,7 @@ func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool)
|
||||
}
|
||||
|
||||
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
|
||||
if !create && value.IsNil() {
|
||||
if !createPath && value.IsNil() {
|
||||
value = reflect.ValueOf(nil)
|
||||
}
|
||||
}
|
||||
@@ -114,7 +125,7 @@ func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool)
|
||||
// pull out index
|
||||
i := int(*index)
|
||||
if i >= value.Len() { // check out of bounds
|
||||
if create {
|
||||
if createPath {
|
||||
// TODO resize slice
|
||||
} else {
|
||||
continue
|
||||
@@ -125,7 +136,7 @@ func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool)
|
||||
value = reflect.Indirect(value.Index(i))
|
||||
|
||||
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
|
||||
if !create && value.IsNil() {
|
||||
if !createPath && value.IsNil() {
|
||||
value = reflect.ValueOf(nil)
|
||||
}
|
||||
}
|
||||
@@ -142,46 +153,70 @@ func rValuesAtPath(v interface{}, path string, create bool, caseSensitive bool)
|
||||
return values
|
||||
}
|
||||
|
||||
// ValuesAtPath returns a list of objects at the lexical path inside of a structure
|
||||
func ValuesAtPath(i interface{}, path string) []interface{} {
|
||||
if rvals := rValuesAtPath(i, path, false, true); rvals != nil {
|
||||
vals := make([]interface{}, len(rvals))
|
||||
for i, rval := range rvals {
|
||||
vals[i] = rval.Interface()
|
||||
}
|
||||
return vals
|
||||
// ValuesAtPath returns a list of values at the case insensitive lexical
|
||||
// path inside of a structure.
|
||||
func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
|
||||
result, err := jmespath.Search(path, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil
|
||||
|
||||
v := reflect.ValueOf(result)
|
||||
if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) {
|
||||
return nil, nil
|
||||
}
|
||||
if s, ok := result.([]interface{}); ok {
|
||||
return s, err
|
||||
}
|
||||
if v.Kind() == reflect.Map && v.Len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if v.Kind() == reflect.Slice {
|
||||
out := make([]interface{}, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
out[i] = v.Index(i).Interface()
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
return []interface{}{result}, nil
|
||||
}
|
||||
|
||||
// ValuesAtAnyPath returns a list of objects at the case-insensitive lexical
|
||||
// path inside of a structure
|
||||
func ValuesAtAnyPath(i interface{}, path string) []interface{} {
|
||||
if rvals := rValuesAtPath(i, path, false, false); rvals != nil {
|
||||
vals := make([]interface{}, len(rvals))
|
||||
for i, rval := range rvals {
|
||||
vals[i] = rval.Interface()
|
||||
}
|
||||
return vals
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetValueAtPath sets an object at the lexical path inside of a structure
|
||||
// SetValueAtPath sets a value at the case insensitive lexical path inside
|
||||
// of a structure.
|
||||
func SetValueAtPath(i interface{}, path string, v interface{}) {
|
||||
if rvals := rValuesAtPath(i, path, true, true); rvals != nil {
|
||||
if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil {
|
||||
for _, rval := range rvals {
|
||||
rval.Set(reflect.ValueOf(v))
|
||||
if rval.Kind() == reflect.Ptr && rval.IsNil() {
|
||||
continue
|
||||
}
|
||||
setValue(rval, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetValueAtAnyPath sets an object at the case insensitive lexical path inside
|
||||
// of a structure
|
||||
func SetValueAtAnyPath(i interface{}, path string, v interface{}) {
|
||||
if rvals := rValuesAtPath(i, path, true, false); rvals != nil {
|
||||
for _, rval := range rvals {
|
||||
rval.Set(reflect.ValueOf(v))
|
||||
}
|
||||
func setValue(dstVal reflect.Value, src interface{}) {
|
||||
if dstVal.Kind() == reflect.Ptr {
|
||||
dstVal = reflect.Indirect(dstVal)
|
||||
}
|
||||
srcVal := reflect.ValueOf(src)
|
||||
|
||||
if !srcVal.IsValid() { // src is literal nil
|
||||
if dstVal.CanAddr() {
|
||||
// Convert to pointer so that pointer's value can be nil'ed
|
||||
// dstVal = dstVal.Addr()
|
||||
}
|
||||
dstVal.Set(reflect.Zero(dstVal.Type()))
|
||||
|
||||
} else if srcVal.Kind() == reflect.Ptr {
|
||||
if srcVal.IsNil() {
|
||||
srcVal = reflect.Zero(dstVal.Type())
|
||||
} else {
|
||||
srcVal = reflect.ValueOf(src).Elem()
|
||||
}
|
||||
dstVal.Set(srcVal)
|
||||
} else {
|
||||
dstVal.Set(srcVal)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+95
-21
@@ -13,6 +13,7 @@ type Struct struct {
|
||||
B *Struct
|
||||
D *Struct
|
||||
C string
|
||||
E map[string]string
|
||||
}
|
||||
|
||||
var data = Struct{
|
||||
@@ -21,30 +22,69 @@ var data = Struct{
|
||||
B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
|
||||
C: "initial",
|
||||
}
|
||||
var data2 = Struct{A: []Struct{
|
||||
{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
|
||||
{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
|
||||
}}
|
||||
|
||||
func TestValueAtPathSuccess(t *testing.T) {
|
||||
assert.Equal(t, []interface{}{"initial"}, awsutil.ValuesAtPath(data, "C"))
|
||||
assert.Equal(t, []interface{}{"value1"}, awsutil.ValuesAtPath(data, "A[0].C"))
|
||||
assert.Equal(t, []interface{}{"value2"}, awsutil.ValuesAtPath(data, "A[1].C"))
|
||||
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[2].C"))
|
||||
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtAnyPath(data, "a[2].c"))
|
||||
assert.Equal(t, []interface{}{"value3"}, awsutil.ValuesAtPath(data, "A[-1].C"))
|
||||
assert.Equal(t, []interface{}{"value1", "value2", "value3"}, awsutil.ValuesAtPath(data, "A[].C"))
|
||||
assert.Equal(t, []interface{}{"terminal"}, awsutil.ValuesAtPath(data, "B . B . C"))
|
||||
assert.Equal(t, []interface{}{"terminal", "terminal2"}, awsutil.ValuesAtPath(data, "B.*.C"))
|
||||
assert.Equal(t, []interface{}{"initial"}, awsutil.ValuesAtPath(data, "A.D.X || C"))
|
||||
var testCases = []struct {
|
||||
expect []interface{}
|
||||
data interface{}
|
||||
path string
|
||||
}{
|
||||
{[]interface{}{"initial"}, data, "C"},
|
||||
{[]interface{}{"value1"}, data, "A[0].C"},
|
||||
{[]interface{}{"value2"}, data, "A[1].C"},
|
||||
{[]interface{}{"value3"}, data, "A[2].C"},
|
||||
{[]interface{}{"value3"}, data, "a[2].c"},
|
||||
{[]interface{}{"value3"}, data, "A[-1].C"},
|
||||
{[]interface{}{"value1", "value2", "value3"}, data, "A[].C"},
|
||||
{[]interface{}{"terminal"}, data, "B . B . C"},
|
||||
{[]interface{}{"initial"}, data, "A.D.X || C"},
|
||||
{[]interface{}{"initial"}, data, "A[0].B || C"},
|
||||
{[]interface{}{
|
||||
Struct{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
|
||||
Struct{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
|
||||
}, data2, "A"},
|
||||
}
|
||||
for i, c := range testCases {
|
||||
v, err := awsutil.ValuesAtPath(c.data, c.path)
|
||||
assert.NoError(t, err, "case %d, expected no error, %s", i, c.path)
|
||||
assert.Equal(t, c.expect, v, "case %d, %s", i, c.path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueAtPathFailure(t *testing.T) {
|
||||
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "C.x"))
|
||||
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, ".x"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "X.Y.Z"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[100].C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "A[3].C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(data, "B.B.C.Z"))
|
||||
assert.Equal(t, []interface{}(nil), awsutil.ValuesAtPath(data, "z[-1].C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(nil, "A.B.C"))
|
||||
assert.Equal(t, []interface{}{}, awsutil.ValuesAtPath(Struct{}, "A"))
|
||||
var testCases = []struct {
|
||||
expect []interface{}
|
||||
errContains string
|
||||
data interface{}
|
||||
path string
|
||||
}{
|
||||
{nil, "", data, "C.x"},
|
||||
{nil, "SyntaxError: Invalid token: tDot", data, ".x"},
|
||||
{nil, "", data, "X.Y.Z"},
|
||||
{nil, "", data, "A[100].C"},
|
||||
{nil, "", data, "A[3].C"},
|
||||
{nil, "", data, "B.B.C.Z"},
|
||||
{nil, "", data, "z[-1].C"},
|
||||
{nil, "", nil, "A.B.C"},
|
||||
{[]interface{}{}, "", Struct{}, "A"},
|
||||
{nil, "", data, "A[0].B.C"},
|
||||
{nil, "", data, "D"},
|
||||
}
|
||||
|
||||
for i, c := range testCases {
|
||||
v, err := awsutil.ValuesAtPath(c.data, c.path)
|
||||
if c.errContains != "" {
|
||||
assert.Contains(t, err.Error(), c.errContains, "case %d, expected error, %s", i, c.path)
|
||||
continue
|
||||
} else {
|
||||
assert.NoError(t, err, "case %d, expected no error, %s", i, c.path)
|
||||
}
|
||||
assert.Equal(t, c.expect, v, "case %d, %s", i, c.path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetValueAtPathSuccess(t *testing.T) {
|
||||
@@ -61,8 +101,42 @@ func TestSetValueAtPathSuccess(t *testing.T) {
|
||||
assert.Equal(t, "test0", s.B.D.C)
|
||||
|
||||
var s2 Struct
|
||||
awsutil.SetValueAtAnyPath(&s2, "b.b.c", "test0")
|
||||
awsutil.SetValueAtPath(&s2, "b.b.c", "test0")
|
||||
assert.Equal(t, "test0", s2.B.B.C)
|
||||
awsutil.SetValueAtAnyPath(&s2, "A", []Struct{{}})
|
||||
awsutil.SetValueAtPath(&s2, "A", []Struct{{}})
|
||||
assert.Equal(t, []Struct{{}}, s2.A)
|
||||
|
||||
str := "foo"
|
||||
|
||||
s3 := Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", str)
|
||||
assert.Equal(t, "foo", s3.B.B.C)
|
||||
|
||||
s3 = Struct{B: &Struct{B: &Struct{C: str}}}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
|
||||
assert.Equal(t, "", s3.B.B.C)
|
||||
|
||||
s3 = Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
|
||||
assert.Equal(t, "", s3.B.B.C)
|
||||
|
||||
s3 = Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", &str)
|
||||
assert.Equal(t, "foo", s3.B.B.C)
|
||||
|
||||
var s4 struct{ Name *string }
|
||||
awsutil.SetValueAtPath(&s4, "Name", str)
|
||||
assert.Equal(t, str, *s4.Name)
|
||||
|
||||
s4 = struct{ Name *string }{}
|
||||
awsutil.SetValueAtPath(&s4, "Name", nil)
|
||||
assert.Equal(t, (*string)(nil), s4.Name)
|
||||
|
||||
s4 = struct{ Name *string }{Name: &str}
|
||||
awsutil.SetValueAtPath(&s4, "Name", nil)
|
||||
assert.Equal(t, (*string)(nil), s4.Name)
|
||||
|
||||
s4 = struct{ Name *string }{}
|
||||
awsutil.SetValueAtPath(&s4, "Name", &str)
|
||||
assert.Equal(t, str, *s4.Name)
|
||||
}
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package awsutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// StringValue returns the string representation of a value.
|
||||
func StringValue(i interface{}) string {
|
||||
var buf bytes.Buffer
|
||||
stringValue(reflect.ValueOf(i), 0, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
|
||||
for v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
buf.WriteString("{\n")
|
||||
|
||||
names := []string{}
|
||||
for i := 0; i < v.Type().NumField(); i++ {
|
||||
name := v.Type().Field(i).Name
|
||||
f := v.Field(i)
|
||||
if name[0:1] == strings.ToLower(name[0:1]) {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() {
|
||||
continue // ignore unset fields
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
for i, n := range names {
|
||||
val := v.FieldByName(n)
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(n + ": ")
|
||||
stringValue(val, indent+2, buf)
|
||||
|
||||
if i < len(names)-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
case reflect.Slice:
|
||||
nl, id, id2 := "", "", ""
|
||||
if v.Len() > 3 {
|
||||
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
|
||||
}
|
||||
buf.WriteString("[" + nl)
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
buf.WriteString(id2)
|
||||
stringValue(v.Index(i), indent+2, buf)
|
||||
|
||||
if i < v.Len()-1 {
|
||||
buf.WriteString("," + nl)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(nl + id + "]")
|
||||
case reflect.Map:
|
||||
buf.WriteString("{\n")
|
||||
|
||||
for i, k := range v.MapKeys() {
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(k.String() + ": ")
|
||||
stringValue(v.MapIndex(k), indent+2, buf)
|
||||
|
||||
if i < v.Len()-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
default:
|
||||
format := "%v"
|
||||
switch v.Interface().(type) {
|
||||
case string:
|
||||
format = "%q"
|
||||
}
|
||||
fmt.Fprintf(buf, format, v.Interface())
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// A Config provides configuration to a service client instance.
|
||||
type Config struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
Endpoint, SigningRegion string
|
||||
}
|
||||
|
||||
// ConfigProvider provides a generic way for a service client to receive
|
||||
// the ClientConfig without circular dependencies.
|
||||
type ConfigProvider interface {
|
||||
ClientConfig(serviceName string, cfgs ...*aws.Config) Config
|
||||
}
|
||||
|
||||
// A Client implements the base client request and response handling
|
||||
// used by all service clients.
|
||||
type Client struct {
|
||||
request.Retryer
|
||||
metadata.ClientInfo
|
||||
|
||||
Config aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// New will return a pointer to a new initialized service client.
|
||||
func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client {
|
||||
svc := &Client{
|
||||
Config: cfg,
|
||||
ClientInfo: info,
|
||||
Handlers: handlers,
|
||||
}
|
||||
|
||||
switch retryer, ok := cfg.Retryer.(request.Retryer); {
|
||||
case ok:
|
||||
svc.Retryer = retryer
|
||||
case cfg.Retryer != nil && cfg.Logger != nil:
|
||||
s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer)
|
||||
cfg.Logger.Log(s)
|
||||
fallthrough
|
||||
default:
|
||||
maxRetries := aws.IntValue(cfg.MaxRetries)
|
||||
if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
|
||||
maxRetries = 3
|
||||
}
|
||||
svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries}
|
||||
}
|
||||
|
||||
svc.AddDebugHandlers()
|
||||
|
||||
for _, option := range options {
|
||||
option(svc)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// NewRequest returns a new Request pointer for the service API
|
||||
// operation and parameters.
|
||||
func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
|
||||
return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data)
|
||||
}
|
||||
|
||||
// AddDebugHandlers injects debug logging handlers into the service to log request
|
||||
// debug information.
|
||||
func (c *Client) AddDebugHandlers() {
|
||||
if !c.Config.LogLevel.AtLeast(aws.LogDebug) {
|
||||
return
|
||||
}
|
||||
|
||||
c.Handlers.Send.PushFront(logRequest)
|
||||
c.Handlers.Send.PushBack(logResponse)
|
||||
}
|
||||
|
||||
const logReqMsg = `DEBUG: Request %s/%s Details:
|
||||
---[ REQUEST POST-SIGN ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
|
||||
if logBody {
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
}
|
||||
|
||||
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||
---[ RESPONSE ]--------------------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
var msg = "no reponse data"
|
||||
if r.HTTPResponse != nil {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
msg = string(dumpedBody)
|
||||
} else if r.Error != nil {
|
||||
msg = r.Error.Error()
|
||||
}
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ClientInfo.ServiceName, r.Operation.Name, msg))
|
||||
}
|
||||
Generated
Vendored
+4
-8
@@ -1,11 +1,10 @@
|
||||
package service
|
||||
package client
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
@@ -22,16 +21,13 @@ import (
|
||||
// // This implementation always has 100 max retries
|
||||
// func (d retryer) MaxRetries() uint { return 100 }
|
||||
type DefaultRetryer struct {
|
||||
*Service
|
||||
NumMaxRetries int
|
||||
}
|
||||
|
||||
// MaxRetries returns the number of maximum returns the service will use to make
|
||||
// an individual API request.
|
||||
func (d DefaultRetryer) MaxRetries() uint {
|
||||
if aws.IntValue(d.Service.Config.MaxRetries) < 0 {
|
||||
return d.DefaultMaxRetries
|
||||
}
|
||||
return uint(aws.IntValue(d.Service.Config.MaxRetries))
|
||||
func (d DefaultRetryer) MaxRetries() int {
|
||||
return d.NumMaxRetries
|
||||
}
|
||||
|
||||
// RetryRules returns the delay duration before retrying this request again
|
||||
Generated
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
package metadata
|
||||
|
||||
// ClientInfo wraps immutable data from the client.Client structure.
|
||||
type ClientInfo struct {
|
||||
ServiceName string
|
||||
APIVersion string
|
||||
Endpoint string
|
||||
SigningName string
|
||||
SigningRegion string
|
||||
JSONVersion string
|
||||
TargetPrefix string
|
||||
}
|
||||
+48
-17
@@ -7,15 +7,20 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
// DefaultRetries is the default number of retries for a service. The value of
|
||||
// -1 indicates that the service specific retry default will be used.
|
||||
const DefaultRetries = -1
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own default
|
||||
// number of retries. This will be the default action if Config.MaxRetries
|
||||
// is nil also.
|
||||
const UseServiceDefaultRetries = -1
|
||||
|
||||
// RequestRetryer is an alias for a type that implements the request.Retryer interface.
|
||||
type RequestRetryer interface{}
|
||||
|
||||
// A Config provides service configuration for service clients. By default,
|
||||
// all clients will use the {defaults.DefaultConfig} structure.
|
||||
type Config struct {
|
||||
// The credentials object to use when signing requests. Defaults to
|
||||
// {defaults.DefaultChainCredentials}.
|
||||
// a chain of credential providers to search for credentials in environment
|
||||
// variables, shared credential file, and EC2 Instance Roles.
|
||||
Credentials *credentials.Credentials
|
||||
|
||||
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||
@@ -57,6 +62,21 @@ type Config struct {
|
||||
// configuration.
|
||||
MaxRetries *int
|
||||
|
||||
// Retryer guides how HTTP requests should be retried in case of recoverable failures.
|
||||
//
|
||||
// When nil or the value does not implement the request.Retryer interface,
|
||||
// the request.DefaultRetryer will be used.
|
||||
//
|
||||
// When both Retryer and MaxRetries are non-nil, the former is used and
|
||||
// the latter ignored.
|
||||
//
|
||||
// To set the Retryer field in a type-safe manner and with chaining, use
|
||||
// the request.WithRetryer helper function:
|
||||
//
|
||||
// cfg := request.WithRetryer(aws.NewConfig(), myRetryer)
|
||||
//
|
||||
Retryer RequestRetryer
|
||||
|
||||
// Disables semantic parameter validation, which validates input for missing
|
||||
// required fields and/or other semantic request input errors.
|
||||
DisableParamValidation *bool
|
||||
@@ -171,15 +191,17 @@ func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
|
||||
return c
|
||||
}
|
||||
|
||||
// Merge returns a new Config with the other Config's attribute values merged into
|
||||
// this Config. If the other Config's attribute is nil it will not be merged into
|
||||
// the new Config to be returned.
|
||||
func (c Config) Merge(other *Config) *Config {
|
||||
if other == nil {
|
||||
return &c
|
||||
// MergeIn merges the passed in configs into the existing config object.
|
||||
func (c *Config) MergeIn(cfgs ...*Config) {
|
||||
for _, other := range cfgs {
|
||||
mergeInConfig(c, other)
|
||||
}
|
||||
}
|
||||
|
||||
dst := c
|
||||
func mergeInConfig(dst *Config, other *Config) {
|
||||
if other == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if other.Credentials != nil {
|
||||
dst.Credentials = other.Credentials
|
||||
@@ -213,6 +235,10 @@ func (c Config) Merge(other *Config) *Config {
|
||||
dst.MaxRetries = other.MaxRetries
|
||||
}
|
||||
|
||||
if other.Retryer != nil {
|
||||
dst.Retryer = other.Retryer
|
||||
}
|
||||
|
||||
if other.DisableParamValidation != nil {
|
||||
dst.DisableParamValidation = other.DisableParamValidation
|
||||
}
|
||||
@@ -228,12 +254,17 @@ func (c Config) Merge(other *Config) *Config {
|
||||
if other.SleepDelay != nil {
|
||||
dst.SleepDelay = other.SleepDelay
|
||||
}
|
||||
|
||||
return &dst
|
||||
}
|
||||
|
||||
// Copy will return a shallow copy of the Config object.
|
||||
func (c Config) Copy() *Config {
|
||||
dst := c
|
||||
return &dst
|
||||
// Copy will return a shallow copy of the Config object. If any additional
|
||||
// configurations are provided they will be merged into the new config returned.
|
||||
func (c *Config) Copy(cfgs ...*Config) *Config {
|
||||
dst := &Config{}
|
||||
dst.MergeIn(c)
|
||||
|
||||
for _, cfg := range cfgs {
|
||||
dst.MergeIn(cfg)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
+8
-2
@@ -18,7 +18,7 @@ var copyTestConfig = Config{
|
||||
HTTPClient: http.DefaultClient,
|
||||
LogLevel: LogLevel(LogDebug),
|
||||
Logger: NewDefaultLogger(),
|
||||
MaxRetries: Int(DefaultRetries),
|
||||
MaxRetries: Int(3),
|
||||
DisableParamValidation: Bool(true),
|
||||
DisableComputeChecksums: Bool(true),
|
||||
S3ForcePathStyle: Bool(true),
|
||||
@@ -31,6 +31,11 @@ func TestCopy(t *testing.T) {
|
||||
t.Errorf("Copy() = %+v", got)
|
||||
t.Errorf(" want %+v", want)
|
||||
}
|
||||
|
||||
got.Region = String("other")
|
||||
if got.Region == want.Region {
|
||||
t.Errorf("Expect setting copy values not not reflect in source")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyReturnsNewInstance(t *testing.T) {
|
||||
@@ -69,7 +74,8 @@ var mergeTests = []struct {
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
for i, tt := range mergeTests {
|
||||
got := tt.cfg.Merge(tt.in)
|
||||
got := tt.cfg.Copy()
|
||||
got.MergeIn(tt.in)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Config %d %+v", i, tt.cfg)
|
||||
t.Errorf(" Merge(%+v)", tt.in)
|
||||
|
||||
+17
-14
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
@@ -23,7 +24,7 @@ type lener interface {
|
||||
// BuildContentLengthHandler builds the content length of a request based on the body,
|
||||
// or will use the HTTPRequest.Header's "Content-Length" if defined. If unable
|
||||
// to determine request body length and no "Content-Length" was specified it will panic.
|
||||
var BuildContentLengthHandler = request.NamedHandler{"core.BuildContentLengthHandler", func(r *request.Request) {
|
||||
var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLengthHandler", Fn: func(r *request.Request) {
|
||||
if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
|
||||
length, _ := strconv.ParseInt(slength, 10, 64)
|
||||
r.HTTPRequest.ContentLength = length
|
||||
@@ -49,17 +50,19 @@ var BuildContentLengthHandler = request.NamedHandler{"core.BuildContentLengthHan
|
||||
r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
|
||||
}}
|
||||
|
||||
// UserAgentHandler is a request handler for injecting User agent into requests.
|
||||
var UserAgentHandler = request.NamedHandler{"core.UserAgentHandler", func(r *request.Request) {
|
||||
r.HTTPRequest.Header.Set("User-Agent", aws.SDKName+"/"+aws.SDKVersion)
|
||||
}}
|
||||
// SDKVersionUserAgentHandler is a request handler for adding the SDK Version to the user agent.
|
||||
var SDKVersionUserAgentHandler = request.NamedHandler{
|
||||
Name: "core.SDKVersionUserAgentHandler",
|
||||
Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion,
|
||||
runtime.Version(), runtime.GOOS, runtime.GOARCH),
|
||||
}
|
||||
|
||||
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
||||
|
||||
// SendHandler is a request handler to send service request using HTTP client.
|
||||
var SendHandler = request.NamedHandler{"core.SendHandler", func(r *request.Request) {
|
||||
var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *request.Request) {
|
||||
var err error
|
||||
r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest)
|
||||
r.HTTPResponse, err = r.Config.HTTPClient.Do(r.HTTPRequest)
|
||||
if err != nil {
|
||||
// Capture the case where url.Error is returned for error processing
|
||||
// response. e.g. 301 without location header comes back as string
|
||||
@@ -92,7 +95,7 @@ var SendHandler = request.NamedHandler{"core.SendHandler", func(r *request.Reque
|
||||
}}
|
||||
|
||||
// ValidateResponseHandler is a request handler to validate service response.
|
||||
var ValidateResponseHandler = request.NamedHandler{"core.ValidateResponseHandler", func(r *request.Request) {
|
||||
var ValidateResponseHandler = request.NamedHandler{Name: "core.ValidateResponseHandler", Fn: func(r *request.Request) {
|
||||
if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
|
||||
// this may be replaced by an UnmarshalError handler
|
||||
r.Error = awserr.New("UnknownError", "unknown error", nil)
|
||||
@@ -101,7 +104,7 @@ var ValidateResponseHandler = request.NamedHandler{"core.ValidateResponseHandler
|
||||
|
||||
// AfterRetryHandler performs final checks to determine if the request should
|
||||
// be retried and how long to delay.
|
||||
var AfterRetryHandler = request.NamedHandler{"core.AfterRetryHandler", func(r *request.Request) {
|
||||
var AfterRetryHandler = request.NamedHandler{Name: "core.AfterRetryHandler", Fn: func(r *request.Request) {
|
||||
// If one of the other handlers already set the retry state
|
||||
// we don't want to override it based on the service's state
|
||||
if r.Retryable == nil {
|
||||
@@ -110,13 +113,13 @@ var AfterRetryHandler = request.NamedHandler{"core.AfterRetryHandler", func(r *r
|
||||
|
||||
if r.WillRetry() {
|
||||
r.RetryDelay = r.RetryRules(r)
|
||||
r.Service.Config.SleepDelay(r.RetryDelay)
|
||||
r.Config.SleepDelay(r.RetryDelay)
|
||||
|
||||
// when the expired token exception occurs the credentials
|
||||
// need to be expired locally so that the next request to
|
||||
// get credentials will trigger a credentials refresh.
|
||||
if r.IsErrorExpired() {
|
||||
r.Service.Config.Credentials.Expire()
|
||||
r.Config.Credentials.Expire()
|
||||
}
|
||||
|
||||
r.RetryCount++
|
||||
@@ -127,10 +130,10 @@ var AfterRetryHandler = request.NamedHandler{"core.AfterRetryHandler", func(r *r
|
||||
// ValidateEndpointHandler is a request handler to validate a request had the
|
||||
// appropriate Region and Endpoint set. Will set r.Error if the endpoint or
|
||||
// region is not valid.
|
||||
var ValidateEndpointHandler = request.NamedHandler{"core.ValidateEndpointHandler", func(r *request.Request) {
|
||||
if r.Service.SigningRegion == "" && aws.StringValue(r.Service.Config.Region) == "" {
|
||||
var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointHandler", Fn: func(r *request.Request) {
|
||||
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
||||
r.Error = aws.ErrMissingRegion
|
||||
} else if r.Service.Endpoint == "" {
|
||||
} else if r.ClientInfo.Endpoint == "" {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}}
|
||||
|
||||
Generated
Vendored
+11
-5
@@ -13,12 +13,13 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
)
|
||||
|
||||
func TestValidateEndpointHandler(t *testing.T) {
|
||||
os.Clearenv()
|
||||
svc := service.New(aws.NewConfig().WithRegion("us-west-2"))
|
||||
|
||||
svc := awstesting.NewClient(aws.NewConfig().WithRegion("us-west-2"))
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
@@ -30,7 +31,8 @@ func TestValidateEndpointHandler(t *testing.T) {
|
||||
|
||||
func TestValidateEndpointHandlerErrorRegion(t *testing.T) {
|
||||
os.Clearenv()
|
||||
svc := service.New(nil)
|
||||
|
||||
svc := awstesting.NewClient()
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
@@ -58,7 +60,11 @@ func (m *mockCredsProvider) IsExpired() bool {
|
||||
func TestAfterRetryRefreshCreds(t *testing.T) {
|
||||
os.Clearenv()
|
||||
credProvider := &mockCredsProvider{}
|
||||
svc := service.New(&aws.Config{Credentials: credentials.NewCredentials(credProvider), MaxRetries: aws.Int(1)})
|
||||
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewCredentials(credProvider),
|
||||
MaxRetries: aws.Int(1),
|
||||
})
|
||||
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.ValidateResponse.PushBack(func(r *request.Request) {
|
||||
@@ -91,7 +97,7 @@ func (t *testSendHandlerTransport) RoundTrip(r *http.Request) (*http.Response, e
|
||||
}
|
||||
|
||||
func TestSendHandlerError(t *testing.T) {
|
||||
svc := service.New(&aws.Config{
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
HTTPClient: &http.Client{
|
||||
Transport: &testSendHandlerTransport{},
|
||||
},
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// ValidateParametersHandler is a request handler to validate the input parameters.
|
||||
// Validating parameters only has meaning if done prior to the request being sent.
|
||||
var ValidateParametersHandler = request.NamedHandler{"core.ValidateParametersHandler", func(r *request.Request) {
|
||||
var ValidateParametersHandler = request.NamedHandler{Name: "core.ValidateParametersHandler", Fn: func(r *request.Request) {
|
||||
if r.ParamsFilled() {
|
||||
v := validator{errors: []string{}}
|
||||
v.validateAny(reflect.ValueOf(r.Params), "")
|
||||
|
||||
Generated
Vendored
+6
-6
@@ -7,17 +7,17 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testSvc = func() *service.Service {
|
||||
s := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: &aws.Config{},
|
||||
var testSvc = func() *client.Client {
|
||||
s := &client.Client{
|
||||
Config: aws.Config{},
|
||||
ClientInfo: metadata.ClientInfo{
|
||||
ServiceName: "mock-service",
|
||||
APIVersion: "2015-01-01",
|
||||
},
|
||||
|
||||
Generated
Vendored
+34
-29
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
)
|
||||
@@ -25,9 +26,6 @@ import (
|
||||
// Client: &http.Client{
|
||||
// Timeout: 10 * time.Second,
|
||||
// },
|
||||
// // Use default EC2 Role metadata endpoint, Alternate endpoints can be
|
||||
// // specified setting Endpoint to something else.
|
||||
// Endpoint: "",
|
||||
// // Do not use early expiry of credentials. If a non zero value is
|
||||
// // specified the credentials will be expired early
|
||||
// ExpiryWindow: 0,
|
||||
@@ -35,8 +33,8 @@ import (
|
||||
type EC2RoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
// EC2Metadata client to use when connecting to EC2 metadata service
|
||||
Client *ec2metadata.Client
|
||||
// Required EC2Metadata client to use when connecting to EC2 metadata service.
|
||||
Client *ec2metadata.EC2Metadata
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
@@ -50,33 +48,40 @@ type EC2RoleProvider struct {
|
||||
ExpiryWindow time.Duration
|
||||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials object
|
||||
// wrapping the EC2RoleProvider.
|
||||
//
|
||||
// Takes a custom http.Client which can be configured for custom handling of
|
||||
// things such as timeout.
|
||||
//
|
||||
// Endpoint is the URL that the EC2RoleProvider will connect to when retrieving
|
||||
// role and credentials.
|
||||
//
|
||||
// Window is the expiry window that will be subtracted from the expiry returned
|
||||
// by the role credential request. This is done so that the credentials will
|
||||
// expire sooner than their actual lifespan.
|
||||
func NewCredentials(client *ec2metadata.Client, window time.Duration) *credentials.Credentials {
|
||||
return credentials.NewCredentials(&EC2RoleProvider{
|
||||
Client: client,
|
||||
ExpiryWindow: window,
|
||||
})
|
||||
// NewCredentials returns a pointer to a new Credentials object wrapping
|
||||
// the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client.
|
||||
// The ConfigProvider is satisfied by the session.Session type.
|
||||
func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||
p := &EC2RoleProvider{
|
||||
Client: ec2metadata.New(c),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping
|
||||
// the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2
|
||||
// metadata service.
|
||||
func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||
p := &EC2RoleProvider{
|
||||
Client: client,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// Retrieve retrieves credentials from the EC2 service.
|
||||
// Error will be returned if the request fails, or unable to extract
|
||||
// the desired credentials.
|
||||
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
||||
if m.Client == nil {
|
||||
m.Client = ec2metadata.New(nil)
|
||||
}
|
||||
|
||||
credsList, err := requestCredList(m.Client)
|
||||
if err != nil {
|
||||
return credentials.Value{}, err
|
||||
@@ -101,7 +106,7 @@ func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// A ec2RoleCredRespBody provides the shape for deserializing credential
|
||||
// A ec2RoleCredRespBody provides the shape for unmarshalling credential
|
||||
// request responses.
|
||||
type ec2RoleCredRespBody struct {
|
||||
// Success State
|
||||
@@ -119,7 +124,7 @@ const iamSecurityCredsPath = "/iam/security-credentials"
|
||||
|
||||
// requestCredList requests a list of credentials from the EC2 service.
|
||||
// If there are no credentials, or there is an error making or receiving the request
|
||||
func requestCredList(client *ec2metadata.Client) ([]string, error) {
|
||||
func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
|
||||
resp, err := client.GetMetadata(iamSecurityCredsPath)
|
||||
if err != nil {
|
||||
return nil, awserr.New("EC2RoleRequestError", "failed to list EC2 Roles", err)
|
||||
@@ -142,7 +147,7 @@ func requestCredList(client *ec2metadata.Client) ([]string, error) {
|
||||
//
|
||||
// If the credentials cannot be found, or there is an error reading the response
|
||||
// and error will be returned.
|
||||
func requestCred(client *ec2metadata.Client, credsName string) (ec2RoleCredRespBody, error) {
|
||||
func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
|
||||
resp, err := client.GetMetadata(path.Join(iamSecurityCredsPath, credsName))
|
||||
if err != nil {
|
||||
return ec2RoleCredRespBody{},
|
||||
|
||||
Generated
Vendored
+14
-16
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
const credsRespTmpl = `{
|
||||
@@ -54,11 +55,11 @@ func TestEC2RoleProvider(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
assert.Nil(t, err, "Expect no error, %v", err)
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
@@ -70,7 +71,7 @@ func TestEC2RoleProviderFailAssume(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
@@ -91,7 +92,7 @@ func TestEC2RoleProviderIsExpired(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
p.CurrentTime = func() time.Time {
|
||||
return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
|
||||
@@ -100,7 +101,7 @@ func TestEC2RoleProviderIsExpired(t *testing.T) {
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.")
|
||||
|
||||
_, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
assert.Nil(t, err, "Expect no error, %v", err)
|
||||
|
||||
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.")
|
||||
|
||||
@@ -116,7 +117,7 @@ func TestEC2RoleProviderExpiryWindowIsExpired(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
ExpiryWindow: time.Hour * 1,
|
||||
}
|
||||
p.CurrentTime = func() time.Time {
|
||||
@@ -126,7 +127,7 @@ func TestEC2RoleProviderExpiryWindowIsExpired(t *testing.T) {
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.")
|
||||
|
||||
_, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
assert.Nil(t, err, "Expect no error, %v", err)
|
||||
|
||||
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.")
|
||||
|
||||
@@ -137,12 +138,12 @@ func TestEC2RoleProviderExpiryWindowIsExpired(t *testing.T) {
|
||||
assert.True(t, p.IsExpired(), "Expect creds to be expired.")
|
||||
}
|
||||
|
||||
func BenchmarkEC2RoleProvider(b *testing.B) {
|
||||
func BenchmarkEC3RoleProvider(b *testing.B) {
|
||||
server := initTestServer("2014-12-16T01:51:37Z", false)
|
||||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
_, err := p.Retrieve()
|
||||
if err != nil {
|
||||
@@ -150,12 +151,9 @@ func BenchmarkEC2RoleProvider(b *testing.B) {
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, err := p.Retrieve()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := p.Retrieve(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -6,3 +6,7 @@ aws_session_token = token
|
||||
[no_token]
|
||||
aws_access_key_id = accessKey
|
||||
aws_secret_access_key = secret
|
||||
|
||||
[with_colon]
|
||||
aws_access_key_id: accessKey
|
||||
aws_secret_access_key: secret
|
||||
|
||||
Generated
Vendored
+19
-15
@@ -5,7 +5,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/vaughan0/go-ini"
|
||||
"github.com/go-ini/ini"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
@@ -76,32 +76,36 @@ func (p *SharedCredentialsProvider) IsExpired() bool {
|
||||
// The credentials retrieved from the profile will be returned or error. Error will be
|
||||
// returned if it fails to read from the file, or the data is invalid.
|
||||
func loadProfile(filename, profile string) (Value, error) {
|
||||
config, err := ini.LoadFile(filename)
|
||||
config, err := ini.Load(filename)
|
||||
if err != nil {
|
||||
return Value{}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err)
|
||||
}
|
||||
iniProfile := config.Section(profile)
|
||||
|
||||
id, ok := iniProfile["aws_access_key_id"]
|
||||
if !ok {
|
||||
return Value{}, awserr.New("SharedCredsAccessKey",
|
||||
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
|
||||
nil)
|
||||
iniProfile, err := config.GetSection(profile)
|
||||
if err != nil {
|
||||
return Value{}, awserr.New("SharedCredsLoad", "failed to get profile", err)
|
||||
}
|
||||
|
||||
secret, ok := iniProfile["aws_secret_access_key"]
|
||||
if !ok {
|
||||
id, err := iniProfile.GetKey("aws_access_key_id")
|
||||
if err != nil {
|
||||
return Value{}, awserr.New("SharedCredsAccessKey",
|
||||
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
|
||||
err)
|
||||
}
|
||||
|
||||
secret, err := iniProfile.GetKey("aws_secret_access_key")
|
||||
if err != nil {
|
||||
return Value{}, awserr.New("SharedCredsSecret",
|
||||
fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename),
|
||||
nil)
|
||||
}
|
||||
|
||||
token := iniProfile["aws_session_token"]
|
||||
// Default to empty string if not found
|
||||
token := iniProfile.Key("aws_session_token")
|
||||
|
||||
return Value{
|
||||
AccessKeyID: id,
|
||||
SecretAccessKey: secret,
|
||||
SessionToken: token,
|
||||
AccessKeyID: id.String(),
|
||||
SecretAccessKey: secret.String(),
|
||||
SessionToken: token.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+12
@@ -69,6 +69,18 @@ func TestSharedCredentialsProviderWithoutTokenFromProfile(t *testing.T) {
|
||||
assert.Empty(t, creds.SessionToken, "Expect no token")
|
||||
}
|
||||
|
||||
func TestSharedCredentialsProviderColonInCredFile(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
p := SharedCredentialsProvider{Filename: "example.ini", Profile: "with_colon"}
|
||||
creds, err := p.Retrieve()
|
||||
assert.Nil(t, err, "Expect no error")
|
||||
|
||||
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
|
||||
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
|
||||
assert.Empty(t, creds.SessionToken, "Expect no token")
|
||||
}
|
||||
|
||||
func BenchmarkSharedCredentialsProvider(b *testing.B) {
|
||||
os.Clearenv()
|
||||
|
||||
|
||||
Generated
Vendored
+40
-35
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
@@ -18,31 +19,17 @@ type AssumeRoler interface {
|
||||
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
||||
}
|
||||
|
||||
// DefaultDuration is the default amount of time in minutes that the credentials
|
||||
// will be valid for.
|
||||
var DefaultDuration = time.Duration(15) * time.Minute
|
||||
|
||||
// AssumeRoleProvider retrieves temporary credentials from the STS service, and
|
||||
// keeps track of their expiration time. This provider must be used explicitly,
|
||||
// as it is not included in the credentials chain.
|
||||
//
|
||||
// Example how to configure a service to use this provider:
|
||||
//
|
||||
// config := &aws.Config{
|
||||
// Credentials: stscreds.NewCredentials(nil, "arn-of-the-role-to-assume", 10*time.Second),
|
||||
// })
|
||||
// // Use config for creating your AWS service.
|
||||
//
|
||||
// Example how to obtain customised credentials:
|
||||
//
|
||||
// provider := &stscreds.Provider{
|
||||
// // Extend the duration to 1 hour.
|
||||
// Duration: time.Hour,
|
||||
// // Custom role name.
|
||||
// RoleSessionName: "custom-session-name",
|
||||
// }
|
||||
// creds := credentials.NewCredentials(provider)
|
||||
//
|
||||
type AssumeRoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
// Custom STS client. If not set the default STS client will be used.
|
||||
// STS client to make assume role request with.
|
||||
Client AssumeRoler
|
||||
|
||||
// Role to be assumed.
|
||||
@@ -70,37 +57,55 @@ type AssumeRoleProvider struct {
|
||||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// The sts and roleARN parameters are used for building the "AssumeRole" call.
|
||||
// Pass nil as sts to use the default client.
|
||||
// Takes a Config provider to create the STS client. The ConfigProvider is
|
||||
// satisfied by the session.Session type.
|
||||
func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: sts.New(c),
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// Window is the expiry window that will be subtracted from the expiry returned
|
||||
// by the role credential request. This is done so that the credentials will
|
||||
// expire sooner than their actual lifespan.
|
||||
func NewCredentials(client AssumeRoler, roleARN string, window time.Duration) *credentials.Credentials {
|
||||
return credentials.NewCredentials(&AssumeRoleProvider{
|
||||
Client: client,
|
||||
RoleARN: roleARN,
|
||||
ExpiryWindow: window,
|
||||
})
|
||||
// Takes an AssumeRoler which can be satisfiede by the STS client.
|
||||
func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: svc,
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// Retrieve generates a new set of temporary credentials using STS.
|
||||
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||
|
||||
// Apply defaults where parameters are not set.
|
||||
if p.Client == nil {
|
||||
p.Client = sts.New(nil)
|
||||
}
|
||||
if p.RoleSessionName == "" {
|
||||
// Try to work out a role name that will hopefully end up unique.
|
||||
p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano())
|
||||
}
|
||||
if p.Duration == 0 {
|
||||
// Expire as often as AWS permits.
|
||||
p.Duration = 15 * time.Minute
|
||||
p.Duration = DefaultDuration
|
||||
}
|
||||
|
||||
roleOutput, err := p.Client.AssumeRole(&sts.AssumeRoleInput{
|
||||
|
||||
Generated
Vendored
+4
-7
@@ -48,12 +48,9 @@ func BenchmarkAssumeRoleProvider(b *testing.B) {
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, err := p.Retrieve()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := p.Retrieve(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+63
-26
@@ -1,3 +1,5 @@
|
||||
// Package defaults is a collection of helpers to retrieve the SDK's default
|
||||
// configuration and handlers.
|
||||
package defaults
|
||||
|
||||
import (
|
||||
@@ -6,34 +8,69 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
// DefaultChainCredentials is a Credentials which will find the first available
|
||||
// credentials Value from the list of Providers.
|
||||
//
|
||||
// This should be used in the default case. Once the type of credentials are
|
||||
// known switching to the specific Credentials will be more efficient.
|
||||
var DefaultChainCredentials = credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{ExpiryWindow: 5 * time.Minute},
|
||||
})
|
||||
// A Defaults provides a collection of default values for SDK clients.
|
||||
type Defaults struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// DefaultConfig is the default all service configuration will be based off of.
|
||||
// By default, all clients use this structure for initialization options unless
|
||||
// a custom configuration object is passed in.
|
||||
//
|
||||
// You may modify this global structure to change all default configuration
|
||||
// in the SDK. Note that configuration options are copied by value, so any
|
||||
// modifications must happen before constructing a client.
|
||||
var DefaultConfig = aws.NewConfig().
|
||||
WithCredentials(DefaultChainCredentials).
|
||||
WithRegion(os.Getenv("AWS_REGION")).
|
||||
WithHTTPClient(http.DefaultClient).
|
||||
WithMaxRetries(aws.DefaultRetries).
|
||||
WithLogger(aws.NewDefaultLogger()).
|
||||
WithLogLevel(aws.LogOff).
|
||||
WithSleepDelay(time.Sleep)
|
||||
// Get returns the SDK's default values with Config and handlers pre-configured.
|
||||
func Get() Defaults {
|
||||
cfg := Config()
|
||||
handlers := Handlers()
|
||||
cfg.Credentials = CredChain(cfg, handlers)
|
||||
|
||||
return Defaults{
|
||||
Config: cfg,
|
||||
Handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// Config returns the default configuration.
|
||||
func Config() *aws.Config {
|
||||
return aws.NewConfig().
|
||||
WithCredentials(credentials.AnonymousCredentials).
|
||||
WithRegion(os.Getenv("AWS_REGION")).
|
||||
WithHTTPClient(http.DefaultClient).
|
||||
WithMaxRetries(aws.UseServiceDefaultRetries).
|
||||
WithLogger(aws.NewDefaultLogger()).
|
||||
WithLogLevel(aws.LogOff).
|
||||
WithSleepDelay(time.Sleep)
|
||||
}
|
||||
|
||||
// Handlers returns the default request handlers.
|
||||
func Handlers() request.Handlers {
|
||||
var handlers request.Handlers
|
||||
|
||||
handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
|
||||
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
// CredChain returns the default credential chain.
|
||||
func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials {
|
||||
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName, *cfg.Region, true)
|
||||
|
||||
return credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.NewClient(*cfg, handlers, endpoint, signingRegion),
|
||||
ExpiryWindow: 5 * time.Minute,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+4
-4
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
// GetMetadata uses the path provided to request
|
||||
func (c *Client) GetMetadata(p string) (string, error) {
|
||||
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetMetadata",
|
||||
HTTPMethod: "GET",
|
||||
@@ -15,13 +15,13 @@ func (c *Client) GetMetadata(p string) (string, error) {
|
||||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := request.New(c.Service.ServiceInfo, c.Service.Handlers, c.Service.Retryer, op, nil, output)
|
||||
req := c.NewRequest(op, nil, output)
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// Region returns the region the instance is running in.
|
||||
func (c *Client) Region() (string, error) {
|
||||
func (c *EC2Metadata) Region() (string, error) {
|
||||
resp, err := c.GetMetadata("placement/availability-zone")
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -34,7 +34,7 @@ func (c *Client) Region() (string, error) {
|
||||
// Available returns if the application has access to the EC2 Metadata service.
|
||||
// Can be used to determine if application is running within an EC2 Instance and
|
||||
// the metadata service is available.
|
||||
func (c *Client) Available() bool {
|
||||
func (c *EC2Metadata) Available() bool {
|
||||
if _, err := c.GetMetadata("instance-id"); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
+8
-7
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
func initTestServer(path string, resp string) *httptest.Server {
|
||||
@@ -28,15 +29,15 @@ func initTestServer(path string, resp string) *httptest.Server {
|
||||
}
|
||||
|
||||
func TestEndpoint(t *testing.T) {
|
||||
c := ec2metadata.New(&ec2metadata.Config{})
|
||||
c := ec2metadata.New(session.New())
|
||||
op := &request.Operation{
|
||||
Name: "GetMetadata",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: path.Join("/", "meta-data", "testpath"),
|
||||
}
|
||||
|
||||
req := c.Service.NewRequest(op, nil, nil)
|
||||
assert.Equal(t, "http://169.254.169.254/latest", req.Service.Endpoint)
|
||||
req := c.NewRequest(op, nil, nil)
|
||||
assert.Equal(t, "http://169.254.169.254/latest", req.ClientInfo.Endpoint)
|
||||
assert.Equal(t, "http://169.254.169.254/latest/meta-data/testpath", req.HTTPRequest.URL.String())
|
||||
}
|
||||
|
||||
@@ -46,7 +47,7 @@ func TestGetMetadata(t *testing.T) {
|
||||
"success", // real response includes suffix
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
resp, err := c.GetMetadata("some/path")
|
||||
|
||||
@@ -60,7 +61,7 @@ func TestGetRegion(t *testing.T) {
|
||||
"us-west-2a", // real response includes suffix
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
region, err := c.Region()
|
||||
|
||||
@@ -74,7 +75,7 @@ func TestMetadataAvailable(t *testing.T) {
|
||||
"instance-id",
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(&ec2metadata.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
available := c.Available()
|
||||
|
||||
@@ -82,7 +83,7 @@ func TestMetadataAvailable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMetadataNotAvailable(t *testing.T) {
|
||||
c := ec2metadata.New(nil)
|
||||
c := ec2metadata.New(session.New())
|
||||
c.Handlers.Send.Clear()
|
||||
c.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &http.Response{
|
||||
|
||||
+50
-83
@@ -1,3 +1,5 @@
|
||||
// Package ec2metadata provides the client for making API calls to the
|
||||
// EC2 Metadata service.
|
||||
package ec2metadata
|
||||
|
||||
import (
|
||||
@@ -8,89 +10,41 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
)
|
||||
|
||||
// DefaultRetries states the default number of times the service client will
|
||||
// attempt to retry a failed request before failing.
|
||||
const DefaultRetries = 3
|
||||
// ServiceName is the name of the service.
|
||||
const ServiceName = "ec2metadata"
|
||||
|
||||
// A Config provides the configuration for the EC2 Metadata service.
|
||||
type Config struct {
|
||||
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||
// that overrides the default service endpoint for a client. Set this
|
||||
// to nil, or `""` to use the default service endpoint.
|
||||
Endpoint *string
|
||||
|
||||
// The HTTP client to use when sending requests. Defaults to
|
||||
// `http.DefaultClient`.
|
||||
HTTPClient *http.Client
|
||||
|
||||
// An integer value representing the logging level. The default log level
|
||||
// is zero (LogOff), which represents no logging. To enable logging set
|
||||
// to a LogLevel Value.
|
||||
Logger aws.Logger
|
||||
|
||||
// The logger writer interface to write logging messages to. Defaults to
|
||||
// standard out.
|
||||
LogLevel *aws.LogLevelType
|
||||
|
||||
// The maximum number of times that a request will be retried for failures.
|
||||
// Defaults to DefaultRetries for the number of retries to be performed
|
||||
// per request.
|
||||
MaxRetries *int
|
||||
// A EC2Metadata is an EC2 Metadata service Client.
|
||||
type EC2Metadata struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// A Client is an EC2 Metadata service Client.
|
||||
type Client struct {
|
||||
*service.Service
|
||||
}
|
||||
|
||||
// New creates a new instance of the EC2 Metadata service client.
|
||||
// New creates a new instance of the EC2Metadata client with a session.
|
||||
// This client is safe to use across multiple goroutines.
|
||||
//
|
||||
// In the general use case the configuration for this service client should not
|
||||
// be needed and `nil` can be provided. Configuration is only needed if the
|
||||
// `ec2metadata.Config` defaults need to be overridden. Eg. Setting LogLevel.
|
||||
// Example:
|
||||
// // Create a EC2Metadata client from just a session.
|
||||
// svc := ec2metadata.New(mySession)
|
||||
//
|
||||
// @note This configuration will NOT be merged with the default AWS service
|
||||
// client configuration `defaults.DefaultConfig`. Due to circular dependencies
|
||||
// with the defaults package and credentials EC2 Role Provider.
|
||||
func New(config *Config) *Client {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: copyConfig(config),
|
||||
ServiceName: "Client",
|
||||
Endpoint: "http://169.254.169.254/latest",
|
||||
APIVersion: "latest",
|
||||
},
|
||||
}
|
||||
service.Initialize()
|
||||
service.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||
service.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
service.Handlers.Validate.Clear()
|
||||
service.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||
|
||||
return &Client{service}
|
||||
// // Create a EC2Metadata client with additional configuration
|
||||
// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
func copyConfig(config *Config) *aws.Config {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
c := &aws.Config{
|
||||
Credentials: credentials.AnonymousCredentials,
|
||||
Endpoint: config.Endpoint,
|
||||
HTTPClient: config.HTTPClient,
|
||||
Logger: config.Logger,
|
||||
LogLevel: config.LogLevel,
|
||||
MaxRetries: config.MaxRetries,
|
||||
}
|
||||
|
||||
if c.HTTPClient == nil {
|
||||
c.HTTPClient = &http.Client{
|
||||
// NewClient returns a new EC2Metadata client. Should be used to create
|
||||
// a client when not using a session. Generally using just New with a session
|
||||
// is preferred.
|
||||
func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata {
|
||||
// If the default http client is provided, replace it with a custom
|
||||
// client using default timeouts.
|
||||
if cfg.HTTPClient == http.DefaultClient {
|
||||
cfg.HTTPClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
@@ -104,17 +58,30 @@ func copyConfig(config *Config) *aws.Config {
|
||||
},
|
||||
}
|
||||
}
|
||||
if c.Logger == nil {
|
||||
c.Logger = aws.NewDefaultLogger()
|
||||
}
|
||||
if c.LogLevel == nil {
|
||||
c.LogLevel = aws.LogLevel(aws.LogOff)
|
||||
}
|
||||
if c.MaxRetries == nil {
|
||||
c.MaxRetries = aws.Int(DefaultRetries)
|
||||
|
||||
svc := &EC2Metadata{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "latest",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
return c
|
||||
svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
svc.Handlers.Validate.Clear()
|
||||
svc.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||
|
||||
// Add additional options to the service config
|
||||
for _, option := range opts {
|
||||
option(svc.Client)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
type metadataOutput struct {
|
||||
@@ -143,7 +110,7 @@ func unmarshalError(r *request.Request) {
|
||||
}
|
||||
|
||||
func validateEndpointHandler(r *request.Request) {
|
||||
if r.Service.Endpoint == "" {
|
||||
if r.ClientInfo.Endpoint == "" {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,11 +7,11 @@ var (
|
||||
// not found.
|
||||
//
|
||||
// @readonly
|
||||
ErrMissingRegion error = awserr.New("MissingRegion", "could not find region configuration", nil)
|
||||
ErrMissingRegion = awserr.New("MissingRegion", "could not find region configuration", nil)
|
||||
|
||||
// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
|
||||
// resolved for a service.
|
||||
//
|
||||
// @readonly
|
||||
ErrMissingEndpoint error = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
|
||||
ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
|
||||
)
|
||||
|
||||
+28
@@ -1,5 +1,10 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Handlers provides a collection of request handlers for various
|
||||
// stages of handling requests.
|
||||
type Handlers struct {
|
||||
@@ -110,3 +115,26 @@ func (l *HandlerList) Run(r *Request) {
|
||||
f.Fn(r)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
|
||||
// header. If the extra parameters are provided they will be added as metadata to the
|
||||
// name/version pair resulting in the following format.
|
||||
// "name/version (extra0; extra1; ...)"
|
||||
// The user agent part will be concatenated with this current request's user agent string.
|
||||
func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) {
|
||||
ua := fmt.Sprintf("%s/%s", name, version)
|
||||
if len(extra) > 0 {
|
||||
ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; "))
|
||||
}
|
||||
return func(r *Request) {
|
||||
AddToUserAgent(r, ua)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header.
|
||||
// The input string will be concatenated with the current request's user agent string.
|
||||
func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
|
||||
return func(r *Request) {
|
||||
AddToUserAgent(r, s)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ func TestMultipleHandlers(t *testing.T) {
|
||||
|
||||
func TestNamedHandlers(t *testing.T) {
|
||||
l := request.HandlerList{}
|
||||
named := request.NamedHandler{"Name", func(r *request.Request) {}}
|
||||
named2 := request.NamedHandler{"NotName", func(r *request.Request) {}}
|
||||
named := request.NamedHandler{Name: "Name", Fn: func(r *request.Request) {}}
|
||||
named2 := request.NamedHandler{Name: "NotName", Fn: func(r *request.Request) {}}
|
||||
l.PushBackNamed(named)
|
||||
l.PushBackNamed(named)
|
||||
l.PushBackNamed(named2)
|
||||
|
||||
+27
-96
@@ -12,15 +12,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
)
|
||||
|
||||
// A Request is the service request to be made.
|
||||
type Request struct {
|
||||
Config aws.Config
|
||||
ClientInfo metadata.ClientInfo
|
||||
Handlers Handlers
|
||||
|
||||
Retryer
|
||||
Service serviceinfo.ServiceInfo
|
||||
Handlers Handlers
|
||||
Time time.Time
|
||||
ExpireTime time.Duration
|
||||
Operation *Operation
|
||||
@@ -32,7 +33,7 @@ type Request struct {
|
||||
Error error
|
||||
Data interface{}
|
||||
RequestID string
|
||||
RetryCount uint
|
||||
RetryCount int
|
||||
Retryable *bool
|
||||
RetryDelay time.Duration
|
||||
|
||||
@@ -61,7 +62,9 @@ type Paginator struct {
|
||||
// Params is any value of input parameters to be the request payload.
|
||||
// Data is pointer value to an object which the request's response
|
||||
// payload will be deserialized to.
|
||||
func New(service serviceinfo.ServiceInfo, handlers Handlers, retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
|
||||
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
|
||||
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
|
||||
|
||||
method := operation.HTTPMethod
|
||||
if method == "" {
|
||||
method = "POST"
|
||||
@@ -72,12 +75,14 @@ func New(service serviceinfo.ServiceInfo, handlers Handlers, retryer Retryer, op
|
||||
}
|
||||
|
||||
httpReq, _ := http.NewRequest(method, "", nil)
|
||||
httpReq.URL, _ = url.Parse(service.Endpoint + p)
|
||||
httpReq.URL, _ = url.Parse(clientInfo.Endpoint + p)
|
||||
|
||||
r := &Request{
|
||||
Config: cfg,
|
||||
ClientInfo: clientInfo,
|
||||
Handlers: handlers.Copy(),
|
||||
|
||||
Retryer: retryer,
|
||||
Service: service,
|
||||
Handlers: handlers.Copy(),
|
||||
Time: time.Now(),
|
||||
ExpireTime: 0,
|
||||
Operation: operation,
|
||||
@@ -140,7 +145,7 @@ func (r *Request) Presign(expireTime time.Duration) (string, error) {
|
||||
}
|
||||
|
||||
func debugLogReqError(r *Request, stage string, retrying bool, err error) {
|
||||
if !r.Service.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
|
||||
if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -149,8 +154,8 @@ func debugLogReqError(r *Request, stage string, retrying bool, err error) {
|
||||
retryStr = "will retry"
|
||||
}
|
||||
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
|
||||
stage, r.Service.ServiceName, r.Operation.Name, retryStr, err))
|
||||
r.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
|
||||
stage, r.ClientInfo.ServiceName, r.Operation.Name, retryStr, err))
|
||||
}
|
||||
|
||||
// Build will build the request's object so it can be signed and sent
|
||||
@@ -205,9 +210,9 @@ func (r *Request) Send() error {
|
||||
}
|
||||
|
||||
if aws.BoolValue(r.Retryable) {
|
||||
if r.Service.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
|
||||
r.Service.ServiceName, r.Operation.Name, r.RetryCount))
|
||||
if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
|
||||
r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
|
||||
}
|
||||
|
||||
// Re-seek the body back to the original point in for a retry so that
|
||||
@@ -264,85 +269,11 @@ func (r *Request) Send() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasNextPage returns true if this request has more pages of data available.
|
||||
func (r *Request) HasNextPage() bool {
|
||||
return r.nextPageTokens() != nil
|
||||
}
|
||||
|
||||
// nextPageTokens returns the tokens to use when asking for the next page of
|
||||
// data.
|
||||
func (r *Request) nextPageTokens() []interface{} {
|
||||
if r.Operation.Paginator == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Operation.TruncationToken != "" {
|
||||
tr := awsutil.ValuesAtAnyPath(r.Data, r.Operation.TruncationToken)
|
||||
if tr == nil || len(tr) == 0 {
|
||||
return nil
|
||||
}
|
||||
switch v := tr[0].(type) {
|
||||
case bool:
|
||||
if v == false {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found := false
|
||||
tokens := make([]interface{}, len(r.Operation.OutputTokens))
|
||||
|
||||
for i, outtok := range r.Operation.OutputTokens {
|
||||
v := awsutil.ValuesAtAnyPath(r.Data, outtok)
|
||||
if v != nil && len(v) > 0 {
|
||||
found = true
|
||||
tokens[i] = v[0]
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
return tokens
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NextPage returns a new Request that can be executed to return the next
|
||||
// page of result data. Call .Send() on this request to execute it.
|
||||
func (r *Request) NextPage() *Request {
|
||||
tokens := r.nextPageTokens()
|
||||
if tokens == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
|
||||
nr := New(r.Service, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
|
||||
for i, intok := range nr.Operation.InputTokens {
|
||||
awsutil.SetValueAtAnyPath(nr.Params, intok, tokens[i])
|
||||
}
|
||||
return nr
|
||||
}
|
||||
|
||||
// EachPage iterates over each page of a paginated request object. The fn
|
||||
// parameter should be a function with the following sample signature:
|
||||
//
|
||||
// func(page *T, lastPage bool) bool {
|
||||
// return true // return false to stop iterating
|
||||
// }
|
||||
//
|
||||
// Where "T" is the structure type matching the output structure of the given
|
||||
// operation. For example, a request object generated by
|
||||
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
|
||||
// as the structure "T". The lastPage value represents whether the page is
|
||||
// the last page of data or not. The return value of this function should
|
||||
// return true to keep iterating or false to stop.
|
||||
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
|
||||
for page := r; page != nil; page = page.NextPage() {
|
||||
page.Send()
|
||||
shouldContinue := fn(page.Data, !page.HasNextPage())
|
||||
if page.Error != nil || !shouldContinue {
|
||||
return page.Error
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
// AddToUserAgent adds the string to the end of the request's current user agent.
|
||||
func AddToUserAgent(r *Request, s string) {
|
||||
curUA := r.HTTPRequest.Header.Get("User-Agent")
|
||||
if len(curUA) > 0 {
|
||||
s = curUA + " " + s
|
||||
}
|
||||
r.HTTPRequest.Header.Set("User-Agent", s)
|
||||
}
|
||||
|
||||
Generated
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
//type Paginater interface {
|
||||
// HasNextPage() bool
|
||||
// NextPage() *Request
|
||||
// EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error
|
||||
//}
|
||||
|
||||
// HasNextPage returns true if this request has more pages of data available.
|
||||
func (r *Request) HasNextPage() bool {
|
||||
return len(r.nextPageTokens()) > 0
|
||||
}
|
||||
|
||||
// nextPageTokens returns the tokens to use when asking for the next page of
|
||||
// data.
|
||||
func (r *Request) nextPageTokens() []interface{} {
|
||||
if r.Operation.Paginator == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Operation.TruncationToken != "" {
|
||||
tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken)
|
||||
if len(tr) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch v := tr[0].(type) {
|
||||
case *bool:
|
||||
if !aws.BoolValue(v) {
|
||||
return nil
|
||||
}
|
||||
case bool:
|
||||
if v == false {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tokens := []interface{}{}
|
||||
tokenAdded := false
|
||||
for _, outToken := range r.Operation.OutputTokens {
|
||||
v, _ := awsutil.ValuesAtPath(r.Data, outToken)
|
||||
if len(v) > 0 {
|
||||
tokens = append(tokens, v[0])
|
||||
tokenAdded = true
|
||||
} else {
|
||||
tokens = append(tokens, nil)
|
||||
}
|
||||
}
|
||||
if !tokenAdded {
|
||||
return nil
|
||||
}
|
||||
|
||||
return tokens
|
||||
}
|
||||
|
||||
// NextPage returns a new Request that can be executed to return the next
|
||||
// page of result data. Call .Send() on this request to execute it.
|
||||
func (r *Request) NextPage() *Request {
|
||||
tokens := r.nextPageTokens()
|
||||
if len(tokens) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
|
||||
nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
|
||||
for i, intok := range nr.Operation.InputTokens {
|
||||
awsutil.SetValueAtPath(nr.Params, intok, tokens[i])
|
||||
}
|
||||
return nr
|
||||
}
|
||||
|
||||
// EachPage iterates over each page of a paginated request object. The fn
|
||||
// parameter should be a function with the following sample signature:
|
||||
//
|
||||
// func(page *T, lastPage bool) bool {
|
||||
// return true // return false to stop iterating
|
||||
// }
|
||||
//
|
||||
// Where "T" is the structure type matching the output structure of the given
|
||||
// operation. For example, a request object generated by
|
||||
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
|
||||
// as the structure "T". The lastPage value represents whether the page is
|
||||
// the last page of data or not. The return value of this function should
|
||||
// return true to keep iterating or false to stop.
|
||||
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
|
||||
for page := r; page != nil; page = page.NextPage() {
|
||||
if err := page.Send(); err != nil {
|
||||
return err
|
||||
}
|
||||
if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage {
|
||||
return page.Error
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
+160
-12
@@ -9,14 +9,101 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/aws/aws-sdk-go/service/route53"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
var _ = unit.Imported
|
||||
// Use DynamoDB methods for simplicity
|
||||
func TestPaginationQueryPage(t *testing.T) {
|
||||
db := dynamodb.New(unit.Session)
|
||||
tokens, pages, numPages, gotToEnd := []map[string]*dynamodb.AttributeValue{}, []map[string]*dynamodb.AttributeValue{}, 0, false
|
||||
|
||||
reqNum := 0
|
||||
resps := []*dynamodb.QueryOutput{
|
||||
{
|
||||
LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}},
|
||||
Count: aws.Int64(1),
|
||||
Items: []map[string]*dynamodb.AttributeValue{
|
||||
map[string]*dynamodb.AttributeValue{
|
||||
"key": {S: aws.String("key1")},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}},
|
||||
Count: aws.Int64(1),
|
||||
Items: []map[string]*dynamodb.AttributeValue{
|
||||
map[string]*dynamodb.AttributeValue{
|
||||
"key": {S: aws.String("key2")},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LastEvaluatedKey: map[string]*dynamodb.AttributeValue{},
|
||||
Count: aws.Int64(1),
|
||||
Items: []map[string]*dynamodb.AttributeValue{
|
||||
map[string]*dynamodb.AttributeValue{
|
||||
"key": {S: aws.String("key3")},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
db.Handlers.Send.Clear() // mock sending
|
||||
db.Handlers.Unmarshal.Clear()
|
||||
db.Handlers.UnmarshalMeta.Clear()
|
||||
db.Handlers.ValidateResponse.Clear()
|
||||
db.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
in := r.Params.(*dynamodb.QueryInput)
|
||||
if in == nil {
|
||||
tokens = append(tokens, nil)
|
||||
} else if len(in.ExclusiveStartKey) != 0 {
|
||||
tokens = append(tokens, in.ExclusiveStartKey)
|
||||
}
|
||||
})
|
||||
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
params := &dynamodb.QueryInput{
|
||||
Limit: aws.Int64(2),
|
||||
TableName: aws.String("tablename"),
|
||||
}
|
||||
err := db.QueryPages(params, func(p *dynamodb.QueryOutput, last bool) bool {
|
||||
numPages++
|
||||
for _, item := range p.Items {
|
||||
pages = append(pages, item)
|
||||
}
|
||||
if last {
|
||||
if gotToEnd {
|
||||
assert.Fail(t, "last=true happened twice")
|
||||
}
|
||||
gotToEnd = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t,
|
||||
[]map[string]*dynamodb.AttributeValue{
|
||||
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}},
|
||||
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}},
|
||||
}, tokens)
|
||||
assert.Equal(t,
|
||||
[]map[string]*dynamodb.AttributeValue{
|
||||
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}},
|
||||
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}},
|
||||
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key3")}},
|
||||
}, pages)
|
||||
assert.Equal(t, 3, numPages)
|
||||
assert.True(t, gotToEnd)
|
||||
assert.Nil(t, params.ExclusiveStartKey)
|
||||
}
|
||||
|
||||
// Use DynamoDB methods for simplicity
|
||||
func TestPagination(t *testing.T) {
|
||||
db := dynamodb.New(nil)
|
||||
db := dynamodb.New(unit.Session)
|
||||
tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
|
||||
|
||||
reqNum := 0
|
||||
@@ -68,7 +155,7 @@ func TestPagination(t *testing.T) {
|
||||
|
||||
// Use DynamoDB methods for simplicity
|
||||
func TestPaginationEachPage(t *testing.T) {
|
||||
db := dynamodb.New(nil)
|
||||
db := dynamodb.New(unit.Session)
|
||||
tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
|
||||
|
||||
reqNum := 0
|
||||
@@ -121,7 +208,7 @@ func TestPaginationEachPage(t *testing.T) {
|
||||
|
||||
// Use DynamoDB methods for simplicity
|
||||
func TestPaginationEarlyExit(t *testing.T) {
|
||||
db := dynamodb.New(nil)
|
||||
db := dynamodb.New(unit.Session)
|
||||
numPages, gotToEnd := 0, false
|
||||
|
||||
reqNum := 0
|
||||
@@ -161,7 +248,7 @@ func TestPaginationEarlyExit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSkipPagination(t *testing.T) {
|
||||
client := s3.New(nil)
|
||||
client := s3.New(unit.Session)
|
||||
client.Handlers.Send.Clear() // mock sending
|
||||
client.Handlers.Unmarshal.Clear()
|
||||
client.Handlers.UnmarshalMeta.Clear()
|
||||
@@ -186,10 +273,9 @@ func TestSkipPagination(t *testing.T) {
|
||||
|
||||
// Use S3 for simplicity
|
||||
func TestPaginationTruncation(t *testing.T) {
|
||||
count := 0
|
||||
client := s3.New(nil)
|
||||
client := s3.New(unit.Session)
|
||||
|
||||
reqNum := &count
|
||||
reqNum := 0
|
||||
resps := []*s3.ListObjectsOutput{
|
||||
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key1")}}},
|
||||
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key2")}}},
|
||||
@@ -202,8 +288,8 @@ func TestPaginationTruncation(t *testing.T) {
|
||||
client.Handlers.UnmarshalMeta.Clear()
|
||||
client.Handlers.ValidateResponse.Clear()
|
||||
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = resps[*reqNum]
|
||||
*reqNum++
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
params := &s3.ListObjectsInput{Bucket: aws.String("bucket")}
|
||||
@@ -218,7 +304,7 @@ func TestPaginationTruncation(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Try again without truncation token at all
|
||||
count = 0
|
||||
reqNum = 0
|
||||
resps[1].IsTruncated = nil
|
||||
resps[2].IsTruncated = aws.Bool(true)
|
||||
results = []string{}
|
||||
@@ -229,7 +315,69 @@ func TestPaginationTruncation(t *testing.T) {
|
||||
|
||||
assert.Equal(t, []string{"Key1", "Key2"}, results)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestPaginationNilToken(t *testing.T) {
|
||||
client := route53.New(unit.Session)
|
||||
|
||||
reqNum := 0
|
||||
resps := []*route53.ListResourceRecordSetsOutput{
|
||||
{
|
||||
ResourceRecordSets: []*route53.ResourceRecordSet{
|
||||
{Name: aws.String("first.example.com.")},
|
||||
},
|
||||
IsTruncated: aws.Bool(true),
|
||||
NextRecordName: aws.String("second.example.com."),
|
||||
NextRecordType: aws.String("MX"),
|
||||
NextRecordIdentifier: aws.String("second"),
|
||||
MaxItems: aws.String("1"),
|
||||
},
|
||||
{
|
||||
ResourceRecordSets: []*route53.ResourceRecordSet{
|
||||
{Name: aws.String("second.example.com.")},
|
||||
},
|
||||
IsTruncated: aws.Bool(true),
|
||||
NextRecordName: aws.String("third.example.com."),
|
||||
NextRecordType: aws.String("MX"),
|
||||
MaxItems: aws.String("1"),
|
||||
},
|
||||
{
|
||||
ResourceRecordSets: []*route53.ResourceRecordSet{
|
||||
{Name: aws.String("third.example.com.")},
|
||||
},
|
||||
IsTruncated: aws.Bool(false),
|
||||
MaxItems: aws.String("1"),
|
||||
},
|
||||
}
|
||||
client.Handlers.Send.Clear() // mock sending
|
||||
client.Handlers.Unmarshal.Clear()
|
||||
client.Handlers.UnmarshalMeta.Clear()
|
||||
client.Handlers.ValidateResponse.Clear()
|
||||
|
||||
idents := []string{}
|
||||
client.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
p := r.Params.(*route53.ListResourceRecordSetsInput)
|
||||
idents = append(idents, aws.StringValue(p.StartRecordIdentifier))
|
||||
|
||||
})
|
||||
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
params := &route53.ListResourceRecordSetsInput{
|
||||
HostedZoneId: aws.String("id-zone"),
|
||||
}
|
||||
|
||||
results := []string{}
|
||||
err := client.ListResourceRecordSetsPages(params, func(p *route53.ListResourceRecordSetsOutput, last bool) bool {
|
||||
results = append(results, *p.ResourceRecordSets[0].Name)
|
||||
return true
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"", "second", ""}, idents)
|
||||
assert.Equal(t, []string{"first.example.com.", "second.example.com.", "third.example.com."}, results)
|
||||
}
|
||||
|
||||
// Benchmarks
|
||||
@@ -251,7 +399,7 @@ var benchResps = []*dynamodb.ListTablesOutput{
|
||||
}
|
||||
|
||||
var benchDb = func() *dynamodb.DynamoDB {
|
||||
db := dynamodb.New(nil)
|
||||
db := dynamodb.New(unit.Session)
|
||||
db.Handlers.Send.Clear() // mock sending
|
||||
db.Handlers.Unmarshal.Clear()
|
||||
db.Handlers.UnmarshalMeta.Clear()
|
||||
|
||||
+42
-9
@@ -7,15 +7,17 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
)
|
||||
|
||||
type testData struct {
|
||||
@@ -74,7 +76,7 @@ func TestRequestRecoverRetry5xx(t *testing.T) {
|
||||
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
|
||||
}
|
||||
|
||||
s := service.New(aws.NewConfig().WithMaxRetries(10))
|
||||
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
@@ -100,7 +102,7 @@ func TestRequestRecoverRetry4xxRetryable(t *testing.T) {
|
||||
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
|
||||
}
|
||||
|
||||
s := service.New(aws.NewConfig().WithMaxRetries(10))
|
||||
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
@@ -119,7 +121,7 @@ func TestRequestRecoverRetry4xxRetryable(t *testing.T) {
|
||||
|
||||
// test that retries don't occur for 4xx status codes with a response type that can't be retried
|
||||
func TestRequest4xxUnretryable(t *testing.T) {
|
||||
s := service.New(aws.NewConfig().WithMaxRetries(10))
|
||||
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
@@ -155,7 +157,7 @@ func TestRequestExhaustRetries(t *testing.T) {
|
||||
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
|
||||
}
|
||||
|
||||
s := service.New(aws.NewConfig().WithMaxRetries(aws.DefaultRetries).WithSleepDelay(sleepDelay))
|
||||
s := awstesting.NewClient(aws.NewConfig().WithSleepDelay(sleepDelay))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
@@ -193,7 +195,7 @@ func TestRequestRecoverExpiredCreds(t *testing.T) {
|
||||
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
|
||||
}
|
||||
|
||||
s := service.New(&aws.Config{MaxRetries: aws.Int(10), Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "")})
|
||||
s := awstesting.NewClient(&aws.Config{MaxRetries: aws.Int(10), Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "")})
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.PushBack(unmarshal)
|
||||
s.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
@@ -202,12 +204,12 @@ func TestRequestRecoverExpiredCreds(t *testing.T) {
|
||||
credExpiredAfterRetry := false
|
||||
|
||||
s.Handlers.AfterRetry.PushBack(func(r *request.Request) {
|
||||
credExpiredAfterRetry = r.Service.Config.Credentials.IsExpired()
|
||||
credExpiredAfterRetry = r.Config.Credentials.IsExpired()
|
||||
})
|
||||
|
||||
s.Handlers.Sign.Clear()
|
||||
s.Handlers.Sign.PushBack(func(r *request.Request) {
|
||||
r.Service.Config.Credentials.Get()
|
||||
r.Config.Credentials.Get()
|
||||
})
|
||||
s.Handlers.Send.Clear() // mock sending
|
||||
s.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
@@ -226,3 +228,34 @@ func TestRequestRecoverExpiredCreds(t *testing.T) {
|
||||
assert.Equal(t, 1, int(r.RetryCount))
|
||||
assert.Equal(t, "valid", out.Data)
|
||||
}
|
||||
|
||||
func TestMakeAddtoUserAgentHandler(t *testing.T) {
|
||||
fn := request.MakeAddToUserAgentHandler("name", "version", "extra1", "extra2")
|
||||
r := &request.Request{HTTPRequest: &http.Request{Header: http.Header{}}}
|
||||
r.HTTPRequest.Header.Set("User-Agent", "foo/bar")
|
||||
fn(r)
|
||||
|
||||
assert.Equal(t, "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"))
|
||||
}
|
||||
|
||||
func TestMakeAddtoUserAgentFreeFormHandler(t *testing.T) {
|
||||
fn := request.MakeAddToUserAgentFreeFormHandler("name/version (extra1; extra2)")
|
||||
r := &request.Request{HTTPRequest: &http.Request{Header: http.Header{}}}
|
||||
r.HTTPRequest.Header.Set("User-Agent", "foo/bar")
|
||||
fn(r)
|
||||
|
||||
assert.Equal(t, "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"))
|
||||
}
|
||||
|
||||
func TestRequestUserAgent(t *testing.T) {
|
||||
s := awstesting.NewClient(&aws.Config{Region: aws.String("us-east-1")})
|
||||
// s.Handlers.Validate.Clear()
|
||||
|
||||
req := s.NewRequest(&request.Operation{Name: "Operation"}, nil, &testData{})
|
||||
req.HTTPRequest.Header.Set("User-Agent", "foo/bar")
|
||||
assert.NoError(t, req.Build())
|
||||
|
||||
expectUA := fmt.Sprintf("foo/bar %s/%s (%s; %s; %s)",
|
||||
aws.SDKName, aws.SDKVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
assert.Equal(t, expectUA, req.HTTPRequest.Header.Get("User-Agent"))
|
||||
}
|
||||
|
||||
+10
-1
@@ -3,6 +3,7 @@ package request
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
@@ -12,13 +13,21 @@ import (
|
||||
type Retryer interface {
|
||||
RetryRules(*Request) time.Duration
|
||||
ShouldRetry(*Request) bool
|
||||
MaxRetries() uint
|
||||
MaxRetries() int
|
||||
}
|
||||
|
||||
// WithRetryer sets a config Retryer value to the given Config returning it
|
||||
// for chaining.
|
||||
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
|
||||
cfg.Retryer = retryer
|
||||
return cfg
|
||||
}
|
||||
|
||||
// retryableCodes is a collection of service response codes which are retry-able
|
||||
// without any further action.
|
||||
var retryableCodes = map[string]struct{}{
|
||||
"RequestError": {},
|
||||
"RequestTimeout": {},
|
||||
"ProvisionedThroughputExceededException": {},
|
||||
"Throttling": {},
|
||||
"ThrottlingException": {},
|
||||
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
// A Service implements the base service request and response handling
|
||||
// used by all services.
|
||||
type Service struct {
|
||||
serviceinfo.ServiceInfo
|
||||
request.Retryer
|
||||
DefaultMaxRetries uint
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||
|
||||
// New will return a pointer to a new Server object initialized.
|
||||
func New(config *aws.Config) *Service {
|
||||
svc := &Service{ServiceInfo: serviceinfo.ServiceInfo{Config: config}}
|
||||
svc.Initialize()
|
||||
return svc
|
||||
}
|
||||
|
||||
// Initialize initializes the service.
|
||||
func (s *Service) Initialize() {
|
||||
if s.Config == nil {
|
||||
s.Config = &aws.Config{}
|
||||
}
|
||||
if s.Config.HTTPClient == nil {
|
||||
s.Config.HTTPClient = http.DefaultClient
|
||||
}
|
||||
if s.Config.SleepDelay == nil {
|
||||
s.Config.SleepDelay = time.Sleep
|
||||
}
|
||||
|
||||
s.Retryer = DefaultRetryer{s}
|
||||
s.DefaultMaxRetries = 3
|
||||
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
s.Handlers.Build.PushBackNamed(corehandlers.UserAgentHandler)
|
||||
s.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
s.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
s.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
s.Handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
if !aws.BoolValue(s.Config.DisableParamValidation) {
|
||||
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
|
||||
}
|
||||
s.AddDebugHandlers()
|
||||
s.buildEndpoint()
|
||||
}
|
||||
|
||||
// NewRequest returns a new Request pointer for the service API
|
||||
// operation and parameters.
|
||||
func (s *Service) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
|
||||
return request.New(s.ServiceInfo, s.Handlers, s.Retryer, operation, params, data)
|
||||
}
|
||||
|
||||
// buildEndpoint builds the endpoint values the service will use to make requests with.
|
||||
func (s *Service) buildEndpoint() {
|
||||
if aws.StringValue(s.Config.Endpoint) != "" {
|
||||
s.Endpoint = *s.Config.Endpoint
|
||||
} else if s.Endpoint == "" {
|
||||
s.Endpoint, s.SigningRegion =
|
||||
endpoints.EndpointForRegion(s.ServiceName, aws.StringValue(s.Config.Region))
|
||||
}
|
||||
|
||||
if s.Endpoint != "" && !schemeRE.MatchString(s.Endpoint) {
|
||||
scheme := "https"
|
||||
if aws.BoolValue(s.Config.DisableSSL) {
|
||||
scheme = "http"
|
||||
}
|
||||
s.Endpoint = scheme + "://" + s.Endpoint
|
||||
}
|
||||
}
|
||||
|
||||
// AddDebugHandlers injects debug logging handlers into the service to log request
|
||||
// debug information.
|
||||
func (s *Service) AddDebugHandlers() {
|
||||
if !s.Config.LogLevel.AtLeast(aws.LogDebug) {
|
||||
return
|
||||
}
|
||||
|
||||
s.Handlers.Send.PushFront(logRequest)
|
||||
s.Handlers.Send.PushBack(logResponse)
|
||||
}
|
||||
|
||||
const logReqMsg = `DEBUG: Request %s/%s Details:
|
||||
---[ REQUEST POST-SIGN ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Service.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
|
||||
if logBody {
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
|
||||
}
|
||||
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.Service.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
}
|
||||
|
||||
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||
---[ RESPONSE ]--------------------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
var msg = "no reponse data"
|
||||
if r.HTTPResponse != nil {
|
||||
logBody := r.Service.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
msg = string(dumpedBody)
|
||||
} else if r.Error != nil {
|
||||
msg = r.Error.Error()
|
||||
}
|
||||
r.Service.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.Service.ServiceName, r.Operation.Name, msg))
|
||||
}
|
||||
Generated
Vendored
-15
@@ -1,15 +0,0 @@
|
||||
package serviceinfo
|
||||
|
||||
import "github.com/aws/aws-sdk-go/aws"
|
||||
|
||||
// ServiceInfo wraps immutable data from the service.Service structure.
|
||||
type ServiceInfo struct {
|
||||
Config *aws.Config
|
||||
ServiceName string
|
||||
APIVersion string
|
||||
Endpoint string
|
||||
SigningName string
|
||||
SigningRegion string
|
||||
JSONVersion string
|
||||
TargetPrefix string
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
// Package session provides a way to create service clients with shared configuration
|
||||
// and handlers.
|
||||
package session
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
// A Session provides a central location to create service clients from and
|
||||
// store configurations and request handlers for those services.
|
||||
//
|
||||
// Sessions are safe to create service clients concurrently, but it is not safe
|
||||
// to mutate the session concurrently.
|
||||
type Session struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// New creates a new instance of the handlers merging in the provided Configs
|
||||
// on top of the SDK's default configurations. Once the session is created it
|
||||
// can be mutated to modify Configs or Handlers. The session is safe to be read
|
||||
// concurrently, but it should not be written to concurrently.
|
||||
//
|
||||
// Example:
|
||||
// // Create a session with the default config and request handlers.
|
||||
// sess := session.New()
|
||||
//
|
||||
// // Create a session with a custom region
|
||||
// sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
|
||||
//
|
||||
// // Create a session, and add additional handlers for all service
|
||||
// // clients created with the session to inherit. Adds logging handler.
|
||||
// sess := session.New()
|
||||
// sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||
// // Log every request made and its payload
|
||||
// logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params)
|
||||
// })
|
||||
//
|
||||
// // Create a S3 client instance from a session
|
||||
// sess := session.New()
|
||||
// svc := s3.New(sess)
|
||||
func New(cfgs ...*aws.Config) *Session {
|
||||
def := defaults.Get()
|
||||
s := &Session{
|
||||
Config: def.Config,
|
||||
Handlers: def.Handlers,
|
||||
}
|
||||
s.Config.MergeIn(cfgs...)
|
||||
|
||||
initHandlers(s)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func initHandlers(s *Session) {
|
||||
// Add the Validate parameter handler if it is not disabled.
|
||||
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
|
||||
if !aws.BoolValue(s.Config.DisableParamValidation) {
|
||||
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy creates and returns a copy of the current session, coping the config
|
||||
// and handlers. If any additional configs are provided they will be merged
|
||||
// on top of the session's copied config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a copy of the current session, configured for the us-west-2 region.
|
||||
// sess.Copy(&aws.Config{Region: aws.String("us-west-2"})
|
||||
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
||||
newSession := &Session{
|
||||
Config: s.Config.Copy(cfgs...),
|
||||
Handlers: s.Handlers.Copy(),
|
||||
}
|
||||
|
||||
initHandlers(newSession)
|
||||
|
||||
return newSession
|
||||
}
|
||||
|
||||
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
||||
// configure the service client instances. Passing the Session to the service
|
||||
// client's constructor (New) will use this method to configure the client.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.New()
|
||||
// s3.New(sess)
|
||||
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
||||
s = s.Copy(cfgs...)
|
||||
endpoint, signingRegion := endpoints.NormalizeEndpoint(
|
||||
aws.StringValue(s.Config.Endpoint), serviceName,
|
||||
aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))
|
||||
|
||||
return client.Config{
|
||||
Config: s.Config,
|
||||
Handlers: s.Handlers,
|
||||
Endpoint: endpoint,
|
||||
SigningRegion: signingRegion,
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package session_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
func TestNewDefaultSession(t *testing.T) {
|
||||
s := session.New(&aws.Config{Region: aws.String("region")})
|
||||
|
||||
assert.Equal(t, "region", *s.Config.Region)
|
||||
assert.Equal(t, http.DefaultClient, s.Config.HTTPClient)
|
||||
assert.NotNil(t, s.Config.Logger)
|
||||
assert.Equal(t, aws.LogOff, *s.Config.LogLevel)
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ReadSeekCloser wraps a io.Reader returning a ReaderSeakerCloser
|
||||
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser
|
||||
func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
|
||||
return ReaderSeekerCloser{r}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,4 +5,4 @@ package aws
|
||||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "0.9.16"
|
||||
const SDKVersion = "1.0.0"
|
||||
|
||||
+38
-4
@@ -4,11 +4,27 @@ package endpoints
|
||||
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
|
||||
//go:generate gofmt -s -w endpoints_map.go
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NormalizeEndpoint takes and endpoint and service API information to return a
|
||||
// normalized endpoint and signing region. If the endpoint is not an empty string
|
||||
// the service name and region will be used to look up the service's API endpoint.
|
||||
// If the endpoint is provided the scheme will be added if it is not present.
|
||||
func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL bool) (normEndpoint, signingRegion string) {
|
||||
if endpoint == "" {
|
||||
return EndpointForRegion(serviceName, region, disableSSL)
|
||||
}
|
||||
|
||||
return AddScheme(endpoint, disableSSL), ""
|
||||
}
|
||||
|
||||
// EndpointForRegion returns an endpoint and its signing region for a service and region.
|
||||
// if the service and region pair are not found endpoint and signingRegion will be empty.
|
||||
func EndpointForRegion(svcName, region string) (endpoint, signingRegion string) {
|
||||
func EndpointForRegion(svcName, region string, disableSSL bool) (endpoint, signingRegion string) {
|
||||
derivedKeys := []string{
|
||||
region + "/" + svcName,
|
||||
region + "/*",
|
||||
@@ -24,8 +40,26 @@ func EndpointForRegion(svcName, region string) (endpoint, signingRegion string)
|
||||
|
||||
endpoint = ep
|
||||
signingRegion = val.SigningRegion
|
||||
return
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
return AddScheme(endpoint, disableSSL), signingRegion
|
||||
}
|
||||
|
||||
// Regular expression to determine if the endpoint string is prefixed with a scheme.
|
||||
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||
|
||||
// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
|
||||
// scheme. If disableSSL is true HTTP will be added instead of the default HTTPS.
|
||||
func AddScheme(endpoint string, disableSSL bool) string {
|
||||
if endpoint != "" && !schemeRE.MatchString(endpoint) {
|
||||
scheme := "https"
|
||||
if disableSSL {
|
||||
scheme = "http"
|
||||
}
|
||||
endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
|
||||
}
|
||||
|
||||
return endpoint
|
||||
}
|
||||
|
||||
+8
@@ -29,6 +29,10 @@
|
||||
"endpoint": "",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/ec2metadata": {
|
||||
"endpoint": "http://169.254.169.254/latest",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/iam": {
|
||||
"endpoint": "iam.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
@@ -45,6 +49,10 @@
|
||||
"endpoint": "sts.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"*/waf": {
|
||||
"endpoint": "waf.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
},
|
||||
"us-east-1/sdb": {
|
||||
"endpoint": "sdb.amazonaws.com",
|
||||
"signingRegion": "us-east-1"
|
||||
|
||||
Generated
Vendored
+8
@@ -30,6 +30,10 @@ var endpointsMap = endpointStruct{
|
||||
Endpoint: "",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/ec2metadata": {
|
||||
Endpoint: "http://169.254.169.254/latest",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/iam": {
|
||||
Endpoint: "iam.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
@@ -46,6 +50,10 @@ var endpointsMap = endpointStruct{
|
||||
Endpoint: "sts.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"*/waf": {
|
||||
Endpoint: "waf.amazonaws.com",
|
||||
SigningRegion: "us-east-1",
|
||||
},
|
||||
"ap-northeast-1/s3": {
|
||||
Endpoint: "s3-{region}.amazonaws.com",
|
||||
},
|
||||
|
||||
Generated
Vendored
+20
-7
@@ -1,28 +1,41 @@
|
||||
package endpoints
|
||||
package endpoints_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
func TestGenericEndpoint(t *testing.T) {
|
||||
name := "service"
|
||||
region := "mock-region-1"
|
||||
|
||||
ep, sr := endpoints.EndpointForRegion(name, region, false)
|
||||
assert.Equal(t, fmt.Sprintf("https://%s.%s.amazonaws.com", name, region), ep)
|
||||
assert.Empty(t, sr)
|
||||
}
|
||||
|
||||
func TestGlobalEndpoints(t *testing.T) {
|
||||
region := "mock-region-1"
|
||||
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts"}
|
||||
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts", "waf"}
|
||||
|
||||
for _, name := range svcs {
|
||||
ep, sr := EndpointForRegion(name, region)
|
||||
assert.Equal(t, name+".amazonaws.com", ep)
|
||||
ep, sr := endpoints.EndpointForRegion(name, region, false)
|
||||
assert.Equal(t, fmt.Sprintf("https://%s.amazonaws.com", name), ep)
|
||||
assert.Equal(t, "us-east-1", sr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicesInCN(t *testing.T) {
|
||||
region := "cn-north-1"
|
||||
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts", "s3"}
|
||||
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts", "s3", "waf"}
|
||||
|
||||
for _, name := range svcs {
|
||||
ep, _ := EndpointForRegion(name, region)
|
||||
assert.Equal(t, name+"."+region+".amazonaws.com.cn", ep)
|
||||
ep, sr := endpoints.EndpointForRegion(name, region, false)
|
||||
assert.Equal(t, fmt.Sprintf("https://%s.%s.amazonaws.com.cn", name, region), ep)
|
||||
assert.Empty(t, sr)
|
||||
}
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -15,7 +15,7 @@ import (
|
||||
func Build(r *request.Request) {
|
||||
body := url.Values{
|
||||
"Action": {r.Operation.Name},
|
||||
"Version": {r.Service.APIVersion},
|
||||
"Version": {r.ClientInfo.APIVersion},
|
||||
}
|
||||
if err := queryutil.Parse(body, r.Params, true); err != nil {
|
||||
r.Error = awserr.New("SerializationError", "failed encoding EC2 Query request", err)
|
||||
|
||||
Generated
Vendored
+2
-2
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
)
|
||||
@@ -67,7 +67,7 @@ func BenchmarkEC2QueryBuild_Simple_ec2AttachNetworkInterface(b *testing.B) {
|
||||
}
|
||||
|
||||
func benchEC2QueryBuild(b *testing.B, opName string, params interface{}) {
|
||||
svc := service.New(nil)
|
||||
svc := awstesting.NewClient()
|
||||
svc.ServiceName = "ec2"
|
||||
svc.APIVersion = "2015-04-15"
|
||||
|
||||
|
||||
Generated
Vendored
+316
-147
@@ -12,10 +12,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||
@@ -35,30 +35,52 @@ var _ = ioutil.Discard
|
||||
var _ = util.Trim("")
|
||||
var _ = url.Values{}
|
||||
var _ = io.EOF
|
||||
var _ = aws.String
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService1ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService1ProtocolTest client.
|
||||
func NewInputService1ProtocolTest(config *aws.Config) *InputService1ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice1protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService1ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService1ProtocolTest client from just a session.
|
||||
// svc := inputservice1protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService1ProtocolTest client with additional configuration
|
||||
// svc := inputservice1protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService1ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService1ProtocolTest {
|
||||
c := p.ClientConfig("inputservice1protocoltest", cfgs...)
|
||||
return newInputService1ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService1ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService1ProtocolTest {
|
||||
svc := &InputService1ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice1protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService1ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService1ProtocolTest operation and runs any
|
||||
@@ -113,29 +135,50 @@ type metadataInputService1TestShapeInputService1TestCaseOperation1Output struct
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService2ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService2ProtocolTest client.
|
||||
func NewInputService2ProtocolTest(config *aws.Config) *InputService2ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice2protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService2ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService2ProtocolTest client from just a session.
|
||||
// svc := inputservice2protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService2ProtocolTest client with additional configuration
|
||||
// svc := inputservice2protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService2ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService2ProtocolTest {
|
||||
c := p.ClientConfig("inputservice2protocoltest", cfgs...)
|
||||
return newInputService2ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService2ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService2ProtocolTest {
|
||||
svc := &InputService2ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice2protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService2ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService2ProtocolTest operation and runs any
|
||||
@@ -192,29 +235,50 @@ type metadataInputService2TestShapeInputService2TestCaseOperation1Output struct
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService3ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService3ProtocolTest client.
|
||||
func NewInputService3ProtocolTest(config *aws.Config) *InputService3ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice3protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService3ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService3ProtocolTest client from just a session.
|
||||
// svc := inputservice3protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService3ProtocolTest client with additional configuration
|
||||
// svc := inputservice3protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService3ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService3ProtocolTest {
|
||||
c := p.ClientConfig("inputservice3protocoltest", cfgs...)
|
||||
return newInputService3ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService3ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService3ProtocolTest {
|
||||
svc := &InputService3ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice3protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService3ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService3ProtocolTest operation and runs any
|
||||
@@ -277,29 +341,50 @@ type metadataInputService3TestShapeStructType struct {
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService4ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService4ProtocolTest client.
|
||||
func NewInputService4ProtocolTest(config *aws.Config) *InputService4ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice4protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService4ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService4ProtocolTest client from just a session.
|
||||
// svc := inputservice4protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService4ProtocolTest client with additional configuration
|
||||
// svc := inputservice4protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService4ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService4ProtocolTest {
|
||||
c := p.ClientConfig("inputservice4protocoltest", cfgs...)
|
||||
return newInputService4ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService4ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService4ProtocolTest {
|
||||
svc := &InputService4ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice4protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService4ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService4ProtocolTest operation and runs any
|
||||
@@ -352,29 +437,50 @@ type metadataInputService4TestShapeInputService4TestCaseOperation1Output struct
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService5ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService5ProtocolTest client.
|
||||
func NewInputService5ProtocolTest(config *aws.Config) *InputService5ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice5protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService5ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService5ProtocolTest client from just a session.
|
||||
// svc := inputservice5protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService5ProtocolTest client with additional configuration
|
||||
// svc := inputservice5protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService5ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService5ProtocolTest {
|
||||
c := p.ClientConfig("inputservice5protocoltest", cfgs...)
|
||||
return newInputService5ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService5ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService5ProtocolTest {
|
||||
svc := &InputService5ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice5protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService5ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService5ProtocolTest operation and runs any
|
||||
@@ -427,29 +533,50 @@ type metadataInputService5TestShapeInputService5TestCaseOperation1Output struct
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService6ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService6ProtocolTest client.
|
||||
func NewInputService6ProtocolTest(config *aws.Config) *InputService6ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice6protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService6ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService6ProtocolTest client from just a session.
|
||||
// svc := inputservice6protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService6ProtocolTest client with additional configuration
|
||||
// svc := inputservice6protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService6ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService6ProtocolTest {
|
||||
c := p.ClientConfig("inputservice6protocoltest", cfgs...)
|
||||
return newInputService6ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService6ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService6ProtocolTest {
|
||||
svc := &InputService6ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice6protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService6ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService6ProtocolTest operation and runs any
|
||||
@@ -502,29 +629,50 @@ type metadataInputService6TestShapeInputService6TestCaseOperation1Output struct
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService7ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService7ProtocolTest client.
|
||||
func NewInputService7ProtocolTest(config *aws.Config) *InputService7ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice7protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService7ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService7ProtocolTest client from just a session.
|
||||
// svc := inputservice7protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService7ProtocolTest client with additional configuration
|
||||
// svc := inputservice7protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService7ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService7ProtocolTest {
|
||||
c := p.ClientConfig("inputservice7protocoltest", cfgs...)
|
||||
return newInputService7ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService7ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService7ProtocolTest {
|
||||
svc := &InputService7ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice7protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService7ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService7ProtocolTest operation and runs any
|
||||
@@ -577,29 +725,50 @@ type metadataInputService7TestShapeInputService7TestCaseOperation1Output struct
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type InputService8ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new InputService8ProtocolTest client.
|
||||
func NewInputService8ProtocolTest(config *aws.Config) *InputService8ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "inputservice8protocoltest",
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
// New creates a new instance of the InputService8ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a InputService8ProtocolTest client from just a session.
|
||||
// svc := inputservice8protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a InputService8ProtocolTest client with additional configuration
|
||||
// svc := inputservice8protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewInputService8ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService8ProtocolTest {
|
||||
c := p.ClientConfig("inputservice8protocoltest", cfgs...)
|
||||
return newInputService8ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newInputService8ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *InputService8ProtocolTest {
|
||||
svc := &InputService8ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "inputservice8protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2014-01-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &InputService8ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a InputService8ProtocolTest operation and runs any
|
||||
@@ -657,8 +826,8 @@ type metadataInputService8TestShapeInputService8TestCaseOperation1Output struct
|
||||
//
|
||||
|
||||
func TestInputService1ProtocolTestScalarMembersCase1(t *testing.T) {
|
||||
svc := NewInputService1ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService1ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService1TestShapeInputService1TestCaseOperation1Input{
|
||||
Bar: aws.String("val2"),
|
||||
@@ -684,8 +853,8 @@ func TestInputService1ProtocolTestScalarMembersCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInputService2ProtocolTestStructureWithLocationNameAndQueryNameAppliedToMembersCase1(t *testing.T) {
|
||||
svc := NewInputService2ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService2ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService2TestShapeInputService2TestCaseOperation1Input{
|
||||
Bar: aws.String("val2"),
|
||||
@@ -712,8 +881,8 @@ func TestInputService2ProtocolTestStructureWithLocationNameAndQueryNameAppliedTo
|
||||
}
|
||||
|
||||
func TestInputService3ProtocolTestNestedStructureMembersCase1(t *testing.T) {
|
||||
svc := NewInputService3ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService3ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService3TestShapeInputService3TestCaseOperation1Input{
|
||||
StructArg: &InputService3TestShapeStructType{
|
||||
@@ -740,8 +909,8 @@ func TestInputService3ProtocolTestNestedStructureMembersCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInputService4ProtocolTestListTypesCase1(t *testing.T) {
|
||||
svc := NewInputService4ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService4ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService4TestShapeInputService4TestCaseOperation1Input{
|
||||
ListArg: []*string{
|
||||
@@ -770,8 +939,8 @@ func TestInputService4ProtocolTestListTypesCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInputService5ProtocolTestListWithLocationNameAppliedToMemberCase1(t *testing.T) {
|
||||
svc := NewInputService5ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService5ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService5TestShapeInputService5TestCaseOperation1Input{
|
||||
ListArg: []*string{
|
||||
@@ -800,8 +969,8 @@ func TestInputService5ProtocolTestListWithLocationNameAppliedToMemberCase1(t *te
|
||||
}
|
||||
|
||||
func TestInputService6ProtocolTestListWithLocationNameAndQueryNameCase1(t *testing.T) {
|
||||
svc := NewInputService6ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService6ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService6TestShapeInputService6TestCaseOperation1Input{
|
||||
ListArg: []*string{
|
||||
@@ -830,8 +999,8 @@ func TestInputService6ProtocolTestListWithLocationNameAndQueryNameCase1(t *testi
|
||||
}
|
||||
|
||||
func TestInputService7ProtocolTestBase64EncodedBlobsCase1(t *testing.T) {
|
||||
svc := NewInputService7ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService7ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService7TestShapeInputService7TestCaseOperation1Input{
|
||||
BlobArg: []byte("foo"),
|
||||
@@ -856,8 +1025,8 @@ func TestInputService7ProtocolTestBase64EncodedBlobsCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) {
|
||||
svc := NewInputService8ProtocolTest(nil)
|
||||
svc.Endpoint = "https://test"
|
||||
sess := session.New()
|
||||
svc := NewInputService8ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
input := &InputService8TestShapeInputService8TestCaseOperation1Input{
|
||||
TimeArg: aws.Time(time.Unix(1422172800, 0)),
|
||||
|
||||
Generated
Vendored
+433
-139
@@ -12,10 +12,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
|
||||
@@ -35,30 +35,52 @@ var _ = ioutil.Discard
|
||||
var _ = util.Trim("")
|
||||
var _ = url.Values{}
|
||||
var _ = io.EOF
|
||||
var _ = aws.String
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService1ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService1ProtocolTest client.
|
||||
func NewOutputService1ProtocolTest(config *aws.Config) *OutputService1ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice1protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService1ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService1ProtocolTest client from just a session.
|
||||
// svc := outputservice1protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService1ProtocolTest client with additional configuration
|
||||
// svc := outputservice1protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService1ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService1ProtocolTest {
|
||||
c := p.ClientConfig("outputservice1protocoltest", cfgs...)
|
||||
return newOutputService1ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService1ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService1ProtocolTest {
|
||||
svc := &OutputService1ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice1protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService1ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService1ProtocolTest operation and runs any
|
||||
@@ -125,29 +147,50 @@ type metadataOutputService1TestShapeOutputService1TestCaseOperation1Output struc
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService2ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService2ProtocolTest client.
|
||||
func NewOutputService2ProtocolTest(config *aws.Config) *OutputService2ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice2protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService2ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService2ProtocolTest client from just a session.
|
||||
// svc := outputservice2protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService2ProtocolTest client with additional configuration
|
||||
// svc := outputservice2protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService2ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService2ProtocolTest {
|
||||
c := p.ClientConfig("outputservice2protocoltest", cfgs...)
|
||||
return newOutputService2ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService2ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService2ProtocolTest {
|
||||
svc := &OutputService2ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice2protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService2ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService2ProtocolTest operation and runs any
|
||||
@@ -200,29 +243,50 @@ type metadataOutputService2TestShapeOutputService2TestCaseOperation1Output struc
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService3ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService3ProtocolTest client.
|
||||
func NewOutputService3ProtocolTest(config *aws.Config) *OutputService3ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice3protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService3ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService3ProtocolTest client from just a session.
|
||||
// svc := outputservice3protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService3ProtocolTest client with additional configuration
|
||||
// svc := outputservice3protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService3ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService3ProtocolTest {
|
||||
c := p.ClientConfig("outputservice3protocoltest", cfgs...)
|
||||
return newOutputService3ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService3ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService3ProtocolTest {
|
||||
svc := &OutputService3ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice3protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService3ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService3ProtocolTest operation and runs any
|
||||
@@ -275,29 +339,50 @@ type metadataOutputService3TestShapeOutputService3TestCaseOperation1Output struc
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService4ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService4ProtocolTest client.
|
||||
func NewOutputService4ProtocolTest(config *aws.Config) *OutputService4ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice4protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService4ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService4ProtocolTest client from just a session.
|
||||
// svc := outputservice4protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService4ProtocolTest client with additional configuration
|
||||
// svc := outputservice4protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService4ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService4ProtocolTest {
|
||||
c := p.ClientConfig("outputservice4protocoltest", cfgs...)
|
||||
return newOutputService4ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService4ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService4ProtocolTest {
|
||||
svc := &OutputService4ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice4protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService4ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService4ProtocolTest operation and runs any
|
||||
@@ -350,29 +435,50 @@ type metadataOutputService4TestShapeOutputService4TestCaseOperation1Output struc
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService5ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService5ProtocolTest client.
|
||||
func NewOutputService5ProtocolTest(config *aws.Config) *OutputService5ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice5protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService5ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService5ProtocolTest client from just a session.
|
||||
// svc := outputservice5protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService5ProtocolTest client with additional configuration
|
||||
// svc := outputservice5protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService5ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService5ProtocolTest {
|
||||
c := p.ClientConfig("outputservice5protocoltest", cfgs...)
|
||||
return newOutputService5ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService5ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService5ProtocolTest {
|
||||
svc := &OutputService5ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice5protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService5ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService5ProtocolTest operation and runs any
|
||||
@@ -425,29 +531,50 @@ type metadataOutputService5TestShapeOutputService5TestCaseOperation1Output struc
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService6ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService6ProtocolTest client.
|
||||
func NewOutputService6ProtocolTest(config *aws.Config) *OutputService6ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice6protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService6ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService6ProtocolTest client from just a session.
|
||||
// svc := outputservice6protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService6ProtocolTest client with additional configuration
|
||||
// svc := outputservice6protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService6ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService6ProtocolTest {
|
||||
c := p.ClientConfig("outputservice6protocoltest", cfgs...)
|
||||
return newOutputService6ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService6ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService6ProtocolTest {
|
||||
svc := &OutputService6ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice6protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService6ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService6ProtocolTest operation and runs any
|
||||
@@ -510,29 +637,50 @@ type metadataOutputService6TestShapeStructureType struct {
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService7ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService7ProtocolTest client.
|
||||
func NewOutputService7ProtocolTest(config *aws.Config) *OutputService7ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice7protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService7ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService7ProtocolTest client from just a session.
|
||||
// svc := outputservice7protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService7ProtocolTest client with additional configuration
|
||||
// svc := outputservice7protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService7ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService7ProtocolTest {
|
||||
c := p.ClientConfig("outputservice7protocoltest", cfgs...)
|
||||
return newOutputService7ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService7ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService7ProtocolTest {
|
||||
svc := &OutputService7ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice7protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService7ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService7ProtocolTest operation and runs any
|
||||
@@ -585,29 +733,50 @@ type metadataOutputService7TestShapeOutputService7TestCaseOperation1Output struc
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService8ProtocolTest struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New returns a new OutputService8ProtocolTest client.
|
||||
func NewOutputService8ProtocolTest(config *aws.Config) *OutputService8ProtocolTest {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "outputservice8protocoltest",
|
||||
APIVersion: "",
|
||||
},
|
||||
// New creates a new instance of the OutputService8ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService8ProtocolTest client from just a session.
|
||||
// svc := outputservice8protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService8ProtocolTest client with additional configuration
|
||||
// svc := outputservice8protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService8ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService8ProtocolTest {
|
||||
c := p.ClientConfig("outputservice8protocoltest", cfgs...)
|
||||
return newOutputService8ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService8ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService8ProtocolTest {
|
||||
svc := &OutputService8ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice8protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return &OutputService8ProtocolTest{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService8ProtocolTest operation and runs any
|
||||
@@ -660,12 +829,109 @@ type metadataOutputService8TestShapeOutputService8TestCaseOperation1Output struc
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type OutputService9ProtocolTest struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New creates a new instance of the OutputService9ProtocolTest client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a OutputService9ProtocolTest client from just a session.
|
||||
// svc := outputservice9protocoltest.New(mySession)
|
||||
//
|
||||
// // Create a OutputService9ProtocolTest client with additional configuration
|
||||
// svc := outputservice9protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func NewOutputService9ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService9ProtocolTest {
|
||||
c := p.ClientConfig("outputservice9protocoltest", cfgs...)
|
||||
return newOutputService9ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newOutputService9ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *OutputService9ProtocolTest {
|
||||
svc := &OutputService9ProtocolTest{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "outputservice9protocoltest",
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
// Handlers
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a OutputService9ProtocolTest operation and runs any
|
||||
// custom request initialization.
|
||||
func (c *OutputService9ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request {
|
||||
req := c.NewRequest(op, params, data)
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
const opOutputService9TestCaseOperation1 = "OperationName"
|
||||
|
||||
// OutputService9TestCaseOperation1Request generates a request for the OutputService9TestCaseOperation1 operation.
|
||||
func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1Request(input *OutputService9TestShapeOutputService9TestCaseOperation1Input) (req *request.Request, output *OutputService9TestShapeOutputService9TestCaseOperation1Output) {
|
||||
op := &request.Operation{
|
||||
Name: opOutputService9TestCaseOperation1,
|
||||
}
|
||||
|
||||
if input == nil {
|
||||
input = &OutputService9TestShapeOutputService9TestCaseOperation1Input{}
|
||||
}
|
||||
|
||||
req = c.newRequest(op, input, output)
|
||||
output = &OutputService9TestShapeOutputService9TestCaseOperation1Output{}
|
||||
req.Data = output
|
||||
return
|
||||
}
|
||||
|
||||
func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1(input *OutputService9TestShapeOutputService9TestCaseOperation1Input) (*OutputService9TestShapeOutputService9TestCaseOperation1Output, error) {
|
||||
req, out := c.OutputService9TestCaseOperation1Request(input)
|
||||
err := req.Send()
|
||||
return out, err
|
||||
}
|
||||
|
||||
type OutputService9TestShapeOutputService9TestCaseOperation1Input struct {
|
||||
metadataOutputService9TestShapeOutputService9TestCaseOperation1Input `json:"-" xml:"-"`
|
||||
}
|
||||
|
||||
type metadataOutputService9TestShapeOutputService9TestCaseOperation1Input struct {
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
type OutputService9TestShapeOutputService9TestCaseOperation1Output struct {
|
||||
Foo *string `type:"string"`
|
||||
|
||||
metadataOutputService9TestShapeOutputService9TestCaseOperation1Output `json:"-" xml:"-"`
|
||||
}
|
||||
|
||||
type metadataOutputService9TestShapeOutputService9TestCaseOperation1Output struct {
|
||||
SDKShapeTraits bool `type:"structure"`
|
||||
}
|
||||
|
||||
//
|
||||
// Tests begin here
|
||||
//
|
||||
|
||||
func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) {
|
||||
svc := NewOutputService1ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService1ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><Str>myname</Str><FooNum>123</FooNum><FalseBool>false</FalseBool><TrueBool>true</TrueBool><Float>1.2</Float><Double>1.3</Double><Long>200</Long><Char>a</Char><RequestId>request-id</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService1TestCaseOperation1Request(nil)
|
||||
@@ -692,7 +958,8 @@ func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOutputService2ProtocolTestBlobCase1(t *testing.T) {
|
||||
svc := NewOutputService2ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService2ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><Blob>dmFsdWU=</Blob><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService2TestCaseOperation1Request(nil)
|
||||
@@ -712,7 +979,8 @@ func TestOutputService2ProtocolTestBlobCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOutputService3ProtocolTestListsCase1(t *testing.T) {
|
||||
svc := NewOutputService3ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService3ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><ListMember><member>abc</member><member>123</member></ListMember><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService3TestCaseOperation1Request(nil)
|
||||
@@ -733,7 +1001,8 @@ func TestOutputService3ProtocolTestListsCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOutputService4ProtocolTestListWithCustomMemberNameCase1(t *testing.T) {
|
||||
svc := NewOutputService4ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService4ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><ListMember><item>abc</item><item>123</item></ListMember><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService4TestCaseOperation1Request(nil)
|
||||
@@ -754,7 +1023,8 @@ func TestOutputService4ProtocolTestListWithCustomMemberNameCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOutputService5ProtocolTestFlattenedListCase1(t *testing.T) {
|
||||
svc := NewOutputService5ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService5ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><ListMember>abc</ListMember><ListMember>123</ListMember><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService5TestCaseOperation1Request(nil)
|
||||
@@ -775,7 +1045,8 @@ func TestOutputService5ProtocolTestFlattenedListCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOutputService6ProtocolTestNormalMapCase1(t *testing.T) {
|
||||
svc := NewOutputService6ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService6ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><Map><entry><key>qux</key><value><foo>bar</foo></value></entry><entry><key>baz</key><value><foo>bam</foo></value></entry></Map><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService6TestCaseOperation1Request(nil)
|
||||
@@ -796,7 +1067,8 @@ func TestOutputService6ProtocolTestNormalMapCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOutputService7ProtocolTestFlattenedMapCase1(t *testing.T) {
|
||||
svc := NewOutputService7ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService7ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><Map><key>qux</key><value>bar</value></Map><Map><key>baz</key><value>bam</value></Map><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService7TestCaseOperation1Request(nil)
|
||||
@@ -817,7 +1089,8 @@ func TestOutputService7ProtocolTestFlattenedMapCase1(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOutputService8ProtocolTestNamedMapCase1(t *testing.T) {
|
||||
svc := NewOutputService8ProtocolTest(nil)
|
||||
sess := session.New()
|
||||
svc := NewOutputService8ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><Map><foo>qux</foo><bar>bar</bar></Map><Map><foo>baz</foo><bar>bam</bar></Map><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService8TestCaseOperation1Request(nil)
|
||||
@@ -836,3 +1109,24 @@ func TestOutputService8ProtocolTestNamedMapCase1(t *testing.T) {
|
||||
assert.Equal(t, "bar", *out.Map["qux"])
|
||||
|
||||
}
|
||||
|
||||
func TestOutputService9ProtocolTestEmptyStringCase1(t *testing.T) {
|
||||
sess := session.New()
|
||||
svc := NewOutputService9ProtocolTest(sess, &aws.Config{Endpoint: aws.String("https://test")})
|
||||
|
||||
buf := bytes.NewReader([]byte("<OperationNameResponse><Foo/><RequestId>requestid</RequestId></OperationNameResponse>"))
|
||||
req, out := svc.OutputService9TestCaseOperation1Request(nil)
|
||||
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
|
||||
|
||||
// set headers
|
||||
|
||||
// unmarshal response
|
||||
ec2query.UnmarshalMeta(req)
|
||||
ec2query.Unmarshal(req)
|
||||
assert.NoError(t, req.Error)
|
||||
|
||||
// assert response
|
||||
assert.NotNil(t, out) // ensure out variable is used
|
||||
assert.Equal(t, "", *out.Foo)
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import (
|
||||
func Build(r *request.Request) {
|
||||
body := url.Values{
|
||||
"Action": {r.Operation.Name},
|
||||
"Version": {r.Service.APIVersion},
|
||||
"Version": {r.ClientInfo.APIVersion},
|
||||
}
|
||||
if err := queryutil.Parse(body, r.Params, false); err != nil {
|
||||
r.Error = awserr.New("SerializationError", "failed encoding Query request", err)
|
||||
|
||||
Generated
Vendored
+1123
-423
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+2
-2
@@ -72,7 +72,7 @@ func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix stri
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
|
||||
value := elemOf(value.Field(i))
|
||||
elemValue := elemOf(value.Field(i))
|
||||
field := t.Field(i)
|
||||
var name string
|
||||
|
||||
@@ -97,7 +97,7 @@ func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix stri
|
||||
name = prefix + "." + name
|
||||
}
|
||||
|
||||
if err := q.parseValue(v, value, name, field.Tag); err != nil {
|
||||
if err := q.parseValue(v, elemValue, name, field.Tag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
Generated
Vendored
+667
-241
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+3
-4
@@ -5,16 +5,15 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var _ = unit.Imported
|
||||
|
||||
func TestPresignHandler(t *testing.T) {
|
||||
svc := s3.New(nil)
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
|
||||
Bucket: aws.String("bucket"),
|
||||
Key: aws.String("key"),
|
||||
|
||||
+8
-8
@@ -67,18 +67,18 @@ type signer struct {
|
||||
func Sign(req *request.Request) {
|
||||
// If the request does not need to be signed ignore the signing of the
|
||||
// request if the AnonymousCredentials object is used.
|
||||
if req.Service.Config.Credentials == credentials.AnonymousCredentials {
|
||||
if req.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
region := req.Service.SigningRegion
|
||||
region := req.ClientInfo.SigningRegion
|
||||
if region == "" {
|
||||
region = aws.StringValue(req.Service.Config.Region)
|
||||
region = aws.StringValue(req.Config.Region)
|
||||
}
|
||||
|
||||
name := req.Service.SigningName
|
||||
name := req.ClientInfo.SigningName
|
||||
if name == "" {
|
||||
name = req.Service.ServiceName
|
||||
name = req.ClientInfo.ServiceName
|
||||
}
|
||||
|
||||
s := signer{
|
||||
@@ -89,9 +89,9 @@ func Sign(req *request.Request) {
|
||||
Body: req.Body,
|
||||
ServiceName: name,
|
||||
Region: region,
|
||||
Credentials: req.Service.Config.Credentials,
|
||||
Debug: req.Service.Config.LogLevel.Value(),
|
||||
Logger: req.Service.Config.Logger,
|
||||
Credentials: req.Config.Credentials,
|
||||
Debug: req.Config.LogLevel.Value(),
|
||||
Logger: req.Config.Logger,
|
||||
}
|
||||
|
||||
req.Error = s.sign()
|
||||
|
||||
+13
-8
@@ -6,11 +6,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
)
|
||||
|
||||
func buildSigner(serviceName string, region string, signTime time.Time, expireTime time.Duration, body string) signer {
|
||||
@@ -118,7 +119,7 @@ func TestSignPrecomputedBodyChecksum(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAnonymousCredentials(t *testing.T) {
|
||||
svc := service.New(&aws.Config{Credentials: credentials.AnonymousCredentials})
|
||||
svc := awstesting.NewClient(&aws.Config{Credentials: credentials.AnonymousCredentials})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
@@ -142,7 +143,7 @@ func TestAnonymousCredentials(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIgnoreResignRequestWithValidCreds(t *testing.T) {
|
||||
svc := service.New(&aws.Config{
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"),
|
||||
Region: aws.String("us-west-2"),
|
||||
})
|
||||
@@ -164,7 +165,7 @@ func TestIgnoreResignRequestWithValidCreds(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIgnorePreResignRequestWithValidCreds(t *testing.T) {
|
||||
svc := service.New(&aws.Config{
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"),
|
||||
Region: aws.String("us-west-2"),
|
||||
})
|
||||
@@ -188,7 +189,7 @@ func TestIgnorePreResignRequestWithValidCreds(t *testing.T) {
|
||||
|
||||
func TestResignRequestExpiredCreds(t *testing.T) {
|
||||
creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
|
||||
svc := service.New(&aws.Config{Credentials: creds})
|
||||
svc := awstesting.NewClient(&aws.Config{Credentials: creds})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
@@ -208,9 +209,13 @@ func TestResignRequestExpiredCreds(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPreResignRequestExpiredCreds(t *testing.T) {
|
||||
provider := &credentials.StaticProvider{credentials.Value{"AKID", "SECRET", "SESSION"}}
|
||||
provider := &credentials.StaticProvider{Value: credentials.Value{
|
||||
AccessKeyID: "AKID",
|
||||
SecretAccessKey: "SECRET",
|
||||
SessionToken: "SESSION",
|
||||
}}
|
||||
creds := credentials.NewCredentials(provider)
|
||||
svc := service.New(&aws.Config{Credentials: creds})
|
||||
svc := awstesting.NewClient(&aws.Config{Credentials: creds})
|
||||
r := svc.NewRequest(
|
||||
&request.Operation{
|
||||
Name: "BatchGetItem",
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package waiter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// A Config provides a collection of configuration values to setup a generated
|
||||
// waiter code with.
|
||||
type Config struct {
|
||||
Name string
|
||||
Delay int
|
||||
MaxAttempts int
|
||||
Operation string
|
||||
Acceptors []WaitAcceptor
|
||||
}
|
||||
|
||||
// A WaitAcceptor provides the information needed to wait for an API operation
|
||||
// to complete.
|
||||
type WaitAcceptor struct {
|
||||
Expected interface{}
|
||||
Matcher string
|
||||
State string
|
||||
Argument string
|
||||
}
|
||||
|
||||
// A Waiter provides waiting for an operation to complete.
|
||||
type Waiter struct {
|
||||
Config
|
||||
Client interface{}
|
||||
Input interface{}
|
||||
}
|
||||
|
||||
// Wait waits for an operation to complete, expire max attempts, or fail. Error
|
||||
// is returned if the operation fails.
|
||||
func (w *Waiter) Wait() error {
|
||||
client := reflect.ValueOf(w.Client)
|
||||
in := reflect.ValueOf(w.Input)
|
||||
method := client.MethodByName(w.Config.Operation + "Request")
|
||||
|
||||
for i := 0; i < w.MaxAttempts; i++ {
|
||||
res := method.Call([]reflect.Value{in})
|
||||
req := res[0].Interface().(*request.Request)
|
||||
req.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Waiter"))
|
||||
|
||||
err := req.Send()
|
||||
for _, a := range w.Acceptors {
|
||||
if err != nil && a.Matcher != "error" {
|
||||
// Only matcher error is valid if there is a request error
|
||||
continue
|
||||
}
|
||||
|
||||
result := false
|
||||
var vals []interface{}
|
||||
switch a.Matcher {
|
||||
case "pathAll", "path":
|
||||
// Require all matches to be equal for result to match
|
||||
vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument)
|
||||
result = true
|
||||
for _, val := range vals {
|
||||
if !awsutil.DeepEqual(val, a.Expected) {
|
||||
result = false
|
||||
break
|
||||
}
|
||||
}
|
||||
case "pathAny":
|
||||
// Only a single match needs to equal for the result to match
|
||||
vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument)
|
||||
for _, val := range vals {
|
||||
if awsutil.DeepEqual(val, a.Expected) {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
case "status":
|
||||
s := a.Expected.(int)
|
||||
result = s == req.HTTPResponse.StatusCode
|
||||
case "error":
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
result = aerr.Code() == a.Expected.(string)
|
||||
}
|
||||
case "pathList":
|
||||
// ignored matcher
|
||||
default:
|
||||
logf(client, "WARNING: Waiter for %s encountered unexpected matcher: %s",
|
||||
w.Config.Operation, a.Matcher)
|
||||
}
|
||||
|
||||
if !result {
|
||||
// If there was no matching result found there is nothing more to do
|
||||
// for this response, retry the request.
|
||||
continue
|
||||
}
|
||||
|
||||
switch a.State {
|
||||
case "success":
|
||||
// waiter completed
|
||||
return nil
|
||||
case "failure":
|
||||
// Waiter failure state triggered
|
||||
return awserr.New("ResourceNotReady",
|
||||
fmt.Sprintf("failed waiting for successful resource state"), err)
|
||||
case "retry":
|
||||
// clear the error and retry the operation
|
||||
err = nil
|
||||
default:
|
||||
logf(client, "WARNING: Waiter for %s encountered unexpected state: %s",
|
||||
w.Config.Operation, a.State)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * time.Duration(w.Delay))
|
||||
}
|
||||
|
||||
return awserr.New("ResourceNotReady",
|
||||
fmt.Sprintf("exceeded %d wait attempts", w.MaxAttempts), nil)
|
||||
}
|
||||
|
||||
func logf(client reflect.Value, msg string, args ...interface{}) {
|
||||
cfgVal := client.FieldByName("Config")
|
||||
if !cfgVal.IsValid() {
|
||||
return
|
||||
}
|
||||
if cfg, ok := cfgVal.Interface().(*aws.Config); ok && cfg.Logger != nil {
|
||||
cfg.Logger.Log(fmt.Sprintf(msg, args...))
|
||||
}
|
||||
}
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
package waiter_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/private/waiter"
|
||||
)
|
||||
|
||||
type mockClient struct {
|
||||
*client.Client
|
||||
}
|
||||
type MockInput struct{}
|
||||
type MockOutput struct {
|
||||
States []*MockState
|
||||
}
|
||||
type MockState struct {
|
||||
State *string
|
||||
}
|
||||
|
||||
func (c *mockClient) MockRequest(input *MockInput) (*request.Request, *MockOutput) {
|
||||
op := &request.Operation{
|
||||
Name: "Mock",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
}
|
||||
|
||||
if input == nil {
|
||||
input = &MockInput{}
|
||||
}
|
||||
|
||||
output := &MockOutput{}
|
||||
req := c.NewRequest(op, input, output)
|
||||
req.Data = output
|
||||
return req, output
|
||||
}
|
||||
|
||||
func TestWaiterPathAll(t *testing.T) {
|
||||
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
|
||||
Region: aws.String("mock-region"),
|
||||
})}
|
||||
svc.Handlers.Send.Clear() // mock sending
|
||||
svc.Handlers.Unmarshal.Clear()
|
||||
svc.Handlers.UnmarshalMeta.Clear()
|
||||
svc.Handlers.ValidateResponse.Clear()
|
||||
|
||||
reqNum := 0
|
||||
resps := []*MockOutput{
|
||||
{ // Request 1
|
||||
States: []*MockState{
|
||||
{State: aws.String("pending")},
|
||||
{State: aws.String("pending")},
|
||||
},
|
||||
},
|
||||
{ // Request 2
|
||||
States: []*MockState{
|
||||
{State: aws.String("running")},
|
||||
{State: aws.String("pending")},
|
||||
},
|
||||
},
|
||||
{ // Request 3
|
||||
States: []*MockState{
|
||||
{State: aws.String("running")},
|
||||
{State: aws.String("running")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
numBuiltReq := 0
|
||||
svc.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
numBuiltReq++
|
||||
})
|
||||
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
if reqNum >= len(resps) {
|
||||
assert.Fail(t, "too many polling requests made")
|
||||
return
|
||||
}
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "Mock",
|
||||
Delay: 0,
|
||||
MaxAttempts: 10,
|
||||
Acceptors: []waiter.WaitAcceptor{
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "pathAll",
|
||||
Argument: "States[].State",
|
||||
Expected: "running",
|
||||
},
|
||||
},
|
||||
}
|
||||
w := waiter.Waiter{
|
||||
Client: svc,
|
||||
Input: &MockInput{},
|
||||
Config: waiterCfg,
|
||||
}
|
||||
|
||||
err := w.Wait()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, numBuiltReq)
|
||||
assert.Equal(t, 3, reqNum)
|
||||
}
|
||||
|
||||
func TestWaiterPath(t *testing.T) {
|
||||
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
|
||||
Region: aws.String("mock-region"),
|
||||
})}
|
||||
svc.Handlers.Send.Clear() // mock sending
|
||||
svc.Handlers.Unmarshal.Clear()
|
||||
svc.Handlers.UnmarshalMeta.Clear()
|
||||
svc.Handlers.ValidateResponse.Clear()
|
||||
|
||||
reqNum := 0
|
||||
resps := []*MockOutput{
|
||||
{ // Request 1
|
||||
States: []*MockState{
|
||||
{State: aws.String("pending")},
|
||||
{State: aws.String("pending")},
|
||||
},
|
||||
},
|
||||
{ // Request 2
|
||||
States: []*MockState{
|
||||
{State: aws.String("running")},
|
||||
{State: aws.String("pending")},
|
||||
},
|
||||
},
|
||||
{ // Request 3
|
||||
States: []*MockState{
|
||||
{State: aws.String("running")},
|
||||
{State: aws.String("running")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
numBuiltReq := 0
|
||||
svc.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
numBuiltReq++
|
||||
})
|
||||
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
if reqNum >= len(resps) {
|
||||
assert.Fail(t, "too many polling requests made")
|
||||
return
|
||||
}
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "Mock",
|
||||
Delay: 0,
|
||||
MaxAttempts: 10,
|
||||
Acceptors: []waiter.WaitAcceptor{
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "path",
|
||||
Argument: "States[].State",
|
||||
Expected: "running",
|
||||
},
|
||||
},
|
||||
}
|
||||
w := waiter.Waiter{
|
||||
Client: svc,
|
||||
Input: &MockInput{},
|
||||
Config: waiterCfg,
|
||||
}
|
||||
|
||||
err := w.Wait()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, numBuiltReq)
|
||||
assert.Equal(t, 3, reqNum)
|
||||
}
|
||||
|
||||
func TestWaiterFailure(t *testing.T) {
|
||||
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
|
||||
Region: aws.String("mock-region"),
|
||||
})}
|
||||
svc.Handlers.Send.Clear() // mock sending
|
||||
svc.Handlers.Unmarshal.Clear()
|
||||
svc.Handlers.UnmarshalMeta.Clear()
|
||||
svc.Handlers.ValidateResponse.Clear()
|
||||
|
||||
reqNum := 0
|
||||
resps := []*MockOutput{
|
||||
{ // Request 1
|
||||
States: []*MockState{
|
||||
{State: aws.String("pending")},
|
||||
{State: aws.String("pending")},
|
||||
},
|
||||
},
|
||||
{ // Request 2
|
||||
States: []*MockState{
|
||||
{State: aws.String("running")},
|
||||
{State: aws.String("pending")},
|
||||
},
|
||||
},
|
||||
{ // Request 3
|
||||
States: []*MockState{
|
||||
{State: aws.String("running")},
|
||||
{State: aws.String("stopping")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
numBuiltReq := 0
|
||||
svc.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
numBuiltReq++
|
||||
})
|
||||
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
if reqNum >= len(resps) {
|
||||
assert.Fail(t, "too many polling requests made")
|
||||
return
|
||||
}
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "Mock",
|
||||
Delay: 0,
|
||||
MaxAttempts: 10,
|
||||
Acceptors: []waiter.WaitAcceptor{
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "pathAll",
|
||||
Argument: "States[].State",
|
||||
Expected: "running",
|
||||
},
|
||||
{
|
||||
State: "failure",
|
||||
Matcher: "pathAny",
|
||||
Argument: "States[].State",
|
||||
Expected: "stopping",
|
||||
},
|
||||
},
|
||||
}
|
||||
w := waiter.Waiter{
|
||||
Client: svc,
|
||||
Input: &MockInput{},
|
||||
Config: waiterCfg,
|
||||
}
|
||||
|
||||
err := w.Wait().(awserr.Error)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "ResourceNotReady", err.Code())
|
||||
assert.Equal(t, "failed waiting for successful resource state", err.Message())
|
||||
assert.Equal(t, 3, numBuiltReq)
|
||||
assert.Equal(t, 3, reqNum)
|
||||
}
|
||||
|
||||
func TestWaiterError(t *testing.T) {
|
||||
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
|
||||
Region: aws.String("mock-region"),
|
||||
})}
|
||||
svc.Handlers.Send.Clear() // mock sending
|
||||
svc.Handlers.Unmarshal.Clear()
|
||||
svc.Handlers.UnmarshalMeta.Clear()
|
||||
svc.Handlers.ValidateResponse.Clear()
|
||||
|
||||
reqNum := 0
|
||||
resps := []*MockOutput{
|
||||
{ // Request 1
|
||||
States: []*MockState{
|
||||
{State: aws.String("pending")},
|
||||
{State: aws.String("pending")},
|
||||
},
|
||||
},
|
||||
{ // Request 2, error case
|
||||
},
|
||||
{ // Request 3
|
||||
States: []*MockState{
|
||||
{State: aws.String("running")},
|
||||
{State: aws.String("running")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
numBuiltReq := 0
|
||||
svc.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
numBuiltReq++
|
||||
})
|
||||
svc.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
if reqNum == 1 {
|
||||
r.Error = awserr.New("MockException", "mock exception message", nil)
|
||||
r.HTTPResponse = &http.Response{
|
||||
StatusCode: 400,
|
||||
Status: http.StatusText(400),
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
reqNum++
|
||||
}
|
||||
})
|
||||
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
|
||||
if reqNum >= len(resps) {
|
||||
assert.Fail(t, "too many polling requests made")
|
||||
return
|
||||
}
|
||||
r.Data = resps[reqNum]
|
||||
reqNum++
|
||||
})
|
||||
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "Mock",
|
||||
Delay: 0,
|
||||
MaxAttempts: 10,
|
||||
Acceptors: []waiter.WaitAcceptor{
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "pathAll",
|
||||
Argument: "States[].State",
|
||||
Expected: "running",
|
||||
},
|
||||
{
|
||||
State: "retry",
|
||||
Matcher: "error",
|
||||
Argument: "",
|
||||
Expected: "MockException",
|
||||
},
|
||||
},
|
||||
}
|
||||
w := waiter.Waiter{
|
||||
Client: svc,
|
||||
Input: &MockInput{},
|
||||
Config: waiterCfg,
|
||||
}
|
||||
|
||||
err := w.Wait()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, numBuiltReq)
|
||||
assert.Equal(t, 3, reqNum)
|
||||
}
|
||||
|
||||
func TestWaiterStatus(t *testing.T) {
|
||||
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
|
||||
Region: aws.String("mock-region"),
|
||||
})}
|
||||
svc.Handlers.Send.Clear() // mock sending
|
||||
svc.Handlers.Unmarshal.Clear()
|
||||
svc.Handlers.UnmarshalMeta.Clear()
|
||||
svc.Handlers.ValidateResponse.Clear()
|
||||
|
||||
reqNum := 0
|
||||
svc.Handlers.Build.PushBack(func(r *request.Request) {
|
||||
reqNum++
|
||||
})
|
||||
svc.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
code := 200
|
||||
if reqNum == 3 {
|
||||
code = 404
|
||||
}
|
||||
r.HTTPResponse = &http.Response{
|
||||
StatusCode: code,
|
||||
Status: http.StatusText(code),
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
})
|
||||
|
||||
waiterCfg := waiter.Config{
|
||||
Operation: "Mock",
|
||||
Delay: 0,
|
||||
MaxAttempts: 10,
|
||||
Acceptors: []waiter.WaitAcceptor{
|
||||
{
|
||||
State: "success",
|
||||
Matcher: "status",
|
||||
Argument: "",
|
||||
Expected: 404,
|
||||
},
|
||||
},
|
||||
}
|
||||
w := waiter.Waiter{
|
||||
Client: svc,
|
||||
Input: &MockInput{},
|
||||
Config: waiterCfg,
|
||||
}
|
||||
|
||||
err := w.Wait()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, reqNum)
|
||||
}
|
||||
+3
@@ -74,6 +74,7 @@ func (c *CloudWatch) DescribeAlarmHistory(input *DescribeAlarmHistoryInput) (*De
|
||||
|
||||
func (c *CloudWatch) DescribeAlarmHistoryPages(input *DescribeAlarmHistoryInput, fn func(p *DescribeAlarmHistoryOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeAlarmHistoryRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeAlarmHistoryOutput), lastPage)
|
||||
})
|
||||
@@ -116,6 +117,7 @@ func (c *CloudWatch) DescribeAlarms(input *DescribeAlarmsInput) (*DescribeAlarms
|
||||
|
||||
func (c *CloudWatch) DescribeAlarmsPages(input *DescribeAlarmsInput, fn func(p *DescribeAlarmsOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeAlarmsRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeAlarmsOutput), lastPage)
|
||||
})
|
||||
@@ -293,6 +295,7 @@ func (c *CloudWatch) ListMetrics(input *ListMetricsInput) (*ListMetricsOutput, e
|
||||
|
||||
func (c *CloudWatch) ListMetricsPages(input *ListMetricsInput, fn func(p *ListMetricsOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.ListMetricsRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*ListMetricsOutput), lastPage)
|
||||
})
|
||||
|
||||
Generated
Vendored
+2
@@ -60,3 +60,5 @@ type CloudWatchAPI interface {
|
||||
|
||||
SetAlarmState(*cloudwatch.SetAlarmStateInput) (*cloudwatch.SetAlarmStateOutput, error)
|
||||
}
|
||||
|
||||
var _ CloudWatchAPI = (*cloudwatch.CloudWatch)(nil)
|
||||
|
||||
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface/interface_test.go
Generated
Vendored
-15
@@ -1,15 +0,0 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package cloudwatchiface_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInterface(t *testing.T) {
|
||||
assert.Implements(t, (*cloudwatchiface.CloudWatchAPI)(nil), cloudwatch.New(nil))
|
||||
}
|
||||
Generated
Vendored
+12
-11
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
)
|
||||
|
||||
@@ -15,7 +16,7 @@ var _ time.Duration
|
||||
var _ bytes.Buffer
|
||||
|
||||
func ExampleCloudWatch_DeleteAlarms() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.DeleteAlarmsInput{
|
||||
AlarmNames: []*string{ // Required
|
||||
@@ -37,7 +38,7 @@ func ExampleCloudWatch_DeleteAlarms() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_DescribeAlarmHistory() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.DescribeAlarmHistoryInput{
|
||||
AlarmName: aws.String("AlarmName"),
|
||||
@@ -61,7 +62,7 @@ func ExampleCloudWatch_DescribeAlarmHistory() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_DescribeAlarms() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.DescribeAlarmsInput{
|
||||
ActionPrefix: aws.String("ActionPrefix"),
|
||||
@@ -88,7 +89,7 @@ func ExampleCloudWatch_DescribeAlarms() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_DescribeAlarmsForMetric() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.DescribeAlarmsForMetricInput{
|
||||
MetricName: aws.String("MetricName"), // Required
|
||||
@@ -118,7 +119,7 @@ func ExampleCloudWatch_DescribeAlarmsForMetric() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_DisableAlarmActions() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.DisableAlarmActionsInput{
|
||||
AlarmNames: []*string{ // Required
|
||||
@@ -140,7 +141,7 @@ func ExampleCloudWatch_DisableAlarmActions() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_EnableAlarmActions() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.EnableAlarmActionsInput{
|
||||
AlarmNames: []*string{ // Required
|
||||
@@ -162,7 +163,7 @@ func ExampleCloudWatch_EnableAlarmActions() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_GetMetricStatistics() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.GetMetricStatisticsInput{
|
||||
EndTime: aws.Time(time.Now()), // Required
|
||||
@@ -197,7 +198,7 @@ func ExampleCloudWatch_GetMetricStatistics() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_ListMetrics() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.ListMetricsInput{
|
||||
Dimensions: []*cloudwatch.DimensionFilter{
|
||||
@@ -225,7 +226,7 @@ func ExampleCloudWatch_ListMetrics() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_PutMetricAlarm() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.PutMetricAlarmInput{
|
||||
AlarmName: aws.String("AlarmName"), // Required
|
||||
@@ -273,7 +274,7 @@ func ExampleCloudWatch_PutMetricAlarm() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_PutMetricData() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.PutMetricDataInput{
|
||||
MetricData: []*cloudwatch.MetricDatum{ // Required
|
||||
@@ -314,7 +315,7 @@ func ExampleCloudWatch_PutMetricData() {
|
||||
}
|
||||
|
||||
func ExampleCloudWatch_SetAlarmState() {
|
||||
svc := cloudwatch.New(nil)
|
||||
svc := cloudwatch.New(session.New())
|
||||
|
||||
params := &cloudwatch.SetAlarmStateInput{
|
||||
AlarmName: aws.String("AlarmName"), // Required
|
||||
|
||||
+47
-24
@@ -4,10 +4,9 @@ package cloudwatch
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||
"github.com/aws/aws-sdk-go/private/signer/v4"
|
||||
)
|
||||
@@ -52,40 +51,64 @@ import (
|
||||
// Center (http://aws.amazon.com/php/) AWS Python Developer Center (http://aws.amazon.com/python/)
|
||||
// AWS Ruby Developer Center (http://aws.amazon.com/ruby/) AWS Windows and .NET
|
||||
// Developer Center (http://aws.amazon.com/net/)
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type CloudWatch struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom service initialization logic
|
||||
var initService func(*service.Service)
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// New returns a new CloudWatch client.
|
||||
func New(config *aws.Config) *CloudWatch {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "monitoring",
|
||||
APIVersion: "2010-08-01",
|
||||
},
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "monitoring"
|
||||
|
||||
// New creates a new instance of the CloudWatch client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a CloudWatch client from just a session.
|
||||
// svc := cloudwatch.New(mySession)
|
||||
//
|
||||
// // Create a CloudWatch client with additional configuration
|
||||
// svc := cloudwatch.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *CloudWatch {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *CloudWatch {
|
||||
svc := &CloudWatch{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2010-08-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(query.UnmarshalError)
|
||||
|
||||
// Run custom service initialization if present
|
||||
if initService != nil {
|
||||
initService(service)
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return &CloudWatch{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a CloudWatch operation and runs any
|
||||
|
||||
+58
-24
@@ -871,7 +871,7 @@ func (c *EC2) CreateCustomerGatewayRequest(input *CreateCustomerGatewayInput) (r
|
||||
// gateway is the appliance at your end of the VPN connection. (The device on
|
||||
// the AWS side of the VPN connection is the virtual private gateway.) You must
|
||||
// provide the Internet-routable IP address of the customer gateway's external
|
||||
// interface. The IP address must be static and can't be behind a device performing
|
||||
// interface. The IP address must be static and may be behind a device performing
|
||||
// network address translation (NAT).
|
||||
//
|
||||
// For devices that use Border Gateway Protocol (BGP), you can also provide
|
||||
@@ -1598,6 +1598,9 @@ func (c *EC2) CreateTagsRequest(input *CreateTagsInput) (req *request.Request, o
|
||||
// of a key and optional value. Tag keys must be unique per resource.
|
||||
//
|
||||
// For more information about tags, see Tagging Your Resources (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html)
|
||||
// in the Amazon Elastic Compute Cloud User Guide. For more information about
|
||||
// creating IAM policies that control users' access to resources based on tags,
|
||||
// see Supported Resource-Level Permissions for Amazon EC2 API Actions (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-supported-iam-actions-resources.html)
|
||||
// in the Amazon Elastic Compute Cloud User Guide.
|
||||
func (c *EC2) CreateTags(input *CreateTagsInput) (*CreateTagsOutput, error) {
|
||||
req, out := c.CreateTagsRequest(input)
|
||||
@@ -3100,6 +3103,7 @@ func (c *EC2) DescribeInstanceStatus(input *DescribeInstanceStatusInput) (*Descr
|
||||
|
||||
func (c *EC2) DescribeInstanceStatusPages(input *DescribeInstanceStatusInput, fn func(p *DescribeInstanceStatusOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeInstanceStatusRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeInstanceStatusOutput), lastPage)
|
||||
})
|
||||
@@ -3149,6 +3153,7 @@ func (c *EC2) DescribeInstances(input *DescribeInstancesInput) (*DescribeInstanc
|
||||
|
||||
func (c *EC2) DescribeInstancesPages(input *DescribeInstancesInput, fn func(p *DescribeInstancesOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeInstancesRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeInstancesOutput), lastPage)
|
||||
})
|
||||
@@ -3534,6 +3539,7 @@ func (c *EC2) DescribeReservedInstancesModifications(input *DescribeReservedInst
|
||||
|
||||
func (c *EC2) DescribeReservedInstancesModificationsPages(input *DescribeReservedInstancesModificationsInput, fn func(p *DescribeReservedInstancesModificationsOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeReservedInstancesModificationsRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeReservedInstancesModificationsOutput), lastPage)
|
||||
})
|
||||
@@ -3581,6 +3587,7 @@ func (c *EC2) DescribeReservedInstancesOfferings(input *DescribeReservedInstance
|
||||
|
||||
func (c *EC2) DescribeReservedInstancesOfferingsPages(input *DescribeReservedInstancesOfferingsInput, fn func(p *DescribeReservedInstancesOfferingsOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeReservedInstancesOfferingsRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeReservedInstancesOfferingsOutput), lastPage)
|
||||
})
|
||||
@@ -3697,7 +3704,7 @@ func (c *EC2) DescribeSnapshotsRequest(input *DescribeSnapshotsInput) (req *requ
|
||||
Paginator: &request.Paginator{
|
||||
InputTokens: []string{"NextToken"},
|
||||
OutputTokens: []string{"NextToken"},
|
||||
LimitToken: "",
|
||||
LimitToken: "MaxResults",
|
||||
TruncationToken: "",
|
||||
},
|
||||
}
|
||||
@@ -3760,6 +3767,7 @@ func (c *EC2) DescribeSnapshots(input *DescribeSnapshotsInput) (*DescribeSnapsho
|
||||
|
||||
func (c *EC2) DescribeSnapshotsPages(input *DescribeSnapshotsInput, fn func(p *DescribeSnapshotsOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeSnapshotsRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeSnapshotsOutput), lastPage)
|
||||
})
|
||||
@@ -3961,6 +3969,7 @@ func (c *EC2) DescribeSpotPriceHistory(input *DescribeSpotPriceHistoryInput) (*D
|
||||
|
||||
func (c *EC2) DescribeSpotPriceHistoryPages(input *DescribeSpotPriceHistoryInput, fn func(p *DescribeSpotPriceHistoryOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeSpotPriceHistoryRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeSpotPriceHistoryOutput), lastPage)
|
||||
})
|
||||
@@ -4004,6 +4013,12 @@ func (c *EC2) DescribeTagsRequest(input *DescribeTagsInput) (req *request.Reques
|
||||
Name: opDescribeTags,
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
Paginator: &request.Paginator{
|
||||
InputTokens: []string{"NextToken"},
|
||||
OutputTokens: []string{"NextToken"},
|
||||
LimitToken: "MaxResults",
|
||||
TruncationToken: "",
|
||||
},
|
||||
}
|
||||
|
||||
if input == nil {
|
||||
@@ -4026,6 +4041,14 @@ func (c *EC2) DescribeTags(input *DescribeTagsInput) (*DescribeTagsOutput, error
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *EC2) DescribeTagsPages(input *DescribeTagsInput, fn func(p *DescribeTagsOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeTagsRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeTagsOutput), lastPage)
|
||||
})
|
||||
}
|
||||
|
||||
const opDescribeVolumeAttribute = "DescribeVolumeAttribute"
|
||||
|
||||
// DescribeVolumeAttributeRequest generates a request for the DescribeVolumeAttribute operation.
|
||||
@@ -4126,6 +4149,7 @@ func (c *EC2) DescribeVolumeStatus(input *DescribeVolumeStatusInput) (*DescribeV
|
||||
|
||||
func (c *EC2) DescribeVolumeStatusPages(input *DescribeVolumeStatusInput, fn func(p *DescribeVolumeStatusOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeVolumeStatusRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeVolumeStatusOutput), lastPage)
|
||||
})
|
||||
@@ -4176,6 +4200,7 @@ func (c *EC2) DescribeVolumes(input *DescribeVolumesInput) (*DescribeVolumesOutp
|
||||
|
||||
func (c *EC2) DescribeVolumesPages(input *DescribeVolumesInput, fn func(p *DescribeVolumesOutput, lastPage bool) (shouldContinue bool)) error {
|
||||
page, _ := c.DescribeVolumesRequest(input)
|
||||
page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator"))
|
||||
return page.EachPage(func(p interface{}, lastPage bool) bool {
|
||||
return fn(p.(*DescribeVolumesOutput), lastPage)
|
||||
})
|
||||
@@ -9206,7 +9231,8 @@ func (s CreateSpotDatafeedSubscriptionOutput) GoString() string {
|
||||
type CreateSubnetInput struct {
|
||||
// The Availability Zone for the subnet.
|
||||
//
|
||||
// Default: Amazon EC2 selects one for you (recommended).
|
||||
// Default: AWS selects one for you. If you create more than one subnet in
|
||||
// your VPC, we may not necessarily select a different zone for each subnet.
|
||||
AvailabilityZone *string `type:"string"`
|
||||
|
||||
// The network range for the subnet, in CIDR notation. For example, 10.0.0.0/24.
|
||||
@@ -12262,7 +12288,7 @@ type DescribeInstancesInput struct {
|
||||
//
|
||||
// network-interface.vpc-id - The ID of the VPC for the network interface.
|
||||
//
|
||||
// network-interface.network-interface.id - The ID of the network interface.
|
||||
// network-interface.network-interface-id - The ID of the network interface.
|
||||
//
|
||||
// network-interface.owner-id - The ID of the owner of the network interface.
|
||||
//
|
||||
@@ -14153,7 +14179,7 @@ type DescribeSpotInstanceRequestsInput struct {
|
||||
//
|
||||
// launch.image-id - The ID of the AMI.
|
||||
//
|
||||
// launch.instance-type - The type of instance (for example, m1.small).
|
||||
// launch.instance-type - The type of instance (for example, m3.medium).
|
||||
//
|
||||
// launch.kernel-id - The kernel ID.
|
||||
//
|
||||
@@ -14291,7 +14317,7 @@ type DescribeSpotPriceHistoryInput struct {
|
||||
//
|
||||
// availability-zone - The Availability Zone for which prices should be returned.
|
||||
//
|
||||
// instance-type - The type of instance (for example, m1.small).
|
||||
// instance-type - The type of instance (for example, m3.medium).
|
||||
//
|
||||
// product-description - The product description for the Spot price (Linux/UNIX
|
||||
// | SUSE Linux | Windows | Linux/UNIX (Amazon VPC) | SUSE Linux (Amazon VPC)
|
||||
@@ -17491,7 +17517,7 @@ type Instance struct {
|
||||
// Any block device mapping entries for the instance.
|
||||
BlockDeviceMappings []*InstanceBlockDeviceMapping `locationName:"blockDeviceMapping" locationNameList:"item" type:"list"`
|
||||
|
||||
// The idempotency token you provided when you launched the instance.
|
||||
// The idempotency token you provided when you launched the instance, if applicable.
|
||||
ClientToken *string `locationName:"clientToken" type:"string"`
|
||||
|
||||
// Indicates whether the instance is optimized for EBS I/O. This optimization
|
||||
@@ -17504,7 +17530,7 @@ type Instance struct {
|
||||
// The hypervisor type of the instance.
|
||||
Hypervisor *string `locationName:"hypervisor" type:"string" enum:"HypervisorType"`
|
||||
|
||||
// The IAM instance profile associated with the instance.
|
||||
// The IAM instance profile associated with the instance, if applicable.
|
||||
IamInstanceProfile *IamInstanceProfile `locationName:"iamInstanceProfile" type:"structure"`
|
||||
|
||||
// The ID of the AMI used to launch the instance.
|
||||
@@ -17519,7 +17545,7 @@ type Instance struct {
|
||||
// The instance type.
|
||||
InstanceType *string `locationName:"instanceType" type:"string" enum:"InstanceType"`
|
||||
|
||||
// The kernel associated with this instance.
|
||||
// The kernel associated with this instance, if applicable.
|
||||
KernelId *string `locationName:"kernelId" type:"string"`
|
||||
|
||||
// The name of the key pair, if this instance was launched with an associated
|
||||
@@ -17535,7 +17561,7 @@ type Instance struct {
|
||||
// [EC2-VPC] One or more network interfaces for the instance.
|
||||
NetworkInterfaces []*InstanceNetworkInterface `locationName:"networkInterfaceSet" locationNameList:"item" type:"list"`
|
||||
|
||||
// The location where the instance launched.
|
||||
// The location where the instance launched, if applicable.
|
||||
Placement *Placement `locationName:"placement" type:"structure"`
|
||||
|
||||
// The value is Windows for Windows instances; otherwise blank.
|
||||
@@ -17543,23 +17569,25 @@ type Instance struct {
|
||||
|
||||
// The private DNS name assigned to the instance. This DNS name can only be
|
||||
// used inside the Amazon EC2 network. This name is not available until the
|
||||
// instance enters the running state.
|
||||
// instance enters the running state. For EC2-VPC, this name is only available
|
||||
// if you've enabled DNS hostnames for your VPC.
|
||||
PrivateDnsName *string `locationName:"privateDnsName" type:"string"`
|
||||
|
||||
// The private IP address assigned to the instance.
|
||||
PrivateIpAddress *string `locationName:"privateIpAddress" type:"string"`
|
||||
|
||||
// The product codes attached to this instance.
|
||||
// The product codes attached to this instance, if applicable.
|
||||
ProductCodes []*ProductCode `locationName:"productCodes" locationNameList:"item" type:"list"`
|
||||
|
||||
// The public DNS name assigned to the instance. This name is not available
|
||||
// until the instance enters the running state.
|
||||
// until the instance enters the running state. For EC2-VPC, this name is only
|
||||
// available if you've enabled DNS hostnames for your VPC.
|
||||
PublicDnsName *string `locationName:"dnsName" type:"string"`
|
||||
|
||||
// The public IP address assigned to the instance.
|
||||
// The public IP address assigned to the instance, if applicable.
|
||||
PublicIpAddress *string `locationName:"ipAddress" type:"string"`
|
||||
|
||||
// The RAM disk associated with this instance.
|
||||
// The RAM disk associated with this instance, if applicable.
|
||||
RamdiskId *string `locationName:"ramdiskId" type:"string"`
|
||||
|
||||
// The root device name (for example, /dev/sda1 or /dev/xvda).
|
||||
@@ -17580,7 +17608,7 @@ type Instance struct {
|
||||
// in the Amazon Virtual Private Cloud User Guide.
|
||||
SourceDestCheck *bool `locationName:"sourceDestCheck" type:"boolean"`
|
||||
|
||||
// The ID of the Spot Instance request.
|
||||
// If the request is a Spot instance request, the ID of the request.
|
||||
SpotInstanceRequestId *string `locationName:"spotInstanceRequestId" type:"string"`
|
||||
|
||||
// Specifies whether enhanced networking is enabled.
|
||||
@@ -17595,7 +17623,7 @@ type Instance struct {
|
||||
// The reason for the most recent state transition. This might be an empty string.
|
||||
StateTransitionReason *string `locationName:"reason" type:"string"`
|
||||
|
||||
// The ID of the subnet in which the instance is running.
|
||||
// [EC2-VPC] The ID of the subnet in which the instance is running.
|
||||
SubnetId *string `locationName:"subnetId" type:"string"`
|
||||
|
||||
// Any tags assigned to the instance.
|
||||
@@ -17604,7 +17632,7 @@ type Instance struct {
|
||||
// The virtualization type of the instance.
|
||||
VirtualizationType *string `locationName:"virtualizationType" type:"string" enum:"VirtualizationType"`
|
||||
|
||||
// The ID of the VPC in which the instance is running.
|
||||
// [EC2-VPC] The ID of the VPC in which the instance is running.
|
||||
VpcId *string `locationName:"vpcId" type:"string"`
|
||||
|
||||
metadataInstance `json:"-" xml:"-"`
|
||||
@@ -18960,7 +18988,9 @@ type ModifyVpcAttributeInput struct {
|
||||
// Indicates whether the instances launched in the VPC get DNS hostnames. If
|
||||
// enabled, instances in the VPC get DNS hostnames; otherwise, they do not.
|
||||
//
|
||||
// You can only enable DNS hostnames if you also enable DNS support.
|
||||
// You cannot modify the DNS resolution and DNS hostnames attributes in the
|
||||
// same request. Use separate requests for each attribute. You can only enable
|
||||
// DNS hostnames if you've enabled DNS support.
|
||||
EnableDnsHostnames *AttributeBooleanValue `type:"structure"`
|
||||
|
||||
// Indicates whether the DNS resolution is supported for the VPC. If enabled,
|
||||
@@ -18968,6 +18998,9 @@ type ModifyVpcAttributeInput struct {
|
||||
// or the reserved IP address at the base of the VPC network range "plus two"
|
||||
// will succeed. If disabled, the Amazon provided DNS service in the VPC that
|
||||
// resolves public DNS hostnames to IP addresses is not enabled.
|
||||
//
|
||||
// You cannot modify the DNS resolution and DNS hostnames attributes in the
|
||||
// same request. Use separate requests for each attribute.
|
||||
EnableDnsSupport *AttributeBooleanValue `type:"structure"`
|
||||
|
||||
// The ID of the VPC.
|
||||
@@ -20589,7 +20622,7 @@ type RequestSpotInstancesInput struct {
|
||||
// the instance a two-minute warning before it terminates.
|
||||
//
|
||||
// Note that you can't specify an Availability Zone group or a launch group
|
||||
// if you specify a required duration.
|
||||
// if you specify a duration.
|
||||
BlockDurationMinutes *int64 `locationName:"blockDurationMinutes" type:"integer"`
|
||||
|
||||
// Unique, case-sensitive identifier that you provide to ensure the idempotency
|
||||
@@ -22348,8 +22381,8 @@ func (s SpotFleetRequestConfigData) GoString() string {
|
||||
|
||||
// Describes a Spot instance request.
|
||||
type SpotInstanceRequest struct {
|
||||
// If you specified a required duration and your request was fulfilled, this
|
||||
// is the fixed hourly price in effect for the Spot instance while it runs.
|
||||
// If you specified a duration and your Spot instance request was fulfilled,
|
||||
// this is the fixed hourly price in effect for the Spot instance while it runs.
|
||||
ActualBlockHourlyPrice *string `locationName:"actualBlockHourlyPrice" type:"string"`
|
||||
|
||||
// The Availability Zone group. If you specify the same Availability Zone group
|
||||
@@ -22357,7 +22390,7 @@ type SpotInstanceRequest struct {
|
||||
// Availability Zone.
|
||||
AvailabilityZoneGroup *string `locationName:"availabilityZoneGroup" type:"string"`
|
||||
|
||||
// The required duration for the Spot instance, in minutes.
|
||||
// The duration for the Spot instance, in minutes.
|
||||
BlockDurationMinutes *int64 `locationName:"blockDurationMinutes" type:"integer"`
|
||||
|
||||
// The date and time when the Spot instance request was created, in UTC format
|
||||
@@ -22460,7 +22493,8 @@ func (s SpotInstanceStateFault) GoString() string {
|
||||
|
||||
// Describes the status of a Spot instance request.
|
||||
type SpotInstanceStatus struct {
|
||||
// The status code.
|
||||
// The status code. For a list of status codes, see Spot Bid Status Codes (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html#spot-instance-bid-status-understand)
|
||||
// in the Amazon Elastic Compute Cloud User Guide.
|
||||
Code *string `locationName:"code" type:"string"`
|
||||
|
||||
// The description for the status code.
|
||||
|
||||
+18
-20
@@ -3,8 +3,10 @@ package ec2
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -20,38 +22,34 @@ func fillPresignedURL(r *request.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
params := r.Params.(*CopySnapshotInput)
|
||||
origParams := r.Params.(*CopySnapshotInput)
|
||||
|
||||
// Stop if PresignedURL/DestinationRegion is set
|
||||
if params.PresignedUrl != nil || params.DestinationRegion != nil {
|
||||
if origParams.PresignedUrl != nil || origParams.DestinationRegion != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// First generate a copy of parameters
|
||||
r.Params = awsutil.CopyOf(r.Params)
|
||||
params = r.Params.(*CopySnapshotInput)
|
||||
origParams.DestinationRegion = r.Config.Region
|
||||
newParams := awsutil.CopyOf(r.Params).(*CopySnapshotInput)
|
||||
|
||||
// Set destination region. Avoids infinite handler loop.
|
||||
// Also needed to sign sub-request.
|
||||
params.DestinationRegion = r.Service.Config.Region
|
||||
|
||||
// Create a new client pointing at source region.
|
||||
// We will use this to presign the CopySnapshot request against
|
||||
// the source region
|
||||
config := r.Service.Config.Copy().
|
||||
// Create a new request based on the existing request. We will use this to
|
||||
// presign the CopySnapshot request against the source region.
|
||||
cfg := r.Config.Copy(aws.NewConfig().
|
||||
WithEndpoint("").
|
||||
WithRegion(*params.SourceRegion)
|
||||
WithRegion(aws.StringValue(origParams.SourceRegion)))
|
||||
|
||||
client := New(config)
|
||||
clientInfo := r.ClientInfo
|
||||
clientInfo.Endpoint, clientInfo.SigningRegion = endpoints.EndpointForRegion(
|
||||
clientInfo.ServiceName, aws.StringValue(cfg.Region), aws.BoolValue(cfg.DisableSSL))
|
||||
|
||||
// Presign a CopySnapshot request with modified params
|
||||
req, _ := client.CopySnapshotRequest(params)
|
||||
url, err := req.Presign(300 * time.Second) // 5 minutes should be enough.
|
||||
|
||||
if err != nil { // bubble error back up to original request
|
||||
req := request.New(*cfg, clientInfo, r.Handlers, r.Retryer, r.Operation, newParams, r.Data)
|
||||
url, err := req.Presign(5 * time.Minute) // 5 minutes should be enough.
|
||||
if err != nil { // bubble error back up to original request
|
||||
r.Error = err
|
||||
return
|
||||
}
|
||||
|
||||
// We have our URL, set it on params
|
||||
params.PresignedUrl = &url
|
||||
origParams.PresignedUrl = &url
|
||||
}
|
||||
|
||||
Generated
Vendored
+4
-5
@@ -11,10 +11,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var _ = unit.Imported
|
||||
|
||||
func TestCopySnapshotPresignedURL(t *testing.T) {
|
||||
svc := ec2.New(&aws.Config{Region: aws.String("us-west-2")})
|
||||
svc := ec2.New(unit.Session, &aws.Config{Region: aws.String("us-west-2")})
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
// Doesn't panic on nil input
|
||||
@@ -30,7 +28,8 @@ func TestCopySnapshotPresignedURL(t *testing.T) {
|
||||
|
||||
b, _ := ioutil.ReadAll(req.HTTPRequest.Body)
|
||||
q, _ := url.ParseQuery(string(b))
|
||||
url, _ := url.QueryUnescape(q.Get("PresignedUrl"))
|
||||
u, _ := url.QueryUnescape(q.Get("PresignedUrl"))
|
||||
assert.Equal(t, "us-west-2", q.Get("DestinationRegion"))
|
||||
assert.Regexp(t, `^https://ec2\.us-west-1\.amazon.+&DestinationRegion=us-west-2`, url)
|
||||
assert.Equal(t, "us-west-1", q.Get("SourceRegion"))
|
||||
assert.Regexp(t, `^https://ec2\.us-west-1\.amazonaws\.com/.+&DestinationRegion=us-west-2`, u)
|
||||
}
|
||||
|
||||
Generated
Vendored
+4
@@ -486,6 +486,8 @@ type EC2API interface {
|
||||
|
||||
DescribeTags(*ec2.DescribeTagsInput) (*ec2.DescribeTagsOutput, error)
|
||||
|
||||
DescribeTagsPages(*ec2.DescribeTagsInput, func(*ec2.DescribeTagsOutput, bool) bool) error
|
||||
|
||||
DescribeVolumeAttributeRequest(*ec2.DescribeVolumeAttributeInput) (*request.Request, *ec2.DescribeVolumeAttributeOutput)
|
||||
|
||||
DescribeVolumeAttribute(*ec2.DescribeVolumeAttributeInput) (*ec2.DescribeVolumeAttributeOutput, error)
|
||||
@@ -758,3 +760,5 @@ type EC2API interface {
|
||||
|
||||
UnmonitorInstances(*ec2.UnmonitorInstancesInput) (*ec2.UnmonitorInstancesOutput, error)
|
||||
}
|
||||
|
||||
var _ EC2API = (*ec2.EC2)(nil)
|
||||
|
||||
Generated
Vendored
-15
@@ -1,15 +0,0 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
|
||||
|
||||
package ec2iface_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInterface(t *testing.T) {
|
||||
assert.Implements(t, (*ec2iface.EC2API)(nil), ec2.New(nil))
|
||||
}
|
||||
+184
-183
File diff suppressed because it is too large
Load Diff
+47
-24
@@ -4,10 +4,9 @@ package ec2
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/service"
|
||||
"github.com/aws/aws-sdk-go/aws/service/serviceinfo"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
|
||||
"github.com/aws/aws-sdk-go/private/signer/v4"
|
||||
)
|
||||
@@ -16,40 +15,64 @@ import (
|
||||
// in the Amazon Web Services (AWS) cloud. Using Amazon EC2 eliminates your
|
||||
// need to invest in hardware up front, so you can develop and deploy applications
|
||||
// faster.
|
||||
//The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
type EC2 struct {
|
||||
*service.Service
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// Used for custom service initialization logic
|
||||
var initService func(*service.Service)
|
||||
// Used for custom client initialization logic
|
||||
var initClient func(*client.Client)
|
||||
|
||||
// Used for custom request initialization logic
|
||||
var initRequest func(*request.Request)
|
||||
|
||||
// New returns a new EC2 client.
|
||||
func New(config *aws.Config) *EC2 {
|
||||
service := &service.Service{
|
||||
ServiceInfo: serviceinfo.ServiceInfo{
|
||||
Config: defaults.DefaultConfig.Merge(config),
|
||||
ServiceName: "ec2",
|
||||
APIVersion: "2015-10-01",
|
||||
},
|
||||
// A ServiceName is the name of the service the client will make API calls to.
|
||||
const ServiceName = "ec2"
|
||||
|
||||
// New creates a new instance of the EC2 client with a session.
|
||||
// If additional configuration is needed for the client instance use the optional
|
||||
// aws.Config parameter to add your extra config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a EC2 client from just a session.
|
||||
// svc := ec2.New(mySession)
|
||||
//
|
||||
// // Create a EC2 client with additional configuration
|
||||
// svc := ec2.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2 {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// newClient creates, initializes and returns a new service client instance.
|
||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *EC2 {
|
||||
svc := &EC2{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
SigningRegion: signingRegion,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "2015-10-01",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
service.Initialize()
|
||||
|
||||
// Handlers
|
||||
service.Handlers.Sign.PushBack(v4.Sign)
|
||||
service.Handlers.Build.PushBack(ec2query.Build)
|
||||
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
svc.Handlers.Sign.PushBack(v4.Sign)
|
||||
svc.Handlers.Build.PushBack(ec2query.Build)
|
||||
svc.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
|
||||
svc.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
|
||||
svc.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
|
||||
|
||||
// Run custom service initialization if present
|
||||
if initService != nil {
|
||||
initService(service)
|
||||
// Run custom client initialization if present
|
||||
if initClient != nil {
|
||||
initClient(svc.Client)
|
||||
}
|
||||
|
||||
return &EC2{service}
|
||||
return svc
|
||||
}
|
||||
|
||||
// newRequest creates a new request for a EC2 operation and runs any
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user