functional_tests.go 213 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939
  1. // +build ignore
  2. /*
  3. * Minio Go Library for Amazon S3 Compatible Cloud Storage
  4. * Copyright 2015-2017 Minio, Inc.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package main
  19. import (
  20. "bytes"
  21. "context"
  22. "encoding/hex"
  23. "encoding/json"
  24. "errors"
  25. "fmt"
  26. "io"
  27. "io/ioutil"
  28. "math/rand"
  29. "mime/multipart"
  30. "net/http"
  31. "net/url"
  32. "os"
  33. "path/filepath"
  34. "reflect"
  35. "runtime"
  36. "strconv"
  37. "strings"
  38. "time"
  39. humanize "github.com/dustin/go-humanize"
  40. minio "github.com/minio/minio-go"
  41. log "github.com/sirupsen/logrus"
  42. "github.com/minio/minio-go/pkg/encrypt"
  43. "github.com/minio/minio-go/pkg/policy"
  44. )
  45. const letterBytes = "abcdefghijklmnopqrstuvwxyz01234569"
  46. const (
  47. letterIdxBits = 6 // 6 bits to represent a letter index
  48. letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
  49. letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
  50. )
  51. const (
  52. serverEndpoint = "SERVER_ENDPOINT"
  53. accessKey = "ACCESS_KEY"
  54. secretKey = "SECRET_KEY"
  55. enableHTTPS = "ENABLE_HTTPS"
  56. )
  57. type mintJSONFormatter struct {
  58. }
  59. func (f *mintJSONFormatter) Format(entry *log.Entry) ([]byte, error) {
  60. data := make(log.Fields, len(entry.Data))
  61. for k, v := range entry.Data {
  62. switch v := v.(type) {
  63. case error:
  64. // Otherwise errors are ignored by `encoding/json`
  65. // https://github.com/sirupsen/logrus/issues/137
  66. data[k] = v.Error()
  67. default:
  68. data[k] = v
  69. }
  70. }
  71. serialized, err := json.Marshal(data)
  72. if err != nil {
  73. return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
  74. }
  75. return append(serialized, '\n'), nil
  76. }
  77. func cleanEmptyEntries(fields log.Fields) log.Fields {
  78. cleanFields := log.Fields{}
  79. for k, v := range fields {
  80. if v != "" {
  81. cleanFields[k] = v
  82. }
  83. }
  84. return cleanFields
  85. }
  86. // log successful test runs
  87. func successLogger(testName string, function string, args map[string]interface{}, startTime time.Time) *log.Entry {
  88. // calculate the test case duration
  89. duration := time.Since(startTime)
  90. // log with the fields as per mint
  91. fields := log.Fields{"name": "minio-go: " + testName, "function": function, "args": args, "duration": duration.Nanoseconds() / 1000000, "status": "PASS"}
  92. return log.WithFields(cleanEmptyEntries(fields))
  93. }
  94. // As few of the features are not available in Gateway(s) currently, Check if err value is NotImplemented,
  95. // and log as NA in that case and continue execution. Otherwise log as failure and return
  96. func logError(testName string, function string, args map[string]interface{}, startTime time.Time, alert string, message string, err error) {
  97. // If server returns NotImplemented we assume it is gateway mode and hence log it as info and move on to next tests
  98. // Special case for ComposeObject API as it is implemented on client side and adds specific error details like `Error in upload-part-copy` in
  99. // addition to NotImplemented error returned from server
  100. if isErrNotImplemented(err) {
  101. ignoredLog(testName, function, args, startTime, message).Info()
  102. } else {
  103. failureLog(testName, function, args, startTime, alert, message, err).Fatal()
  104. }
  105. }
  106. // log failed test runs
  107. func failureLog(testName string, function string, args map[string]interface{}, startTime time.Time, alert string, message string, err error) *log.Entry {
  108. // calculate the test case duration
  109. duration := time.Since(startTime)
  110. var fields log.Fields
  111. // log with the fields as per mint
  112. if err != nil {
  113. fields = log.Fields{"name": "minio-go: " + testName, "function": function, "args": args,
  114. "duration": duration.Nanoseconds() / 1000000, "status": "FAIL", "alert": alert, "message": message, "error": err}
  115. } else {
  116. fields = log.Fields{"name": "minio-go: " + testName, "function": function, "args": args,
  117. "duration": duration.Nanoseconds() / 1000000, "status": "FAIL", "alert": alert, "message": message}
  118. }
  119. return log.WithFields(cleanEmptyEntries(fields))
  120. }
  121. // log not applicable test runs
  122. func ignoredLog(testName string, function string, args map[string]interface{}, startTime time.Time, alert string) *log.Entry {
  123. // calculate the test case duration
  124. duration := time.Since(startTime)
  125. // log with the fields as per mint
  126. fields := log.Fields{"name": "minio-go: " + testName, "function": function, "args": args,
  127. "duration": duration.Nanoseconds() / 1000000, "status": "NA", "alert": alert}
  128. return log.WithFields(cleanEmptyEntries(fields))
  129. }
  130. // Delete objects in given bucket, recursively
  131. func cleanupBucket(bucketName string, c *minio.Client) error {
  132. // Create a done channel to control 'ListObjectsV2' go routine.
  133. doneCh := make(chan struct{})
  134. // Exit cleanly upon return.
  135. defer close(doneCh)
  136. // Iterate over all objects in the bucket via listObjectsV2 and delete
  137. for objCh := range c.ListObjectsV2(bucketName, "", true, doneCh) {
  138. if objCh.Err != nil {
  139. return objCh.Err
  140. }
  141. if objCh.Key != "" {
  142. err := c.RemoveObject(bucketName, objCh.Key)
  143. if err != nil {
  144. return err
  145. }
  146. }
  147. }
  148. for objPartInfo := range c.ListIncompleteUploads(bucketName, "", true, doneCh) {
  149. if objPartInfo.Err != nil {
  150. return objPartInfo.Err
  151. }
  152. if objPartInfo.Key != "" {
  153. err := c.RemoveIncompleteUpload(bucketName, objPartInfo.Key)
  154. if err != nil {
  155. return err
  156. }
  157. }
  158. }
  159. // objects are already deleted, clear the buckets now
  160. err := c.RemoveBucket(bucketName)
  161. if err != nil {
  162. return err
  163. }
  164. return err
  165. }
  166. func isErrNotImplemented(err error) bool {
  167. return minio.ToErrorResponse(err).Code == "NotImplemented"
  168. }
  169. func init() {
  170. // If server endpoint is not set, all tests default to
  171. // using https://play.minio.io:9000
  172. if os.Getenv(serverEndpoint) == "" {
  173. os.Setenv(serverEndpoint, "play.minio.io:9000")
  174. os.Setenv(accessKey, "Q3AM3UQ867SPQQA43P2F")
  175. os.Setenv(secretKey, "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
  176. os.Setenv(enableHTTPS, "1")
  177. }
  178. }
  179. var mintDataDir = os.Getenv("MINT_DATA_DIR")
  180. func getMintDataDirFilePath(filename string) (fp string) {
  181. if mintDataDir == "" {
  182. return
  183. }
  184. return filepath.Join(mintDataDir, filename)
  185. }
  186. type sizedReader struct {
  187. io.Reader
  188. size int
  189. }
  190. func (l *sizedReader) Size() int {
  191. return l.size
  192. }
  193. func (l *sizedReader) Close() error {
  194. return nil
  195. }
  196. type randomReader struct{ seed []byte }
  197. func (r *randomReader) Read(b []byte) (int, error) {
  198. return copy(b, bytes.Repeat(r.seed, len(b))), nil
  199. }
  200. // read data from file if it exists or optionally create a buffer of particular size
  201. func getDataReader(fileName string) io.ReadCloser {
  202. if mintDataDir == "" {
  203. size := dataFileMap[fileName]
  204. return &sizedReader{
  205. Reader: io.LimitReader(&randomReader{
  206. seed: []byte("a"),
  207. }, int64(size)),
  208. size: size,
  209. }
  210. }
  211. reader, _ := os.Open(getMintDataDirFilePath(fileName))
  212. return reader
  213. }
  214. // randString generates random names and prepends them with a known prefix.
  215. func randString(n int, src rand.Source, prefix string) string {
  216. b := make([]byte, n)
  217. // A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
  218. for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
  219. if remain == 0 {
  220. cache, remain = src.Int63(), letterIdxMax
  221. }
  222. if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
  223. b[i] = letterBytes[idx]
  224. i--
  225. }
  226. cache >>= letterIdxBits
  227. remain--
  228. }
  229. return prefix + string(b[0:30-len(prefix)])
  230. }
  231. var dataFileMap = map[string]int{
  232. "datafile-1-b": 1,
  233. "datafile-10-kB": 10 * humanize.KiByte,
  234. "datafile-33-kB": 33 * humanize.KiByte,
  235. "datafile-100-kB": 100 * humanize.KiByte,
  236. "datafile-1.03-MB": 1056 * humanize.KiByte,
  237. "datafile-1-MB": 1 * humanize.MiByte,
  238. "datafile-5-MB": 5 * humanize.MiByte,
  239. "datafile-6-MB": 6 * humanize.MiByte,
  240. "datafile-11-MB": 11 * humanize.MiByte,
  241. "datafile-65-MB": 65 * humanize.MiByte,
  242. }
  243. func isQuickMode() bool {
  244. return os.Getenv("MODE") == "quick"
  245. }
  246. func getFuncName() string {
  247. pc, _, _, _ := runtime.Caller(1)
  248. return strings.TrimPrefix(runtime.FuncForPC(pc).Name(), "main.")
  249. }
  250. // Tests bucket re-create errors.
  251. func testMakeBucketError() {
  252. region := "eu-central-1"
  253. // initialize logging params
  254. startTime := time.Now()
  255. testName := getFuncName()
  256. function := "MakeBucket(bucketName, region)"
  257. // initialize logging params
  258. args := map[string]interface{}{
  259. "bucketName": "",
  260. "region": region,
  261. }
  262. // skipping region functional tests for non s3 runs
  263. if os.Getenv(serverEndpoint) != "s3.amazonaws.com" {
  264. ignoredLog(testName, function, args, startTime, "Skipped region functional tests for non s3 runs").Info()
  265. return
  266. }
  267. // Seed random based on current time.
  268. rand.Seed(time.Now().Unix())
  269. // Instantiate new minio client object.
  270. c, err := minio.New(
  271. os.Getenv(serverEndpoint),
  272. os.Getenv(accessKey),
  273. os.Getenv(secretKey),
  274. mustParseBool(os.Getenv(enableHTTPS)),
  275. )
  276. if err != nil {
  277. logError(testName, function, args, startTime, "", "Minio client creation failed", err)
  278. return
  279. }
  280. // Enable tracing, write to stderr.
  281. // c.TraceOn(os.Stderr)
  282. // Set user agent.
  283. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  284. // Generate a new random bucket name.
  285. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  286. args["bucketName"] = bucketName
  287. // Make a new bucket in 'eu-central-1'.
  288. if err = c.MakeBucket(bucketName, region); err != nil {
  289. logError(testName, function, args, startTime, "", "MakeBucket Failed", err)
  290. return
  291. }
  292. if err = c.MakeBucket(bucketName, region); err == nil {
  293. logError(testName, function, args, startTime, "", "Bucket already exists", err)
  294. return
  295. }
  296. // Verify valid error response from server.
  297. if minio.ToErrorResponse(err).Code != "BucketAlreadyExists" &&
  298. minio.ToErrorResponse(err).Code != "BucketAlreadyOwnedByYou" {
  299. logError(testName, function, args, startTime, "", "Invalid error returned by server", err)
  300. return
  301. }
  302. // Delete all objects and buckets
  303. if err = cleanupBucket(bucketName, c); err != nil {
  304. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  305. return
  306. }
  307. successLogger(testName, function, args, startTime).Info()
  308. }
  309. func testMetadataSizeLimit() {
  310. startTime := time.Now()
  311. testName := getFuncName()
  312. function := "PutObject(bucketName, objectName, reader, objectSize, opts)"
  313. args := map[string]interface{}{
  314. "bucketName": "",
  315. "objectName": "",
  316. "opts.UserMetadata": "",
  317. }
  318. rand.Seed(startTime.Unix())
  319. // Instantiate new minio client object.
  320. c, err := minio.New(
  321. os.Getenv(serverEndpoint),
  322. os.Getenv(accessKey),
  323. os.Getenv(secretKey),
  324. mustParseBool(os.Getenv(enableHTTPS)),
  325. )
  326. if err != nil {
  327. logError(testName, function, args, startTime, "", "Minio client creation failed", err)
  328. return
  329. }
  330. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  331. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  332. args["bucketName"] = bucketName
  333. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  334. args["objectName"] = objectName
  335. err = c.MakeBucket(bucketName, "us-east-1")
  336. if err != nil {
  337. logError(testName, function, args, startTime, "", "Make bucket failed", err)
  338. return
  339. }
  340. const HeaderSizeLimit = 8 * 1024
  341. const UserMetadataLimit = 2 * 1024
  342. // Meta-data greater than the 2 KB limit of AWS - PUT calls with this meta-data should fail
  343. metadata := make(map[string]string)
  344. metadata["X-Amz-Meta-Mint-Test"] = string(bytes.Repeat([]byte("m"), 1+UserMetadataLimit-len("X-Amz-Meta-Mint-Test")))
  345. args["metadata"] = fmt.Sprint(metadata)
  346. _, err = c.PutObject(bucketName, objectName, bytes.NewReader(nil), 0, minio.PutObjectOptions{UserMetadata: metadata})
  347. if err == nil {
  348. logError(testName, function, args, startTime, "", "Created object with user-defined metadata exceeding metadata size limits", nil)
  349. return
  350. }
  351. // Meta-data (headers) greater than the 8 KB limit of AWS - PUT calls with this meta-data should fail
  352. metadata = make(map[string]string)
  353. metadata["X-Amz-Mint-Test"] = string(bytes.Repeat([]byte("m"), 1+HeaderSizeLimit-len("X-Amz-Mint-Test")))
  354. args["metadata"] = fmt.Sprint(metadata)
  355. _, err = c.PutObject(bucketName, objectName, bytes.NewReader(nil), 0, minio.PutObjectOptions{UserMetadata: metadata})
  356. if err == nil {
  357. logError(testName, function, args, startTime, "", "Created object with headers exceeding header size limits", nil)
  358. return
  359. }
  360. // Delete all objects and buckets
  361. if err = cleanupBucket(bucketName, c); err != nil {
  362. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  363. return
  364. }
  365. successLogger(testName, function, args, startTime).Info()
  366. }
  367. // Tests various bucket supported formats.
  368. func testMakeBucketRegions() {
  369. region := "eu-central-1"
  370. // initialize logging params
  371. startTime := time.Now()
  372. testName := getFuncName()
  373. function := "MakeBucket(bucketName, region)"
  374. // initialize logging params
  375. args := map[string]interface{}{
  376. "bucketName": "",
  377. "region": region,
  378. }
  379. // skipping region functional tests for non s3 runs
  380. if os.Getenv(serverEndpoint) != "s3.amazonaws.com" {
  381. ignoredLog(testName, function, args, startTime, "Skipped region functional tests for non s3 runs").Info()
  382. return
  383. }
  384. // Seed random based on current time.
  385. rand.Seed(time.Now().Unix())
  386. // Instantiate new minio client object.
  387. c, err := minio.New(
  388. os.Getenv(serverEndpoint),
  389. os.Getenv(accessKey),
  390. os.Getenv(secretKey),
  391. mustParseBool(os.Getenv(enableHTTPS)),
  392. )
  393. if err != nil {
  394. logError(testName, function, args, startTime, "", "Minio client creation failed", err)
  395. return
  396. }
  397. // Enable tracing, write to stderr.
  398. // c.TraceOn(os.Stderr)
  399. // Set user agent.
  400. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  401. // Generate a new random bucket name.
  402. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  403. args["bucketName"] = bucketName
  404. // Make a new bucket in 'eu-central-1'.
  405. if err = c.MakeBucket(bucketName, region); err != nil {
  406. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  407. return
  408. }
  409. // Delete all objects and buckets
  410. if err = cleanupBucket(bucketName, c); err != nil {
  411. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  412. return
  413. }
  414. // Make a new bucket with '.' in its name, in 'us-west-2'. This
  415. // request is internally staged into a path style instead of
  416. // virtual host style.
  417. region = "us-west-2"
  418. args["region"] = region
  419. if err = c.MakeBucket(bucketName+".withperiod", region); err != nil {
  420. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  421. return
  422. }
  423. // Delete all objects and buckets
  424. if err = cleanupBucket(bucketName+".withperiod", c); err != nil {
  425. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  426. return
  427. }
  428. successLogger(testName, function, args, startTime).Info()
  429. }
  430. // Test PutObject using a large data to trigger multipart readat
  431. func testPutObjectReadAt() {
  432. // initialize logging params
  433. startTime := time.Now()
  434. testName := getFuncName()
  435. function := "PutObject(bucketName, objectName, reader, opts)"
  436. args := map[string]interface{}{
  437. "bucketName": "",
  438. "objectName": "",
  439. "opts": "objectContentType",
  440. }
  441. // Seed random based on current time.
  442. rand.Seed(time.Now().Unix())
  443. // Instantiate new minio client object.
  444. c, err := minio.New(
  445. os.Getenv(serverEndpoint),
  446. os.Getenv(accessKey),
  447. os.Getenv(secretKey),
  448. mustParseBool(os.Getenv(enableHTTPS)),
  449. )
  450. if err != nil {
  451. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  452. return
  453. }
  454. // Enable tracing, write to stderr.
  455. // c.TraceOn(os.Stderr)
  456. // Set user agent.
  457. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  458. // Generate a new random bucket name.
  459. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  460. args["bucketName"] = bucketName
  461. // Make a new bucket.
  462. err = c.MakeBucket(bucketName, "us-east-1")
  463. if err != nil {
  464. logError(testName, function, args, startTime, "", "Make bucket failed", err)
  465. return
  466. }
  467. bufSize := dataFileMap["datafile-65-MB"]
  468. var reader = getDataReader("datafile-65-MB")
  469. defer reader.Close()
  470. // Save the data
  471. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  472. args["objectName"] = objectName
  473. // Object content type
  474. objectContentType := "binary/octet-stream"
  475. args["objectContentType"] = objectContentType
  476. n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: objectContentType})
  477. if err != nil {
  478. logError(testName, function, args, startTime, "", "PutObject failed", err)
  479. return
  480. }
  481. if n != int64(bufSize) {
  482. logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
  483. return
  484. }
  485. // Read the data back
  486. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  487. if err != nil {
  488. logError(testName, function, args, startTime, "", "Get Object failed", err)
  489. return
  490. }
  491. st, err := r.Stat()
  492. if err != nil {
  493. logError(testName, function, args, startTime, "", "Stat Object failed", err)
  494. return
  495. }
  496. if st.Size != int64(bufSize) {
  497. logError(testName, function, args, startTime, "", fmt.Sprintf("Number of bytes in stat does not match, expected %d got %d", bufSize, st.Size), err)
  498. return
  499. }
  500. if st.ContentType != objectContentType {
  501. logError(testName, function, args, startTime, "", "Content types don't match", err)
  502. return
  503. }
  504. if err := r.Close(); err != nil {
  505. logError(testName, function, args, startTime, "", "Object Close failed", err)
  506. return
  507. }
  508. if err := r.Close(); err == nil {
  509. logError(testName, function, args, startTime, "", "Object is already closed, didn't return error on Close", err)
  510. return
  511. }
  512. // Delete all objects and buckets
  513. if err = cleanupBucket(bucketName, c); err != nil {
  514. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  515. return
  516. }
  517. successLogger(testName, function, args, startTime).Info()
  518. }
  519. // Test PutObject using a large data to trigger multipart readat
  520. func testPutObjectWithMetadata() {
  521. // initialize logging params
  522. startTime := time.Now()
  523. testName := getFuncName()
  524. function := "PutObject(bucketName, objectName, reader,size, opts)"
  525. args := map[string]interface{}{
  526. "bucketName": "",
  527. "objectName": "",
  528. "opts": "minio.PutObjectOptions{UserMetadata: metadata, Progress: progress}",
  529. }
  530. if isQuickMode() {
  531. ignoredLog(testName, function, args, startTime, "Skipping functional tests for short runs").Info()
  532. return
  533. }
  534. // Seed random based on current time.
  535. rand.Seed(time.Now().Unix())
  536. // Instantiate new minio client object.
  537. c, err := minio.New(
  538. os.Getenv(serverEndpoint),
  539. os.Getenv(accessKey),
  540. os.Getenv(secretKey),
  541. mustParseBool(os.Getenv(enableHTTPS)),
  542. )
  543. if err != nil {
  544. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  545. return
  546. }
  547. // Enable tracing, write to stderr.
  548. // c.TraceOn(os.Stderr)
  549. // Set user agent.
  550. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  551. // Generate a new random bucket name.
  552. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  553. args["bucketName"] = bucketName
  554. // Make a new bucket.
  555. err = c.MakeBucket(bucketName, "us-east-1")
  556. if err != nil {
  557. logError(testName, function, args, startTime, "", "Make bucket failed", err)
  558. return
  559. }
  560. bufSize := dataFileMap["datafile-65-MB"]
  561. var reader = getDataReader("datafile-65-MB")
  562. defer reader.Close()
  563. // Save the data
  564. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  565. args["objectName"] = objectName
  566. // Object custom metadata
  567. customContentType := "custom/contenttype"
  568. args["metadata"] = map[string][]string{
  569. "Content-Type": {customContentType},
  570. }
  571. n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{
  572. ContentType: customContentType})
  573. if err != nil {
  574. logError(testName, function, args, startTime, "", "PutObject failed", err)
  575. return
  576. }
  577. if n != int64(bufSize) {
  578. logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match, expected "+string(bufSize)+" got "+string(n), err)
  579. return
  580. }
  581. // Read the data back
  582. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  583. if err != nil {
  584. logError(testName, function, args, startTime, "", "GetObject failed", err)
  585. return
  586. }
  587. st, err := r.Stat()
  588. if err != nil {
  589. logError(testName, function, args, startTime, "", "Stat failed", err)
  590. return
  591. }
  592. if st.Size != int64(bufSize) {
  593. logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
  594. return
  595. }
  596. if st.ContentType != customContentType {
  597. logError(testName, function, args, startTime, "", "ContentType does not match, expected "+customContentType+" got "+st.ContentType, err)
  598. return
  599. }
  600. if err := r.Close(); err != nil {
  601. logError(testName, function, args, startTime, "", "Object Close failed", err)
  602. return
  603. }
  604. if err := r.Close(); err == nil {
  605. logError(testName, function, args, startTime, "", "Object already closed, should respond with error", err)
  606. return
  607. }
  608. // Delete all objects and buckets
  609. if err = cleanupBucket(bucketName, c); err != nil {
  610. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  611. return
  612. }
  613. successLogger(testName, function, args, startTime).Info()
  614. }
  615. // Test put object with streaming signature.
  616. func testPutObjectStreaming() {
  617. // initialize logging params
  618. objectName := "test-object"
  619. startTime := time.Now()
  620. testName := getFuncName()
  621. function := "PutObject(bucketName, objectName, reader,size,opts)"
  622. args := map[string]interface{}{
  623. "bucketName": "",
  624. "objectName": objectName,
  625. "size": -1,
  626. "opts": "",
  627. }
  628. // Seed random based on current time.
  629. rand.Seed(time.Now().Unix())
  630. // Instantiate new minio client object.
  631. c, err := minio.NewV4(
  632. os.Getenv(serverEndpoint),
  633. os.Getenv(accessKey),
  634. os.Getenv(secretKey),
  635. mustParseBool(os.Getenv(enableHTTPS)),
  636. )
  637. if err != nil {
  638. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  639. return
  640. }
  641. // Enable tracing, write to stderr.
  642. // c.TraceOn(os.Stderr)
  643. // Set user agent.
  644. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  645. // Generate a new random bucket name.
  646. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  647. args["bucketName"] = bucketName
  648. // Make a new bucket.
  649. err = c.MakeBucket(bucketName, "us-east-1")
  650. if err != nil {
  651. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  652. return
  653. }
  654. // Upload an object.
  655. sizes := []int64{0, 64*1024 - 1, 64 * 1024}
  656. for _, size := range sizes {
  657. data := bytes.Repeat([]byte("a"), int(size))
  658. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(data), int64(size), minio.PutObjectOptions{})
  659. if err != nil {
  660. logError(testName, function, args, startTime, "", "PutObjectStreaming failed", err)
  661. return
  662. }
  663. if n != size {
  664. logError(testName, function, args, startTime, "", "Expected upload object size doesn't match with PutObjectStreaming return value", err)
  665. return
  666. }
  667. }
  668. // Delete all objects and buckets
  669. if err = cleanupBucket(bucketName, c); err != nil {
  670. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  671. return
  672. }
  673. successLogger(testName, function, args, startTime).Info()
  674. }
  675. // Test listing partially uploaded objects.
  676. func testListPartiallyUploaded() {
  677. // initialize logging params
  678. startTime := time.Now()
  679. testName := getFuncName()
  680. function := "ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh)"
  681. args := map[string]interface{}{
  682. "bucketName": "",
  683. "objectName": "",
  684. "isRecursive": "",
  685. }
  686. // Seed random based on current time.
  687. rand.Seed(time.Now().Unix())
  688. // Instantiate new minio client object.
  689. c, err := minio.New(
  690. os.Getenv(serverEndpoint),
  691. os.Getenv(accessKey),
  692. os.Getenv(secretKey),
  693. mustParseBool(os.Getenv(enableHTTPS)),
  694. )
  695. if err != nil {
  696. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  697. return
  698. }
  699. // Set user agent.
  700. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  701. // Enable tracing, write to stdout.
  702. // c.TraceOn(os.Stderr)
  703. // Generate a new random bucket name.
  704. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  705. args["bucketName"] = bucketName
  706. // Make a new bucket.
  707. err = c.MakeBucket(bucketName, "us-east-1")
  708. if err != nil {
  709. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  710. return
  711. }
  712. bufSize := dataFileMap["datafile-65-MB"]
  713. r := bytes.NewReader(bytes.Repeat([]byte("0"), bufSize*2))
  714. reader, writer := io.Pipe()
  715. go func() {
  716. i := 0
  717. for i < 25 {
  718. _, cerr := io.CopyN(writer, r, (int64(bufSize)*2)/25)
  719. if cerr != nil {
  720. logError(testName, function, args, startTime, "", "Copy failed", err)
  721. return
  722. }
  723. i++
  724. r.Seek(0, 0)
  725. }
  726. writer.CloseWithError(errors.New("proactively closed to be verified later"))
  727. }()
  728. objectName := bucketName + "-resumable"
  729. args["objectName"] = objectName
  730. _, err = c.PutObject(bucketName, objectName, reader, int64(bufSize*2), minio.PutObjectOptions{ContentType: "application/octet-stream"})
  731. if err == nil {
  732. logError(testName, function, args, startTime, "", "PutObject should fail", err)
  733. return
  734. }
  735. if !strings.Contains(err.Error(), "proactively closed to be verified later") {
  736. logError(testName, function, args, startTime, "", "String not found in PutObject output", err)
  737. return
  738. }
  739. doneCh := make(chan struct{})
  740. defer close(doneCh)
  741. isRecursive := true
  742. args["isRecursive"] = isRecursive
  743. multiPartObjectCh := c.ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh)
  744. for multiPartObject := range multiPartObjectCh {
  745. if multiPartObject.Err != nil {
  746. logError(testName, function, args, startTime, "", "Multipart object error", multiPartObject.Err)
  747. return
  748. }
  749. }
  750. // Delete all objects and buckets
  751. if err = cleanupBucket(bucketName, c); err != nil {
  752. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  753. return
  754. }
  755. successLogger(testName, function, args, startTime).Info()
  756. }
  757. // Test get object seeker from the end, using whence set to '2'.
  758. func testGetObjectSeekEnd() {
  759. // initialize logging params
  760. startTime := time.Now()
  761. testName := getFuncName()
  762. function := "GetObject(bucketName, objectName)"
  763. args := map[string]interface{}{}
  764. // Seed random based on current time.
  765. rand.Seed(time.Now().Unix())
  766. // Instantiate new minio client object.
  767. c, err := minio.New(
  768. os.Getenv(serverEndpoint),
  769. os.Getenv(accessKey),
  770. os.Getenv(secretKey),
  771. mustParseBool(os.Getenv(enableHTTPS)),
  772. )
  773. if err != nil {
  774. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  775. return
  776. }
  777. // Enable tracing, write to stderr.
  778. // c.TraceOn(os.Stderr)
  779. // Set user agent.
  780. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  781. // Generate a new random bucket name.
  782. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  783. args["bucketName"] = bucketName
  784. // Make a new bucket.
  785. err = c.MakeBucket(bucketName, "us-east-1")
  786. if err != nil {
  787. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  788. return
  789. }
  790. // Generate 33K of data.
  791. bufSize := dataFileMap["datafile-33-kB"]
  792. var reader = getDataReader("datafile-33-kB")
  793. defer reader.Close()
  794. // Save the data
  795. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  796. args["objectName"] = objectName
  797. buf, err := ioutil.ReadAll(reader)
  798. if err != nil {
  799. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  800. return
  801. }
  802. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  803. if err != nil {
  804. logError(testName, function, args, startTime, "", "PutObject failed", err)
  805. return
  806. }
  807. if n != int64(bufSize) {
  808. logError(testName, function, args, startTime, "", "Number of bytes read does not match, expected "+string(int64(bufSize))+" got "+string(n), err)
  809. return
  810. }
  811. // Read the data back
  812. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  813. if err != nil {
  814. logError(testName, function, args, startTime, "", "GetObject failed", err)
  815. return
  816. }
  817. st, err := r.Stat()
  818. if err != nil {
  819. logError(testName, function, args, startTime, "", "Stat failed", err)
  820. return
  821. }
  822. if st.Size != int64(bufSize) {
  823. logError(testName, function, args, startTime, "", "Number of bytes read does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
  824. return
  825. }
  826. pos, err := r.Seek(-100, 2)
  827. if err != nil {
  828. logError(testName, function, args, startTime, "", "Object Seek failed", err)
  829. return
  830. }
  831. if pos != st.Size-100 {
  832. logError(testName, function, args, startTime, "", "Incorrect position", err)
  833. return
  834. }
  835. buf2 := make([]byte, 100)
  836. m, err := io.ReadFull(r, buf2)
  837. if err != nil {
  838. logError(testName, function, args, startTime, "", "Error reading through io.ReadFull", err)
  839. return
  840. }
  841. if m != len(buf2) {
  842. logError(testName, function, args, startTime, "", "Number of bytes dont match, expected "+string(len(buf2))+" got "+string(m), err)
  843. return
  844. }
  845. hexBuf1 := fmt.Sprintf("%02x", buf[len(buf)-100:])
  846. hexBuf2 := fmt.Sprintf("%02x", buf2[:m])
  847. if hexBuf1 != hexBuf2 {
  848. logError(testName, function, args, startTime, "", "Values at same index dont match", err)
  849. return
  850. }
  851. pos, err = r.Seek(-100, 2)
  852. if err != nil {
  853. logError(testName, function, args, startTime, "", "Object Seek failed", err)
  854. return
  855. }
  856. if pos != st.Size-100 {
  857. logError(testName, function, args, startTime, "", "Incorrect position", err)
  858. return
  859. }
  860. if err = r.Close(); err != nil {
  861. logError(testName, function, args, startTime, "", "ObjectClose failed", err)
  862. return
  863. }
  864. // Delete all objects and buckets
  865. if err = cleanupBucket(bucketName, c); err != nil {
  866. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  867. return
  868. }
  869. successLogger(testName, function, args, startTime).Info()
  870. }
  871. // Test get object reader to not throw error on being closed twice.
  872. func testGetObjectClosedTwice() {
  873. // initialize logging params
  874. startTime := time.Now()
  875. testName := getFuncName()
  876. function := "GetObject(bucketName, objectName)"
  877. args := map[string]interface{}{}
  878. // Seed random based on current time.
  879. rand.Seed(time.Now().Unix())
  880. // Instantiate new minio client object.
  881. c, err := minio.New(
  882. os.Getenv(serverEndpoint),
  883. os.Getenv(accessKey),
  884. os.Getenv(secretKey),
  885. mustParseBool(os.Getenv(enableHTTPS)),
  886. )
  887. if err != nil {
  888. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  889. return
  890. }
  891. // Enable tracing, write to stderr.
  892. // c.TraceOn(os.Stderr)
  893. // Set user agent.
  894. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  895. // Generate a new random bucket name.
  896. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  897. args["bucketName"] = bucketName
  898. // Make a new bucket.
  899. err = c.MakeBucket(bucketName, "us-east-1")
  900. if err != nil {
  901. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  902. return
  903. }
  904. // Generate 33K of data.
  905. bufSize := dataFileMap["datafile-33-kB"]
  906. var reader = getDataReader("datafile-33-kB")
  907. defer reader.Close()
  908. // Save the data
  909. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  910. args["objectName"] = objectName
  911. n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  912. if err != nil {
  913. logError(testName, function, args, startTime, "", "PutObject failed", err)
  914. return
  915. }
  916. if n != int64(bufSize) {
  917. logError(testName, function, args, startTime, "", "PutObject response doesn't match sent bytes, expected "+string(int64(bufSize))+" got "+string(n), err)
  918. return
  919. }
  920. // Read the data back
  921. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  922. if err != nil {
  923. logError(testName, function, args, startTime, "", "GetObject failed", err)
  924. return
  925. }
  926. st, err := r.Stat()
  927. if err != nil {
  928. logError(testName, function, args, startTime, "", "Stat failed", err)
  929. return
  930. }
  931. if st.Size != int64(bufSize) {
  932. logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
  933. return
  934. }
  935. if err := r.Close(); err != nil {
  936. logError(testName, function, args, startTime, "", "Object Close failed", err)
  937. return
  938. }
  939. if err := r.Close(); err == nil {
  940. logError(testName, function, args, startTime, "", "Already closed object. No error returned", err)
  941. return
  942. }
  943. // Delete all objects and buckets
  944. if err = cleanupBucket(bucketName, c); err != nil {
  945. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  946. return
  947. }
  948. successLogger(testName, function, args, startTime).Info()
  949. }
  950. // Test removing multiple objects with Remove API
  951. func testRemoveMultipleObjects() {
  952. // initialize logging params
  953. startTime := time.Now()
  954. testName := getFuncName()
  955. function := "RemoveObjects(bucketName, objectsCh)"
  956. args := map[string]interface{}{
  957. "bucketName": "",
  958. }
  959. // Seed random based on current time.
  960. rand.Seed(time.Now().Unix())
  961. // Instantiate new minio client object.
  962. c, err := minio.New(
  963. os.Getenv(serverEndpoint),
  964. os.Getenv(accessKey),
  965. os.Getenv(secretKey),
  966. mustParseBool(os.Getenv(enableHTTPS)),
  967. )
  968. if err != nil {
  969. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  970. return
  971. }
  972. // Set user agent.
  973. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  974. // Enable tracing, write to stdout.
  975. // c.TraceOn(os.Stderr)
  976. // Generate a new random bucket name.
  977. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  978. args["bucketName"] = bucketName
  979. // Make a new bucket.
  980. err = c.MakeBucket(bucketName, "us-east-1")
  981. if err != nil {
  982. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  983. return
  984. }
  985. r := bytes.NewReader(bytes.Repeat([]byte("a"), 8))
  986. // Multi remove of 1100 objects
  987. nrObjects := 200
  988. objectsCh := make(chan string)
  989. go func() {
  990. defer close(objectsCh)
  991. // Upload objects and send them to objectsCh
  992. for i := 0; i < nrObjects; i++ {
  993. objectName := "sample" + strconv.Itoa(i) + ".txt"
  994. _, err = c.PutObject(bucketName, objectName, r, 8, minio.PutObjectOptions{ContentType: "application/octet-stream"})
  995. if err != nil {
  996. logError(testName, function, args, startTime, "", "PutObject failed", err)
  997. continue
  998. }
  999. objectsCh <- objectName
  1000. }
  1001. }()
  1002. // Call RemoveObjects API
  1003. errorCh := c.RemoveObjects(bucketName, objectsCh)
  1004. // Check if errorCh doesn't receive any error
  1005. select {
  1006. case r, more := <-errorCh:
  1007. if more {
  1008. logError(testName, function, args, startTime, "", "Unexpected error", r.Err)
  1009. return
  1010. }
  1011. }
  1012. // Delete all objects and buckets
  1013. if err = cleanupBucket(bucketName, c); err != nil {
  1014. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1015. return
  1016. }
  1017. successLogger(testName, function, args, startTime).Info()
  1018. }
  1019. // Tests removing partially uploaded objects.
  1020. func testRemovePartiallyUploaded() {
  1021. // initialize logging params
  1022. startTime := time.Now()
  1023. testName := getFuncName()
  1024. function := "RemoveIncompleteUpload(bucketName, objectName)"
  1025. args := map[string]interface{}{}
  1026. // Seed random based on current time.
  1027. rand.Seed(time.Now().Unix())
  1028. // Instantiate new minio client object.
  1029. c, err := minio.New(
  1030. os.Getenv(serverEndpoint),
  1031. os.Getenv(accessKey),
  1032. os.Getenv(secretKey),
  1033. mustParseBool(os.Getenv(enableHTTPS)),
  1034. )
  1035. if err != nil {
  1036. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1037. return
  1038. }
  1039. // Set user agent.
  1040. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1041. // Enable tracing, write to stdout.
  1042. // c.TraceOn(os.Stderr)
  1043. // Generate a new random bucket name.
  1044. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1045. args["bucketName"] = bucketName
  1046. // Make a new bucket.
  1047. err = c.MakeBucket(bucketName, "us-east-1")
  1048. if err != nil {
  1049. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1050. return
  1051. }
  1052. r := bytes.NewReader(bytes.Repeat([]byte("a"), 128*1024))
  1053. reader, writer := io.Pipe()
  1054. go func() {
  1055. i := 0
  1056. for i < 25 {
  1057. _, cerr := io.CopyN(writer, r, 128*1024)
  1058. if cerr != nil {
  1059. logError(testName, function, args, startTime, "", "Copy failed", err)
  1060. return
  1061. }
  1062. i++
  1063. r.Seek(0, 0)
  1064. }
  1065. writer.CloseWithError(errors.New("proactively closed to be verified later"))
  1066. }()
  1067. objectName := bucketName + "-resumable"
  1068. args["objectName"] = objectName
  1069. _, err = c.PutObject(bucketName, objectName, reader, 128*1024, minio.PutObjectOptions{ContentType: "application/octet-stream"})
  1070. if err == nil {
  1071. logError(testName, function, args, startTime, "", "PutObject should fail", err)
  1072. return
  1073. }
  1074. if !strings.Contains(err.Error(), "proactively closed to be verified later") {
  1075. logError(testName, function, args, startTime, "", "String not found", err)
  1076. return
  1077. }
  1078. err = c.RemoveIncompleteUpload(bucketName, objectName)
  1079. if err != nil {
  1080. logError(testName, function, args, startTime, "", "RemoveIncompleteUpload failed", err)
  1081. return
  1082. }
  1083. // Delete all objects and buckets
  1084. if err = cleanupBucket(bucketName, c); err != nil {
  1085. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1086. return
  1087. }
  1088. successLogger(testName, function, args, startTime).Info()
  1089. }
  1090. // Tests FPutObject of a big file to trigger multipart
  1091. func testFPutObjectMultipart() {
  1092. // initialize logging params
  1093. startTime := time.Now()
  1094. testName := getFuncName()
  1095. function := "FPutObject(bucketName, objectName, fileName, opts)"
  1096. args := map[string]interface{}{
  1097. "bucketName": "",
  1098. "objectName": "",
  1099. "fileName": "",
  1100. "opts": "",
  1101. }
  1102. // Seed random based on current time.
  1103. rand.Seed(time.Now().Unix())
  1104. // Instantiate new minio client object.
  1105. c, err := minio.New(
  1106. os.Getenv(serverEndpoint),
  1107. os.Getenv(accessKey),
  1108. os.Getenv(secretKey),
  1109. mustParseBool(os.Getenv(enableHTTPS)),
  1110. )
  1111. if err != nil {
  1112. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1113. return
  1114. }
  1115. // Enable tracing, write to stderr.
  1116. // c.TraceOn(os.Stderr)
  1117. // Set user agent.
  1118. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1119. // Generate a new random bucket name.
  1120. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1121. args["bucketName"] = bucketName
  1122. // Make a new bucket.
  1123. err = c.MakeBucket(bucketName, "us-east-1")
  1124. if err != nil {
  1125. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1126. return
  1127. }
  1128. // Upload 4 parts to utilize all 3 'workers' in multipart and still have a part to upload.
  1129. var fileName = getMintDataDirFilePath("datafile-65-MB")
  1130. if fileName == "" {
  1131. // Make a temp file with minPartSize bytes of data.
  1132. file, err := ioutil.TempFile(os.TempDir(), "FPutObjectTest")
  1133. if err != nil {
  1134. logError(testName, function, args, startTime, "", "TempFile creation failed", err)
  1135. return
  1136. }
  1137. // Upload 2 parts to utilize all 3 'workers' in multipart and still have a part to upload.
  1138. if _, err = io.Copy(file, getDataReader("datafile-65-MB")); err != nil {
  1139. logError(testName, function, args, startTime, "", "Copy failed", err)
  1140. return
  1141. }
  1142. if err = file.Close(); err != nil {
  1143. logError(testName, function, args, startTime, "", "File Close failed", err)
  1144. return
  1145. }
  1146. fileName = file.Name()
  1147. args["fileName"] = fileName
  1148. }
  1149. totalSize := dataFileMap["datafile-65-MB"]
  1150. // Set base object name
  1151. objectName := bucketName + "FPutObject" + "-standard"
  1152. args["objectName"] = objectName
  1153. objectContentType := "testapplication/octet-stream"
  1154. args["objectContentType"] = objectContentType
  1155. // Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
  1156. n, err := c.FPutObject(bucketName, objectName, fileName, minio.PutObjectOptions{ContentType: objectContentType})
  1157. if err != nil {
  1158. logError(testName, function, args, startTime, "", "FPutObject failed", err)
  1159. return
  1160. }
  1161. if n != int64(totalSize) {
  1162. logError(testName, function, args, startTime, "", "FPutObject failed", err)
  1163. return
  1164. }
  1165. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  1166. if err != nil {
  1167. logError(testName, function, args, startTime, "", "GetObject failed", err)
  1168. return
  1169. }
  1170. objInfo, err := r.Stat()
  1171. if err != nil {
  1172. logError(testName, function, args, startTime, "", "Unexpected error", err)
  1173. return
  1174. }
  1175. if objInfo.Size != int64(totalSize) {
  1176. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(totalSize))+" got "+string(objInfo.Size), err)
  1177. return
  1178. }
  1179. if objInfo.ContentType != objectContentType {
  1180. logError(testName, function, args, startTime, "", "ContentType doesn't match", err)
  1181. return
  1182. }
  1183. // Delete all objects and buckets
  1184. if err = cleanupBucket(bucketName, c); err != nil {
  1185. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1186. return
  1187. }
  1188. successLogger(testName, function, args, startTime).Info()
  1189. }
  1190. // Tests FPutObject with null contentType (default = application/octet-stream)
  1191. func testFPutObject() {
  1192. // initialize logging params
  1193. startTime := time.Now()
  1194. testName := getFuncName()
  1195. function := "FPutObject(bucketName, objectName, fileName, opts)"
  1196. args := map[string]interface{}{
  1197. "bucketName": "",
  1198. "objectName": "",
  1199. "fileName": "",
  1200. "opts": "",
  1201. }
  1202. // Seed random based on current time.
  1203. rand.Seed(time.Now().Unix())
  1204. // Instantiate new minio client object.
  1205. c, err := minio.New(
  1206. os.Getenv(serverEndpoint),
  1207. os.Getenv(accessKey),
  1208. os.Getenv(secretKey),
  1209. mustParseBool(os.Getenv(enableHTTPS)),
  1210. )
  1211. if err != nil {
  1212. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1213. return
  1214. }
  1215. // Enable tracing, write to stderr.
  1216. // c.TraceOn(os.Stderr)
  1217. // Set user agent.
  1218. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1219. // Generate a new random bucket name.
  1220. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1221. location := "us-east-1"
  1222. // Make a new bucket.
  1223. args["bucketName"] = bucketName
  1224. args["location"] = location
  1225. function = "MakeBucket()bucketName, location"
  1226. err = c.MakeBucket(bucketName, location)
  1227. if err != nil {
  1228. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1229. return
  1230. }
  1231. // Upload 3 parts worth of data to use all 3 of multiparts 'workers' and have an extra part.
  1232. // Use different data in part for multipart tests to check parts are uploaded in correct order.
  1233. var fName = getMintDataDirFilePath("datafile-65-MB")
  1234. if fName == "" {
  1235. // Make a temp file with minPartSize bytes of data.
  1236. file, err := ioutil.TempFile(os.TempDir(), "FPutObjectTest")
  1237. if err != nil {
  1238. logError(testName, function, args, startTime, "", "TempFile creation failed", err)
  1239. return
  1240. }
  1241. // Upload 3 parts to utilize all 3 'workers' in multipart and still have a part to upload.
  1242. if _, err = io.Copy(file, getDataReader("datafile-65-MB")); err != nil {
  1243. logError(testName, function, args, startTime, "", "File copy failed", err)
  1244. return
  1245. }
  1246. // Close the file pro-actively for windows.
  1247. if err = file.Close(); err != nil {
  1248. logError(testName, function, args, startTime, "", "File close failed", err)
  1249. return
  1250. }
  1251. defer os.Remove(file.Name())
  1252. fName = file.Name()
  1253. }
  1254. totalSize := dataFileMap["datafile-65-MB"]
  1255. // Set base object name
  1256. function = "FPutObject(bucketName, objectName, fileName, opts)"
  1257. objectName := bucketName + "FPutObject"
  1258. args["objectName"] = objectName + "-standard"
  1259. args["fileName"] = fName
  1260. args["opts"] = minio.PutObjectOptions{ContentType: "application/octet-stream"}
  1261. // Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
  1262. n, err := c.FPutObject(bucketName, objectName+"-standard", fName, minio.PutObjectOptions{ContentType: "application/octet-stream"})
  1263. if err != nil {
  1264. logError(testName, function, args, startTime, "", "FPutObject failed", err)
  1265. return
  1266. }
  1267. if n != int64(totalSize) {
  1268. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(totalSize)+", got "+string(n), err)
  1269. return
  1270. }
  1271. // Perform FPutObject with no contentType provided (Expecting application/octet-stream)
  1272. args["objectName"] = objectName + "-Octet"
  1273. n, err = c.FPutObject(bucketName, objectName+"-Octet", fName, minio.PutObjectOptions{})
  1274. if err != nil {
  1275. logError(testName, function, args, startTime, "", "File close failed", err)
  1276. return
  1277. }
  1278. if n != int64(totalSize) {
  1279. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(totalSize)+", got "+string(n), err)
  1280. return
  1281. }
  1282. srcFile, err := os.Open(fName)
  1283. if err != nil {
  1284. logError(testName, function, args, startTime, "", "File open failed", err)
  1285. return
  1286. }
  1287. defer srcFile.Close()
  1288. // Add extension to temp file name
  1289. tmpFile, err := os.Create(fName + ".gtar")
  1290. if err != nil {
  1291. logError(testName, function, args, startTime, "", "File create failed", err)
  1292. return
  1293. }
  1294. defer tmpFile.Close()
  1295. _, err = io.Copy(tmpFile, srcFile)
  1296. if err != nil {
  1297. logError(testName, function, args, startTime, "", "File copy failed", err)
  1298. return
  1299. }
  1300. // Perform FPutObject with no contentType provided (Expecting application/x-gtar)
  1301. args["objectName"] = objectName + "-GTar"
  1302. n, err = c.FPutObject(bucketName, objectName+"-GTar", fName+".gtar", minio.PutObjectOptions{})
  1303. if err != nil {
  1304. logError(testName, function, args, startTime, "", "FPutObject failed", err)
  1305. return
  1306. }
  1307. if n != int64(totalSize) {
  1308. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(totalSize)+", got "+string(n), err)
  1309. return
  1310. }
  1311. // Check headers
  1312. function = "StatObject(bucketName, objectName, opts)"
  1313. args["objectName"] = objectName + "-standard"
  1314. rStandard, err := c.StatObject(bucketName, objectName+"-standard", minio.StatObjectOptions{})
  1315. if err != nil {
  1316. logError(testName, function, args, startTime, "", "StatObject failed", err)
  1317. return
  1318. }
  1319. if rStandard.ContentType != "application/octet-stream" {
  1320. logError(testName, function, args, startTime, "", "ContentType does not match, expected application/octet-stream, got "+rStandard.ContentType, err)
  1321. return
  1322. }
  1323. function = "StatObject(bucketName, objectName, opts)"
  1324. args["objectName"] = objectName + "-Octet"
  1325. rOctet, err := c.StatObject(bucketName, objectName+"-Octet", minio.StatObjectOptions{})
  1326. if err != nil {
  1327. logError(testName, function, args, startTime, "", "StatObject failed", err)
  1328. return
  1329. }
  1330. if rOctet.ContentType != "application/octet-stream" {
  1331. logError(testName, function, args, startTime, "", "ContentType does not match, expected application/octet-stream, got "+rStandard.ContentType, err)
  1332. return
  1333. }
  1334. function = "StatObject(bucketName, objectName, opts)"
  1335. args["objectName"] = objectName + "-GTar"
  1336. rGTar, err := c.StatObject(bucketName, objectName+"-GTar", minio.StatObjectOptions{})
  1337. if err != nil {
  1338. logError(testName, function, args, startTime, "", "StatObject failed", err)
  1339. return
  1340. }
  1341. if rGTar.ContentType != "application/x-gtar" {
  1342. logError(testName, function, args, startTime, "", "ContentType does not match, expected application/x-gtar, got "+rStandard.ContentType, err)
  1343. return
  1344. }
  1345. // Delete all objects and buckets
  1346. if err = cleanupBucket(bucketName, c); err != nil {
  1347. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1348. return
  1349. }
  1350. if err = os.Remove(fName + ".gtar"); err != nil {
  1351. logError(testName, function, args, startTime, "", "File remove failed", err)
  1352. return
  1353. }
  1354. successLogger(testName, function, args, startTime).Info()
  1355. }
  1356. // Tests FPutObjectWithContext request context cancels after timeout
  1357. func testFPutObjectWithContext() {
  1358. // initialize logging params
  1359. startTime := time.Now()
  1360. testName := getFuncName()
  1361. function := "FPutObject(bucketName, objectName, fileName, opts)"
  1362. args := map[string]interface{}{
  1363. "bucketName": "",
  1364. "objectName": "",
  1365. "fileName": "",
  1366. "opts": "",
  1367. }
  1368. // Seed random based on current time.
  1369. rand.Seed(time.Now().Unix())
  1370. // Instantiate new minio client object.
  1371. c, err := minio.New(
  1372. os.Getenv(serverEndpoint),
  1373. os.Getenv(accessKey),
  1374. os.Getenv(secretKey),
  1375. mustParseBool(os.Getenv(enableHTTPS)),
  1376. )
  1377. if err != nil {
  1378. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1379. return
  1380. }
  1381. // Enable tracing, write to stderr.
  1382. // c.TraceOn(os.Stderr)
  1383. // Set user agent.
  1384. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1385. // Generate a new random bucket name.
  1386. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1387. args["bucketName"] = bucketName
  1388. // Make a new bucket.
  1389. err = c.MakeBucket(bucketName, "us-east-1")
  1390. if err != nil {
  1391. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1392. return
  1393. }
  1394. // Upload 1 parts worth of data to use multipart upload.
  1395. // Use different data in part for multipart tests to check parts are uploaded in correct order.
  1396. var fName = getMintDataDirFilePath("datafile-1-MB")
  1397. if fName == "" {
  1398. // Make a temp file with 1 MiB bytes of data.
  1399. file, err := ioutil.TempFile(os.TempDir(), "FPutObjectWithContextTest")
  1400. if err != nil {
  1401. logError(testName, function, args, startTime, "", "TempFile creation failed", err)
  1402. return
  1403. }
  1404. // Upload 1 parts to trigger multipart upload
  1405. if _, err = io.Copy(file, getDataReader("datafile-1-MB")); err != nil {
  1406. logError(testName, function, args, startTime, "", "File copy failed", err)
  1407. return
  1408. }
  1409. // Close the file pro-actively for windows.
  1410. if err = file.Close(); err != nil {
  1411. logError(testName, function, args, startTime, "", "File close failed", err)
  1412. return
  1413. }
  1414. defer os.Remove(file.Name())
  1415. fName = file.Name()
  1416. }
  1417. totalSize := dataFileMap["datafile-1-MB"]
  1418. // Set base object name
  1419. objectName := bucketName + "FPutObjectWithContext"
  1420. args["objectName"] = objectName
  1421. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  1422. args["ctx"] = ctx
  1423. defer cancel()
  1424. // Perform standard FPutObjectWithContext with contentType provided (Expecting application/octet-stream)
  1425. _, err = c.FPutObjectWithContext(ctx, bucketName, objectName+"-Shorttimeout", fName, minio.PutObjectOptions{ContentType: "application/octet-stream"})
  1426. if err == nil {
  1427. logError(testName, function, args, startTime, "", "FPutObjectWithContext should fail on short timeout", err)
  1428. return
  1429. }
  1430. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  1431. defer cancel()
  1432. // Perform FPutObjectWithContext with a long timeout. Expect the put object to succeed
  1433. n, err := c.FPutObjectWithContext(ctx, bucketName, objectName+"-Longtimeout", fName, minio.PutObjectOptions{})
  1434. if err != nil {
  1435. logError(testName, function, args, startTime, "", "FPutObjectWithContext shouldn't fail on long timeout", err)
  1436. return
  1437. }
  1438. if n != int64(totalSize) {
  1439. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(totalSize)+", got "+string(n), err)
  1440. return
  1441. }
  1442. _, err = c.StatObject(bucketName, objectName+"-Longtimeout", minio.StatObjectOptions{})
  1443. if err != nil {
  1444. logError(testName, function, args, startTime, "", "StatObject failed", err)
  1445. return
  1446. }
  1447. // Delete all objects and buckets
  1448. if err = cleanupBucket(bucketName, c); err != nil {
  1449. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1450. return
  1451. }
  1452. successLogger(testName, function, args, startTime).Info()
  1453. }
  1454. // Tests FPutObjectWithContext request context cancels after timeout
  1455. func testFPutObjectWithContextV2() {
  1456. // initialize logging params
  1457. startTime := time.Now()
  1458. testName := getFuncName()
  1459. function := "FPutObjectWithContext(ctx, bucketName, objectName, fileName, opts)"
  1460. args := map[string]interface{}{
  1461. "bucketName": "",
  1462. "objectName": "",
  1463. "opts": "minio.PutObjectOptions{ContentType:objectContentType}",
  1464. }
  1465. // Seed random based on current time.
  1466. rand.Seed(time.Now().Unix())
  1467. // Instantiate new minio client object.
  1468. c, err := minio.NewV2(
  1469. os.Getenv(serverEndpoint),
  1470. os.Getenv(accessKey),
  1471. os.Getenv(secretKey),
  1472. mustParseBool(os.Getenv(enableHTTPS)),
  1473. )
  1474. if err != nil {
  1475. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1476. return
  1477. }
  1478. // Enable tracing, write to stderr.
  1479. // c.TraceOn(os.Stderr)
  1480. // Set user agent.
  1481. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1482. // Generate a new random bucket name.
  1483. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1484. args["bucketName"] = bucketName
  1485. // Make a new bucket.
  1486. err = c.MakeBucket(bucketName, "us-east-1")
  1487. if err != nil {
  1488. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1489. return
  1490. }
  1491. // Upload 1 parts worth of data to use multipart upload.
  1492. // Use different data in part for multipart tests to check parts are uploaded in correct order.
  1493. var fName = getMintDataDirFilePath("datafile-1-MB")
  1494. if fName == "" {
  1495. // Make a temp file with 1 MiB bytes of data.
  1496. file, err := ioutil.TempFile(os.TempDir(), "FPutObjectWithContextTest")
  1497. if err != nil {
  1498. logError(testName, function, args, startTime, "", "Temp file creation failed", err)
  1499. return
  1500. }
  1501. // Upload 1 parts to trigger multipart upload
  1502. if _, err = io.Copy(file, getDataReader("datafile-1-MB")); err != nil {
  1503. logError(testName, function, args, startTime, "", "File copy failed", err)
  1504. return
  1505. }
  1506. // Close the file pro-actively for windows.
  1507. if err = file.Close(); err != nil {
  1508. logError(testName, function, args, startTime, "", "File close failed", err)
  1509. return
  1510. }
  1511. defer os.Remove(file.Name())
  1512. fName = file.Name()
  1513. }
  1514. totalSize := dataFileMap["datafile-1-MB"]
  1515. // Set base object name
  1516. objectName := bucketName + "FPutObjectWithContext"
  1517. args["objectName"] = objectName
  1518. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  1519. args["ctx"] = ctx
  1520. defer cancel()
  1521. // Perform standard FPutObjectWithContext with contentType provided (Expecting application/octet-stream)
  1522. _, err = c.FPutObjectWithContext(ctx, bucketName, objectName+"-Shorttimeout", fName, minio.PutObjectOptions{ContentType: "application/octet-stream"})
  1523. if err == nil {
  1524. logError(testName, function, args, startTime, "", "FPutObjectWithContext should fail on short timeout", err)
  1525. return
  1526. }
  1527. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  1528. defer cancel()
  1529. // Perform FPutObjectWithContext with a long timeout. Expect the put object to succeed
  1530. n, err := c.FPutObjectWithContext(ctx, bucketName, objectName+"-Longtimeout", fName, minio.PutObjectOptions{})
  1531. if err != nil {
  1532. logError(testName, function, args, startTime, "", "FPutObjectWithContext shouldn't fail on longer timeout", err)
  1533. return
  1534. }
  1535. if n != int64(totalSize) {
  1536. logError(testName, function, args, startTime, "", "Number of bytes does not match:wanted"+string(totalSize)+" got "+string(n), err)
  1537. return
  1538. }
  1539. _, err = c.StatObject(bucketName, objectName+"-Longtimeout", minio.StatObjectOptions{})
  1540. if err != nil {
  1541. logError(testName, function, args, startTime, "", "StatObject failed", err)
  1542. return
  1543. }
  1544. // Delete all objects and buckets
  1545. if err = cleanupBucket(bucketName, c); err != nil {
  1546. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1547. return
  1548. }
  1549. successLogger(testName, function, args, startTime).Info()
  1550. }
  1551. // Test validates putObject with context to see if request cancellation is honored.
  1552. func testPutObjectWithContext() {
  1553. // initialize logging params
  1554. startTime := time.Now()
  1555. testName := getFuncName()
  1556. function := "PutObjectWithContext(ctx, bucketName, objectName, fileName, opts)"
  1557. args := map[string]interface{}{
  1558. "ctx": "",
  1559. "bucketName": "",
  1560. "objectName": "",
  1561. "opts": "",
  1562. }
  1563. // Instantiate new minio client object.
  1564. c, err := minio.NewV4(
  1565. os.Getenv(serverEndpoint),
  1566. os.Getenv(accessKey),
  1567. os.Getenv(secretKey),
  1568. mustParseBool(os.Getenv(enableHTTPS)),
  1569. )
  1570. if err != nil {
  1571. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1572. return
  1573. }
  1574. // Enable tracing, write to stderr.
  1575. // c.TraceOn(os.Stderr)
  1576. // Set user agent.
  1577. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1578. // Make a new bucket.
  1579. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1580. args["bucketName"] = bucketName
  1581. err = c.MakeBucket(bucketName, "us-east-1")
  1582. if err != nil {
  1583. logError(testName, function, args, startTime, "", "MakeBucket call failed", err)
  1584. return
  1585. }
  1586. bufSize := dataFileMap["datafile-33-kB"]
  1587. var reader = getDataReader("datafile-33-kB")
  1588. defer reader.Close()
  1589. objectName := fmt.Sprintf("test-file-%v", rand.Uint32())
  1590. args["objectName"] = objectName
  1591. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  1592. args["ctx"] = ctx
  1593. args["opts"] = minio.PutObjectOptions{ContentType: "binary/octet-stream"}
  1594. defer cancel()
  1595. _, err = c.PutObjectWithContext(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  1596. if err == nil {
  1597. logError(testName, function, args, startTime, "", "PutObjectWithContext should fail on short timeout", err)
  1598. return
  1599. }
  1600. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  1601. args["ctx"] = ctx
  1602. defer cancel()
  1603. reader = getDataReader("datafile-33-kB")
  1604. defer reader.Close()
  1605. _, err = c.PutObjectWithContext(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  1606. if err != nil {
  1607. logError(testName, function, args, startTime, "", "PutObjectWithContext with long timeout failed", err)
  1608. return
  1609. }
  1610. // Delete all objects and buckets
  1611. if err = cleanupBucket(bucketName, c); err != nil {
  1612. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1613. return
  1614. }
  1615. successLogger(testName, function, args, startTime).Info()
  1616. }
  1617. // Tests get object ReaderSeeker interface methods.
  1618. func testGetObjectReadSeekFunctional() {
  1619. // initialize logging params
  1620. startTime := time.Now()
  1621. testName := getFuncName()
  1622. function := "GetObject(bucketName, objectName)"
  1623. args := map[string]interface{}{}
  1624. // Seed random based on current time.
  1625. rand.Seed(time.Now().Unix())
  1626. // Instantiate new minio client object.
  1627. c, err := minio.New(
  1628. os.Getenv(serverEndpoint),
  1629. os.Getenv(accessKey),
  1630. os.Getenv(secretKey),
  1631. mustParseBool(os.Getenv(enableHTTPS)),
  1632. )
  1633. if err != nil {
  1634. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1635. return
  1636. }
  1637. // Enable tracing, write to stderr.
  1638. // c.TraceOn(os.Stderr)
  1639. // Set user agent.
  1640. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1641. // Generate a new random bucket name.
  1642. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1643. args["bucketName"] = bucketName
  1644. // Make a new bucket.
  1645. err = c.MakeBucket(bucketName, "us-east-1")
  1646. if err != nil {
  1647. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1648. return
  1649. }
  1650. // Generate 33K of data.
  1651. bufSize := dataFileMap["datafile-33-kB"]
  1652. var reader = getDataReader("datafile-33-kB")
  1653. defer reader.Close()
  1654. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  1655. args["objectName"] = objectName
  1656. buf, err := ioutil.ReadAll(reader)
  1657. if err != nil {
  1658. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  1659. return
  1660. }
  1661. // Save the data
  1662. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  1663. if err != nil {
  1664. logError(testName, function, args, startTime, "", "PutObject failed", err)
  1665. return
  1666. }
  1667. if n != int64(bufSize) {
  1668. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+", got "+string(n), err)
  1669. return
  1670. }
  1671. defer func() {
  1672. // Delete all objects and buckets
  1673. if err = cleanupBucket(bucketName, c); err != nil {
  1674. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1675. return
  1676. }
  1677. }()
  1678. // Read the data back
  1679. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  1680. if err != nil {
  1681. logError(testName, function, args, startTime, "", "GetObject failed", err)
  1682. return
  1683. }
  1684. st, err := r.Stat()
  1685. if err != nil {
  1686. logError(testName, function, args, startTime, "", "Stat object failed", err)
  1687. return
  1688. }
  1689. if st.Size != int64(bufSize) {
  1690. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
  1691. return
  1692. }
  1693. // This following function helps us to compare data from the reader after seek
  1694. // with the data from the original buffer
  1695. cmpData := func(r io.Reader, start, end int) {
  1696. if end-start == 0 {
  1697. return
  1698. }
  1699. buffer := bytes.NewBuffer([]byte{})
  1700. if _, err := io.CopyN(buffer, r, int64(bufSize)); err != nil {
  1701. if err != io.EOF {
  1702. logError(testName, function, args, startTime, "", "CopyN failed", err)
  1703. return
  1704. }
  1705. }
  1706. if !bytes.Equal(buf[start:end], buffer.Bytes()) {
  1707. logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
  1708. return
  1709. }
  1710. }
  1711. // Generic seek error for errors other than io.EOF
  1712. seekErr := errors.New("seek error")
  1713. testCases := []struct {
  1714. offset int64
  1715. whence int
  1716. pos int64
  1717. err error
  1718. shouldCmp bool
  1719. start int
  1720. end int
  1721. }{
  1722. // Start from offset 0, fetch data and compare
  1723. {0, 0, 0, nil, true, 0, 0},
  1724. // Start from offset 2048, fetch data and compare
  1725. {2048, 0, 2048, nil, true, 2048, bufSize},
  1726. // Start from offset larger than possible
  1727. {int64(bufSize) + 1024, 0, 0, seekErr, false, 0, 0},
  1728. // Move to offset 0 without comparing
  1729. {0, 0, 0, nil, false, 0, 0},
  1730. // Move one step forward and compare
  1731. {1, 1, 1, nil, true, 1, bufSize},
  1732. // Move larger than possible
  1733. {int64(bufSize), 1, 0, seekErr, false, 0, 0},
  1734. // Provide negative offset with CUR_SEEK
  1735. {int64(-1), 1, 0, seekErr, false, 0, 0},
  1736. // Test with whence SEEK_END and with positive offset
  1737. {1024, 2, int64(bufSize) - 1024, io.EOF, true, 0, 0},
  1738. // Test with whence SEEK_END and with negative offset
  1739. {-1024, 2, int64(bufSize) - 1024, nil, true, bufSize - 1024, bufSize},
  1740. // Test with whence SEEK_END and with large negative offset
  1741. {-int64(bufSize) * 2, 2, 0, seekErr, true, 0, 0},
  1742. }
  1743. for i, testCase := range testCases {
  1744. // Perform seek operation
  1745. n, err := r.Seek(testCase.offset, testCase.whence)
  1746. // We expect an error
  1747. if testCase.err == seekErr && err == nil {
  1748. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", unexpected err value: expected: "+testCase.err.Error()+", found: "+err.Error(), err)
  1749. return
  1750. }
  1751. // We expect a specific error
  1752. if testCase.err != seekErr && testCase.err != err {
  1753. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", unexpected err value: expected: "+testCase.err.Error()+", found: "+err.Error(), err)
  1754. return
  1755. }
  1756. // If we expect an error go to the next loop
  1757. if testCase.err != nil {
  1758. continue
  1759. }
  1760. // Check the returned seek pos
  1761. if n != testCase.pos {
  1762. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", number of bytes seeked does not match, expected "+string(testCase.pos)+", got "+string(n), err)
  1763. return
  1764. }
  1765. // Compare only if shouldCmp is activated
  1766. if testCase.shouldCmp {
  1767. cmpData(r, testCase.start, testCase.end)
  1768. }
  1769. }
  1770. successLogger(testName, function, args, startTime).Info()
  1771. }
  1772. // Tests get object ReaderAt interface methods.
  1773. func testGetObjectReadAtFunctional() {
  1774. // initialize logging params
  1775. startTime := time.Now()
  1776. testName := getFuncName()
  1777. function := "GetObject(bucketName, objectName)"
  1778. args := map[string]interface{}{}
  1779. // Seed random based on current time.
  1780. rand.Seed(time.Now().Unix())
  1781. // Instantiate new minio client object.
  1782. c, err := minio.New(
  1783. os.Getenv(serverEndpoint),
  1784. os.Getenv(accessKey),
  1785. os.Getenv(secretKey),
  1786. mustParseBool(os.Getenv(enableHTTPS)),
  1787. )
  1788. if err != nil {
  1789. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1790. return
  1791. }
  1792. // Enable tracing, write to stderr.
  1793. // c.TraceOn(os.Stderr)
  1794. // Set user agent.
  1795. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1796. // Generate a new random bucket name.
  1797. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1798. args["bucketName"] = bucketName
  1799. // Make a new bucket.
  1800. err = c.MakeBucket(bucketName, "us-east-1")
  1801. if err != nil {
  1802. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1803. return
  1804. }
  1805. // Generate 33K of data.
  1806. bufSize := dataFileMap["datafile-33-kB"]
  1807. var reader = getDataReader("datafile-33-kB")
  1808. defer reader.Close()
  1809. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  1810. args["objectName"] = objectName
  1811. buf, err := ioutil.ReadAll(reader)
  1812. if err != nil {
  1813. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  1814. return
  1815. }
  1816. // Save the data
  1817. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  1818. if err != nil {
  1819. logError(testName, function, args, startTime, "", "PutObject failed", err)
  1820. return
  1821. }
  1822. if n != int64(bufSize) {
  1823. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+", got "+string(n), err)
  1824. return
  1825. }
  1826. // read the data back
  1827. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  1828. if err != nil {
  1829. logError(testName, function, args, startTime, "", "PutObject failed", err)
  1830. return
  1831. }
  1832. offset := int64(2048)
  1833. // read directly
  1834. buf1 := make([]byte, 512)
  1835. buf2 := make([]byte, 512)
  1836. buf3 := make([]byte, 512)
  1837. buf4 := make([]byte, 512)
  1838. // Test readAt before stat is called.
  1839. m, err := r.ReadAt(buf1, offset)
  1840. if err != nil {
  1841. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  1842. return
  1843. }
  1844. if m != len(buf1) {
  1845. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf1))+", got "+string(m), err)
  1846. return
  1847. }
  1848. if !bytes.Equal(buf1, buf[offset:offset+512]) {
  1849. logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
  1850. return
  1851. }
  1852. offset += 512
  1853. st, err := r.Stat()
  1854. if err != nil {
  1855. logError(testName, function, args, startTime, "", "Stat failed", err)
  1856. return
  1857. }
  1858. if st.Size != int64(bufSize) {
  1859. logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+", got "+string(st.Size), err)
  1860. return
  1861. }
  1862. m, err = r.ReadAt(buf2, offset)
  1863. if err != nil {
  1864. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  1865. return
  1866. }
  1867. if m != len(buf2) {
  1868. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf2))+", got "+string(m), err)
  1869. return
  1870. }
  1871. if !bytes.Equal(buf2, buf[offset:offset+512]) {
  1872. logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
  1873. return
  1874. }
  1875. offset += 512
  1876. m, err = r.ReadAt(buf3, offset)
  1877. if err != nil {
  1878. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  1879. return
  1880. }
  1881. if m != len(buf3) {
  1882. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf3))+", got "+string(m), err)
  1883. return
  1884. }
  1885. if !bytes.Equal(buf3, buf[offset:offset+512]) {
  1886. logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
  1887. return
  1888. }
  1889. offset += 512
  1890. m, err = r.ReadAt(buf4, offset)
  1891. if err != nil {
  1892. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  1893. return
  1894. }
  1895. if m != len(buf4) {
  1896. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf4))+", got "+string(m), err)
  1897. return
  1898. }
  1899. if !bytes.Equal(buf4, buf[offset:offset+512]) {
  1900. logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
  1901. return
  1902. }
  1903. buf5 := make([]byte, n)
  1904. // Read the whole object.
  1905. m, err = r.ReadAt(buf5, 0)
  1906. if err != nil {
  1907. if err != io.EOF {
  1908. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  1909. return
  1910. }
  1911. }
  1912. if m != len(buf5) {
  1913. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf5))+", got "+string(m), err)
  1914. return
  1915. }
  1916. if !bytes.Equal(buf, buf5) {
  1917. logError(testName, function, args, startTime, "", "Incorrect data read in GetObject, than what was previously uploaded", err)
  1918. return
  1919. }
  1920. buf6 := make([]byte, n+1)
  1921. // Read the whole object and beyond.
  1922. _, err = r.ReadAt(buf6, 0)
  1923. if err != nil {
  1924. if err != io.EOF {
  1925. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  1926. return
  1927. }
  1928. }
  1929. // Delete all objects and buckets
  1930. if err = cleanupBucket(bucketName, c); err != nil {
  1931. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  1932. return
  1933. }
  1934. successLogger(testName, function, args, startTime).Info()
  1935. }
  1936. // Test Presigned Post Policy
  1937. func testPresignedPostPolicy() {
  1938. // initialize logging params
  1939. startTime := time.Now()
  1940. testName := getFuncName()
  1941. function := "PresignedPostPolicy(policy)"
  1942. args := map[string]interface{}{
  1943. "policy": "",
  1944. }
  1945. // Seed random based on current time.
  1946. rand.Seed(time.Now().Unix())
  1947. // Instantiate new minio client object
  1948. c, err := minio.NewV4(
  1949. os.Getenv(serverEndpoint),
  1950. os.Getenv(accessKey),
  1951. os.Getenv(secretKey),
  1952. mustParseBool(os.Getenv(enableHTTPS)),
  1953. )
  1954. if err != nil {
  1955. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  1956. return
  1957. }
  1958. // Enable tracing, write to stderr.
  1959. // c.TraceOn(os.Stderr)
  1960. // Set user agent.
  1961. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  1962. // Generate a new random bucket name.
  1963. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  1964. // Make a new bucket in 'us-east-1' (source bucket).
  1965. err = c.MakeBucket(bucketName, "us-east-1")
  1966. if err != nil {
  1967. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  1968. return
  1969. }
  1970. // Generate 33K of data.
  1971. bufSize := dataFileMap["datafile-33-kB"]
  1972. var reader = getDataReader("datafile-33-kB")
  1973. defer reader.Close()
  1974. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  1975. metadataKey := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  1976. metadataValue := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  1977. buf, err := ioutil.ReadAll(reader)
  1978. if err != nil {
  1979. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  1980. return
  1981. }
  1982. // Save the data
  1983. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  1984. if err != nil {
  1985. logError(testName, function, args, startTime, "", "PutObject failed", err)
  1986. return
  1987. }
  1988. if n != int64(bufSize) {
  1989. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+" got "+string(n), err)
  1990. return
  1991. }
  1992. policy := minio.NewPostPolicy()
  1993. if err := policy.SetBucket(""); err == nil {
  1994. logError(testName, function, args, startTime, "", "SetBucket did not fail for invalid conditions", err)
  1995. return
  1996. }
  1997. if err := policy.SetKey(""); err == nil {
  1998. logError(testName, function, args, startTime, "", "SetKey did not fail for invalid conditions", err)
  1999. return
  2000. }
  2001. if err := policy.SetKeyStartsWith(""); err == nil {
  2002. logError(testName, function, args, startTime, "", "SetKeyStartsWith did not fail for invalid conditions", err)
  2003. return
  2004. }
  2005. if err := policy.SetExpires(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)); err == nil {
  2006. logError(testName, function, args, startTime, "", "SetExpires did not fail for invalid conditions", err)
  2007. return
  2008. }
  2009. if err := policy.SetContentType(""); err == nil {
  2010. logError(testName, function, args, startTime, "", "SetContentType did not fail for invalid conditions", err)
  2011. return
  2012. }
  2013. if err := policy.SetContentLengthRange(1024*1024, 1024); err == nil {
  2014. logError(testName, function, args, startTime, "", "SetContentLengthRange did not fail for invalid conditions", err)
  2015. return
  2016. }
  2017. if err := policy.SetUserMetadata("", ""); err == nil {
  2018. logError(testName, function, args, startTime, "", "SetUserMetadata did not fail for invalid conditions", err)
  2019. return
  2020. }
  2021. policy.SetBucket(bucketName)
  2022. policy.SetKey(objectName)
  2023. policy.SetExpires(time.Now().UTC().AddDate(0, 0, 10)) // expires in 10 days
  2024. policy.SetContentType("binary/octet-stream")
  2025. policy.SetContentLengthRange(10, 1024*1024)
  2026. policy.SetUserMetadata(metadataKey, metadataValue)
  2027. args["policy"] = policy.String()
  2028. presignedPostPolicyURL, formData, err := c.PresignedPostPolicy(policy)
  2029. if err != nil {
  2030. logError(testName, function, args, startTime, "", "PresignedPostPolicy failed", err)
  2031. return
  2032. }
  2033. var formBuf bytes.Buffer
  2034. writer := multipart.NewWriter(&formBuf)
  2035. for k, v := range formData {
  2036. writer.WriteField(k, v)
  2037. }
  2038. // Get a 33KB file to upload and test if set post policy works
  2039. var filePath = getMintDataDirFilePath("datafile-33-kB")
  2040. if filePath == "" {
  2041. // Make a temp file with 33 KB data.
  2042. file, err := ioutil.TempFile(os.TempDir(), "PresignedPostPolicyTest")
  2043. if err != nil {
  2044. logError(testName, function, args, startTime, "", "TempFile creation failed", err)
  2045. return
  2046. }
  2047. if _, err = io.Copy(file, getDataReader("datafile-33-kB")); err != nil {
  2048. logError(testName, function, args, startTime, "", "Copy failed", err)
  2049. return
  2050. }
  2051. if err = file.Close(); err != nil {
  2052. logError(testName, function, args, startTime, "", "File Close failed", err)
  2053. return
  2054. }
  2055. filePath = file.Name()
  2056. }
  2057. // add file to post request
  2058. f, err := os.Open(filePath)
  2059. defer f.Close()
  2060. if err != nil {
  2061. logError(testName, function, args, startTime, "", "File open failed", err)
  2062. return
  2063. }
  2064. w, err := writer.CreateFormFile("file", filePath)
  2065. if err != nil {
  2066. logError(testName, function, args, startTime, "", "CreateFormFile failed", err)
  2067. return
  2068. }
  2069. _, err = io.Copy(w, f)
  2070. if err != nil {
  2071. logError(testName, function, args, startTime, "", "Copy failed", err)
  2072. return
  2073. }
  2074. writer.Close()
  2075. // make post request with correct form data
  2076. res, err := http.Post(presignedPostPolicyURL.String(), writer.FormDataContentType(), bytes.NewReader(formBuf.Bytes()))
  2077. if err != nil {
  2078. logError(testName, function, args, startTime, "", "Http request failed", err)
  2079. return
  2080. }
  2081. defer res.Body.Close()
  2082. if res.StatusCode != http.StatusNoContent {
  2083. logError(testName, function, args, startTime, "", "Http request failed", errors.New(res.Status))
  2084. return
  2085. }
  2086. // expected path should be absolute path of the object
  2087. var scheme string
  2088. if mustParseBool(os.Getenv(enableHTTPS)) {
  2089. scheme = "https://"
  2090. } else {
  2091. scheme = "http://"
  2092. }
  2093. expectedLocation := scheme + os.Getenv(serverEndpoint) + "/" + bucketName + "/" + objectName
  2094. if val, ok := res.Header["Location"]; ok {
  2095. if val[0] != expectedLocation {
  2096. logError(testName, function, args, startTime, "", "Location in header response is incorrect", err)
  2097. return
  2098. }
  2099. } else {
  2100. logError(testName, function, args, startTime, "", "Location not found in header response", err)
  2101. return
  2102. }
  2103. // Delete all objects and buckets
  2104. if err = cleanupBucket(bucketName, c); err != nil {
  2105. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  2106. return
  2107. }
  2108. successLogger(testName, function, args, startTime).Info()
  2109. }
  2110. // Tests copy object
  2111. func testCopyObject() {
  2112. // initialize logging params
  2113. startTime := time.Now()
  2114. testName := getFuncName()
  2115. function := "CopyObject(dst, src)"
  2116. args := map[string]interface{}{}
  2117. // Seed random based on current time.
  2118. rand.Seed(time.Now().Unix())
  2119. // Instantiate new minio client object
  2120. c, err := minio.NewV4(
  2121. os.Getenv(serverEndpoint),
  2122. os.Getenv(accessKey),
  2123. os.Getenv(secretKey),
  2124. mustParseBool(os.Getenv(enableHTTPS)),
  2125. )
  2126. if err != nil {
  2127. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  2128. return
  2129. }
  2130. // Enable tracing, write to stderr.
  2131. // c.TraceOn(os.Stderr)
  2132. // Set user agent.
  2133. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  2134. // Generate a new random bucket name.
  2135. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  2136. // Make a new bucket in 'us-east-1' (source bucket).
  2137. err = c.MakeBucket(bucketName, "us-east-1")
  2138. if err != nil {
  2139. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  2140. return
  2141. }
  2142. // Make a new bucket in 'us-east-1' (destination bucket).
  2143. err = c.MakeBucket(bucketName+"-copy", "us-east-1")
  2144. if err != nil {
  2145. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  2146. return
  2147. }
  2148. // Generate 33K of data.
  2149. bufSize := dataFileMap["datafile-33-kB"]
  2150. var reader = getDataReader("datafile-33-kB")
  2151. // Save the data
  2152. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  2153. n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  2154. if err != nil {
  2155. logError(testName, function, args, startTime, "", "PutObject failed", err)
  2156. return
  2157. }
  2158. if n != int64(bufSize) {
  2159. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+", got "+string(n), err)
  2160. return
  2161. }
  2162. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  2163. if err != nil {
  2164. logError(testName, function, args, startTime, "", "GetObject failed", err)
  2165. return
  2166. }
  2167. // Check the various fields of source object against destination object.
  2168. objInfo, err := r.Stat()
  2169. if err != nil {
  2170. logError(testName, function, args, startTime, "", "Stat failed", err)
  2171. return
  2172. }
  2173. // Copy Source
  2174. src := minio.NewSourceInfo(bucketName, objectName, nil)
  2175. args["src"] = src
  2176. // Set copy conditions.
  2177. // All invalid conditions first.
  2178. err = src.SetModifiedSinceCond(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC))
  2179. if err == nil {
  2180. logError(testName, function, args, startTime, "", "SetModifiedSinceCond did not fail for invalid conditions", err)
  2181. return
  2182. }
  2183. err = src.SetUnmodifiedSinceCond(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC))
  2184. if err == nil {
  2185. logError(testName, function, args, startTime, "", "SetUnmodifiedSinceCond did not fail for invalid conditions", err)
  2186. return
  2187. }
  2188. err = src.SetMatchETagCond("")
  2189. if err == nil {
  2190. logError(testName, function, args, startTime, "", "SetMatchETagCond did not fail for invalid conditions", err)
  2191. return
  2192. }
  2193. err = src.SetMatchETagExceptCond("")
  2194. if err == nil {
  2195. logError(testName, function, args, startTime, "", "SetMatchETagExceptCond did not fail for invalid conditions", err)
  2196. return
  2197. }
  2198. err = src.SetModifiedSinceCond(time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC))
  2199. if err != nil {
  2200. logError(testName, function, args, startTime, "", "SetModifiedSinceCond failed", err)
  2201. return
  2202. }
  2203. err = src.SetMatchETagCond(objInfo.ETag)
  2204. if err != nil {
  2205. logError(testName, function, args, startTime, "", "SetMatchETagCond failed", err)
  2206. return
  2207. }
  2208. dst, err := minio.NewDestinationInfo(bucketName+"-copy", objectName+"-copy", nil, nil)
  2209. args["dst"] = dst
  2210. if err != nil {
  2211. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  2212. return
  2213. }
  2214. // Perform the Copy
  2215. err = c.CopyObject(dst, src)
  2216. if err != nil {
  2217. logError(testName, function, args, startTime, "", "CopyObject failed", err)
  2218. return
  2219. }
  2220. // Source object
  2221. r, err = c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  2222. if err != nil {
  2223. logError(testName, function, args, startTime, "", "GetObject failed", err)
  2224. return
  2225. }
  2226. // Destination object
  2227. readerCopy, err := c.GetObject(bucketName+"-copy", objectName+"-copy", minio.GetObjectOptions{})
  2228. if err != nil {
  2229. logError(testName, function, args, startTime, "", "GetObject failed", err)
  2230. return
  2231. }
  2232. // Check the various fields of source object against destination object.
  2233. objInfo, err = r.Stat()
  2234. if err != nil {
  2235. logError(testName, function, args, startTime, "", "Stat failed", err)
  2236. return
  2237. }
  2238. objInfoCopy, err := readerCopy.Stat()
  2239. if err != nil {
  2240. logError(testName, function, args, startTime, "", "Stat failed", err)
  2241. return
  2242. }
  2243. if objInfo.Size != objInfoCopy.Size {
  2244. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(objInfoCopy.Size)+", got "+string(objInfo.Size), err)
  2245. return
  2246. }
  2247. // CopyObject again but with wrong conditions
  2248. src = minio.NewSourceInfo(bucketName, objectName, nil)
  2249. err = src.SetUnmodifiedSinceCond(time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC))
  2250. if err != nil {
  2251. logError(testName, function, args, startTime, "", "SetUnmodifiedSinceCond failed", err)
  2252. return
  2253. }
  2254. err = src.SetMatchETagExceptCond(objInfo.ETag)
  2255. if err != nil {
  2256. logError(testName, function, args, startTime, "", "SetMatchETagExceptCond failed", err)
  2257. return
  2258. }
  2259. // Perform the Copy which should fail
  2260. err = c.CopyObject(dst, src)
  2261. if err == nil {
  2262. logError(testName, function, args, startTime, "", "CopyObject did not fail for invalid conditions", err)
  2263. return
  2264. }
  2265. // Delete all objects and buckets
  2266. if err = cleanupBucket(bucketName, c); err != nil {
  2267. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  2268. return
  2269. }
  2270. if err = cleanupBucket(bucketName+"-copy", c); err != nil {
  2271. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  2272. return
  2273. }
  2274. successLogger(testName, function, args, startTime).Info()
  2275. }
  2276. // TestEncryptionPutGet tests client side encryption
  2277. func testEncryptionPutGet() {
  2278. // initialize logging params
  2279. startTime := time.Now()
  2280. testName := getFuncName()
  2281. function := "PutEncryptedObject(bucketName, objectName, reader, cbcMaterials, metadata, progress)"
  2282. args := map[string]interface{}{
  2283. "bucketName": "",
  2284. "objectName": "",
  2285. "cbcMaterials": "",
  2286. "metadata": "",
  2287. }
  2288. // Seed random based on current time.
  2289. rand.Seed(time.Now().Unix())
  2290. // Instantiate new minio client object
  2291. c, err := minio.NewV4(
  2292. os.Getenv(serverEndpoint),
  2293. os.Getenv(accessKey),
  2294. os.Getenv(secretKey),
  2295. mustParseBool(os.Getenv(enableHTTPS)),
  2296. )
  2297. if err != nil {
  2298. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  2299. return
  2300. }
  2301. // Enable tracing, write to stderr.
  2302. // c.TraceOn(os.Stderr)
  2303. // Set user agent.
  2304. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  2305. // Generate a new random bucket name.
  2306. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  2307. args["bucketName"] = bucketName
  2308. // Make a new bucket.
  2309. err = c.MakeBucket(bucketName, "us-east-1")
  2310. if err != nil {
  2311. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  2312. return
  2313. }
  2314. // Generate a symmetric key
  2315. symKey := encrypt.NewSymmetricKey([]byte("my-secret-key-00"))
  2316. // Generate an assymmetric key from predefine public and private certificates
  2317. privateKey, err := hex.DecodeString(
  2318. "30820277020100300d06092a864886f70d0101010500048202613082025d" +
  2319. "0201000281810087b42ea73243a3576dc4c0b6fa245d339582dfdbddc20c" +
  2320. "bb8ab666385034d997210c54ba79275c51162a1221c3fb1a4c7c61131ca6" +
  2321. "5563b319d83474ef5e803fbfa7e52b889e1893b02586b724250de7ac6351" +
  2322. "cc0b7c638c980acec0a07020a78eed7eaa471eca4b92071394e061346c06" +
  2323. "15ccce2f465dee2080a89e43f29b5702030100010281801dd5770c3af8b3" +
  2324. "c85cd18cacad81a11bde1acfac3eac92b00866e142301fee565365aa9af4" +
  2325. "57baebf8bb7711054d071319a51dd6869aef3848ce477a0dc5f0dbc0c336" +
  2326. "5814b24c820491ae2bb3c707229a654427e03307fec683e6b27856688f08" +
  2327. "bdaa88054c5eeeb773793ff7543ee0fb0e2ad716856f2777f809ef7e6fa4" +
  2328. "41024100ca6b1edf89e8a8f93cce4b98c76c6990a09eb0d32ad9d3d04fbf" +
  2329. "0b026fa935c44f0a1c05dd96df192143b7bda8b110ec8ace28927181fd8c" +
  2330. "d2f17330b9b63535024100aba0260afb41489451baaeba423bee39bcbd1e" +
  2331. "f63dd44ee2d466d2453e683bf46d019a8baead3a2c7fca987988eb4d565e" +
  2332. "27d6be34605953f5034e4faeec9bdb0241009db2cb00b8be8c36710aff96" +
  2333. "6d77a6dec86419baca9d9e09a2b761ea69f7d82db2ae5b9aae4246599bb2" +
  2334. "d849684d5ab40e8802cfe4a2b358ad56f2b939561d2902404e0ead9ecafd" +
  2335. "bb33f22414fa13cbcc22a86bdf9c212ce1a01af894e3f76952f36d6c904c" +
  2336. "bd6a7e0de52550c9ddf31f1e8bfe5495f79e66a25fca5c20b3af5b870241" +
  2337. "0083456232aa58a8c45e5b110494599bda8dbe6a094683a0539ddd24e19d" +
  2338. "47684263bbe285ad953d725942d670b8f290d50c0bca3d1dc9688569f1d5" +
  2339. "9945cb5c7d")
  2340. if err != nil {
  2341. logError(testName, function, args, startTime, "", "DecodeString for symmetric Key generation failed", err)
  2342. return
  2343. }
  2344. publicKey, err := hex.DecodeString("30819f300d06092a864886f70d010101050003818d003081890281810087" +
  2345. "b42ea73243a3576dc4c0b6fa245d339582dfdbddc20cbb8ab666385034d9" +
  2346. "97210c54ba79275c51162a1221c3fb1a4c7c61131ca65563b319d83474ef" +
  2347. "5e803fbfa7e52b889e1893b02586b724250de7ac6351cc0b7c638c980ace" +
  2348. "c0a07020a78eed7eaa471eca4b92071394e061346c0615ccce2f465dee20" +
  2349. "80a89e43f29b570203010001")
  2350. if err != nil {
  2351. logError(testName, function, args, startTime, "", "DecodeString for symmetric Key generation failed", err)
  2352. return
  2353. }
  2354. // Generate an asymmetric key
  2355. asymKey, err := encrypt.NewAsymmetricKey(privateKey, publicKey)
  2356. if err != nil {
  2357. logError(testName, function, args, startTime, "", "NewAsymmetricKey for symmetric Key generation failed", err)
  2358. return
  2359. }
  2360. testCases := []struct {
  2361. buf []byte
  2362. encKey encrypt.Key
  2363. }{
  2364. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 0)},
  2365. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1)},
  2366. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 15)},
  2367. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 16)},
  2368. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 17)},
  2369. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 31)},
  2370. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 32)},
  2371. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 33)},
  2372. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1024)},
  2373. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1024*2)},
  2374. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1024*1024)},
  2375. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 0)},
  2376. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 1)},
  2377. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 16)},
  2378. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 32)},
  2379. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 1024)},
  2380. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 1024*1024)},
  2381. }
  2382. for i, testCase := range testCases {
  2383. // Generate a random object name
  2384. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  2385. args["objectName"] = objectName
  2386. // Secured object
  2387. cbcMaterials, err := encrypt.NewCBCSecureMaterials(testCase.encKey)
  2388. args["cbcMaterials"] = cbcMaterials
  2389. if err != nil {
  2390. logError(testName, function, args, startTime, "", "NewCBCSecureMaterials failed", err)
  2391. return
  2392. }
  2393. // Put encrypted data
  2394. _, err = c.PutEncryptedObject(bucketName, objectName, bytes.NewReader(testCase.buf), cbcMaterials)
  2395. if err != nil {
  2396. logError(testName, function, args, startTime, "", "PutEncryptedObject failed", err)
  2397. return
  2398. }
  2399. // Read the data back
  2400. r, err := c.GetEncryptedObject(bucketName, objectName, cbcMaterials)
  2401. if err != nil {
  2402. logError(testName, function, args, startTime, "", "GetEncryptedObject failed", err)
  2403. return
  2404. }
  2405. defer r.Close()
  2406. // Compare the sent object with the received one
  2407. recvBuffer := bytes.NewBuffer([]byte{})
  2408. if _, err = io.Copy(recvBuffer, r); err != nil {
  2409. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", error: "+err.Error(), err)
  2410. return
  2411. }
  2412. if recvBuffer.Len() != len(testCase.buf) {
  2413. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Number of bytes of received object does not match, expected "+string(len(testCase.buf))+", got "+string(recvBuffer.Len()), err)
  2414. return
  2415. }
  2416. if !bytes.Equal(testCase.buf, recvBuffer.Bytes()) {
  2417. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Encrypted sent is not equal to decrypted, expected "+string(testCase.buf)+", got "+string(recvBuffer.Bytes()), err)
  2418. return
  2419. }
  2420. successLogger(testName, function, args, startTime).Info()
  2421. }
  2422. // Delete all objects and buckets
  2423. if err = cleanupBucket(bucketName, c); err != nil {
  2424. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  2425. return
  2426. }
  2427. successLogger(testName, function, args, startTime).Info()
  2428. }
  2429. // TestEncryptionFPut tests client side encryption
  2430. func testEncryptionFPut() {
  2431. // initialize logging params
  2432. startTime := time.Now()
  2433. testName := getFuncName()
  2434. function := "FPutEncryptedObject(bucketName, objectName, filePath, contentType, cbcMaterials)"
  2435. args := map[string]interface{}{
  2436. "bucketName": "",
  2437. "objectName": "",
  2438. "filePath": "",
  2439. "contentType": "",
  2440. "cbcMaterials": "",
  2441. }
  2442. // Seed random based on current time.
  2443. rand.Seed(time.Now().Unix())
  2444. // Instantiate new minio client object
  2445. c, err := minio.NewV4(
  2446. os.Getenv(serverEndpoint),
  2447. os.Getenv(accessKey),
  2448. os.Getenv(secretKey),
  2449. mustParseBool(os.Getenv(enableHTTPS)),
  2450. )
  2451. if err != nil {
  2452. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  2453. return
  2454. }
  2455. // Enable tracing, write to stderr.
  2456. // c.TraceOn(os.Stderr)
  2457. // Set user agent.
  2458. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  2459. // Generate a new random bucket name.
  2460. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  2461. args["bucketName"] = bucketName
  2462. // Make a new bucket.
  2463. err = c.MakeBucket(bucketName, "us-east-1")
  2464. if err != nil {
  2465. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  2466. return
  2467. }
  2468. // Generate a symmetric key
  2469. symKey := encrypt.NewSymmetricKey([]byte("my-secret-key-00"))
  2470. // Generate an assymmetric key from predefine public and private certificates
  2471. privateKey, err := hex.DecodeString(
  2472. "30820277020100300d06092a864886f70d0101010500048202613082025d" +
  2473. "0201000281810087b42ea73243a3576dc4c0b6fa245d339582dfdbddc20c" +
  2474. "bb8ab666385034d997210c54ba79275c51162a1221c3fb1a4c7c61131ca6" +
  2475. "5563b319d83474ef5e803fbfa7e52b889e1893b02586b724250de7ac6351" +
  2476. "cc0b7c638c980acec0a07020a78eed7eaa471eca4b92071394e061346c06" +
  2477. "15ccce2f465dee2080a89e43f29b5702030100010281801dd5770c3af8b3" +
  2478. "c85cd18cacad81a11bde1acfac3eac92b00866e142301fee565365aa9af4" +
  2479. "57baebf8bb7711054d071319a51dd6869aef3848ce477a0dc5f0dbc0c336" +
  2480. "5814b24c820491ae2bb3c707229a654427e03307fec683e6b27856688f08" +
  2481. "bdaa88054c5eeeb773793ff7543ee0fb0e2ad716856f2777f809ef7e6fa4" +
  2482. "41024100ca6b1edf89e8a8f93cce4b98c76c6990a09eb0d32ad9d3d04fbf" +
  2483. "0b026fa935c44f0a1c05dd96df192143b7bda8b110ec8ace28927181fd8c" +
  2484. "d2f17330b9b63535024100aba0260afb41489451baaeba423bee39bcbd1e" +
  2485. "f63dd44ee2d466d2453e683bf46d019a8baead3a2c7fca987988eb4d565e" +
  2486. "27d6be34605953f5034e4faeec9bdb0241009db2cb00b8be8c36710aff96" +
  2487. "6d77a6dec86419baca9d9e09a2b761ea69f7d82db2ae5b9aae4246599bb2" +
  2488. "d849684d5ab40e8802cfe4a2b358ad56f2b939561d2902404e0ead9ecafd" +
  2489. "bb33f22414fa13cbcc22a86bdf9c212ce1a01af894e3f76952f36d6c904c" +
  2490. "bd6a7e0de52550c9ddf31f1e8bfe5495f79e66a25fca5c20b3af5b870241" +
  2491. "0083456232aa58a8c45e5b110494599bda8dbe6a094683a0539ddd24e19d" +
  2492. "47684263bbe285ad953d725942d670b8f290d50c0bca3d1dc9688569f1d5" +
  2493. "9945cb5c7d")
  2494. if err != nil {
  2495. logError(testName, function, args, startTime, "", "DecodeString for symmetric Key generation failed", err)
  2496. return
  2497. }
  2498. publicKey, err := hex.DecodeString("30819f300d06092a864886f70d010101050003818d003081890281810087" +
  2499. "b42ea73243a3576dc4c0b6fa245d339582dfdbddc20cbb8ab666385034d9" +
  2500. "97210c54ba79275c51162a1221c3fb1a4c7c61131ca65563b319d83474ef" +
  2501. "5e803fbfa7e52b889e1893b02586b724250de7ac6351cc0b7c638c980ace" +
  2502. "c0a07020a78eed7eaa471eca4b92071394e061346c0615ccce2f465dee20" +
  2503. "80a89e43f29b570203010001")
  2504. if err != nil {
  2505. logError(testName, function, args, startTime, "", "DecodeString for symmetric Key generation failed", err)
  2506. return
  2507. }
  2508. // Generate an asymmetric key
  2509. asymKey, err := encrypt.NewAsymmetricKey(privateKey, publicKey)
  2510. if err != nil {
  2511. logError(testName, function, args, startTime, "", "NewAsymmetricKey for symmetric Key generation failed", err)
  2512. return
  2513. }
  2514. // Object custom metadata
  2515. customContentType := "custom/contenttype"
  2516. args["metadata"] = customContentType
  2517. testCases := []struct {
  2518. buf []byte
  2519. encKey encrypt.Key
  2520. }{
  2521. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 0)},
  2522. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1)},
  2523. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 15)},
  2524. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 16)},
  2525. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 17)},
  2526. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 31)},
  2527. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 32)},
  2528. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 33)},
  2529. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1024)},
  2530. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1024*2)},
  2531. {encKey: symKey, buf: bytes.Repeat([]byte("F"), 1024*1024)},
  2532. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 0)},
  2533. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 1)},
  2534. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 16)},
  2535. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 32)},
  2536. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 1024)},
  2537. {encKey: asymKey, buf: bytes.Repeat([]byte("F"), 1024*1024)},
  2538. }
  2539. for i, testCase := range testCases {
  2540. // Generate a random object name
  2541. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  2542. args["objectName"] = objectName
  2543. // Secured object
  2544. cbcMaterials, err := encrypt.NewCBCSecureMaterials(testCase.encKey)
  2545. args["cbcMaterials"] = cbcMaterials
  2546. if err != nil {
  2547. logError(testName, function, args, startTime, "", "NewCBCSecureMaterials failed", err)
  2548. return
  2549. }
  2550. // Generate a random file name.
  2551. fileName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  2552. file, err := os.Create(fileName)
  2553. if err != nil {
  2554. logError(testName, function, args, startTime, "", "file create failed", err)
  2555. return
  2556. }
  2557. _, err = file.Write(testCase.buf)
  2558. if err != nil {
  2559. logError(testName, function, args, startTime, "", "file write failed", err)
  2560. return
  2561. }
  2562. file.Close()
  2563. // Put encrypted data
  2564. if _, err = c.FPutEncryptedObject(bucketName, objectName, fileName, cbcMaterials); err != nil {
  2565. logError(testName, function, args, startTime, "", "FPutEncryptedObject failed", err)
  2566. return
  2567. }
  2568. // Read the data back
  2569. r, err := c.GetEncryptedObject(bucketName, objectName, cbcMaterials)
  2570. if err != nil {
  2571. logError(testName, function, args, startTime, "", "GetEncryptedObject failed", err)
  2572. return
  2573. }
  2574. defer r.Close()
  2575. // Compare the sent object with the received one
  2576. recvBuffer := bytes.NewBuffer([]byte{})
  2577. if _, err = io.Copy(recvBuffer, r); err != nil {
  2578. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", error: "+err.Error(), err)
  2579. return
  2580. }
  2581. if recvBuffer.Len() != len(testCase.buf) {
  2582. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Number of bytes of received object does not match, expected "+string(len(testCase.buf))+", got "+string(recvBuffer.Len()), err)
  2583. return
  2584. }
  2585. if !bytes.Equal(testCase.buf, recvBuffer.Bytes()) {
  2586. logError(testName, function, args, startTime, "", "Test "+string(i+1)+", Encrypted sent is not equal to decrypted, expected "+string(testCase.buf)+", got "+string(recvBuffer.Bytes()), err)
  2587. return
  2588. }
  2589. if err = os.Remove(fileName); err != nil {
  2590. logError(testName, function, args, startTime, "", "File remove failed", err)
  2591. return
  2592. }
  2593. }
  2594. // Delete all objects and buckets
  2595. if err = cleanupBucket(bucketName, c); err != nil {
  2596. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  2597. return
  2598. }
  2599. successLogger(testName, function, args, startTime).Info()
  2600. }
  2601. func testBucketNotification() {
  2602. // initialize logging params
  2603. startTime := time.Now()
  2604. testName := getFuncName()
  2605. function := "SetBucketNotification(bucketName)"
  2606. args := map[string]interface{}{
  2607. "bucketName": "",
  2608. }
  2609. if os.Getenv("NOTIFY_BUCKET") == "" ||
  2610. os.Getenv("NOTIFY_SERVICE") == "" ||
  2611. os.Getenv("NOTIFY_REGION") == "" ||
  2612. os.Getenv("NOTIFY_ACCOUNTID") == "" ||
  2613. os.Getenv("NOTIFY_RESOURCE") == "" {
  2614. ignoredLog(testName, function, args, startTime, "Skipped notification test as it is not configured").Info()
  2615. return
  2616. }
  2617. // Seed random based on current time.
  2618. rand.Seed(time.Now().Unix())
  2619. c, err := minio.New(
  2620. os.Getenv(serverEndpoint),
  2621. os.Getenv(accessKey),
  2622. os.Getenv(secretKey),
  2623. mustParseBool(os.Getenv(enableHTTPS)),
  2624. )
  2625. if err != nil {
  2626. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  2627. return
  2628. }
  2629. // Enable to debug
  2630. // c.TraceOn(os.Stderr)
  2631. // Set user agent.
  2632. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  2633. bucketName := os.Getenv("NOTIFY_BUCKET")
  2634. args["bucketName"] = bucketName
  2635. topicArn := minio.NewArn("aws", os.Getenv("NOTIFY_SERVICE"), os.Getenv("NOTIFY_REGION"), os.Getenv("NOTIFY_ACCOUNTID"), os.Getenv("NOTIFY_RESOURCE"))
  2636. queueArn := minio.NewArn("aws", "dummy-service", "dummy-region", "dummy-accountid", "dummy-resource")
  2637. topicConfig := minio.NewNotificationConfig(topicArn)
  2638. topicConfig.AddEvents(minio.ObjectCreatedAll, minio.ObjectRemovedAll)
  2639. topicConfig.AddFilterSuffix("jpg")
  2640. queueConfig := minio.NewNotificationConfig(queueArn)
  2641. queueConfig.AddEvents(minio.ObjectCreatedAll)
  2642. queueConfig.AddFilterPrefix("photos/")
  2643. bNotification := minio.BucketNotification{}
  2644. bNotification.AddTopic(topicConfig)
  2645. // Add the same topicConfig again, should have no effect
  2646. // because it is duplicated
  2647. bNotification.AddTopic(topicConfig)
  2648. if len(bNotification.TopicConfigs) != 1 {
  2649. logError(testName, function, args, startTime, "", "Duplicate entry added", err)
  2650. return
  2651. }
  2652. // Add and remove a queue config
  2653. bNotification.AddQueue(queueConfig)
  2654. bNotification.RemoveQueueByArn(queueArn)
  2655. err = c.SetBucketNotification(bucketName, bNotification)
  2656. if err != nil {
  2657. logError(testName, function, args, startTime, "", "SetBucketNotification failed", err)
  2658. return
  2659. }
  2660. bNotification, err = c.GetBucketNotification(bucketName)
  2661. if err != nil {
  2662. logError(testName, function, args, startTime, "", "GetBucketNotification failed", err)
  2663. return
  2664. }
  2665. if len(bNotification.TopicConfigs) != 1 {
  2666. logError(testName, function, args, startTime, "", "Topic config is empty", err)
  2667. return
  2668. }
  2669. if bNotification.TopicConfigs[0].Filter.S3Key.FilterRules[0].Value != "jpg" {
  2670. logError(testName, function, args, startTime, "", "Couldn't get the suffix", err)
  2671. return
  2672. }
  2673. err = c.RemoveAllBucketNotification(bucketName)
  2674. if err != nil {
  2675. logError(testName, function, args, startTime, "", "RemoveAllBucketNotification failed", err)
  2676. return
  2677. }
  2678. // Delete all objects and buckets
  2679. if err = cleanupBucket(bucketName, c); err != nil {
  2680. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  2681. return
  2682. }
  2683. successLogger(testName, function, args, startTime).Info()
  2684. }
  2685. // Tests comprehensive list of all methods.
  2686. func testFunctional() {
  2687. // initialize logging params
  2688. startTime := time.Now()
  2689. testName := getFuncName()
  2690. function := "testFunctional()"
  2691. function_all := ""
  2692. args := map[string]interface{}{}
  2693. // Seed random based on current time.
  2694. rand.Seed(time.Now().Unix())
  2695. c, err := minio.New(
  2696. os.Getenv(serverEndpoint),
  2697. os.Getenv(accessKey),
  2698. os.Getenv(secretKey),
  2699. mustParseBool(os.Getenv(enableHTTPS)),
  2700. )
  2701. if err != nil {
  2702. logError(testName, function, nil, startTime, "", "Minio client object creation failed", err)
  2703. return
  2704. }
  2705. // Enable to debug
  2706. // c.TraceOn(os.Stderr)
  2707. // Set user agent.
  2708. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  2709. // Generate a new random bucket name.
  2710. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  2711. // Make a new bucket.
  2712. function = "MakeBucket(bucketName, region)"
  2713. function_all = "MakeBucket(bucketName, region)"
  2714. args["bucketName"] = bucketName
  2715. err = c.MakeBucket(bucketName, "us-east-1")
  2716. if err != nil {
  2717. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  2718. return
  2719. }
  2720. // Generate a random file name.
  2721. fileName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  2722. file, err := os.Create(fileName)
  2723. if err != nil {
  2724. logError(testName, function, args, startTime, "", "File creation failed", err)
  2725. return
  2726. }
  2727. for i := 0; i < 3; i++ {
  2728. buf := make([]byte, rand.Intn(1<<19))
  2729. _, err = file.Write(buf)
  2730. if err != nil {
  2731. logError(testName, function, args, startTime, "", "File write failed", err)
  2732. return
  2733. }
  2734. }
  2735. file.Close()
  2736. // Verify if bucket exits and you have access.
  2737. var exists bool
  2738. function = "BucketExists(bucketName)"
  2739. function_all += ", " + function
  2740. args = map[string]interface{}{
  2741. "bucketName": bucketName,
  2742. }
  2743. exists, err = c.BucketExists(bucketName)
  2744. if err != nil {
  2745. logError(testName, function, args, startTime, "", "BucketExists failed", err)
  2746. return
  2747. }
  2748. if !exists {
  2749. logError(testName, function, args, startTime, "", "Could not find the bucket", err)
  2750. return
  2751. }
  2752. // Asserting the default bucket policy.
  2753. function = "GetBucketPolicy(bucketName, objectPrefix)"
  2754. function_all += ", " + function
  2755. args = map[string]interface{}{
  2756. "bucketName": bucketName,
  2757. "objectPrefix": "",
  2758. }
  2759. policyAccess, err := c.GetBucketPolicy(bucketName, "")
  2760. if err != nil {
  2761. logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
  2762. return
  2763. }
  2764. if policyAccess != "none" {
  2765. logError(testName, function, args, startTime, "", "policy should be set to none", err)
  2766. return
  2767. }
  2768. // Set the bucket policy to 'public readonly'.
  2769. function = "SetBucketPolicy(bucketName, objectPrefix, bucketPolicy)"
  2770. function_all += ", " + function
  2771. args = map[string]interface{}{
  2772. "bucketName": bucketName,
  2773. "objectPrefix": "",
  2774. "bucketPolicy": policy.BucketPolicyReadOnly,
  2775. }
  2776. err = c.SetBucketPolicy(bucketName, "", policy.BucketPolicyReadOnly)
  2777. if err != nil {
  2778. logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
  2779. return
  2780. }
  2781. // should return policy `readonly`.
  2782. function = "GetBucketPolicy(bucketName, objectPrefix)"
  2783. function_all += ", " + function
  2784. args = map[string]interface{}{
  2785. "bucketName": bucketName,
  2786. "objectPrefix": "",
  2787. }
  2788. policyAccess, err = c.GetBucketPolicy(bucketName, "")
  2789. if err != nil {
  2790. logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
  2791. return
  2792. }
  2793. if policyAccess != "readonly" {
  2794. logError(testName, function, args, startTime, "", "policy should be set to readonly", err)
  2795. return
  2796. }
  2797. // Make the bucket 'public writeonly'.
  2798. function = "SetBucketPolicy(bucketName, objectPrefix, bucketPolicy)"
  2799. function_all += ", " + function
  2800. args = map[string]interface{}{
  2801. "bucketName": bucketName,
  2802. "objectPrefix": "",
  2803. "bucketPolicy": policy.BucketPolicyWriteOnly,
  2804. }
  2805. err = c.SetBucketPolicy(bucketName, "", policy.BucketPolicyWriteOnly)
  2806. if err != nil {
  2807. logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
  2808. return
  2809. }
  2810. // should return policy `writeonly`.
  2811. function = "GetBucketPolicy(bucketName, objectPrefix)"
  2812. function_all += ", " + function
  2813. args = map[string]interface{}{
  2814. "bucketName": bucketName,
  2815. "objectPrefix": "",
  2816. }
  2817. policyAccess, err = c.GetBucketPolicy(bucketName, "")
  2818. if err != nil {
  2819. logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
  2820. return
  2821. }
  2822. if policyAccess != "writeonly" {
  2823. logError(testName, function, args, startTime, "", "policy should be set to writeonly", err)
  2824. return
  2825. }
  2826. // Make the bucket 'public read/write'.
  2827. function = "SetBucketPolicy(bucketName, objectPrefix, bucketPolicy)"
  2828. function_all += ", " + function
  2829. args = map[string]interface{}{
  2830. "bucketName": bucketName,
  2831. "objectPrefix": "",
  2832. "bucketPolicy": policy.BucketPolicyReadWrite,
  2833. }
  2834. err = c.SetBucketPolicy(bucketName, "", policy.BucketPolicyReadWrite)
  2835. if err != nil {
  2836. logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
  2837. return
  2838. }
  2839. // should return policy `readwrite`.
  2840. function = "GetBucketPolicy(bucketName, objectPrefix)"
  2841. function_all += ", " + function
  2842. args = map[string]interface{}{
  2843. "bucketName": bucketName,
  2844. "objectPrefix": "",
  2845. }
  2846. policyAccess, err = c.GetBucketPolicy(bucketName, "")
  2847. if err != nil {
  2848. logError(testName, function, args, startTime, "", "GetBucketPolicy failed", err)
  2849. return
  2850. }
  2851. if policyAccess != "readwrite" {
  2852. logError(testName, function, args, startTime, "", "policy should be set to readwrite", err)
  2853. return
  2854. }
  2855. // List all buckets.
  2856. function = "ListBuckets()"
  2857. function_all += ", " + function
  2858. args = nil
  2859. buckets, err := c.ListBuckets()
  2860. if len(buckets) == 0 {
  2861. logError(testName, function, args, startTime, "", "Found bucket list to be empty", err)
  2862. return
  2863. }
  2864. if err != nil {
  2865. logError(testName, function, args, startTime, "", "ListBuckets failed", err)
  2866. return
  2867. }
  2868. // Verify if previously created bucket is listed in list buckets.
  2869. bucketFound := false
  2870. for _, bucket := range buckets {
  2871. if bucket.Name == bucketName {
  2872. bucketFound = true
  2873. }
  2874. }
  2875. // If bucket not found error out.
  2876. if !bucketFound {
  2877. logError(testName, function, args, startTime, "", "Bucket: "+bucketName+" not found", err)
  2878. return
  2879. }
  2880. objectName := bucketName + "unique"
  2881. // Generate data
  2882. buf := bytes.Repeat([]byte("f"), 1<<19)
  2883. function = "PutObject(bucketName, objectName, reader, contentType)"
  2884. function_all += ", " + function
  2885. args = map[string]interface{}{
  2886. "bucketName": bucketName,
  2887. "objectName": objectName,
  2888. "contentType": "",
  2889. }
  2890. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
  2891. if err != nil {
  2892. logError(testName, function, args, startTime, "", "PutObject failed", err)
  2893. return
  2894. }
  2895. if n != int64(len(buf)) {
  2896. logError(testName, function, args, startTime, "", "Length doesn't match, expected "+string(int64(len(buf)))+" got "+string(n), err)
  2897. return
  2898. }
  2899. args = map[string]interface{}{
  2900. "bucketName": bucketName,
  2901. "objectName": objectName + "-nolength",
  2902. "contentType": "binary/octet-stream",
  2903. }
  2904. n, err = c.PutObject(bucketName, objectName+"-nolength", bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  2905. if err != nil {
  2906. logError(testName, function, args, startTime, "", "PutObject failed", err)
  2907. return
  2908. }
  2909. if n != int64(len(buf)) {
  2910. logError(testName, function, args, startTime, "", "Length doesn't match, expected "+string(int64(len(buf)))+" got "+string(n), err)
  2911. return
  2912. }
  2913. // Instantiate a done channel to close all listing.
  2914. doneCh := make(chan struct{})
  2915. defer close(doneCh)
  2916. objFound := false
  2917. isRecursive := true // Recursive is true.
  2918. function = "ListObjects(bucketName, objectName, isRecursive, doneCh)"
  2919. function_all += ", " + function
  2920. args = map[string]interface{}{
  2921. "bucketName": bucketName,
  2922. "objectName": objectName,
  2923. "isRecursive": isRecursive,
  2924. }
  2925. for obj := range c.ListObjects(bucketName, objectName, isRecursive, doneCh) {
  2926. if obj.Key == objectName {
  2927. objFound = true
  2928. break
  2929. }
  2930. }
  2931. if !objFound {
  2932. logError(testName, function, args, startTime, "", "Object "+objectName+" not found", err)
  2933. return
  2934. }
  2935. objFound = false
  2936. isRecursive = true // Recursive is true.
  2937. function = "ListObjectsV2(bucketName, objectName, isRecursive, doneCh)"
  2938. function_all += ", " + function
  2939. args = map[string]interface{}{
  2940. "bucketName": bucketName,
  2941. "objectName": objectName,
  2942. "isRecursive": isRecursive,
  2943. }
  2944. for obj := range c.ListObjectsV2(bucketName, objectName, isRecursive, doneCh) {
  2945. if obj.Key == objectName {
  2946. objFound = true
  2947. break
  2948. }
  2949. }
  2950. if !objFound {
  2951. logError(testName, function, args, startTime, "", "Object "+objectName+" not found", err)
  2952. return
  2953. }
  2954. incompObjNotFound := true
  2955. function = "ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh)"
  2956. function_all += ", " + function
  2957. args = map[string]interface{}{
  2958. "bucketName": bucketName,
  2959. "objectName": objectName,
  2960. "isRecursive": isRecursive,
  2961. }
  2962. for objIncompl := range c.ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh) {
  2963. if objIncompl.Key != "" {
  2964. incompObjNotFound = false
  2965. break
  2966. }
  2967. }
  2968. if !incompObjNotFound {
  2969. logError(testName, function, args, startTime, "", "Unexpected dangling incomplete upload found", err)
  2970. return
  2971. }
  2972. function = "GetObject(bucketName, objectName)"
  2973. function_all += ", " + function
  2974. args = map[string]interface{}{
  2975. "bucketName": bucketName,
  2976. "objectName": objectName,
  2977. }
  2978. newReader, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  2979. if err != nil {
  2980. logError(testName, function, args, startTime, "", "GetObject failed", err)
  2981. return
  2982. }
  2983. newReadBytes, err := ioutil.ReadAll(newReader)
  2984. if err != nil {
  2985. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  2986. return
  2987. }
  2988. if !bytes.Equal(newReadBytes, buf) {
  2989. logError(testName, function, args, startTime, "", "GetObject bytes mismatch", err)
  2990. return
  2991. }
  2992. function = "FGetObject(bucketName, objectName, fileName)"
  2993. function_all += ", " + function
  2994. args = map[string]interface{}{
  2995. "bucketName": bucketName,
  2996. "objectName": objectName,
  2997. "fileName": fileName + "-f",
  2998. }
  2999. err = c.FGetObject(bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
  3000. if err != nil {
  3001. logError(testName, function, args, startTime, "", "FGetObject failed", err)
  3002. return
  3003. }
  3004. function = "PresignedHeadObject(bucketName, objectName, expires, reqParams)"
  3005. function_all += ", " + function
  3006. args = map[string]interface{}{
  3007. "bucketName": bucketName,
  3008. "objectName": "",
  3009. "expires": 3600 * time.Second,
  3010. }
  3011. if _, err = c.PresignedHeadObject(bucketName, "", 3600*time.Second, nil); err == nil {
  3012. logError(testName, function, args, startTime, "", "PresignedHeadObject success", err)
  3013. return
  3014. }
  3015. // Generate presigned HEAD object url.
  3016. function = "PresignedHeadObject(bucketName, objectName, expires, reqParams)"
  3017. function_all += ", " + function
  3018. args = map[string]interface{}{
  3019. "bucketName": bucketName,
  3020. "objectName": objectName,
  3021. "expires": 3600 * time.Second,
  3022. }
  3023. presignedHeadURL, err := c.PresignedHeadObject(bucketName, objectName, 3600*time.Second, nil)
  3024. if err != nil {
  3025. logError(testName, function, args, startTime, "", "PresignedHeadObject failed", err)
  3026. return
  3027. }
  3028. // Verify if presigned url works.
  3029. resp, err := http.Head(presignedHeadURL.String())
  3030. if err != nil {
  3031. logError(testName, function, args, startTime, "", "PresignedHeadObject response incorrect", err)
  3032. return
  3033. }
  3034. if resp.StatusCode != http.StatusOK {
  3035. logError(testName, function, args, startTime, "", "PresignedHeadObject response incorrect, status "+string(resp.StatusCode), err)
  3036. return
  3037. }
  3038. if resp.Header.Get("ETag") == "" {
  3039. logError(testName, function, args, startTime, "", "PresignedHeadObject response incorrect", err)
  3040. return
  3041. }
  3042. resp.Body.Close()
  3043. function = "PresignedGetObject(bucketName, objectName, expires, reqParams)"
  3044. function_all += ", " + function
  3045. args = map[string]interface{}{
  3046. "bucketName": bucketName,
  3047. "objectName": "",
  3048. "expires": 3600 * time.Second,
  3049. }
  3050. _, err = c.PresignedGetObject(bucketName, "", 3600*time.Second, nil)
  3051. if err == nil {
  3052. logError(testName, function, args, startTime, "", "PresignedGetObject success", err)
  3053. return
  3054. }
  3055. // Generate presigned GET object url.
  3056. function = "PresignedGetObject(bucketName, objectName, expires, reqParams)"
  3057. function_all += ", " + function
  3058. args = map[string]interface{}{
  3059. "bucketName": bucketName,
  3060. "objectName": objectName,
  3061. "expires": 3600 * time.Second,
  3062. }
  3063. presignedGetURL, err := c.PresignedGetObject(bucketName, objectName, 3600*time.Second, nil)
  3064. if err != nil {
  3065. logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
  3066. return
  3067. }
  3068. // Verify if presigned url works.
  3069. resp, err = http.Get(presignedGetURL.String())
  3070. if err != nil {
  3071. logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
  3072. return
  3073. }
  3074. if resp.StatusCode != http.StatusOK {
  3075. logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect, status "+string(resp.StatusCode), err)
  3076. return
  3077. }
  3078. newPresignedBytes, err := ioutil.ReadAll(resp.Body)
  3079. if err != nil {
  3080. logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
  3081. return
  3082. }
  3083. resp.Body.Close()
  3084. if !bytes.Equal(newPresignedBytes, buf) {
  3085. logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
  3086. return
  3087. }
  3088. // Set request parameters.
  3089. reqParams := make(url.Values)
  3090. reqParams.Set("response-content-disposition", "attachment; filename=\"test.txt\"")
  3091. args = map[string]interface{}{
  3092. "bucketName": bucketName,
  3093. "objectName": objectName,
  3094. "expires": 3600 * time.Second,
  3095. "reqParams": reqParams,
  3096. }
  3097. presignedGetURL, err = c.PresignedGetObject(bucketName, objectName, 3600*time.Second, reqParams)
  3098. if err != nil {
  3099. logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
  3100. return
  3101. }
  3102. // Verify if presigned url works.
  3103. resp, err = http.Get(presignedGetURL.String())
  3104. if err != nil {
  3105. logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
  3106. return
  3107. }
  3108. if resp.StatusCode != http.StatusOK {
  3109. logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect, status "+string(resp.StatusCode), err)
  3110. return
  3111. }
  3112. newPresignedBytes, err = ioutil.ReadAll(resp.Body)
  3113. if err != nil {
  3114. logError(testName, function, args, startTime, "", "PresignedGetObject response incorrect", err)
  3115. return
  3116. }
  3117. if !bytes.Equal(newPresignedBytes, buf) {
  3118. logError(testName, function, args, startTime, "", "Bytes mismatch for presigned GET URL", err)
  3119. return
  3120. }
  3121. if resp.Header.Get("Content-Disposition") != "attachment; filename=\"test.txt\"" {
  3122. logError(testName, function, args, startTime, "", "wrong Content-Disposition received "+string(resp.Header.Get("Content-Disposition")), err)
  3123. return
  3124. }
  3125. function = "PresignedPutObject(bucketName, objectName, expires)"
  3126. function_all += ", " + function
  3127. args = map[string]interface{}{
  3128. "bucketName": bucketName,
  3129. "objectName": "",
  3130. "expires": 3600 * time.Second,
  3131. }
  3132. _, err = c.PresignedPutObject(bucketName, "", 3600*time.Second)
  3133. if err == nil {
  3134. logError(testName, function, args, startTime, "", "PresignedPutObject success", err)
  3135. return
  3136. }
  3137. function = "PresignedPutObject(bucketName, objectName, expires)"
  3138. function_all += ", " + function
  3139. args = map[string]interface{}{
  3140. "bucketName": bucketName,
  3141. "objectName": objectName + "-presigned",
  3142. "expires": 3600 * time.Second,
  3143. }
  3144. presignedPutURL, err := c.PresignedPutObject(bucketName, objectName+"-presigned", 3600*time.Second)
  3145. if err != nil {
  3146. logError(testName, function, args, startTime, "", "PresignedPutObject failed", err)
  3147. return
  3148. }
  3149. buf = bytes.Repeat([]byte("g"), 1<<19)
  3150. req, err := http.NewRequest("PUT", presignedPutURL.String(), bytes.NewReader(buf))
  3151. if err != nil {
  3152. logError(testName, function, args, startTime, "", "Couldn't make HTTP request with PresignedPutObject URL", err)
  3153. return
  3154. }
  3155. httpClient := &http.Client{
  3156. // Setting a sensible time out of 30secs to wait for response
  3157. // headers. Request is pro-actively cancelled after 30secs
  3158. // with no response.
  3159. Timeout: 30 * time.Second,
  3160. Transport: http.DefaultTransport,
  3161. }
  3162. resp, err = httpClient.Do(req)
  3163. if err != nil {
  3164. logError(testName, function, args, startTime, "", "PresignedPutObject failed", err)
  3165. return
  3166. }
  3167. newReader, err = c.GetObject(bucketName, objectName+"-presigned", minio.GetObjectOptions{})
  3168. if err != nil {
  3169. logError(testName, function, args, startTime, "", "GetObject after PresignedPutObject failed", err)
  3170. return
  3171. }
  3172. newReadBytes, err = ioutil.ReadAll(newReader)
  3173. if err != nil {
  3174. logError(testName, function, args, startTime, "", "ReadAll after GetObject failed", err)
  3175. return
  3176. }
  3177. if !bytes.Equal(newReadBytes, buf) {
  3178. logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  3179. return
  3180. }
  3181. function = "RemoveObject(bucketName, objectName)"
  3182. function_all += ", " + function
  3183. args = map[string]interface{}{
  3184. "bucketName": bucketName,
  3185. "objectName": objectName,
  3186. }
  3187. err = c.RemoveObject(bucketName, objectName)
  3188. if err != nil {
  3189. logError(testName, function, args, startTime, "", "RemoveObject failed", err)
  3190. return
  3191. }
  3192. args["objectName"] = objectName + "-f"
  3193. err = c.RemoveObject(bucketName, objectName+"-f")
  3194. if err != nil {
  3195. logError(testName, function, args, startTime, "", "RemoveObject failed", err)
  3196. return
  3197. }
  3198. args["objectName"] = objectName + "-nolength"
  3199. err = c.RemoveObject(bucketName, objectName+"-nolength")
  3200. if err != nil {
  3201. logError(testName, function, args, startTime, "", "RemoveObject failed", err)
  3202. return
  3203. }
  3204. args["objectName"] = objectName + "-presigned"
  3205. err = c.RemoveObject(bucketName, objectName+"-presigned")
  3206. if err != nil {
  3207. logError(testName, function, args, startTime, "", "RemoveObject failed", err)
  3208. return
  3209. }
  3210. function = "RemoveBucket(bucketName)"
  3211. function_all += ", " + function
  3212. args = map[string]interface{}{
  3213. "bucketName": bucketName,
  3214. }
  3215. err = c.RemoveBucket(bucketName)
  3216. if err != nil {
  3217. logError(testName, function, args, startTime, "", "RemoveBucket failed", err)
  3218. return
  3219. }
  3220. err = c.RemoveBucket(bucketName)
  3221. if err == nil {
  3222. logError(testName, function, args, startTime, "", "RemoveBucket did not fail for invalid bucket name", err)
  3223. return
  3224. }
  3225. if err.Error() != "The specified bucket does not exist" {
  3226. logError(testName, function, args, startTime, "", "RemoveBucket failed", err)
  3227. return
  3228. }
  3229. if err = os.Remove(fileName); err != nil {
  3230. logError(testName, function, args, startTime, "", "File Remove failed", err)
  3231. return
  3232. }
  3233. if err = os.Remove(fileName + "-f"); err != nil {
  3234. logError(testName, function, args, startTime, "", "File Remove failed", err)
  3235. return
  3236. }
  3237. successLogger(testName, function_all, args, startTime).Info()
  3238. }
  3239. // Test for validating GetObject Reader* methods functioning when the
  3240. // object is modified in the object store.
  3241. func testGetObjectModified() {
  3242. // initialize logging params
  3243. startTime := time.Now()
  3244. testName := getFuncName()
  3245. function := "GetObject(bucketName, objectName)"
  3246. args := map[string]interface{}{}
  3247. // Instantiate new minio client object.
  3248. c, err := minio.NewV4(
  3249. os.Getenv(serverEndpoint),
  3250. os.Getenv(accessKey),
  3251. os.Getenv(secretKey),
  3252. mustParseBool(os.Getenv(enableHTTPS)),
  3253. )
  3254. if err != nil {
  3255. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  3256. return
  3257. }
  3258. // Enable tracing, write to stderr.
  3259. // c.TraceOn(os.Stderr)
  3260. // Set user agent.
  3261. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3262. // Make a new bucket.
  3263. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3264. args["bucketName"] = bucketName
  3265. err = c.MakeBucket(bucketName, "us-east-1")
  3266. if err != nil {
  3267. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3268. return
  3269. }
  3270. defer c.RemoveBucket(bucketName)
  3271. // Upload an object.
  3272. objectName := "myobject"
  3273. args["objectName"] = objectName
  3274. content := "helloworld"
  3275. _, err = c.PutObject(bucketName, objectName, strings.NewReader(content), int64(len(content)), minio.PutObjectOptions{ContentType: "application/text"})
  3276. if err != nil {
  3277. logError(testName, function, args, startTime, "", "Failed to upload "+objectName+", to bucket "+bucketName, err)
  3278. return
  3279. }
  3280. defer c.RemoveObject(bucketName, objectName)
  3281. reader, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  3282. if err != nil {
  3283. logError(testName, function, args, startTime, "", "Failed to GetObject "+objectName+", from bucket "+bucketName, err)
  3284. return
  3285. }
  3286. defer reader.Close()
  3287. // Read a few bytes of the object.
  3288. b := make([]byte, 5)
  3289. n, err := reader.ReadAt(b, 0)
  3290. if err != nil {
  3291. logError(testName, function, args, startTime, "", "Failed to read object "+objectName+", from bucket "+bucketName+" at an offset", err)
  3292. return
  3293. }
  3294. // Upload different contents to the same object while object is being read.
  3295. newContent := "goodbyeworld"
  3296. _, err = c.PutObject(bucketName, objectName, strings.NewReader(newContent), int64(len(newContent)), minio.PutObjectOptions{ContentType: "application/text"})
  3297. if err != nil {
  3298. logError(testName, function, args, startTime, "", "Failed to upload "+objectName+", to bucket "+bucketName, err)
  3299. return
  3300. }
  3301. // Confirm that a Stat() call in between doesn't change the Object's cached etag.
  3302. _, err = reader.Stat()
  3303. expectedError := "At least one of the pre-conditions you specified did not hold"
  3304. if err.Error() != expectedError {
  3305. logError(testName, function, args, startTime, "", "Expected Stat to fail with error "+expectedError+", but received "+err.Error(), err)
  3306. return
  3307. }
  3308. // Read again only to find object contents have been modified since last read.
  3309. _, err = reader.ReadAt(b, int64(n))
  3310. if err.Error() != expectedError {
  3311. logError(testName, function, args, startTime, "", "Expected ReadAt to fail with error "+expectedError+", but received "+err.Error(), err)
  3312. return
  3313. }
  3314. // Delete all objects and buckets
  3315. if err = cleanupBucket(bucketName, c); err != nil {
  3316. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3317. return
  3318. }
  3319. successLogger(testName, function, args, startTime).Info()
  3320. }
  3321. // Test validates putObject to upload a file seeked at a given offset.
  3322. func testPutObjectUploadSeekedObject() {
  3323. // initialize logging params
  3324. startTime := time.Now()
  3325. testName := getFuncName()
  3326. function := "PutObject(bucketName, objectName, fileToUpload, contentType)"
  3327. args := map[string]interface{}{
  3328. "bucketName": "",
  3329. "objectName": "",
  3330. "fileToUpload": "",
  3331. "contentType": "binary/octet-stream",
  3332. }
  3333. // Instantiate new minio client object.
  3334. c, err := minio.NewV4(
  3335. os.Getenv(serverEndpoint),
  3336. os.Getenv(accessKey),
  3337. os.Getenv(secretKey),
  3338. mustParseBool(os.Getenv(enableHTTPS)),
  3339. )
  3340. if err != nil {
  3341. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  3342. return
  3343. }
  3344. // Enable tracing, write to stderr.
  3345. // c.TraceOn(os.Stderr)
  3346. // Set user agent.
  3347. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3348. // Make a new bucket.
  3349. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3350. args["bucketName"] = bucketName
  3351. err = c.MakeBucket(bucketName, "us-east-1")
  3352. if err != nil {
  3353. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3354. return
  3355. }
  3356. defer c.RemoveBucket(bucketName)
  3357. var tempfile *os.File
  3358. if fileName := getMintDataDirFilePath("datafile-100-kB"); fileName != "" {
  3359. tempfile, err = os.Open(fileName)
  3360. if err != nil {
  3361. logError(testName, function, args, startTime, "", "File open failed", err)
  3362. return
  3363. }
  3364. args["fileToUpload"] = fileName
  3365. } else {
  3366. tempfile, err = ioutil.TempFile("", "minio-go-upload-test-")
  3367. if err != nil {
  3368. logError(testName, function, args, startTime, "", "TempFile create failed", err)
  3369. return
  3370. }
  3371. args["fileToUpload"] = tempfile.Name()
  3372. // Generate 100kB data
  3373. if _, err = io.Copy(tempfile, getDataReader("datafile-100-kB")); err != nil {
  3374. logError(testName, function, args, startTime, "", "File copy failed", err)
  3375. return
  3376. }
  3377. defer os.Remove(tempfile.Name())
  3378. // Seek back to the beginning of the file.
  3379. tempfile.Seek(0, 0)
  3380. }
  3381. var length = 100 * humanize.KiByte
  3382. objectName := fmt.Sprintf("test-file-%v", rand.Uint32())
  3383. args["objectName"] = objectName
  3384. offset := length / 2
  3385. if _, err = tempfile.Seek(int64(offset), 0); err != nil {
  3386. logError(testName, function, args, startTime, "", "TempFile seek failed", err)
  3387. return
  3388. }
  3389. n, err := c.PutObject(bucketName, objectName, tempfile, int64(length-offset), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  3390. if err != nil {
  3391. logError(testName, function, args, startTime, "", "PutObject failed", err)
  3392. return
  3393. }
  3394. if n != int64(length-offset) {
  3395. logError(testName, function, args, startTime, "", fmt.Sprintf("Invalid length returned, expected %d got %d", int64(length-offset), n), err)
  3396. return
  3397. }
  3398. tempfile.Close()
  3399. obj, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  3400. if err != nil {
  3401. logError(testName, function, args, startTime, "", "GetObject failed", err)
  3402. return
  3403. }
  3404. n, err = obj.Seek(int64(offset), 0)
  3405. if err != nil {
  3406. logError(testName, function, args, startTime, "", "Seek failed", err)
  3407. return
  3408. }
  3409. if n != int64(offset) {
  3410. logError(testName, function, args, startTime, "", fmt.Sprintf("Invalid offset returned, expected %d got %d", int64(offset), n), err)
  3411. return
  3412. }
  3413. n, err = c.PutObject(bucketName, objectName+"getobject", obj, int64(length-offset), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  3414. if err != nil {
  3415. logError(testName, function, args, startTime, "", "PutObject failed", err)
  3416. return
  3417. }
  3418. if n != int64(length-offset) {
  3419. logError(testName, function, args, startTime, "", fmt.Sprintf("Invalid offset returned, expected %d got %d", int64(length-offset), n), err)
  3420. return
  3421. }
  3422. // Delete all objects and buckets
  3423. if err = cleanupBucket(bucketName, c); err != nil {
  3424. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3425. return
  3426. }
  3427. successLogger(testName, function, args, startTime).Info()
  3428. }
  3429. // Tests bucket re-create errors.
  3430. func testMakeBucketErrorV2() {
  3431. // initialize logging params
  3432. startTime := time.Now()
  3433. testName := getFuncName()
  3434. function := "MakeBucket(bucketName, region)"
  3435. args := map[string]interface{}{
  3436. "bucketName": "",
  3437. "region": "eu-west-1",
  3438. }
  3439. if os.Getenv(serverEndpoint) != "s3.amazonaws.com" {
  3440. ignoredLog(testName, function, args, startTime, "Skipped region functional tests for non s3 runs").Info()
  3441. return
  3442. }
  3443. // Seed random based on current time.
  3444. rand.Seed(time.Now().Unix())
  3445. // Instantiate new minio client object.
  3446. c, err := minio.NewV2(
  3447. os.Getenv(serverEndpoint),
  3448. os.Getenv(accessKey),
  3449. os.Getenv(secretKey),
  3450. mustParseBool(os.Getenv(enableHTTPS)),
  3451. )
  3452. if err != nil {
  3453. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  3454. return
  3455. }
  3456. // Enable tracing, write to stderr.
  3457. // c.TraceOn(os.Stderr)
  3458. // Set user agent.
  3459. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3460. // Generate a new random bucket name.
  3461. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3462. region := "eu-west-1"
  3463. args["bucketName"] = bucketName
  3464. args["region"] = region
  3465. // Make a new bucket in 'eu-west-1'.
  3466. if err = c.MakeBucket(bucketName, region); err != nil {
  3467. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3468. return
  3469. }
  3470. if err = c.MakeBucket(bucketName, region); err == nil {
  3471. logError(testName, function, args, startTime, "", "MakeBucket did not fail for existing bucket name", err)
  3472. return
  3473. }
  3474. // Verify valid error response from server.
  3475. if minio.ToErrorResponse(err).Code != "BucketAlreadyExists" &&
  3476. minio.ToErrorResponse(err).Code != "BucketAlreadyOwnedByYou" {
  3477. logError(testName, function, args, startTime, "", "Invalid error returned by server", err)
  3478. }
  3479. // Delete all objects and buckets
  3480. if err = cleanupBucket(bucketName, c); err != nil {
  3481. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3482. return
  3483. }
  3484. successLogger(testName, function, args, startTime).Info()
  3485. }
  3486. // Test get object reader to not throw error on being closed twice.
  3487. func testGetObjectClosedTwiceV2() {
  3488. // initialize logging params
  3489. startTime := time.Now()
  3490. testName := getFuncName()
  3491. function := "MakeBucket(bucketName, region)"
  3492. args := map[string]interface{}{
  3493. "bucketName": "",
  3494. "region": "eu-west-1",
  3495. }
  3496. // Seed random based on current time.
  3497. rand.Seed(time.Now().Unix())
  3498. // Instantiate new minio client object.
  3499. c, err := minio.NewV2(
  3500. os.Getenv(serverEndpoint),
  3501. os.Getenv(accessKey),
  3502. os.Getenv(secretKey),
  3503. mustParseBool(os.Getenv(enableHTTPS)),
  3504. )
  3505. if err != nil {
  3506. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  3507. return
  3508. }
  3509. // Enable tracing, write to stderr.
  3510. // c.TraceOn(os.Stderr)
  3511. // Set user agent.
  3512. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3513. // Generate a new random bucket name.
  3514. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3515. args["bucketName"] = bucketName
  3516. // Make a new bucket.
  3517. err = c.MakeBucket(bucketName, "us-east-1")
  3518. if err != nil {
  3519. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3520. return
  3521. }
  3522. // Generate 33K of data.
  3523. bufSize := dataFileMap["datafile-33-kB"]
  3524. var reader = getDataReader("datafile-33-kB")
  3525. defer reader.Close()
  3526. // Save the data
  3527. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  3528. args["objectName"] = objectName
  3529. n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  3530. if err != nil {
  3531. logError(testName, function, args, startTime, "", "PutObject failed", err)
  3532. return
  3533. }
  3534. if n != int64(bufSize) {
  3535. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(bufSize)+" got "+string(n), err)
  3536. return
  3537. }
  3538. // Read the data back
  3539. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  3540. if err != nil {
  3541. logError(testName, function, args, startTime, "", "GetObject failed", err)
  3542. return
  3543. }
  3544. st, err := r.Stat()
  3545. if err != nil {
  3546. logError(testName, function, args, startTime, "", "Stat failed", err)
  3547. return
  3548. }
  3549. if st.Size != int64(bufSize) {
  3550. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(bufSize)+" got "+string(st.Size), err)
  3551. return
  3552. }
  3553. if err := r.Close(); err != nil {
  3554. logError(testName, function, args, startTime, "", "Stat failed", err)
  3555. return
  3556. }
  3557. if err := r.Close(); err == nil {
  3558. logError(testName, function, args, startTime, "", "Object is already closed, should return error", err)
  3559. return
  3560. }
  3561. // Delete all objects and buckets
  3562. if err = cleanupBucket(bucketName, c); err != nil {
  3563. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3564. return
  3565. }
  3566. successLogger(testName, function, args, startTime).Info()
  3567. }
  3568. // Tests removing partially uploaded objects.
  3569. func testRemovePartiallyUploadedV2() {
  3570. // initialize logging params
  3571. startTime := time.Now()
  3572. testName := getFuncName()
  3573. function := "RemoveIncompleteUpload(bucketName, objectName)"
  3574. args := map[string]interface{}{}
  3575. // Seed random based on current time.
  3576. rand.Seed(time.Now().Unix())
  3577. // Instantiate new minio client object.
  3578. c, err := minio.NewV2(
  3579. os.Getenv(serverEndpoint),
  3580. os.Getenv(accessKey),
  3581. os.Getenv(secretKey),
  3582. mustParseBool(os.Getenv(enableHTTPS)),
  3583. )
  3584. if err != nil {
  3585. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  3586. return
  3587. }
  3588. // Set user agent.
  3589. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3590. // Enable tracing, write to stdout.
  3591. // c.TraceOn(os.Stderr)
  3592. // Generate a new random bucket name.
  3593. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3594. args["bucketName"] = bucketName
  3595. // make a new bucket.
  3596. err = c.MakeBucket(bucketName, "us-east-1")
  3597. if err != nil {
  3598. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3599. return
  3600. }
  3601. r := bytes.NewReader(bytes.Repeat([]byte("a"), 128*1024))
  3602. reader, writer := io.Pipe()
  3603. go func() {
  3604. i := 0
  3605. for i < 25 {
  3606. _, cerr := io.CopyN(writer, r, 128*1024)
  3607. if cerr != nil {
  3608. logError(testName, function, args, startTime, "", "Copy failed", cerr)
  3609. return
  3610. }
  3611. i++
  3612. r.Seek(0, 0)
  3613. }
  3614. writer.CloseWithError(errors.New("proactively closed to be verified later"))
  3615. }()
  3616. objectName := bucketName + "-resumable"
  3617. args["objectName"] = objectName
  3618. _, err = c.PutObject(bucketName, objectName, reader, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"})
  3619. if err == nil {
  3620. logError(testName, function, args, startTime, "", "PutObject should fail", err)
  3621. return
  3622. }
  3623. if err.Error() != "proactively closed to be verified later" {
  3624. logError(testName, function, args, startTime, "", "Unexpected error, expected : proactively closed to be verified later", err)
  3625. return
  3626. }
  3627. err = c.RemoveIncompleteUpload(bucketName, objectName)
  3628. if err != nil {
  3629. logError(testName, function, args, startTime, "", "RemoveIncompleteUpload failed", err)
  3630. return
  3631. }
  3632. // Delete all objects and buckets
  3633. if err = cleanupBucket(bucketName, c); err != nil {
  3634. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3635. return
  3636. }
  3637. successLogger(testName, function, args, startTime).Info()
  3638. }
  3639. // Tests FPutObject hidden contentType setting
  3640. func testFPutObjectV2() {
  3641. // initialize logging params
  3642. startTime := time.Now()
  3643. testName := getFuncName()
  3644. function := "FPutObject(bucketName, objectName, fileName, opts)"
  3645. args := map[string]interface{}{
  3646. "bucketName": "",
  3647. "objectName": "",
  3648. "fileName": "",
  3649. "opts": "",
  3650. }
  3651. // Seed random based on current time.
  3652. rand.Seed(time.Now().Unix())
  3653. // Instantiate new minio client object.
  3654. c, err := minio.NewV2(
  3655. os.Getenv(serverEndpoint),
  3656. os.Getenv(accessKey),
  3657. os.Getenv(secretKey),
  3658. mustParseBool(os.Getenv(enableHTTPS)),
  3659. )
  3660. if err != nil {
  3661. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  3662. return
  3663. }
  3664. // Enable tracing, write to stderr.
  3665. // c.TraceOn(os.Stderr)
  3666. // Set user agent.
  3667. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3668. // Generate a new random bucket name.
  3669. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3670. args["bucketName"] = bucketName
  3671. // Make a new bucket.
  3672. err = c.MakeBucket(bucketName, "us-east-1")
  3673. if err != nil {
  3674. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3675. return
  3676. }
  3677. // Make a temp file with 11*1024*1024 bytes of data.
  3678. file, err := ioutil.TempFile(os.TempDir(), "FPutObjectTest")
  3679. if err != nil {
  3680. logError(testName, function, args, startTime, "", "TempFile creation failed", err)
  3681. return
  3682. }
  3683. r := bytes.NewReader(bytes.Repeat([]byte("b"), 11*1024*1024))
  3684. n, err := io.CopyN(file, r, 11*1024*1024)
  3685. if err != nil {
  3686. logError(testName, function, args, startTime, "", "Copy failed", err)
  3687. return
  3688. }
  3689. if n != int64(11*1024*1024) {
  3690. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(11*1024*1024))+" got "+string(n), err)
  3691. return
  3692. }
  3693. // Close the file pro-actively for windows.
  3694. err = file.Close()
  3695. if err != nil {
  3696. logError(testName, function, args, startTime, "", "File close failed", err)
  3697. return
  3698. }
  3699. // Set base object name
  3700. objectName := bucketName + "FPutObject"
  3701. args["objectName"] = objectName
  3702. args["fileName"] = file.Name()
  3703. // Perform standard FPutObject with contentType provided (Expecting application/octet-stream)
  3704. n, err = c.FPutObject(bucketName, objectName+"-standard", file.Name(), minio.PutObjectOptions{ContentType: "application/octet-stream"})
  3705. if err != nil {
  3706. logError(testName, function, args, startTime, "", "FPutObject failed", err)
  3707. return
  3708. }
  3709. if n != int64(11*1024*1024) {
  3710. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(11*1024*1024))+" got "+string(n), err)
  3711. return
  3712. }
  3713. // Perform FPutObject with no contentType provided (Expecting application/octet-stream)
  3714. args["objectName"] = objectName + "-Octet"
  3715. args["contentType"] = ""
  3716. n, err = c.FPutObject(bucketName, objectName+"-Octet", file.Name(), minio.PutObjectOptions{})
  3717. if err != nil {
  3718. logError(testName, function, args, startTime, "", "FPutObject failed", err)
  3719. return
  3720. }
  3721. if n != int64(11*1024*1024) {
  3722. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(11*1024*1024))+" got "+string(n), err)
  3723. return
  3724. }
  3725. // Add extension to temp file name
  3726. fileName := file.Name()
  3727. err = os.Rename(file.Name(), fileName+".gtar")
  3728. if err != nil {
  3729. logError(testName, function, args, startTime, "", "Rename failed", err)
  3730. return
  3731. }
  3732. // Perform FPutObject with no contentType provided (Expecting application/x-gtar)
  3733. args["objectName"] = objectName + "-Octet"
  3734. args["contentType"] = ""
  3735. args["fileName"] = fileName + ".gtar"
  3736. n, err = c.FPutObject(bucketName, objectName+"-GTar", fileName+".gtar", minio.PutObjectOptions{})
  3737. if err != nil {
  3738. logError(testName, function, args, startTime, "", "FPutObject failed", err)
  3739. return
  3740. }
  3741. if n != int64(11*1024*1024) {
  3742. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(11*1024*1024))+" got "+string(n), err)
  3743. return
  3744. }
  3745. // Check headers
  3746. rStandard, err := c.StatObject(bucketName, objectName+"-standard", minio.StatObjectOptions{})
  3747. if err != nil {
  3748. logError(testName, function, args, startTime, "", "StatObject failed", err)
  3749. return
  3750. }
  3751. if rStandard.ContentType != "application/octet-stream" {
  3752. logError(testName, function, args, startTime, "", "Content-Type headers mismatched, expected: application/octet-stream , got "+rStandard.ContentType, err)
  3753. return
  3754. }
  3755. rOctet, err := c.StatObject(bucketName, objectName+"-Octet", minio.StatObjectOptions{})
  3756. if err != nil {
  3757. logError(testName, function, args, startTime, "", "StatObject failed", err)
  3758. return
  3759. }
  3760. if rOctet.ContentType != "application/octet-stream" {
  3761. logError(testName, function, args, startTime, "", "Content-Type headers mismatched, expected: application/octet-stream , got "+rOctet.ContentType, err)
  3762. return
  3763. }
  3764. rGTar, err := c.StatObject(bucketName, objectName+"-GTar", minio.StatObjectOptions{})
  3765. if err != nil {
  3766. logError(testName, function, args, startTime, "", "StatObject failed", err)
  3767. return
  3768. }
  3769. if rGTar.ContentType != "application/x-gtar" {
  3770. logError(testName, function, args, startTime, "", "Content-Type headers mismatched, expected: application/x-gtar , got "+rGTar.ContentType, err)
  3771. return
  3772. }
  3773. // Delete all objects and buckets
  3774. if err = cleanupBucket(bucketName, c); err != nil {
  3775. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3776. return
  3777. }
  3778. err = os.Remove(fileName + ".gtar")
  3779. if err != nil {
  3780. logError(testName, function, args, startTime, "", "File remove failed", err)
  3781. return
  3782. }
  3783. successLogger(testName, function, args, startTime).Info()
  3784. }
  3785. // Tests various bucket supported formats.
  3786. func testMakeBucketRegionsV2() {
  3787. // initialize logging params
  3788. startTime := time.Now()
  3789. testName := getFuncName()
  3790. function := "MakeBucket(bucketName, region)"
  3791. args := map[string]interface{}{
  3792. "bucketName": "",
  3793. "region": "eu-west-1",
  3794. }
  3795. if os.Getenv(serverEndpoint) != "s3.amazonaws.com" {
  3796. ignoredLog(testName, function, args, startTime, "Skipped region functional tests for non s3 runs").Info()
  3797. return
  3798. }
  3799. // Seed random based on current time.
  3800. rand.Seed(time.Now().Unix())
  3801. // Instantiate new minio client object.
  3802. c, err := minio.NewV2(
  3803. os.Getenv(serverEndpoint),
  3804. os.Getenv(accessKey),
  3805. os.Getenv(secretKey),
  3806. mustParseBool(os.Getenv(enableHTTPS)),
  3807. )
  3808. if err != nil {
  3809. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  3810. return
  3811. }
  3812. // Enable tracing, write to stderr.
  3813. // c.TraceOn(os.Stderr)
  3814. // Set user agent.
  3815. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3816. // Generate a new random bucket name.
  3817. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3818. args["bucketName"] = bucketName
  3819. // Make a new bucket in 'eu-central-1'.
  3820. if err = c.MakeBucket(bucketName, "eu-west-1"); err != nil {
  3821. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3822. return
  3823. }
  3824. if err = cleanupBucket(bucketName, c); err != nil {
  3825. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3826. return
  3827. }
  3828. // Make a new bucket with '.' in its name, in 'us-west-2'. This
  3829. // request is internally staged into a path style instead of
  3830. // virtual host style.
  3831. if err = c.MakeBucket(bucketName+".withperiod", "us-west-2"); err != nil {
  3832. args["bucketName"] = bucketName + ".withperiod"
  3833. args["region"] = "us-west-2"
  3834. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3835. return
  3836. }
  3837. // Delete all objects and buckets
  3838. if err = cleanupBucket(bucketName+".withperiod", c); err != nil {
  3839. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3840. return
  3841. }
  3842. successLogger(testName, function, args, startTime).Info()
  3843. }
  3844. // Tests get object ReaderSeeker interface methods.
  3845. func testGetObjectReadSeekFunctionalV2() {
  3846. // initialize logging params
  3847. startTime := time.Now()
  3848. testName := getFuncName()
  3849. function := "GetObject(bucketName, objectName)"
  3850. args := map[string]interface{}{}
  3851. // Seed random based on current time.
  3852. rand.Seed(time.Now().Unix())
  3853. // Instantiate new minio client object.
  3854. c, err := minio.NewV2(
  3855. os.Getenv(serverEndpoint),
  3856. os.Getenv(accessKey),
  3857. os.Getenv(secretKey),
  3858. mustParseBool(os.Getenv(enableHTTPS)),
  3859. )
  3860. if err != nil {
  3861. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  3862. return
  3863. }
  3864. // Enable tracing, write to stderr.
  3865. // c.TraceOn(os.Stderr)
  3866. // Set user agent.
  3867. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  3868. // Generate a new random bucket name.
  3869. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  3870. args["bucketName"] = bucketName
  3871. // Make a new bucket.
  3872. err = c.MakeBucket(bucketName, "us-east-1")
  3873. if err != nil {
  3874. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  3875. return
  3876. }
  3877. // Generate 33K of data.
  3878. bufSize := dataFileMap["datafile-33-kB"]
  3879. var reader = getDataReader("datafile-33-kB")
  3880. defer reader.Close()
  3881. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  3882. args["objectName"] = objectName
  3883. buf, err := ioutil.ReadAll(reader)
  3884. if err != nil {
  3885. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  3886. return
  3887. }
  3888. // Save the data.
  3889. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  3890. if err != nil {
  3891. logError(testName, function, args, startTime, "", "PutObject failed", err)
  3892. return
  3893. }
  3894. if n != int64(bufSize) {
  3895. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+" got "+string(n), err)
  3896. return
  3897. }
  3898. // Read the data back
  3899. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  3900. if err != nil {
  3901. logError(testName, function, args, startTime, "", "GetObject failed", err)
  3902. return
  3903. }
  3904. st, err := r.Stat()
  3905. if err != nil {
  3906. logError(testName, function, args, startTime, "", "Stat failed", err)
  3907. return
  3908. }
  3909. if st.Size != int64(bufSize) {
  3910. logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(int64(bufSize))+" got "+string(st.Size), err)
  3911. return
  3912. }
  3913. offset := int64(2048)
  3914. n, err = r.Seek(offset, 0)
  3915. if err != nil {
  3916. logError(testName, function, args, startTime, "", "Seek failed", err)
  3917. return
  3918. }
  3919. if n != offset {
  3920. logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(offset)+" got "+string(n), err)
  3921. return
  3922. }
  3923. n, err = r.Seek(0, 1)
  3924. if err != nil {
  3925. logError(testName, function, args, startTime, "", "Seek failed", err)
  3926. return
  3927. }
  3928. if n != offset {
  3929. logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(offset)+" got "+string(n), err)
  3930. return
  3931. }
  3932. _, err = r.Seek(offset, 2)
  3933. if err == nil {
  3934. logError(testName, function, args, startTime, "", "Seek on positive offset for whence '2' should error out", err)
  3935. return
  3936. }
  3937. n, err = r.Seek(-offset, 2)
  3938. if err != nil {
  3939. logError(testName, function, args, startTime, "", "Seek failed", err)
  3940. return
  3941. }
  3942. if n != st.Size-offset {
  3943. logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(st.Size-offset)+" got "+string(n), err)
  3944. return
  3945. }
  3946. var buffer1 bytes.Buffer
  3947. if _, err = io.CopyN(&buffer1, r, st.Size); err != nil {
  3948. if err != io.EOF {
  3949. logError(testName, function, args, startTime, "", "Copy failed", err)
  3950. return
  3951. }
  3952. }
  3953. if !bytes.Equal(buf[len(buf)-int(offset):], buffer1.Bytes()) {
  3954. logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
  3955. return
  3956. }
  3957. // Seek again and read again.
  3958. n, err = r.Seek(offset-1, 0)
  3959. if err != nil {
  3960. logError(testName, function, args, startTime, "", "Seek failed", err)
  3961. return
  3962. }
  3963. if n != (offset - 1) {
  3964. logError(testName, function, args, startTime, "", "Number of seeked bytes does not match, expected "+string(offset-1)+" got "+string(n), err)
  3965. return
  3966. }
  3967. var buffer2 bytes.Buffer
  3968. if _, err = io.CopyN(&buffer2, r, st.Size); err != nil {
  3969. if err != io.EOF {
  3970. logError(testName, function, args, startTime, "", "Copy failed", err)
  3971. return
  3972. }
  3973. }
  3974. // Verify now lesser bytes.
  3975. if !bytes.Equal(buf[2047:], buffer2.Bytes()) {
  3976. logError(testName, function, args, startTime, "", "Incorrect read bytes v/s original buffer", err)
  3977. return
  3978. }
  3979. // Delete all objects and buckets
  3980. if err = cleanupBucket(bucketName, c); err != nil {
  3981. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  3982. return
  3983. }
  3984. successLogger(testName, function, args, startTime).Info()
  3985. }
  3986. // Tests get object ReaderAt interface methods.
  3987. func testGetObjectReadAtFunctionalV2() {
  3988. // initialize logging params
  3989. startTime := time.Now()
  3990. testName := getFuncName()
  3991. function := "GetObject(bucketName, objectName)"
  3992. args := map[string]interface{}{}
  3993. // Seed random based on current time.
  3994. rand.Seed(time.Now().Unix())
  3995. // Instantiate new minio client object.
  3996. c, err := minio.NewV2(
  3997. os.Getenv(serverEndpoint),
  3998. os.Getenv(accessKey),
  3999. os.Getenv(secretKey),
  4000. mustParseBool(os.Getenv(enableHTTPS)),
  4001. )
  4002. if err != nil {
  4003. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  4004. return
  4005. }
  4006. // Enable tracing, write to stderr.
  4007. // c.TraceOn(os.Stderr)
  4008. // Set user agent.
  4009. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  4010. // Generate a new random bucket name.
  4011. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  4012. args["bucketName"] = bucketName
  4013. // Make a new bucket.
  4014. err = c.MakeBucket(bucketName, "us-east-1")
  4015. if err != nil {
  4016. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4017. return
  4018. }
  4019. // Generate 33K of data.
  4020. bufSize := dataFileMap["datafile-33-kB"]
  4021. var reader = getDataReader("datafile-33-kB")
  4022. defer reader.Close()
  4023. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  4024. args["objectName"] = objectName
  4025. buf, err := ioutil.ReadAll(reader)
  4026. if err != nil {
  4027. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  4028. return
  4029. }
  4030. // Save the data
  4031. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  4032. if err != nil {
  4033. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4034. return
  4035. }
  4036. if n != int64(bufSize) {
  4037. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(bufSize)+" got "+string(n), err)
  4038. return
  4039. }
  4040. // Read the data back
  4041. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  4042. if err != nil {
  4043. logError(testName, function, args, startTime, "", "GetObject failed", err)
  4044. return
  4045. }
  4046. st, err := r.Stat()
  4047. if err != nil {
  4048. logError(testName, function, args, startTime, "", "Stat failed", err)
  4049. return
  4050. }
  4051. if st.Size != int64(bufSize) {
  4052. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(bufSize)+" got "+string(st.Size), err)
  4053. return
  4054. }
  4055. offset := int64(2048)
  4056. // Read directly
  4057. buf2 := make([]byte, 512)
  4058. buf3 := make([]byte, 512)
  4059. buf4 := make([]byte, 512)
  4060. m, err := r.ReadAt(buf2, offset)
  4061. if err != nil {
  4062. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  4063. return
  4064. }
  4065. if m != len(buf2) {
  4066. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf2))+" got "+string(m), err)
  4067. return
  4068. }
  4069. if !bytes.Equal(buf2, buf[offset:offset+512]) {
  4070. logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
  4071. return
  4072. }
  4073. offset += 512
  4074. m, err = r.ReadAt(buf3, offset)
  4075. if err != nil {
  4076. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  4077. return
  4078. }
  4079. if m != len(buf3) {
  4080. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf3))+" got "+string(m), err)
  4081. return
  4082. }
  4083. if !bytes.Equal(buf3, buf[offset:offset+512]) {
  4084. logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
  4085. return
  4086. }
  4087. offset += 512
  4088. m, err = r.ReadAt(buf4, offset)
  4089. if err != nil {
  4090. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  4091. return
  4092. }
  4093. if m != len(buf4) {
  4094. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf4))+" got "+string(m), err)
  4095. return
  4096. }
  4097. if !bytes.Equal(buf4, buf[offset:offset+512]) {
  4098. logError(testName, function, args, startTime, "", "Incorrect read between two ReadAt from same offset", err)
  4099. return
  4100. }
  4101. buf5 := make([]byte, n)
  4102. // Read the whole object.
  4103. m, err = r.ReadAt(buf5, 0)
  4104. if err != nil {
  4105. if err != io.EOF {
  4106. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  4107. return
  4108. }
  4109. }
  4110. if m != len(buf5) {
  4111. logError(testName, function, args, startTime, "", "ReadAt read shorter bytes before reaching EOF, expected "+string(len(buf5))+" got "+string(m), err)
  4112. return
  4113. }
  4114. if !bytes.Equal(buf, buf5) {
  4115. logError(testName, function, args, startTime, "", "Incorrect data read in GetObject, than what was previously uploaded", err)
  4116. return
  4117. }
  4118. buf6 := make([]byte, n+1)
  4119. // Read the whole object and beyond.
  4120. _, err = r.ReadAt(buf6, 0)
  4121. if err != nil {
  4122. if err != io.EOF {
  4123. logError(testName, function, args, startTime, "", "ReadAt failed", err)
  4124. return
  4125. }
  4126. }
  4127. // Delete all objects and buckets
  4128. if err = cleanupBucket(bucketName, c); err != nil {
  4129. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  4130. return
  4131. }
  4132. successLogger(testName, function, args, startTime).Info()
  4133. }
  4134. // Tests copy object
  4135. func testCopyObjectV2() {
  4136. // initialize logging params
  4137. startTime := time.Now()
  4138. testName := getFuncName()
  4139. function := "CopyObject(destination, source)"
  4140. args := map[string]interface{}{}
  4141. // Seed random based on current time.
  4142. rand.Seed(time.Now().Unix())
  4143. // Instantiate new minio client object
  4144. c, err := minio.NewV2(
  4145. os.Getenv(serverEndpoint),
  4146. os.Getenv(accessKey),
  4147. os.Getenv(secretKey),
  4148. mustParseBool(os.Getenv(enableHTTPS)),
  4149. )
  4150. if err != nil {
  4151. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  4152. return
  4153. }
  4154. // Enable tracing, write to stderr.
  4155. // c.TraceOn(os.Stderr)
  4156. // Set user agent.
  4157. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  4158. // Generate a new random bucket name.
  4159. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  4160. // Make a new bucket in 'us-east-1' (source bucket).
  4161. err = c.MakeBucket(bucketName, "us-east-1")
  4162. if err != nil {
  4163. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4164. return
  4165. }
  4166. // Make a new bucket in 'us-east-1' (destination bucket).
  4167. err = c.MakeBucket(bucketName+"-copy", "us-east-1")
  4168. if err != nil {
  4169. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4170. return
  4171. }
  4172. // Generate 33K of data.
  4173. bufSize := dataFileMap["datafile-33-kB"]
  4174. var reader = getDataReader("datafile-33-kB")
  4175. defer reader.Close()
  4176. // Save the data
  4177. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  4178. n, err := c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  4179. if err != nil {
  4180. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4181. return
  4182. }
  4183. if n != int64(bufSize) {
  4184. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(int64(bufSize))+" got "+string(n), err)
  4185. return
  4186. }
  4187. r, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  4188. if err != nil {
  4189. logError(testName, function, args, startTime, "", "GetObject failed", err)
  4190. return
  4191. }
  4192. // Check the various fields of source object against destination object.
  4193. objInfo, err := r.Stat()
  4194. if err != nil {
  4195. logError(testName, function, args, startTime, "", "Stat failed", err)
  4196. return
  4197. }
  4198. // Copy Source
  4199. src := minio.NewSourceInfo(bucketName, objectName, nil)
  4200. args["source"] = src
  4201. // Set copy conditions.
  4202. // All invalid conditions first.
  4203. err = src.SetModifiedSinceCond(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC))
  4204. if err == nil {
  4205. logError(testName, function, args, startTime, "", "SetModifiedSinceCond did not fail for invalid conditions", err)
  4206. return
  4207. }
  4208. err = src.SetUnmodifiedSinceCond(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC))
  4209. if err == nil {
  4210. logError(testName, function, args, startTime, "", "SetUnmodifiedSinceCond did not fail for invalid conditions", err)
  4211. return
  4212. }
  4213. err = src.SetMatchETagCond("")
  4214. if err == nil {
  4215. logError(testName, function, args, startTime, "", "SetMatchETagCond did not fail for invalid conditions", err)
  4216. return
  4217. }
  4218. err = src.SetMatchETagExceptCond("")
  4219. if err == nil {
  4220. logError(testName, function, args, startTime, "", "SetMatchETagExceptCond did not fail for invalid conditions", err)
  4221. return
  4222. }
  4223. err = src.SetModifiedSinceCond(time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC))
  4224. if err != nil {
  4225. logError(testName, function, args, startTime, "", "SetModifiedSinceCond failed", err)
  4226. return
  4227. }
  4228. err = src.SetMatchETagCond(objInfo.ETag)
  4229. if err != nil {
  4230. logError(testName, function, args, startTime, "", "SetMatchETagCond failed", err)
  4231. return
  4232. }
  4233. dst, err := minio.NewDestinationInfo(bucketName+"-copy", objectName+"-copy", nil, nil)
  4234. args["destination"] = dst
  4235. if err != nil {
  4236. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4237. return
  4238. }
  4239. // Perform the Copy
  4240. err = c.CopyObject(dst, src)
  4241. if err != nil {
  4242. logError(testName, function, args, startTime, "", "CopyObject failed", err)
  4243. return
  4244. }
  4245. // Source object
  4246. r, err = c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  4247. if err != nil {
  4248. logError(testName, function, args, startTime, "", "GetObject failed", err)
  4249. return
  4250. }
  4251. // Destination object
  4252. readerCopy, err := c.GetObject(bucketName+"-copy", objectName+"-copy", minio.GetObjectOptions{})
  4253. if err != nil {
  4254. logError(testName, function, args, startTime, "", "GetObject failed", err)
  4255. return
  4256. }
  4257. // Check the various fields of source object against destination object.
  4258. objInfo, err = r.Stat()
  4259. if err != nil {
  4260. logError(testName, function, args, startTime, "", "Stat failed", err)
  4261. return
  4262. }
  4263. objInfoCopy, err := readerCopy.Stat()
  4264. if err != nil {
  4265. logError(testName, function, args, startTime, "", "Stat failed", err)
  4266. return
  4267. }
  4268. if objInfo.Size != objInfoCopy.Size {
  4269. logError(testName, function, args, startTime, "", "Number of bytes does not match, expected "+string(objInfoCopy.Size)+" got "+string(objInfo.Size), err)
  4270. return
  4271. }
  4272. // CopyObject again but with wrong conditions
  4273. src = minio.NewSourceInfo(bucketName, objectName, nil)
  4274. err = src.SetUnmodifiedSinceCond(time.Date(2014, time.April, 0, 0, 0, 0, 0, time.UTC))
  4275. if err != nil {
  4276. logError(testName, function, args, startTime, "", "SetUnmodifiedSinceCond failed", err)
  4277. return
  4278. }
  4279. err = src.SetMatchETagExceptCond(objInfo.ETag)
  4280. if err != nil {
  4281. logError(testName, function, args, startTime, "", "SetMatchETagExceptCond failed", err)
  4282. return
  4283. }
  4284. // Perform the Copy which should fail
  4285. err = c.CopyObject(dst, src)
  4286. if err == nil {
  4287. logError(testName, function, args, startTime, "", "CopyObject did not fail for invalid conditions", err)
  4288. return
  4289. }
  4290. // Delete all objects and buckets
  4291. if err = cleanupBucket(bucketName, c); err != nil {
  4292. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  4293. return
  4294. }
  4295. if err = cleanupBucket(bucketName+"-copy", c); err != nil {
  4296. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  4297. return
  4298. }
  4299. successLogger(testName, function, args, startTime).Info()
  4300. }
  4301. func testComposeObjectErrorCasesWrapper(c *minio.Client) {
  4302. // initialize logging params
  4303. startTime := time.Now()
  4304. testName := getFuncName()
  4305. function := "ComposeObject(destination, sourceList)"
  4306. args := map[string]interface{}{}
  4307. // Generate a new random bucket name.
  4308. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  4309. // Make a new bucket in 'us-east-1' (source bucket).
  4310. err := c.MakeBucket(bucketName, "us-east-1")
  4311. if err != nil {
  4312. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4313. return
  4314. }
  4315. // Test that more than 10K source objects cannot be
  4316. // concatenated.
  4317. srcArr := [10001]minio.SourceInfo{}
  4318. srcSlice := srcArr[:]
  4319. dst, err := minio.NewDestinationInfo(bucketName, "object", nil, nil)
  4320. if err != nil {
  4321. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4322. return
  4323. }
  4324. args["destination"] = dst
  4325. // Just explain about srcArr in args["sourceList"]
  4326. // to stop having 10,001 null headers logged
  4327. args["sourceList"] = "source array of 10,001 elements"
  4328. if err := c.ComposeObject(dst, srcSlice); err == nil {
  4329. logError(testName, function, args, startTime, "", "Expected error in ComposeObject", err)
  4330. return
  4331. } else if err.Error() != "There must be as least one and up to 10000 source objects." {
  4332. logError(testName, function, args, startTime, "", "Got unexpected error", err)
  4333. return
  4334. }
  4335. // Create a source with invalid offset spec and check that
  4336. // error is returned:
  4337. // 1. Create the source object.
  4338. const badSrcSize = 5 * 1024 * 1024
  4339. buf := bytes.Repeat([]byte("1"), badSrcSize)
  4340. _, err = c.PutObject(bucketName, "badObject", bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
  4341. if err != nil {
  4342. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4343. return
  4344. }
  4345. // 2. Set invalid range spec on the object (going beyond
  4346. // object size)
  4347. badSrc := minio.NewSourceInfo(bucketName, "badObject", nil)
  4348. err = badSrc.SetRange(1, badSrcSize)
  4349. if err != nil {
  4350. logError(testName, function, args, startTime, "", "Setting NewSourceInfo failed", err)
  4351. return
  4352. }
  4353. // 3. ComposeObject call should fail.
  4354. if err := c.ComposeObject(dst, []minio.SourceInfo{badSrc}); err == nil {
  4355. logError(testName, function, args, startTime, "", "ComposeObject expected to fail", err)
  4356. return
  4357. } else if !strings.Contains(err.Error(), "has invalid segment-to-copy") {
  4358. logError(testName, function, args, startTime, "", "Got invalid error", err)
  4359. return
  4360. }
  4361. // Delete all objects and buckets
  4362. if err = cleanupBucket(bucketName, c); err != nil {
  4363. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  4364. return
  4365. }
  4366. successLogger(testName, function, args, startTime).Info()
  4367. }
  4368. // Test expected error cases
  4369. func testComposeObjectErrorCasesV2() {
  4370. // initialize logging params
  4371. startTime := time.Now()
  4372. testName := getFuncName()
  4373. function := "ComposeObject(destination, sourceList)"
  4374. args := map[string]interface{}{}
  4375. // Instantiate new minio client object
  4376. c, err := minio.NewV2(
  4377. os.Getenv(serverEndpoint),
  4378. os.Getenv(accessKey),
  4379. os.Getenv(secretKey),
  4380. mustParseBool(os.Getenv(enableHTTPS)),
  4381. )
  4382. if err != nil {
  4383. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  4384. return
  4385. }
  4386. testComposeObjectErrorCasesWrapper(c)
  4387. }
  4388. func testComposeMultipleSources(c *minio.Client) {
  4389. // initialize logging params
  4390. startTime := time.Now()
  4391. testName := getFuncName()
  4392. function := "ComposeObject(destination, sourceList)"
  4393. args := map[string]interface{}{
  4394. "destination": "",
  4395. "sourceList": "",
  4396. }
  4397. // Generate a new random bucket name.
  4398. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  4399. // Make a new bucket in 'us-east-1' (source bucket).
  4400. err := c.MakeBucket(bucketName, "us-east-1")
  4401. if err != nil {
  4402. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4403. return
  4404. }
  4405. // Upload a small source object
  4406. const srcSize = 1024 * 1024 * 5
  4407. buf := bytes.Repeat([]byte("1"), srcSize)
  4408. _, err = c.PutObject(bucketName, "srcObject", bytes.NewReader(buf), int64(srcSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  4409. if err != nil {
  4410. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4411. return
  4412. }
  4413. // We will append 10 copies of the object.
  4414. srcs := []minio.SourceInfo{}
  4415. for i := 0; i < 10; i++ {
  4416. srcs = append(srcs, minio.NewSourceInfo(bucketName, "srcObject", nil))
  4417. }
  4418. // make the last part very small
  4419. err = srcs[9].SetRange(0, 0)
  4420. if err != nil {
  4421. logError(testName, function, args, startTime, "", "SetRange failed", err)
  4422. return
  4423. }
  4424. args["sourceList"] = srcs
  4425. dst, err := minio.NewDestinationInfo(bucketName, "dstObject", nil, nil)
  4426. args["destination"] = dst
  4427. if err != nil {
  4428. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4429. return
  4430. }
  4431. err = c.ComposeObject(dst, srcs)
  4432. if err != nil {
  4433. logError(testName, function, args, startTime, "", "ComposeObject failed", err)
  4434. return
  4435. }
  4436. objProps, err := c.StatObject(bucketName, "dstObject", minio.StatObjectOptions{})
  4437. if err != nil {
  4438. logError(testName, function, args, startTime, "", "StatObject failed", err)
  4439. return
  4440. }
  4441. if objProps.Size != 9*srcSize+1 {
  4442. logError(testName, function, args, startTime, "", "Size mismatched! Expected "+string(10000*srcSize)+" got "+string(objProps.Size), err)
  4443. return
  4444. }
  4445. // Delete all objects and buckets
  4446. if err = cleanupBucket(bucketName, c); err != nil {
  4447. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  4448. return
  4449. }
  4450. successLogger(testName, function, args, startTime).Info()
  4451. }
  4452. // Test concatenating multiple objects objects
  4453. func testCompose10KSourcesV2() {
  4454. // initialize logging params
  4455. startTime := time.Now()
  4456. testName := getFuncName()
  4457. function := "ComposeObject(destination, sourceList)"
  4458. args := map[string]interface{}{}
  4459. // Instantiate new minio client object
  4460. c, err := minio.NewV2(
  4461. os.Getenv(serverEndpoint),
  4462. os.Getenv(accessKey),
  4463. os.Getenv(secretKey),
  4464. mustParseBool(os.Getenv(enableHTTPS)),
  4465. )
  4466. if err != nil {
  4467. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  4468. return
  4469. }
  4470. testComposeMultipleSources(c)
  4471. }
  4472. func testEncryptedCopyObjectWrapper(c *minio.Client) {
  4473. // initialize logging params
  4474. startTime := time.Now()
  4475. testName := getFuncName()
  4476. function := "CopyObject(destination, source)"
  4477. args := map[string]interface{}{}
  4478. // Generate a new random bucket name.
  4479. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  4480. // Make a new bucket in 'us-east-1' (source bucket).
  4481. err := c.MakeBucket(bucketName, "us-east-1")
  4482. if err != nil {
  4483. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4484. return
  4485. }
  4486. key1 := minio.NewSSEInfo([]byte("32byteslongsecretkeymustbegiven1"), "AES256")
  4487. key2 := minio.NewSSEInfo([]byte("32byteslongsecretkeymustbegiven2"), "AES256")
  4488. // 1. create an sse-c encrypted object to copy by uploading
  4489. const srcSize = 1024 * 1024
  4490. buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 5MiB
  4491. metadata := make(map[string]string)
  4492. for k, v := range key1.GetSSEHeaders() {
  4493. metadata[k] = v
  4494. }
  4495. _, err = c.PutObject(bucketName, "srcObject", bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{UserMetadata: metadata, Progress: nil})
  4496. if err != nil {
  4497. logError(testName, function, args, startTime, "", "PutObject call failed", err)
  4498. return
  4499. }
  4500. // 2. copy object and change encryption key
  4501. src := minio.NewSourceInfo(bucketName, "srcObject", &key1)
  4502. args["source"] = src
  4503. dst, err := minio.NewDestinationInfo(bucketName, "dstObject", &key2, nil)
  4504. if err != nil {
  4505. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4506. return
  4507. }
  4508. args["destination"] = dst
  4509. err = c.CopyObject(dst, src)
  4510. if err != nil {
  4511. logError(testName, function, args, startTime, "", "CopyObject failed", err)
  4512. return
  4513. }
  4514. // 3. get copied object and check if content is equal
  4515. opts := minio.GetObjectOptions{}
  4516. for k, v := range key2.GetSSEHeaders() {
  4517. opts.Set(k, v)
  4518. }
  4519. coreClient := minio.Core{c}
  4520. reader, _, err := coreClient.GetObject(bucketName, "dstObject", opts)
  4521. if err != nil {
  4522. logError(testName, function, args, startTime, "", "GetObject failed", err)
  4523. return
  4524. }
  4525. defer reader.Close()
  4526. decBytes, err := ioutil.ReadAll(reader)
  4527. if err != nil {
  4528. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  4529. return
  4530. }
  4531. if !bytes.Equal(decBytes, buf) {
  4532. logError(testName, function, args, startTime, "", "Downloaded object mismatched for encrypted object", err)
  4533. return
  4534. }
  4535. // Delete all objects and buckets
  4536. if err = cleanupBucket(bucketName, c); err != nil {
  4537. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  4538. return
  4539. }
  4540. successLogger(testName, function, args, startTime).Info()
  4541. }
  4542. // Test encrypted copy object
  4543. func testEncryptedCopyObject() {
  4544. // initialize logging params
  4545. startTime := time.Now()
  4546. testName := getFuncName()
  4547. function := "CopyObject(destination, source)"
  4548. args := map[string]interface{}{}
  4549. // Instantiate new minio client object
  4550. c, err := minio.NewV4(
  4551. os.Getenv(serverEndpoint),
  4552. os.Getenv(accessKey),
  4553. os.Getenv(secretKey),
  4554. mustParseBool(os.Getenv(enableHTTPS)),
  4555. )
  4556. if err != nil {
  4557. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  4558. return
  4559. }
  4560. // c.TraceOn(os.Stderr)
  4561. testEncryptedCopyObjectWrapper(c)
  4562. }
  4563. // Test encrypted copy object
  4564. func testEncryptedCopyObjectV2() {
  4565. // initialize logging params
  4566. startTime := time.Now()
  4567. testName := getFuncName()
  4568. function := "CopyObject(destination, source)"
  4569. args := map[string]interface{}{}
  4570. // Instantiate new minio client object
  4571. c, err := minio.NewV2(
  4572. os.Getenv(serverEndpoint),
  4573. os.Getenv(accessKey),
  4574. os.Getenv(secretKey),
  4575. mustParseBool(os.Getenv(enableHTTPS)),
  4576. )
  4577. if err != nil {
  4578. logError(testName, function, args, startTime, "", "Minio v2 client object creation failed", err)
  4579. return
  4580. }
  4581. testEncryptedCopyObjectWrapper(c)
  4582. }
  4583. func testUserMetadataCopying() {
  4584. // initialize logging params
  4585. startTime := time.Now()
  4586. testName := getFuncName()
  4587. function := "CopyObject(destination, source)"
  4588. args := map[string]interface{}{}
  4589. // Instantiate new minio client object
  4590. c, err := minio.NewV4(
  4591. os.Getenv(serverEndpoint),
  4592. os.Getenv(accessKey),
  4593. os.Getenv(secretKey),
  4594. mustParseBool(os.Getenv(enableHTTPS)),
  4595. )
  4596. if err != nil {
  4597. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  4598. return
  4599. }
  4600. // c.TraceOn(os.Stderr)
  4601. testUserMetadataCopyingWrapper(c)
  4602. }
  4603. func testUserMetadataCopyingWrapper(c *minio.Client) {
  4604. // initialize logging params
  4605. startTime := time.Now()
  4606. testName := getFuncName()
  4607. function := "CopyObject(destination, source)"
  4608. args := map[string]interface{}{}
  4609. // Generate a new random bucket name.
  4610. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  4611. // Make a new bucket in 'us-east-1' (source bucket).
  4612. err := c.MakeBucket(bucketName, "us-east-1")
  4613. if err != nil {
  4614. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4615. return
  4616. }
  4617. fetchMeta := func(object string) (h http.Header) {
  4618. objInfo, err := c.StatObject(bucketName, object, minio.StatObjectOptions{})
  4619. if err != nil {
  4620. logError(testName, function, args, startTime, "", "Stat failed", err)
  4621. return
  4622. }
  4623. h = make(http.Header)
  4624. for k, vs := range objInfo.Metadata {
  4625. if strings.HasPrefix(strings.ToLower(k), "x-amz-meta-") {
  4626. for _, v := range vs {
  4627. h.Add(k, v)
  4628. }
  4629. }
  4630. }
  4631. return h
  4632. }
  4633. // 1. create a client encrypted object to copy by uploading
  4634. const srcSize = 1024 * 1024
  4635. buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 5MiB
  4636. metadata := make(http.Header)
  4637. metadata.Set("x-amz-meta-myheader", "myvalue")
  4638. m := make(map[string]string)
  4639. m["x-amz-meta-myheader"] = "myvalue"
  4640. _, err = c.PutObject(bucketName, "srcObject",
  4641. bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{UserMetadata: m})
  4642. if err != nil {
  4643. logError(testName, function, args, startTime, "", "PutObjectWithMetadata failed", err)
  4644. return
  4645. }
  4646. if !reflect.DeepEqual(metadata, fetchMeta("srcObject")) {
  4647. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4648. return
  4649. }
  4650. // 2. create source
  4651. src := minio.NewSourceInfo(bucketName, "srcObject", nil)
  4652. // 2.1 create destination with metadata set
  4653. dst1, err := minio.NewDestinationInfo(bucketName, "dstObject-1", nil, map[string]string{"notmyheader": "notmyvalue"})
  4654. if err != nil {
  4655. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4656. return
  4657. }
  4658. // 3. Check that copying to an object with metadata set resets
  4659. // the headers on the copy.
  4660. args["source"] = src
  4661. args["destination"] = dst1
  4662. err = c.CopyObject(dst1, src)
  4663. if err != nil {
  4664. logError(testName, function, args, startTime, "", "CopyObject failed", err)
  4665. return
  4666. }
  4667. expectedHeaders := make(http.Header)
  4668. expectedHeaders.Set("x-amz-meta-notmyheader", "notmyvalue")
  4669. if !reflect.DeepEqual(expectedHeaders, fetchMeta("dstObject-1")) {
  4670. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4671. return
  4672. }
  4673. // 4. create destination with no metadata set and same source
  4674. dst2, err := minio.NewDestinationInfo(bucketName, "dstObject-2", nil, nil)
  4675. if err != nil {
  4676. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4677. return
  4678. }
  4679. src = minio.NewSourceInfo(bucketName, "srcObject", nil)
  4680. // 5. Check that copying to an object with no metadata set,
  4681. // copies metadata.
  4682. args["source"] = src
  4683. args["destination"] = dst2
  4684. err = c.CopyObject(dst2, src)
  4685. if err != nil {
  4686. logError(testName, function, args, startTime, "", "CopyObject failed", err)
  4687. return
  4688. }
  4689. expectedHeaders = metadata
  4690. if !reflect.DeepEqual(expectedHeaders, fetchMeta("dstObject-2")) {
  4691. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4692. return
  4693. }
  4694. // 6. Compose a pair of sources.
  4695. srcs := []minio.SourceInfo{
  4696. minio.NewSourceInfo(bucketName, "srcObject", nil),
  4697. minio.NewSourceInfo(bucketName, "srcObject", nil),
  4698. }
  4699. dst3, err := minio.NewDestinationInfo(bucketName, "dstObject-3", nil, nil)
  4700. if err != nil {
  4701. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4702. return
  4703. }
  4704. function = "ComposeObject(destination, sources)"
  4705. args["source"] = srcs
  4706. args["destination"] = dst3
  4707. err = c.ComposeObject(dst3, srcs)
  4708. if err != nil {
  4709. logError(testName, function, args, startTime, "", "ComposeObject failed", err)
  4710. return
  4711. }
  4712. // Check that no headers are copied in this case
  4713. if !reflect.DeepEqual(make(http.Header), fetchMeta("dstObject-3")) {
  4714. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4715. return
  4716. }
  4717. // 7. Compose a pair of sources with dest user metadata set.
  4718. srcs = []minio.SourceInfo{
  4719. minio.NewSourceInfo(bucketName, "srcObject", nil),
  4720. minio.NewSourceInfo(bucketName, "srcObject", nil),
  4721. }
  4722. dst4, err := minio.NewDestinationInfo(bucketName, "dstObject-4", nil, map[string]string{"notmyheader": "notmyvalue"})
  4723. if err != nil {
  4724. logError(testName, function, args, startTime, "", "NewDestinationInfo failed", err)
  4725. return
  4726. }
  4727. function = "ComposeObject(destination, sources)"
  4728. args["source"] = srcs
  4729. args["destination"] = dst4
  4730. err = c.ComposeObject(dst4, srcs)
  4731. if err != nil {
  4732. logError(testName, function, args, startTime, "", "ComposeObject failed", err)
  4733. return
  4734. }
  4735. // Check that no headers are copied in this case
  4736. expectedHeaders = make(http.Header)
  4737. expectedHeaders.Set("x-amz-meta-notmyheader", "notmyvalue")
  4738. if !reflect.DeepEqual(expectedHeaders, fetchMeta("dstObject-4")) {
  4739. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4740. return
  4741. }
  4742. // Delete all objects and buckets
  4743. if err = cleanupBucket(bucketName, c); err != nil {
  4744. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  4745. return
  4746. }
  4747. successLogger(testName, function, args, startTime).Info()
  4748. }
  4749. func testUserMetadataCopyingV2() {
  4750. // initialize logging params
  4751. startTime := time.Now()
  4752. testName := getFuncName()
  4753. function := "CopyObject(destination, source)"
  4754. args := map[string]interface{}{}
  4755. // Instantiate new minio client object
  4756. c, err := minio.NewV2(
  4757. os.Getenv(serverEndpoint),
  4758. os.Getenv(accessKey),
  4759. os.Getenv(secretKey),
  4760. mustParseBool(os.Getenv(enableHTTPS)),
  4761. )
  4762. if err != nil {
  4763. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  4764. return
  4765. }
  4766. // c.TraceOn(os.Stderr)
  4767. testUserMetadataCopyingWrapper(c)
  4768. }
  4769. func testStorageClassMetadataPutObject() {
  4770. // initialize logging params
  4771. startTime := time.Now()
  4772. function := "testStorageClassMetadataPutObject()"
  4773. args := map[string]interface{}{}
  4774. testName := getFuncName()
  4775. // Instantiate new minio client object
  4776. c, err := minio.NewV4(
  4777. os.Getenv(serverEndpoint),
  4778. os.Getenv(accessKey),
  4779. os.Getenv(secretKey),
  4780. mustParseBool(os.Getenv(enableHTTPS)),
  4781. )
  4782. if err != nil {
  4783. logError(testName, function, args, startTime, "", "Minio v4 client object creation failed", err)
  4784. return
  4785. }
  4786. // Generate a new random bucket name.
  4787. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  4788. // Make a new bucket in 'us-east-1' (source bucket).
  4789. err = c.MakeBucket(bucketName, "us-east-1")
  4790. if err != nil {
  4791. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4792. return
  4793. }
  4794. fetchMeta := func(object string) (h http.Header) {
  4795. objInfo, err := c.StatObject(bucketName, object, minio.StatObjectOptions{})
  4796. if err != nil {
  4797. logError(testName, function, args, startTime, "", "Stat failed", err)
  4798. return
  4799. }
  4800. h = make(http.Header)
  4801. for k, vs := range objInfo.Metadata {
  4802. if strings.HasPrefix(strings.ToLower(k), "x-amz-storage-class") {
  4803. for _, v := range vs {
  4804. h.Add(k, v)
  4805. }
  4806. }
  4807. }
  4808. return h
  4809. }
  4810. metadata := make(http.Header)
  4811. metadata.Set("x-amz-storage-class", "REDUCED_REDUNDANCY")
  4812. const srcSize = 1024 * 1024
  4813. buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 1MiB
  4814. _, err = c.PutObject(bucketName, "srcObjectRRSClass",
  4815. bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "REDUCED_REDUNDANCY"})
  4816. if err != nil {
  4817. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4818. return
  4819. }
  4820. if !reflect.DeepEqual(metadata, fetchMeta("srcObjectRRSClass")) {
  4821. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4822. return
  4823. }
  4824. metadata = make(http.Header)
  4825. metadata.Set("x-amz-storage-class", "STANDARD")
  4826. _, err = c.PutObject(bucketName, "srcObjectSSClass",
  4827. bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "STANDARD"})
  4828. if err != nil {
  4829. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4830. return
  4831. }
  4832. if !reflect.DeepEqual(metadata, fetchMeta("srcObjectSSClass")) {
  4833. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4834. return
  4835. }
  4836. successLogger(testName, function, args, startTime).Info()
  4837. }
  4838. func testStorageClassInvalidMetadataPutObject() {
  4839. // initialize logging params
  4840. startTime := time.Now()
  4841. function := "testStorageClassInvalidMetadataPutObject()"
  4842. args := map[string]interface{}{}
  4843. testName := getFuncName()
  4844. // Instantiate new minio client object
  4845. c, err := minio.NewV4(
  4846. os.Getenv(serverEndpoint),
  4847. os.Getenv(accessKey),
  4848. os.Getenv(secretKey),
  4849. mustParseBool(os.Getenv(enableHTTPS)),
  4850. )
  4851. if err != nil {
  4852. logError(testName, function, args, startTime, "", "Minio v4 client object creation failed", err)
  4853. return
  4854. }
  4855. // Generate a new random bucket name.
  4856. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  4857. // Make a new bucket in 'us-east-1' (source bucket).
  4858. err = c.MakeBucket(bucketName, "us-east-1")
  4859. if err != nil {
  4860. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4861. return
  4862. }
  4863. const srcSize = 1024 * 1024
  4864. buf := bytes.Repeat([]byte("abcde"), srcSize) // gives a buffer of 1MiB
  4865. _, err = c.PutObject(bucketName, "srcObjectRRSClass",
  4866. bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "INVALID_STORAGE_CLASS"})
  4867. if err == nil {
  4868. logError(testName, function, args, startTime, "", "PutObject with invalid storage class passed, was expected to fail", err)
  4869. return
  4870. }
  4871. successLogger(testName, function, args, startTime).Info()
  4872. }
  4873. func testStorageClassMetadataCopyObject() {
  4874. // initialize logging params
  4875. startTime := time.Now()
  4876. function := "testStorageClassMetadataCopyObject()"
  4877. args := map[string]interface{}{}
  4878. testName := getFuncName()
  4879. // Instantiate new minio client object
  4880. c, err := minio.NewV4(
  4881. os.Getenv(serverEndpoint),
  4882. os.Getenv(accessKey),
  4883. os.Getenv(secretKey),
  4884. mustParseBool(os.Getenv(enableHTTPS)),
  4885. )
  4886. if err != nil {
  4887. logError(testName, function, args, startTime, "", "Minio v4 client object creation failed", err)
  4888. return
  4889. }
  4890. // Generate a new random bucket name.
  4891. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test")
  4892. // Make a new bucket in 'us-east-1' (source bucket).
  4893. err = c.MakeBucket(bucketName, "us-east-1")
  4894. if err != nil {
  4895. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4896. return
  4897. }
  4898. fetchMeta := func(object string) (h http.Header) {
  4899. objInfo, err := c.StatObject(bucketName, object, minio.StatObjectOptions{})
  4900. if err != nil {
  4901. logError(testName, function, args, startTime, "", "Stat failed", err)
  4902. return
  4903. }
  4904. h = make(http.Header)
  4905. for k, vs := range objInfo.Metadata {
  4906. if strings.HasPrefix(strings.ToLower(k), "x-amz-storage-class") {
  4907. for _, v := range vs {
  4908. h.Add(k, v)
  4909. }
  4910. }
  4911. }
  4912. return h
  4913. }
  4914. metadata := make(http.Header)
  4915. metadata.Set("x-amz-storage-class", "REDUCED_REDUNDANCY")
  4916. const srcSize = 1024 * 1024
  4917. buf := bytes.Repeat([]byte("abcde"), srcSize)
  4918. // Put an object with RRS Storage class
  4919. _, err = c.PutObject(bucketName, "srcObjectRRSClass",
  4920. bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "REDUCED_REDUNDANCY"})
  4921. if err != nil {
  4922. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4923. return
  4924. }
  4925. // Make server side copy of object uploaded in previous step
  4926. src := minio.NewSourceInfo(bucketName, "srcObjectRRSClass", nil)
  4927. dst, err := minio.NewDestinationInfo(bucketName, "srcObjectRRSClassCopy", nil, nil)
  4928. c.CopyObject(dst, src)
  4929. // Fetch the meta data of copied object
  4930. if !reflect.DeepEqual(metadata, fetchMeta("srcObjectRRSClassCopy")) {
  4931. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4932. return
  4933. }
  4934. metadata = make(http.Header)
  4935. metadata.Set("x-amz-storage-class", "STANDARD")
  4936. // Put an object with Standard Storage class
  4937. _, err = c.PutObject(bucketName, "srcObjectSSClass",
  4938. bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{StorageClass: "STANDARD"})
  4939. if err != nil {
  4940. logError(testName, function, args, startTime, "", "PutObject failed", err)
  4941. return
  4942. }
  4943. // Make server side copy of object uploaded in previous step
  4944. src = minio.NewSourceInfo(bucketName, "srcObjectSSClass", nil)
  4945. dst, err = minio.NewDestinationInfo(bucketName, "srcObjectSSClassCopy", nil, nil)
  4946. c.CopyObject(dst, src)
  4947. // Fetch the meta data of copied object
  4948. if !reflect.DeepEqual(metadata, fetchMeta("srcObjectSSClassCopy")) {
  4949. logError(testName, function, args, startTime, "", "Metadata match failed", err)
  4950. return
  4951. }
  4952. successLogger(testName, function, args, startTime).Info()
  4953. }
  4954. // Test put object with size -1 byte object.
  4955. func testPutObjectNoLengthV2() {
  4956. // initialize logging params
  4957. startTime := time.Now()
  4958. testName := getFuncName()
  4959. function := "PutObject(bucketName, objectName, reader, size, opts)"
  4960. args := map[string]interface{}{
  4961. "bucketName": "",
  4962. "objectName": "",
  4963. "size": -1,
  4964. "opts": "",
  4965. }
  4966. // Seed random based on current time.
  4967. rand.Seed(time.Now().Unix())
  4968. // Instantiate new minio client object.
  4969. c, err := minio.NewV2(
  4970. os.Getenv(serverEndpoint),
  4971. os.Getenv(accessKey),
  4972. os.Getenv(secretKey),
  4973. mustParseBool(os.Getenv(enableHTTPS)),
  4974. )
  4975. if err != nil {
  4976. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  4977. return
  4978. }
  4979. // Enable tracing, write to stderr.
  4980. // c.TraceOn(os.Stderr)
  4981. // Set user agent.
  4982. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  4983. // Generate a new random bucket name.
  4984. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  4985. args["bucketName"] = bucketName
  4986. // Make a new bucket.
  4987. err = c.MakeBucket(bucketName, "us-east-1")
  4988. if err != nil {
  4989. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  4990. return
  4991. }
  4992. objectName := bucketName + "unique"
  4993. args["objectName"] = objectName
  4994. bufSize := dataFileMap["datafile-65-MB"]
  4995. var reader = getDataReader("datafile-65-MB")
  4996. defer reader.Close()
  4997. args["size"] = bufSize
  4998. // Upload an object.
  4999. n, err := c.PutObject(bucketName, objectName, reader, -1, minio.PutObjectOptions{})
  5000. if err != nil {
  5001. logError(testName, function, args, startTime, "", "PutObjectWithSize failed", err)
  5002. return
  5003. }
  5004. if n != int64(bufSize) {
  5005. logError(testName, function, args, startTime, "", "Expected upload object size "+string(bufSize)+" got "+string(n), err)
  5006. return
  5007. }
  5008. // Delete all objects and buckets
  5009. if err = cleanupBucket(bucketName, c); err != nil {
  5010. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5011. return
  5012. }
  5013. successLogger(testName, function, args, startTime).Info()
  5014. }
  5015. // Test put objects of unknown size.
  5016. func testPutObjectsUnknownV2() {
  5017. // initialize logging params
  5018. startTime := time.Now()
  5019. testName := getFuncName()
  5020. function := "PutObject(bucketName, objectName, reader,size,opts)"
  5021. args := map[string]interface{}{
  5022. "bucketName": "",
  5023. "objectName": "",
  5024. "size": "",
  5025. "opts": "",
  5026. }
  5027. // Seed random based on current time.
  5028. rand.Seed(time.Now().Unix())
  5029. // Instantiate new minio client object.
  5030. c, err := minio.NewV2(
  5031. os.Getenv(serverEndpoint),
  5032. os.Getenv(accessKey),
  5033. os.Getenv(secretKey),
  5034. mustParseBool(os.Getenv(enableHTTPS)),
  5035. )
  5036. if err != nil {
  5037. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  5038. return
  5039. }
  5040. // Enable tracing, write to stderr.
  5041. // c.TraceOn(os.Stderr)
  5042. // Set user agent.
  5043. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5044. // Generate a new random bucket name.
  5045. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5046. args["bucketName"] = bucketName
  5047. // Make a new bucket.
  5048. err = c.MakeBucket(bucketName, "us-east-1")
  5049. if err != nil {
  5050. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  5051. return
  5052. }
  5053. // Issues are revealed by trying to upload multiple files of unknown size
  5054. // sequentially (on 4GB machines)
  5055. for i := 1; i <= 4; i++ {
  5056. // Simulate that we could be receiving byte slices of data that we want
  5057. // to upload as a file
  5058. rpipe, wpipe := io.Pipe()
  5059. defer rpipe.Close()
  5060. go func() {
  5061. b := []byte("test")
  5062. wpipe.Write(b)
  5063. wpipe.Close()
  5064. }()
  5065. // Upload the object.
  5066. objectName := fmt.Sprintf("%sunique%d", bucketName, i)
  5067. args["objectName"] = objectName
  5068. n, err := c.PutObject(bucketName, objectName, rpipe, -1, minio.PutObjectOptions{})
  5069. if err != nil {
  5070. logError(testName, function, args, startTime, "", "PutObjectStreaming failed", err)
  5071. return
  5072. }
  5073. args["size"] = n
  5074. if n != int64(4) {
  5075. logError(testName, function, args, startTime, "", "Expected upload object size "+string(4)+" got "+string(n), err)
  5076. return
  5077. }
  5078. }
  5079. // Delete all objects and buckets
  5080. if err = cleanupBucket(bucketName, c); err != nil {
  5081. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5082. return
  5083. }
  5084. successLogger(testName, function, args, startTime).Info()
  5085. }
  5086. // Test put object with 0 byte object.
  5087. func testPutObject0ByteV2() {
  5088. // initialize logging params
  5089. startTime := time.Now()
  5090. testName := getFuncName()
  5091. function := "PutObject(bucketName, objectName, reader, size, opts)"
  5092. args := map[string]interface{}{
  5093. "bucketName": "",
  5094. "objectName": "",
  5095. "size": 0,
  5096. "opts": "",
  5097. }
  5098. // Seed random based on current time.
  5099. rand.Seed(time.Now().Unix())
  5100. // Instantiate new minio client object.
  5101. c, err := minio.NewV2(
  5102. os.Getenv(serverEndpoint),
  5103. os.Getenv(accessKey),
  5104. os.Getenv(secretKey),
  5105. mustParseBool(os.Getenv(enableHTTPS)),
  5106. )
  5107. if err != nil {
  5108. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  5109. return
  5110. }
  5111. // Enable tracing, write to stderr.
  5112. // c.TraceOn(os.Stderr)
  5113. // Set user agent.
  5114. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5115. // Generate a new random bucket name.
  5116. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5117. args["bucketName"] = bucketName
  5118. // Make a new bucket.
  5119. err = c.MakeBucket(bucketName, "us-east-1")
  5120. if err != nil {
  5121. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  5122. return
  5123. }
  5124. objectName := bucketName + "unique"
  5125. args["objectName"] = objectName
  5126. args["opts"] = minio.PutObjectOptions{}
  5127. // Upload an object.
  5128. n, err := c.PutObject(bucketName, objectName, bytes.NewReader([]byte("")), 0, minio.PutObjectOptions{})
  5129. if err != nil {
  5130. logError(testName, function, args, startTime, "", "PutObjectWithSize failed", err)
  5131. return
  5132. }
  5133. if n != 0 {
  5134. logError(testName, function, args, startTime, "", "Expected upload object size 0 but got "+string(n), err)
  5135. return
  5136. }
  5137. // Delete all objects and buckets
  5138. if err = cleanupBucket(bucketName, c); err != nil {
  5139. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5140. return
  5141. }
  5142. successLogger(testName, function, args, startTime).Info()
  5143. }
  5144. // Test expected error cases
  5145. func testComposeObjectErrorCases() {
  5146. // initialize logging params
  5147. startTime := time.Now()
  5148. testName := getFuncName()
  5149. function := "ComposeObject(destination, sourceList)"
  5150. args := map[string]interface{}{}
  5151. // Instantiate new minio client object
  5152. c, err := minio.NewV4(
  5153. os.Getenv(serverEndpoint),
  5154. os.Getenv(accessKey),
  5155. os.Getenv(secretKey),
  5156. mustParseBool(os.Getenv(enableHTTPS)),
  5157. )
  5158. if err != nil {
  5159. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  5160. return
  5161. }
  5162. testComposeObjectErrorCasesWrapper(c)
  5163. }
  5164. // Test concatenating 10K objects
  5165. func testCompose10KSources() {
  5166. // initialize logging params
  5167. startTime := time.Now()
  5168. testName := getFuncName()
  5169. function := "ComposeObject(destination, sourceList)"
  5170. args := map[string]interface{}{}
  5171. // Instantiate new minio client object
  5172. c, err := minio.NewV4(
  5173. os.Getenv(serverEndpoint),
  5174. os.Getenv(accessKey),
  5175. os.Getenv(secretKey),
  5176. mustParseBool(os.Getenv(enableHTTPS)),
  5177. )
  5178. if err != nil {
  5179. logError(testName, function, args, startTime, "", "Minio client object creation failed", err)
  5180. return
  5181. }
  5182. testComposeMultipleSources(c)
  5183. }
  5184. // Tests comprehensive list of all methods.
  5185. func testFunctionalV2() {
  5186. // initialize logging params
  5187. startTime := time.Now()
  5188. testName := getFuncName()
  5189. function := "testFunctionalV2()"
  5190. function_all := ""
  5191. args := map[string]interface{}{}
  5192. // Seed random based on current time.
  5193. rand.Seed(time.Now().Unix())
  5194. c, err := minio.NewV2(
  5195. os.Getenv(serverEndpoint),
  5196. os.Getenv(accessKey),
  5197. os.Getenv(secretKey),
  5198. mustParseBool(os.Getenv(enableHTTPS)),
  5199. )
  5200. if err != nil {
  5201. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  5202. return
  5203. }
  5204. // Enable to debug
  5205. // c.TraceOn(os.Stderr)
  5206. // Set user agent.
  5207. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5208. // Generate a new random bucket name.
  5209. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5210. location := "us-east-1"
  5211. // Make a new bucket.
  5212. function = "MakeBucket(bucketName, location)"
  5213. function_all = "MakeBucket(bucketName, location)"
  5214. args = map[string]interface{}{
  5215. "bucketName": bucketName,
  5216. "location": location,
  5217. }
  5218. err = c.MakeBucket(bucketName, location)
  5219. if err != nil {
  5220. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  5221. return
  5222. }
  5223. // Generate a random file name.
  5224. fileName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  5225. file, err := os.Create(fileName)
  5226. if err != nil {
  5227. logError(testName, function, args, startTime, "", "file create failed", err)
  5228. return
  5229. }
  5230. for i := 0; i < 3; i++ {
  5231. buf := make([]byte, rand.Intn(1<<19))
  5232. _, err = file.Write(buf)
  5233. if err != nil {
  5234. logError(testName, function, args, startTime, "", "file write failed", err)
  5235. return
  5236. }
  5237. }
  5238. file.Close()
  5239. // Verify if bucket exits and you have access.
  5240. var exists bool
  5241. function = "BucketExists(bucketName)"
  5242. function_all += ", " + function
  5243. args = map[string]interface{}{
  5244. "bucketName": bucketName,
  5245. }
  5246. exists, err = c.BucketExists(bucketName)
  5247. if err != nil {
  5248. logError(testName, function, args, startTime, "", "BucketExists failed", err)
  5249. return
  5250. }
  5251. if !exists {
  5252. logError(testName, function, args, startTime, "", "Could not find existing bucket "+bucketName, err)
  5253. return
  5254. }
  5255. // Make the bucket 'public read/write'.
  5256. function = "SetBucketPolicy(bucketName, objectPrefix, bucketPolicy)"
  5257. function_all += ", " + function
  5258. args = map[string]interface{}{
  5259. "bucketName": bucketName,
  5260. "objectPrefix": "",
  5261. "bucketPolicy": policy.BucketPolicyReadWrite,
  5262. }
  5263. err = c.SetBucketPolicy(bucketName, "", policy.BucketPolicyReadWrite)
  5264. if err != nil {
  5265. logError(testName, function, args, startTime, "", "SetBucketPolicy failed", err)
  5266. return
  5267. }
  5268. // List all buckets.
  5269. function = "ListBuckets()"
  5270. function_all += ", " + function
  5271. args = nil
  5272. buckets, err := c.ListBuckets()
  5273. if len(buckets) == 0 {
  5274. logError(testName, function, args, startTime, "", "List buckets cannot be empty", err)
  5275. return
  5276. }
  5277. if err != nil {
  5278. logError(testName, function, args, startTime, "", "ListBuckets failed", err)
  5279. return
  5280. }
  5281. // Verify if previously created bucket is listed in list buckets.
  5282. bucketFound := false
  5283. for _, bucket := range buckets {
  5284. if bucket.Name == bucketName {
  5285. bucketFound = true
  5286. }
  5287. }
  5288. // If bucket not found error out.
  5289. if !bucketFound {
  5290. logError(testName, function, args, startTime, "", "Bucket "+bucketName+"not found", err)
  5291. return
  5292. }
  5293. objectName := bucketName + "unique"
  5294. // Generate data
  5295. buf := bytes.Repeat([]byte("n"), rand.Intn(1<<19))
  5296. args = map[string]interface{}{
  5297. "bucketName": bucketName,
  5298. "objectName": objectName,
  5299. "contentType": "",
  5300. }
  5301. n, err := c.PutObject(bucketName, objectName, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{})
  5302. if err != nil {
  5303. logError(testName, function, args, startTime, "", "PutObject failed", err)
  5304. return
  5305. }
  5306. if n != int64(len(buf)) {
  5307. logError(testName, function, args, startTime, "", "Expected uploaded object length "+string(len(buf))+" got "+string(n), err)
  5308. return
  5309. }
  5310. objectName_noLength := objectName + "-nolength"
  5311. args["objectName"] = objectName_noLength
  5312. n, err = c.PutObject(bucketName, objectName_noLength, bytes.NewReader(buf), int64(len(buf)), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  5313. if err != nil {
  5314. logError(testName, function, args, startTime, "", "PutObject failed", err)
  5315. return
  5316. }
  5317. if n != int64(len(buf)) {
  5318. logError(testName, function, args, startTime, "", "Expected uploaded object length "+string(len(buf))+" got "+string(n), err)
  5319. return
  5320. }
  5321. // Instantiate a done channel to close all listing.
  5322. doneCh := make(chan struct{})
  5323. defer close(doneCh)
  5324. objFound := false
  5325. isRecursive := true // Recursive is true.
  5326. function = "ListObjects(bucketName, objectName, isRecursive, doneCh)"
  5327. function_all += ", " + function
  5328. args = map[string]interface{}{
  5329. "bucketName": bucketName,
  5330. "objectName": objectName,
  5331. "isRecursive": isRecursive,
  5332. }
  5333. for obj := range c.ListObjects(bucketName, objectName, isRecursive, doneCh) {
  5334. if obj.Key == objectName {
  5335. objFound = true
  5336. break
  5337. }
  5338. }
  5339. if !objFound {
  5340. logError(testName, function, args, startTime, "", "Could not find existing object "+objectName, err)
  5341. return
  5342. }
  5343. incompObjNotFound := true
  5344. function = "ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh)"
  5345. function_all += ", " + function
  5346. args = map[string]interface{}{
  5347. "bucketName": bucketName,
  5348. "objectName": objectName,
  5349. "isRecursive": isRecursive,
  5350. }
  5351. for objIncompl := range c.ListIncompleteUploads(bucketName, objectName, isRecursive, doneCh) {
  5352. if objIncompl.Key != "" {
  5353. incompObjNotFound = false
  5354. break
  5355. }
  5356. }
  5357. if !incompObjNotFound {
  5358. logError(testName, function, args, startTime, "", "Unexpected dangling incomplete upload found", err)
  5359. return
  5360. }
  5361. function = "GetObject(bucketName, objectName)"
  5362. function_all += ", " + function
  5363. args = map[string]interface{}{
  5364. "bucketName": bucketName,
  5365. "objectName": objectName,
  5366. }
  5367. newReader, err := c.GetObject(bucketName, objectName, minio.GetObjectOptions{})
  5368. if err != nil {
  5369. logError(testName, function, args, startTime, "", "GetObject failed", err)
  5370. return
  5371. }
  5372. newReadBytes, err := ioutil.ReadAll(newReader)
  5373. if err != nil {
  5374. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  5375. return
  5376. }
  5377. if !bytes.Equal(newReadBytes, buf) {
  5378. logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  5379. return
  5380. }
  5381. function = "FGetObject(bucketName, objectName, fileName)"
  5382. function_all += ", " + function
  5383. args = map[string]interface{}{
  5384. "bucketName": bucketName,
  5385. "objectName": objectName,
  5386. "fileName": fileName + "-f",
  5387. }
  5388. err = c.FGetObject(bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
  5389. if err != nil {
  5390. logError(testName, function, args, startTime, "", "FgetObject failed", err)
  5391. return
  5392. }
  5393. // Generate presigned HEAD object url.
  5394. function = "PresignedHeadObject(bucketName, objectName, expires, reqParams)"
  5395. function_all += ", " + function
  5396. args = map[string]interface{}{
  5397. "bucketName": bucketName,
  5398. "objectName": objectName,
  5399. "expires": 3600 * time.Second,
  5400. }
  5401. presignedHeadURL, err := c.PresignedHeadObject(bucketName, objectName, 3600*time.Second, nil)
  5402. if err != nil {
  5403. logError(testName, function, args, startTime, "", "PresignedHeadObject failed", err)
  5404. return
  5405. }
  5406. // Verify if presigned url works.
  5407. resp, err := http.Head(presignedHeadURL.String())
  5408. if err != nil {
  5409. logError(testName, function, args, startTime, "", "PresignedHeadObject URL head request failed", err)
  5410. return
  5411. }
  5412. if resp.StatusCode != http.StatusOK {
  5413. logError(testName, function, args, startTime, "", "PresignedHeadObject URL returns status "+string(resp.StatusCode), err)
  5414. return
  5415. }
  5416. if resp.Header.Get("ETag") == "" {
  5417. logError(testName, function, args, startTime, "", "Got empty ETag", err)
  5418. return
  5419. }
  5420. resp.Body.Close()
  5421. // Generate presigned GET object url.
  5422. function = "PresignedGetObject(bucketName, objectName, expires, reqParams)"
  5423. function_all += ", " + function
  5424. args = map[string]interface{}{
  5425. "bucketName": bucketName,
  5426. "objectName": objectName,
  5427. "expires": 3600 * time.Second,
  5428. }
  5429. presignedGetURL, err := c.PresignedGetObject(bucketName, objectName, 3600*time.Second, nil)
  5430. if err != nil {
  5431. logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
  5432. return
  5433. }
  5434. // Verify if presigned url works.
  5435. resp, err = http.Get(presignedGetURL.String())
  5436. if err != nil {
  5437. logError(testName, function, args, startTime, "", "PresignedGetObject URL GET request failed", err)
  5438. return
  5439. }
  5440. if resp.StatusCode != http.StatusOK {
  5441. logError(testName, function, args, startTime, "", "PresignedGetObject URL returns status "+string(resp.StatusCode), err)
  5442. return
  5443. }
  5444. newPresignedBytes, err := ioutil.ReadAll(resp.Body)
  5445. if err != nil {
  5446. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  5447. return
  5448. }
  5449. resp.Body.Close()
  5450. if !bytes.Equal(newPresignedBytes, buf) {
  5451. logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  5452. return
  5453. }
  5454. // Set request parameters.
  5455. reqParams := make(url.Values)
  5456. reqParams.Set("response-content-disposition", "attachment; filename=\"test.txt\"")
  5457. // Generate presigned GET object url.
  5458. args["reqParams"] = reqParams
  5459. presignedGetURL, err = c.PresignedGetObject(bucketName, objectName, 3600*time.Second, reqParams)
  5460. if err != nil {
  5461. logError(testName, function, args, startTime, "", "PresignedGetObject failed", err)
  5462. return
  5463. }
  5464. // Verify if presigned url works.
  5465. resp, err = http.Get(presignedGetURL.String())
  5466. if err != nil {
  5467. logError(testName, function, args, startTime, "", "PresignedGetObject URL GET request failed", err)
  5468. return
  5469. }
  5470. if resp.StatusCode != http.StatusOK {
  5471. logError(testName, function, args, startTime, "", "PresignedGetObject URL returns status "+string(resp.StatusCode), err)
  5472. return
  5473. }
  5474. newPresignedBytes, err = ioutil.ReadAll(resp.Body)
  5475. if err != nil {
  5476. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  5477. return
  5478. }
  5479. if !bytes.Equal(newPresignedBytes, buf) {
  5480. logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  5481. return
  5482. }
  5483. // Verify content disposition.
  5484. if resp.Header.Get("Content-Disposition") != "attachment; filename=\"test.txt\"" {
  5485. logError(testName, function, args, startTime, "", "wrong Content-Disposition received ", err)
  5486. return
  5487. }
  5488. function = "PresignedPutObject(bucketName, objectName, expires)"
  5489. function_all += ", " + function
  5490. args = map[string]interface{}{
  5491. "bucketName": bucketName,
  5492. "objectName": objectName + "-presigned",
  5493. "expires": 3600 * time.Second,
  5494. }
  5495. presignedPutURL, err := c.PresignedPutObject(bucketName, objectName+"-presigned", 3600*time.Second)
  5496. if err != nil {
  5497. logError(testName, function, args, startTime, "", "PresignedPutObject failed", err)
  5498. return
  5499. }
  5500. // Generate data more than 32K
  5501. buf = bytes.Repeat([]byte("1"), rand.Intn(1<<10)+32*1024)
  5502. req, err := http.NewRequest("PUT", presignedPutURL.String(), bytes.NewReader(buf))
  5503. if err != nil {
  5504. logError(testName, function, args, startTime, "", "HTTP request to PresignedPutObject URL failed", err)
  5505. return
  5506. }
  5507. httpClient := &http.Client{
  5508. // Setting a sensible time out of 30secs to wait for response
  5509. // headers. Request is pro-actively cancelled after 30secs
  5510. // with no response.
  5511. Timeout: 30 * time.Second,
  5512. Transport: http.DefaultTransport,
  5513. }
  5514. resp, err = httpClient.Do(req)
  5515. if err != nil {
  5516. logError(testName, function, args, startTime, "", "HTTP request to PresignedPutObject URL failed", err)
  5517. return
  5518. }
  5519. function = "GetObject(bucketName, objectName)"
  5520. function_all += ", " + function
  5521. args = map[string]interface{}{
  5522. "bucketName": bucketName,
  5523. "objectName": objectName + "-presigned",
  5524. }
  5525. newReader, err = c.GetObject(bucketName, objectName+"-presigned", minio.GetObjectOptions{})
  5526. if err != nil {
  5527. logError(testName, function, args, startTime, "", "GetObject failed", err)
  5528. return
  5529. }
  5530. newReadBytes, err = ioutil.ReadAll(newReader)
  5531. if err != nil {
  5532. logError(testName, function, args, startTime, "", "ReadAll failed", err)
  5533. return
  5534. }
  5535. if !bytes.Equal(newReadBytes, buf) {
  5536. logError(testName, function, args, startTime, "", "Bytes mismatch", err)
  5537. return
  5538. }
  5539. // Delete all objects and buckets
  5540. if err = cleanupBucket(bucketName, c); err != nil {
  5541. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5542. return
  5543. }
  5544. if err = os.Remove(fileName); err != nil {
  5545. logError(testName, function, args, startTime, "", "File remove failed", err)
  5546. return
  5547. }
  5548. if err = os.Remove(fileName + "-f"); err != nil {
  5549. logError(testName, function, args, startTime, "", "File removes failed", err)
  5550. return
  5551. }
  5552. successLogger(testName, function_all, args, startTime).Info()
  5553. }
  5554. // Test get object with GetObjectWithContext
  5555. func testGetObjectWithContext() {
  5556. // initialize logging params
  5557. startTime := time.Now()
  5558. testName := getFuncName()
  5559. function := "GetObjectWithContext(ctx, bucketName, objectName)"
  5560. args := map[string]interface{}{
  5561. "ctx": "",
  5562. "bucketName": "",
  5563. "objectName": "",
  5564. }
  5565. // Seed random based on current time.
  5566. rand.Seed(time.Now().Unix())
  5567. // Instantiate new minio client object.
  5568. c, err := minio.NewV4(
  5569. os.Getenv(serverEndpoint),
  5570. os.Getenv(accessKey),
  5571. os.Getenv(secretKey),
  5572. mustParseBool(os.Getenv(enableHTTPS)),
  5573. )
  5574. if err != nil {
  5575. logError(testName, function, args, startTime, "", "Minio client v4 object creation failed", err)
  5576. return
  5577. }
  5578. // Enable tracing, write to stderr.
  5579. // c.TraceOn(os.Stderr)
  5580. // Set user agent.
  5581. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5582. // Generate a new random bucket name.
  5583. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5584. args["bucketName"] = bucketName
  5585. // Make a new bucket.
  5586. err = c.MakeBucket(bucketName, "us-east-1")
  5587. if err != nil {
  5588. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  5589. return
  5590. }
  5591. bufSize := dataFileMap["datafile-33-kB"]
  5592. var reader = getDataReader("datafile-33-kB")
  5593. defer reader.Close()
  5594. // Save the data
  5595. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  5596. args["objectName"] = objectName
  5597. _, err = c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  5598. if err != nil {
  5599. logError(testName, function, args, startTime, "", "PutObject failed", err)
  5600. return
  5601. }
  5602. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  5603. args["ctx"] = ctx
  5604. defer cancel()
  5605. r, err := c.GetObjectWithContext(ctx, bucketName, objectName, minio.GetObjectOptions{})
  5606. if err != nil {
  5607. logError(testName, function, args, startTime, "", "GetObjectWithContext failed unexpectedly", err)
  5608. return
  5609. }
  5610. if _, err = r.Stat(); err == nil {
  5611. logError(testName, function, args, startTime, "", "GetObjectWithContext should fail on short timeout", err)
  5612. return
  5613. }
  5614. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  5615. args["ctx"] = ctx
  5616. defer cancel()
  5617. // Read the data back
  5618. r, err = c.GetObjectWithContext(ctx, bucketName, objectName, minio.GetObjectOptions{})
  5619. if err != nil {
  5620. logError(testName, function, args, startTime, "", "GetObjectWithContext failed", err)
  5621. return
  5622. }
  5623. st, err := r.Stat()
  5624. if err != nil {
  5625. logError(testName, function, args, startTime, "", "object Stat call failed", err)
  5626. return
  5627. }
  5628. if st.Size != int64(bufSize) {
  5629. logError(testName, function, args, startTime, "", "Number of bytes in stat does not match: want "+string(bufSize)+", got"+string(st.Size), err)
  5630. return
  5631. }
  5632. if err := r.Close(); err != nil {
  5633. logError(testName, function, args, startTime, "", "object Close() call failed", err)
  5634. return
  5635. }
  5636. // Delete all objects and buckets
  5637. if err = cleanupBucket(bucketName, c); err != nil {
  5638. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5639. return
  5640. }
  5641. successLogger(testName, function, args, startTime).Info()
  5642. }
  5643. // Test get object with FGetObjectWithContext
  5644. func testFGetObjectWithContext() {
  5645. // initialize logging params
  5646. startTime := time.Now()
  5647. testName := getFuncName()
  5648. function := "FGetObjectWithContext(ctx, bucketName, objectName, fileName)"
  5649. args := map[string]interface{}{
  5650. "ctx": "",
  5651. "bucketName": "",
  5652. "objectName": "",
  5653. "fileName": "",
  5654. }
  5655. // Seed random based on current time.
  5656. rand.Seed(time.Now().Unix())
  5657. // Instantiate new minio client object.
  5658. c, err := minio.NewV4(
  5659. os.Getenv(serverEndpoint),
  5660. os.Getenv(accessKey),
  5661. os.Getenv(secretKey),
  5662. mustParseBool(os.Getenv(enableHTTPS)),
  5663. )
  5664. if err != nil {
  5665. logError(testName, function, args, startTime, "", "Minio client v4 object creation failed", err)
  5666. return
  5667. }
  5668. // Enable tracing, write to stderr.
  5669. // c.TraceOn(os.Stderr)
  5670. // Set user agent.
  5671. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5672. // Generate a new random bucket name.
  5673. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5674. args["bucketName"] = bucketName
  5675. // Make a new bucket.
  5676. err = c.MakeBucket(bucketName, "us-east-1")
  5677. if err != nil {
  5678. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  5679. return
  5680. }
  5681. bufSize := dataFileMap["datafile-1-MB"]
  5682. var reader = getDataReader("datafile-1-MB")
  5683. defer reader.Close()
  5684. // Save the data
  5685. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  5686. args["objectName"] = objectName
  5687. _, err = c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  5688. if err != nil {
  5689. logError(testName, function, args, startTime, "", "PutObject failed", err)
  5690. return
  5691. }
  5692. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  5693. args["ctx"] = ctx
  5694. defer cancel()
  5695. fileName := "tempfile-context"
  5696. args["fileName"] = fileName
  5697. // Read the data back
  5698. err = c.FGetObjectWithContext(ctx, bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
  5699. if err == nil {
  5700. logError(testName, function, args, startTime, "", "FGetObjectWithContext should fail on short timeout", err)
  5701. return
  5702. }
  5703. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  5704. defer cancel()
  5705. // Read the data back
  5706. err = c.FGetObjectWithContext(ctx, bucketName, objectName, fileName+"-fcontext", minio.GetObjectOptions{})
  5707. if err != nil {
  5708. logError(testName, function, args, startTime, "", "FGetObjectWithContext with long timeout failed", err)
  5709. return
  5710. }
  5711. if err = os.Remove(fileName + "-fcontext"); err != nil {
  5712. logError(testName, function, args, startTime, "", "Remove file failed", err)
  5713. return
  5714. }
  5715. // Delete all objects and buckets
  5716. if err = cleanupBucket(bucketName, c); err != nil {
  5717. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5718. return
  5719. }
  5720. successLogger(testName, function, args, startTime).Info()
  5721. }
  5722. // Test validates putObject with context to see if request cancellation is honored for V2.
  5723. func testPutObjectWithContextV2() {
  5724. // initialize logging params
  5725. startTime := time.Now()
  5726. testName := getFuncName()
  5727. function := "PutObjectWithContext(ctx, bucketName, objectName, reader, size, opts)"
  5728. args := map[string]interface{}{
  5729. "ctx": "",
  5730. "bucketName": "",
  5731. "objectName": "",
  5732. "size": "",
  5733. "opts": "",
  5734. }
  5735. // Instantiate new minio client object.
  5736. c, err := minio.NewV2(
  5737. os.Getenv(serverEndpoint),
  5738. os.Getenv(accessKey),
  5739. os.Getenv(secretKey),
  5740. mustParseBool(os.Getenv(enableHTTPS)),
  5741. )
  5742. if err != nil {
  5743. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  5744. return
  5745. }
  5746. // Enable tracing, write to stderr.
  5747. // c.TraceOn(os.Stderr)
  5748. // Set user agent.
  5749. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5750. // Make a new bucket.
  5751. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5752. args["bucketName"] = bucketName
  5753. err = c.MakeBucket(bucketName, "us-east-1")
  5754. if err != nil {
  5755. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  5756. return
  5757. }
  5758. defer c.RemoveBucket(bucketName)
  5759. bufSize := dataFileMap["datatfile-33-kB"]
  5760. var reader = getDataReader("datafile-33-kB")
  5761. defer reader.Close()
  5762. objectName := fmt.Sprintf("test-file-%v", rand.Uint32())
  5763. args["objectName"] = objectName
  5764. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  5765. args["ctx"] = ctx
  5766. args["size"] = bufSize
  5767. defer cancel()
  5768. _, err = c.PutObjectWithContext(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  5769. if err != nil {
  5770. logError(testName, function, args, startTime, "", "PutObjectWithContext with short timeout failed", err)
  5771. return
  5772. }
  5773. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  5774. args["ctx"] = ctx
  5775. defer cancel()
  5776. reader = getDataReader("datafile-33-kB")
  5777. defer reader.Close()
  5778. _, err = c.PutObjectWithContext(ctx, bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  5779. if err != nil {
  5780. logError(testName, function, args, startTime, "", "PutObjectWithContext with long timeout failed", err)
  5781. return
  5782. }
  5783. // Delete all objects and buckets
  5784. if err = cleanupBucket(bucketName, c); err != nil {
  5785. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5786. return
  5787. }
  5788. successLogger(testName, function, args, startTime).Info()
  5789. }
  5790. // Test get object with GetObjectWithContext
  5791. func testGetObjectWithContextV2() {
  5792. // initialize logging params
  5793. startTime := time.Now()
  5794. testName := getFuncName()
  5795. function := "GetObjectWithContext(ctx, bucketName, objectName)"
  5796. args := map[string]interface{}{
  5797. "ctx": "",
  5798. "bucketName": "",
  5799. "objectName": "",
  5800. }
  5801. // Seed random based on current time.
  5802. rand.Seed(time.Now().Unix())
  5803. // Instantiate new minio client object.
  5804. c, err := minio.NewV2(
  5805. os.Getenv(serverEndpoint),
  5806. os.Getenv(accessKey),
  5807. os.Getenv(secretKey),
  5808. mustParseBool(os.Getenv(enableHTTPS)),
  5809. )
  5810. if err != nil {
  5811. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  5812. return
  5813. }
  5814. // Enable tracing, write to stderr.
  5815. // c.TraceOn(os.Stderr)
  5816. // Set user agent.
  5817. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5818. // Generate a new random bucket name.
  5819. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5820. args["bucketName"] = bucketName
  5821. // Make a new bucket.
  5822. err = c.MakeBucket(bucketName, "us-east-1")
  5823. if err != nil {
  5824. logError(testName, function, args, startTime, "", "MakeBucket failed", err)
  5825. return
  5826. }
  5827. bufSize := dataFileMap["datafile-33-kB"]
  5828. var reader = getDataReader("datafile-33-kB")
  5829. defer reader.Close()
  5830. // Save the data
  5831. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  5832. args["objectName"] = objectName
  5833. _, err = c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  5834. if err != nil {
  5835. logError(testName, function, args, startTime, "", "PutObject call failed", err)
  5836. return
  5837. }
  5838. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  5839. args["ctx"] = ctx
  5840. defer cancel()
  5841. r, err := c.GetObjectWithContext(ctx, bucketName, objectName, minio.GetObjectOptions{})
  5842. if err != nil {
  5843. logError(testName, function, args, startTime, "", "GetObjectWithContext failed unexpectedly", err)
  5844. return
  5845. }
  5846. if _, err = r.Stat(); err == nil {
  5847. logError(testName, function, args, startTime, "", "GetObjectWithContext should fail on short timeout", err)
  5848. return
  5849. }
  5850. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  5851. defer cancel()
  5852. // Read the data back
  5853. r, err = c.GetObjectWithContext(ctx, bucketName, objectName, minio.GetObjectOptions{})
  5854. if err != nil {
  5855. logError(testName, function, args, startTime, "", "GetObjectWithContext shouldn't fail on longer timeout", err)
  5856. return
  5857. }
  5858. st, err := r.Stat()
  5859. if err != nil {
  5860. logError(testName, function, args, startTime, "", "object Stat call failed", err)
  5861. return
  5862. }
  5863. if st.Size != int64(bufSize) {
  5864. logError(testName, function, args, startTime, "", "Number of bytes in stat does not match, expected "+string(bufSize)+" got "+string(st.Size), err)
  5865. return
  5866. }
  5867. if err := r.Close(); err != nil {
  5868. logError(testName, function, args, startTime, "", " object Close() call failed", err)
  5869. return
  5870. }
  5871. // Delete all objects and buckets
  5872. if err = cleanupBucket(bucketName, c); err != nil {
  5873. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5874. return
  5875. }
  5876. successLogger(testName, function, args, startTime).Info()
  5877. }
  5878. // Test get object with FGetObjectWithContext
  5879. func testFGetObjectWithContextV2() {
  5880. // initialize logging params
  5881. startTime := time.Now()
  5882. testName := getFuncName()
  5883. function := "FGetObjectWithContext(ctx, bucketName, objectName,fileName)"
  5884. args := map[string]interface{}{
  5885. "ctx": "",
  5886. "bucketName": "",
  5887. "objectName": "",
  5888. "fileName": "",
  5889. }
  5890. // Seed random based on current time.
  5891. rand.Seed(time.Now().Unix())
  5892. // Instantiate new minio client object.
  5893. c, err := minio.NewV2(
  5894. os.Getenv(serverEndpoint),
  5895. os.Getenv(accessKey),
  5896. os.Getenv(secretKey),
  5897. mustParseBool(os.Getenv(enableHTTPS)),
  5898. )
  5899. if err != nil {
  5900. logError(testName, function, args, startTime, "", "Minio client v2 object creation failed", err)
  5901. return
  5902. }
  5903. // Enable tracing, write to stderr.
  5904. // c.TraceOn(os.Stderr)
  5905. // Set user agent.
  5906. c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0")
  5907. // Generate a new random bucket name.
  5908. bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test-")
  5909. args["bucketName"] = bucketName
  5910. // Make a new bucket.
  5911. err = c.MakeBucket(bucketName, "us-east-1")
  5912. if err != nil {
  5913. logError(testName, function, args, startTime, "", "MakeBucket call failed", err)
  5914. return
  5915. }
  5916. bufSize := dataFileMap["datatfile-1-MB"]
  5917. var reader = getDataReader("datafile-1-MB")
  5918. defer reader.Close()
  5919. // Save the data
  5920. objectName := randString(60, rand.NewSource(time.Now().UnixNano()), "")
  5921. args["objectName"] = objectName
  5922. _, err = c.PutObject(bucketName, objectName, reader, int64(bufSize), minio.PutObjectOptions{ContentType: "binary/octet-stream"})
  5923. if err != nil {
  5924. logError(testName, function, args, startTime, "", "PutObject call failed", err)
  5925. return
  5926. }
  5927. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
  5928. args["ctx"] = ctx
  5929. defer cancel()
  5930. fileName := "tempfile-context"
  5931. args["fileName"] = fileName
  5932. // Read the data back
  5933. err = c.FGetObjectWithContext(ctx, bucketName, objectName, fileName+"-f", minio.GetObjectOptions{})
  5934. if err == nil {
  5935. logError(testName, function, args, startTime, "", "FGetObjectWithContext should fail on short timeout", err)
  5936. return
  5937. }
  5938. ctx, cancel = context.WithTimeout(context.Background(), 1*time.Hour)
  5939. defer cancel()
  5940. // Read the data back
  5941. err = c.FGetObjectWithContext(ctx, bucketName, objectName, fileName+"-fcontext", minio.GetObjectOptions{})
  5942. if err != nil {
  5943. logError(testName, function, args, startTime, "", "FGetObjectWithContext call shouldn't fail on long timeout", err)
  5944. return
  5945. }
  5946. if err = os.Remove(fileName + "-fcontext"); err != nil {
  5947. logError(testName, function, args, startTime, "", "Remove file failed", err)
  5948. return
  5949. }
  5950. // Delete all objects and buckets
  5951. if err = cleanupBucket(bucketName, c); err != nil {
  5952. logError(testName, function, args, startTime, "", "Cleanup failed", err)
  5953. return
  5954. }
  5955. successLogger(testName, function, args, startTime).Info()
  5956. }
  5957. // Convert string to bool and always return false if any error
  5958. func mustParseBool(str string) bool {
  5959. b, err := strconv.ParseBool(str)
  5960. if err != nil {
  5961. return false
  5962. }
  5963. return b
  5964. }
  5965. func main() {
  5966. // Output to stdout instead of the default stderr
  5967. log.SetOutput(os.Stdout)
  5968. // create custom formatter
  5969. mintFormatter := mintJSONFormatter{}
  5970. // set custom formatter
  5971. log.SetFormatter(&mintFormatter)
  5972. // log Info or above -- success cases are Info level, failures are Fatal level
  5973. log.SetLevel(log.InfoLevel)
  5974. tls := mustParseBool(os.Getenv(enableHTTPS))
  5975. // execute tests
  5976. if !isQuickMode() {
  5977. testMakeBucketErrorV2()
  5978. testGetObjectClosedTwiceV2()
  5979. testRemovePartiallyUploadedV2()
  5980. testFPutObjectV2()
  5981. testMakeBucketRegionsV2()
  5982. testGetObjectReadSeekFunctionalV2()
  5983. testGetObjectReadAtFunctionalV2()
  5984. testCopyObjectV2()
  5985. testFunctionalV2()
  5986. testComposeObjectErrorCasesV2()
  5987. testCompose10KSourcesV2()
  5988. testUserMetadataCopyingV2()
  5989. testPutObject0ByteV2()
  5990. testPutObjectNoLengthV2()
  5991. testPutObjectsUnknownV2()
  5992. testGetObjectWithContextV2()
  5993. testFPutObjectWithContextV2()
  5994. testFGetObjectWithContextV2()
  5995. testPutObjectWithContextV2()
  5996. testMakeBucketError()
  5997. testMakeBucketRegions()
  5998. testPutObjectWithMetadata()
  5999. testPutObjectReadAt()
  6000. testPutObjectStreaming()
  6001. testListPartiallyUploaded()
  6002. testGetObjectSeekEnd()
  6003. testGetObjectClosedTwice()
  6004. testRemoveMultipleObjects()
  6005. testRemovePartiallyUploaded()
  6006. testFPutObjectMultipart()
  6007. testFPutObject()
  6008. testGetObjectReadSeekFunctional()
  6009. testGetObjectReadAtFunctional()
  6010. testPresignedPostPolicy()
  6011. testCopyObject()
  6012. testEncryptionPutGet()
  6013. testEncryptionFPut()
  6014. testComposeObjectErrorCases()
  6015. testCompose10KSources()
  6016. testUserMetadataCopying()
  6017. testBucketNotification()
  6018. testFunctional()
  6019. testGetObjectModified()
  6020. testPutObjectUploadSeekedObject()
  6021. testGetObjectWithContext()
  6022. testFPutObjectWithContext()
  6023. testFGetObjectWithContext()
  6024. testPutObjectWithContext()
  6025. testStorageClassMetadataPutObject()
  6026. testStorageClassInvalidMetadataPutObject()
  6027. testStorageClassMetadataCopyObject()
  6028. // SSE-C tests will only work over TLS connection.
  6029. if tls {
  6030. testEncryptedCopyObjectV2()
  6031. testEncryptedCopyObject()
  6032. }
  6033. } else {
  6034. testFunctional()
  6035. testFunctionalV2()
  6036. }
  6037. }