Skip to content
Snippets Groups Projects
rootmux_test.go 9.44 KiB
Newer Older
  • Learn to ignore specific revisions
  • Alexis Poyen's avatar
    Alexis Poyen committed
    package rootmux
    
    import (
    	"encoding/json"
    	"io/ioutil"
    	"net/http"
    	"net/http/cookiejar"
    	"net/http/httptest"
    	"net/url"
    	"os"
    	"regexp"
    	"testing"
    
    
    	"forge.grandlyon.com/apoyen/elections/internal/auth"
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	"forge.grandlyon.com/apoyen/sdk-go/pkg/tester"
    	"forge.grandlyon.com/apoyen/sdk-go/pkg/tokens"
    
    	"forge.grandlyon.com/apoyen/elections/internal/mocks"
    )
    
    var (
    	reg, _              = regexp.Compile("[\n \t]+")
    	initialUsersBuff, _ = ioutil.ReadFile("../../configs/users.json")
    	initialUsers        = reg.ReplaceAllString(string(initialUsersBuff), "")
    	newUser             = `{"id":"3","login":"new_user","memberOf":["USERS"],"password":"test"}`
    	noH                 = tester.Header{Key: "", Value: ""}
    )
    
    func init() {
    	tokens.Init("../../configs/tokenskey.json", true)
    }
    
    func TestAll(t *testing.T) {
    	os.Mkdir("data", os.ModePerm)
    	os.Create("./data/test.db")
    	os.Link("../../data/users.db", "./data/users.db")
    	// Create the mock OAuth2 server
    	oAuth2Server := httptest.NewServer(mocks.CreateMockOAuth2())
    	defer oAuth2Server.Close()
    	// Create the mock API server
    	go http.ListenAndServe(":8091", mocks.CreateMockAPI())
    	// Set the constants with environment variables
    	os.Setenv("HOSTNAME", "sdk-go.io")
    	os.Setenv("ADMIN_GROUP", "ADMINS")
    	os.Setenv("CLIENT_ID", "clientid")
    	os.Setenv("CLIENT_SECRET", "clientsecret")
    	os.Setenv("TOKEN_URL", oAuth2Server.URL+"/token")
    	os.Setenv("USERINFO_URL", oAuth2Server.URL+"/userinfo")
    	os.Setenv("LOGOUT_URL", oAuth2Server.URL+"/logout")
    	// Set up testers
    	os.Setenv("AUTH_URL", oAuth2Server.URL+"/auth-wrong-state") // Set the server to access failing OAuth2 endpoints
    	Oauth2Tests(t)
    	os.Setenv("AUTH_URL", oAuth2Server.URL+"/auth") // Set the server to access the correct OAuth2Endpoint
    	os.Setenv("USERINFO_URL", oAuth2Server.URL+"/admininfo")
    
    
    	resetDataWithData(t)
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	appTests(t)
    
    	resetDataWithData(t)
    	deletionInCascadeTest(t)
    	resetDataWithData(t)
    	removeRoundRemoveDeskRoundsTest(t)
    
    	resetData(t)
    	AdminTests(t)
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	resetDataWithData(t)
    
    	CapturerTests(t)
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	resetDataWithData(t)
    
    	VisualizerTests(t)
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    
    	os.RemoveAll("./data")
    }
    
    /**
    SECURITY TESTS (this tests are to check that the security protections works)
    **/
    func Oauth2Tests(t *testing.T) {
    	// Create the tester
    	ts, do, _ := createTester(t)
    	defer ts.Close() // Close the tester
    	// Try to login (must fail)
    	do("GET", "/OAuth2Login", noH, "", 500, "invalid oauth state")
    }
    
    func appTests(t *testing.T) {
    
    	ts, do, _ := createTester(t)
    	defer ts.Close() // Close the tester
    	tests := func() {
    		// Get the XSRF Token
    		response := do("GET", "/api/common/WhoAmI", noH, "", 200, "")
    		token := auth.TokenData{}
    		json.Unmarshal([]byte(response), &token)
    
    		xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken}
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    
    
    		// Add a capturer to an already bind UserID should fail
    
    		do("POST", "/api/Capturer", xsrfHeader, `{"UserID":2,"Name":"Capturer"}`, 500, `UserID is already bind to a Capturer`)
    
    		// Verify that RoundDesks have been created on Round Creation
    		do("GET", "/api/Round/1", xsrfHeader, ``, 200, `{"ID":1,"ElectionID":1,"Parameter":{"ID":0,"CountBlankAndNull":false,"ShowOnlyCompleted":false,"ShowMap":false},"Date":"2020-06-28","Round":1,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}],"CandidateLists":[]}`)
    		do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}]}`)
    
    	}
    	// Do an OAuth2 login with an known admin
    	do("GET", "/OAuth2Login", noH, "", 200, "<!DOCTYPE html>")
    	tests()
    	// Try to logout (must pass)
    	do("GET", "/Logout", noH, "", 200, "Logout OK")
    }
    
    func deletionInCascadeTest(t *testing.T) {
    
    	ts, do, _ := createTester(t)
    	defer ts.Close() // Close the tester
    	tests := func() {
    		// Get the XSRF Token
    		response := do("GET", "/api/common/WhoAmI", noH, "", 200, "")
    		token := auth.TokenData{}
    		json.Unmarshal([]byte(response), &token)
    		xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken}
    
    		// Test deletion in cascade for generic election
    
    		do("DELETE", "/api/Election/1", xsrfHeader, ``, 200, ``)
    		do("GET", "/api/Area/1", xsrfHeader, ``, 404, `id is missing`)
    		do("GET", "/api/Section/1", xsrfHeader, ``, 404, `id is missing`)
    		do("GET", "/api/Desk/1", xsrfHeader, ``, 404, `id is missing`)
    
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	}
    	// Do an OAuth2 login with an known admin
    	do("GET", "/OAuth2Login", noH, "", 200, "<!DOCTYPE html>")
    	tests()
    	// Try to logout (must pass)
    	do("GET", "/Logout", noH, "", 200, "Logout OK")
    
    }
    
    func removeRoundRemoveDeskRoundsTest(t *testing.T) {
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    
    
    	ts, do, _ := createTester(t)
    	defer ts.Close() // Close the tester
    	tests := func() {
    		// Get the XSRF Token
    		response := do("GET", "/api/common/WhoAmI", noH, "", 200, "")
    		token := auth.TokenData{}
    		json.Unmarshal([]byte(response), &token)
    		xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken}
    
    		// Remove a Round should remove all DeskRounds
    		// Verify DeskRounds creation
    		do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}]}`)
    		// Delete a Round
    		do("DELETE", "/api/Round/1", xsrfHeader, ``, 200, ``)
    		// Verify DeskRounds doesnt exist anymore
    		do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[]}`)
    
    	}
    	// Do an OAuth2 login with an known admin
    	do("GET", "/OAuth2Login", noH, "", 200, "<!DOCTYPE html>")
    	tests()
    	// Try to logout (must pass)
    	do("GET", "/Logout", noH, "", 200, "Logout OK")
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    }
    
    func resetData(t *testing.T) {
    	os.RemoveAll("./data")
    	os.Mkdir("data", os.ModePerm)
    	os.Create("./data/test.db")
    	os.Link("../../data/users.db", "./data/users.db")
    
    	ts, do, _ := createTester(t)
    	defer ts.Close() // Close the tester
    
    	// Init Data in DB tests
    	init := func() {
    		response := do("GET", "/api/common/WhoAmI", noH, "", 200, "")
    		token := auth.TokenData{}
    		json.Unmarshal([]byte(response), &token)
    
    		xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken}
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    
    
    		// Create a capturer
    		do("POST", "/api/Capturer", xsrfHeader, `{"UserID":2,"Name":"Capturer"}`, 200, `{"ID":1,"UserID":2,"Name":"Capturer","DeskRounds":null}`)
    		do("POST", "/api/Capturer", xsrfHeader, `{"UserID":3,"Name":"Capturer"}`, 200, `{"ID":2,"UserID":3,"Name":"Capturer","DeskRounds":null}`)
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    	}
    	do("POST", "/Login", noH, `{"login": "admin","password": "password"}`, 200, "")
    	init()
    	do("GET", "/Logout", noH, "", 200, "Logout OK")
    }
    
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    func resetDataWithData(t *testing.T) {
    	os.RemoveAll("./data")
    	os.Mkdir("data", os.ModePerm)
    	os.Create("./data/test.db")
    	os.Link("../../data/users.db", "./data/users.db")
    
    	ts, do, _ := createTester(t)
    	defer ts.Close() // Close the tester
    
    	// Init Data in DB tests
    	init := func() {
    		response := do("GET", "/api/common/WhoAmI", noH, "", 200, "")
    		token := auth.TokenData{}
    		json.Unmarshal([]byte(response), &token)
    		xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken}
    
    		// Create a capturer
    		do("POST", "/api/Capturer", xsrfHeader, `{"UserID":2,"Name":"Capturer"}`, 200, `{"ID":1,"UserID":2,"Name":"Capturer","DeskRounds":null}`)
    		do("POST", "/api/Capturer", xsrfHeader, `{"UserID":3,"Name":"Capturer"}`, 200, `{"ID":2,"UserID":3,"Name":"Capturer","DeskRounds":null}`)
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    		do("POST", "/api/Election", xsrfHeader, `{"Name":"Grand Lyon 2020","BallotType":"metropolitan-direct"}`, 200, `{"ID":1,"Name":"Grand Lyon 2020","BallotType":"metropolitan-direct","Areas":null,"Rounds":null}`)
    		do("POST", "/api/Area", xsrfHeader, `{"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1"}`, 200, `{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1","Sections":null}`)
    		do("POST", "/api/Section", xsrfHeader, `{"AreaID":1,"Name":"Section 1","MapID":"1"}`, 200, `{"ID":1,"AreaID":1,"Name":"Section 1","MapID":"1","Desks":null}`)
    
    		do("POST", "/api/Desk", xsrfHeader, `{"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587}`, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":null}`)
    		do("POST", "/api/Round", xsrfHeader, `{"ElectionID":1,"Date":"2020-06-28","Round":1}`, 200, `{"ID":1,"ElectionID":1,"Parameter":{"ID":0,"CountBlankAndNull":false,"ShowOnlyCompleted":false,"ShowMap":false},"Date":"2020-06-28","Round":1,"DeskRounds":null,"CandidateLists":null}`)
    
    Alexis POYEN's avatar
    Alexis POYEN committed
    	}
    	do("POST", "/Login", noH, `{"login": "admin","password": "password"}`, 200, "")
    	init()
    	do("GET", "/Logout", noH, "", 200, "Logout OK")
    }
    
    
    Alexis Poyen's avatar
    Alexis Poyen committed
    func createTester(t *testing.T) (*httptest.Server, func(method string, url string, header tester.Header, payload string, expectedStatus int, expectedBody string) string, func(method string, url string, header tester.Header, payload string, expectedStatus int, expectedBody string) string) {
    	// Create the server
    	mux := CreateRootMux(1443, "../../web")
    	ts := httptest.NewServer(mux.Mux)
    	url, _ := url.Parse(ts.URL)
    	port := url.Port()
    	mux.Manager.Config.RedirectURL = "http://" + os.Getenv("HOSTNAME") + ":" + port + "/OAuth2Callback"
    	mux.Manager.Hostname = "http://" + os.Getenv("HOSTNAME") + ":" + port
    	// Create the cookie jar
    	jar, _ := cookiejar.New(nil)
    	// wrap the testing function
    	return ts, tester.CreateServerTester(t, port, os.Getenv("HOSTNAME"), jar), tester.CreateServerTester(t, port, os.Getenv("HOSTNAME"), nil)
    }