/ *
* Minio Cloud Storage , ( C ) 2017 Minio , Inc .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
package cmd
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"
"time"
)
func TestGetCurrentReleaseTime ( t * testing . T ) {
minioVersion1 := time . Now ( ) . UTC ( ) . Format ( time . RFC3339 )
releaseTime1 , _ := time . Parse ( time . RFC3339 , minioVersion1 )
minioVersion2 := "DEVELOPMENT.GOGET"
tmpfile1 , err := ioutil . TempFile ( "" , "get-current-release-time-testcase-1" )
if err != nil {
t . Fatalf ( "Unable to create temporary file. %s" , err )
}
defer os . Remove ( tmpfile1 . Name ( ) )
minioBinaryPath2 := tmpfile1 . Name ( )
fi , err := tmpfile1 . Stat ( )
if err != nil {
t . Fatalf ( "Unable to get temporary file info. %s" , err )
}
if err = tmpfile1 . Close ( ) ; err != nil {
t . Fatalf ( "Unable to create temporary file. %s" , err )
}
releaseTime2 := fi . ModTime ( ) . UTC ( )
minioBinaryPath3 := "go"
if runtime . GOOS == globalWindowsOSName {
minioBinaryPath3 = "go.exe"
}
goBinAbsPath , err := exec . LookPath ( minioBinaryPath3 )
if err != nil {
t . Fatal ( err )
}
fi , err = os . Stat ( goBinAbsPath )
if err != nil {
t . Fatal ( err )
}
releaseTime3 := fi . ModTime ( ) . UTC ( )
// Get a non-absolute binary path.
minioBinaryPath4 := filepath . Base ( tmpfile1 . Name ( ) )
// Get a non-existent absolute binary path
minioBinaryPath5 := "/tmp/non-existent-file"
if runtime . GOOS == globalWindowsOSName {
minioBinaryPath5 = "C:\\tmp\\non-existent-file"
}
errorMessage1 := "exec: \"\": executable file not found in $PATH"
if runtime . GOOS == globalWindowsOSName {
errorMessage1 = "exec: \"\": executable file not found in %PATH%"
}
errorMessage2 := "exec: \"non-existent-file\": executable file not found in $PATH"
if runtime . GOOS == globalWindowsOSName {
errorMessage2 = "exec: \"non-existent-file\": executable file not found in %PATH%"
}
errorMessage3 := fmt . Sprintf ( "exec: \"%s\": executable file not found in $PATH" , minioBinaryPath4 )
if runtime . GOOS == globalWindowsOSName {
errorMessage3 = "exec: \"" + minioBinaryPath4 + "\": executable file not found in %PATH%"
}
errorMessage4 := "Unable to get ModTime of /tmp/non-existent-file. stat /tmp/non-existent-file: no such file or directory"
if runtime . GOOS == "windows" {
errorMessage4 = "Unable to get ModTime of C:\\tmp\\non-existent-file. GetFileAttributesEx C:\\tmp\\non-existent-file: The system cannot find the path specified."
}
testCases := [ ] struct {
minioVersion string
minioBinaryPath string
expectedResult time . Time
expectedErr error
} {
{ minioVersion1 , "" , releaseTime1 , nil } ,
{ minioVersion1 , minioBinaryPath2 , releaseTime1 , nil } ,
{ minioVersion2 , minioBinaryPath2 , releaseTime2 , nil } ,
{ minioVersion2 , minioBinaryPath3 , releaseTime3 , nil } ,
{ "junk" , minioBinaryPath2 , releaseTime2 , nil } ,
{ "3.2.0" , minioBinaryPath2 , releaseTime2 , nil } ,
{ minioVersion2 , "" , time . Time { } , errors . New ( errorMessage1 ) } ,
{ "junk" , "non-existent-file" , time . Time { } , errors . New ( errorMessage2 ) } ,
{ "3.2.0" , "non-existent-file" , time . Time { } , errors . New ( errorMessage2 ) } ,
{ minioVersion2 , minioBinaryPath4 , time . Time { } , errors . New ( errorMessage3 ) } ,
{ minioVersion2 , minioBinaryPath5 , time . Time { } , errors . New ( errorMessage4 ) } ,
}
if runtime . GOOS == "linux" {
testCases = append ( testCases , struct {
minioVersion string
minioBinaryPath string
expectedResult time . Time
expectedErr error
} { "3.2a" , "/proc/1/cwd" , time . Time { } , errors . New ( "Unable to get ModTime of /proc/1/cwd. stat /proc/1/cwd: permission denied" ) } )
}
for _ , testCase := range testCases {
result , err := getCurrentReleaseTime ( testCase . minioVersion , testCase . minioBinaryPath )
if testCase . expectedErr == nil {
if err != nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
} else if err == nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
} else if testCase . expectedErr . Error ( ) != err . Error ( ) {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
if ! testCase . expectedResult . Equal ( result ) {
t . Fatalf ( "result: expected: %v, got: %v" , testCase . expectedResult , result )
}
}
}
func TestIsDocker ( t * testing . T ) {
createTempFile := func ( content string ) string {
tmpfile , err := ioutil . TempFile ( "" , "isdocker-testcase" )
if err != nil {
t . Fatalf ( "Unable to create temporary file. %s" , err )
}
if _ , err = tmpfile . Write ( [ ] byte ( content ) ) ; err != nil {
t . Fatalf ( "Unable to create temporary file. %s" , err )
}
if err = tmpfile . Close ( ) ; err != nil {
t . Fatalf ( "Unable to create temporary file. %s" , err )
}
return tmpfile . Name ( )
}
filename1 := createTempFile ( ` 11 : pids : / user . slice / user - 1000. slice / user @ 1000. service
10 : blkio : /
9 : hugetlb : /
8 : perf_event : /
7 : cpuset : /
6 : devices : / user . slice
5 : net_cls , net_prio : /
4 : cpu , cpuacct : /
3 : memory : / user / bala / 0
2 : freezer : / user / bala / 0
1 : name = systemd : / user . slice / user - 1000. slice / user @ 1000. service / gnome - terminal - server . service
` )
defer os . Remove ( filename1 )
filename2 := createTempFile ( ` 14 : name = systemd : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
13 : pids : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
12 : hugetlb : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
11 : net_prio : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
10 : perf_event : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
9 : net_cls : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
8 : freezer : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
7 : devices : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
6 : memory : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
5 : blkio : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
4 : cpuacct : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
3 : cpu : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
2 : cpuset : / docker / d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727
1 : name = openrc : / docker
` )
defer os . Remove ( filename2 )
testCases := [ ] struct {
filename string
expectedResult bool
expectedErr error
} {
{ "" , false , nil } ,
{ "/tmp/non-existing-file" , false , nil } ,
{ filename1 , false , nil } ,
{ filename2 , true , nil } ,
}
if runtime . GOOS == "linux" {
testCases = append ( testCases , struct {
filename string
expectedResult bool
expectedErr error
} { "/proc/1/cwd" , false , fmt . Errorf ( "open /proc/1/cwd: permission denied" ) } )
}
for _ , testCase := range testCases {
result , err := isDocker ( testCase . filename )
if testCase . expectedErr == nil {
if err != nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
} else if err == nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
} else if testCase . expectedErr . Error ( ) != err . Error ( ) {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
if testCase . expectedResult != result {
t . Fatalf ( "result: expected: %v, got: %v" , testCase . expectedResult , result )
}
}
}
func TestIsSourceBuild ( t * testing . T ) {
testCases := [ ] struct {
minioVersion string
expectedResult bool
} {
{ time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) , false } ,
{ "DEVELOPMENT.GOGET" , true } ,
{ "junk" , true } ,
{ "3.2.4" , true } ,
}
for _ , testCase := range testCases {
result := isSourceBuild ( testCase . minioVersion )
if testCase . expectedResult != result {
t . Fatalf ( "expected: %v, got: %v" , testCase . expectedResult , result )
}
}
}
func TestDownloadReleaseData ( t * testing . T ) {
httpServer1 := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) { } ) )
defer httpServer1 . Close ( )
httpServer2 := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
fmt . Fprintln ( w , "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z" )
} ) )
defer httpServer2 . Close ( )
httpServer3 := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
http . Error ( w , "" , http . StatusNotFound )
} ) )
defer httpServer3 . Close ( )
testCases := [ ] struct {
releaseChecksumURL string
expectedResult string
expectedErr error
} {
{ httpServer1 . URL , "" , nil } ,
{ httpServer2 . URL , "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n" , nil } ,
{ httpServer3 . URL , "" , fmt . Errorf ( "Error downloading URL " + httpServer3 . URL + ". Response: 404 Not Found" ) } ,
}
for _ , testCase := range testCases {
result , err := downloadReleaseData ( testCase . releaseChecksumURL , 1 * time . Second )
if testCase . expectedErr == nil {
if err != nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
} else if err == nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
} else if testCase . expectedErr . Error ( ) != err . Error ( ) {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
if testCase . expectedResult != result {
t . Fatalf ( "result: expected: %v, got: %v" , testCase . expectedResult , result )
}
}
}
func TestParseReleaseData ( t * testing . T ) {
releaseTime , _ := time . Parse ( minioReleaseTagTimeLayout , "2016-10-07T01-16-39Z" )
testCases := [ ] struct {
data string
expectedResult time . Time
expectedErr error
} {
{ "more than two fields" , time . Time { } , fmt . Errorf ( "Unknown release data `more than two fields`" ) } ,
{ "more than" , time . Time { } , fmt . Errorf ( "Unknown release information `than`" ) } ,
{ "more than.two.fields" , time . Time { } , fmt . Errorf ( "Unknown release 'than.two.fields'" ) } ,
{ "more minio.RELEASE.fields" , time . Time { } , fmt . Errorf ( ` Unknown release time format. parsing time "fields" as "2006-01-02T15-04-05Z": cannot parse "fields" as "2006" ` ) } ,
{ "more minio.RELEASE.2016-10-07T01-16-39Z" , releaseTime , nil } ,
{ "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n" , releaseTime , nil } ,
}
for _ , testCase := range testCases {
result , err := parseReleaseData ( testCase . data )
if testCase . expectedErr == nil {
if err != nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
} else if err == nil {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
} else if testCase . expectedErr . Error ( ) != err . Error ( ) {
t . Fatalf ( "error: expected: %v, got: %v" , testCase . expectedErr , err )
}
if ! testCase . expectedResult . Equal ( result ) {
t . Fatalf ( "result: expected: %v, got: %v" , testCase . expectedResult , result )
}
}
}