copied from a project that was version on mercurial

This commit is contained in:
didier.amyot committed 2014-09-19 20:02:10 -07:00
commit ec72b5b91a
24 files changed
+841

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
js/
bower_components/
node_modules/
lib/
+48
View File
@@ -0,0 +1,48 @@
module.exports = (grunt) ->
# Project configuration.
grunt.initConfig(
packagekg: grunt.file.readJSON('package.json')
bower:
install: {}
connect:
server:
options:
port: 4506
base: '.'
keepalive: true
clean: ["js"]
coffee:
compile:
expand: true
cwd: 'coffee'
src: ['**/*.coffee']
dest: 'js'
ext: '.js'
watch:
coffee:
files: ['**/*.coffee']
tasks: ['coffee']
options:
spawn: false
concurrent:
target: ['watch', 'connect'],
)
# Plugins
grunt.loadNpmTasks('grunt-bower-task')
grunt.loadNpmTasks('grunt-contrib-connect')
grunt.loadNpmTasks('grunt-contrib-coffee')
grunt.loadNpmTasks('grunt-contrib-watch')
grunt.loadNpmTasks('grunt-concurrent')
grunt.loadNpmTasks('grunt-contrib-clean')
# tasks
grunt.registerTask('default', ['bower:install', 'clean', 'coffee:compile'])
grunt.registerTask('dev', ['default', 'concurrent:target'])
+22
View File
@@ -0,0 +1,22 @@
{
"name": "bab",
"version": "0.1",
"authors": [
"didier.amyot <didier.amyot@gmail.com>"
],
"description": "Easy home to all your web application.",
"main": "index.html",
"license": "MIT",
"private": true,
"dependencies": {
"underscore": "~1.6.0",
"foundation": "~5.2.1",
"angular": "~1.2.14",
"angular-route": "~1.2.14",
"angular-local-storage": "~0.0.1",
"qunit": "~1.14.0",
"zepto": "~1.1.3",
"angular-sanitize": "~1.2.16",
"fontawesome": "~4.0.3"
}
}
+37
View File
@@ -0,0 +1,37 @@
root = this;
angular.module('bab', [
'ngRoute'
'bab.filters'
'bab.services'
'bab.directives'
'bab.controllers'
]).
config(['$routeProvider', ($routeProvider) ->
$routeProvider.when('/', {templateUrl: 'partials/home.html', controller: 'homeCtrl'})
$routeProvider.when('/login', {templateUrl: 'partials/login.html', controller: 'loginCtrl'})
$routeProvider.when('/about', {templateUrl: 'partials/about.html', controller: 'aboutCtrl'})
$routeProvider.otherwise({redirectTo: '/'})
])
root.filters = angular.module('bab.filters', [])
root.services = angular.module('bab.services', [])
root.directives = angular.module('bab.directives', [])
root.controllers = angular.module('bab.controllers', [])
root.filters.filter 'month', () ->
(text) ->
return ['janvier',
'février',
'mars',
'avril',
'may',
'juin',
'juillet',
'aout',
'september',
'octobre',
'novembre',
'decembre'][Number(text) - 1]
@@ -0,0 +1,4 @@
root = this;
root.controllers.controller('aboutCtrl', ['$scope', ($scope) ->
])
@@ -0,0 +1,8 @@
root = this;
root.controllers.controller('homeCtrl', ['$scope', '$http', ($scope, $http) ->
$scope.services = []
$http.get('/webapps').then (resp) ->
$scope.services = resp.data
])
@@ -0,0 +1,4 @@
root = this;
root.controllers.controller('loginCtrl', ['$scope', ($scope) ->
])
@@ -0,0 +1,9 @@
root = this;
root.controllers.controller('topBarCtrl', ['$scope', ($scope) ->
$scope.$on('$routeChangeSuccess', (next, current) ->
$scope.path = current.originalPath
)
$scope.path = "home"
])
+31
View File
@@ -0,0 +1,31 @@
template = """
<div class="panel">
<div class="row">
<div class="large-12 columns" style="text-align:center;">
<a href="{{ service.url }}"><img src="{{ service.image }}" style="height:100px;"></img></a>
</div>
</div>
<div class="row">
<div class="large-12 columns" style="text-align:center;">
<h3 ><a href="{{ service.url }}"> {{ service.name }} </a></h3>
</div>
</div>
</div>
"""
directive = ($rootScope) ->
directive =
template: template
replace: true,
transclude: false,
restrict: 'E',
scope:
service: "="
controller:["$scope",
($scope, $timeout) ->
]
return directive
directives.directive("babService", ['$rootScope', directive])
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+68
View File
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="401.98px" height="559.472px" viewBox="0 0 401.98 559.472" enable-background="new 0 0 401.98 559.472"
xml:space="preserve">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#F6D2A2" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M10.634,300.493c0.764,15.751,16.499,8.463,23.626,3.539c6.765-4.675,8.743-0.789,9.337-10.015
c0.389-6.064,1.088-12.128,0.744-18.216c-10.23-0.927-21.357,1.509-29.744,7.602C10.277,286.542,2.177,296.561,10.634,300.493"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#C6B198" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M10.634,300.493c2.29-0.852,4.717-1.457,6.271-3.528"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#6AD7E5" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M46.997,112.853C-13.3,95.897,31.536,19.189,79.956,50.74L46.997,112.853z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#6AD7E5" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M314.895,44.984c47.727-33.523,90.856,42.111,35.388,61.141L314.895,44.984z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#F6D2A2" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M325.161,494.343c12.123,7.501,34.282,30.182,16.096,41.18c-17.474,15.999-27.254-17.561-42.591-22.211
C305.271,504.342,313.643,496.163,325.161,494.343z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M341.257,535.522c-2.696-5.361-3.601-11.618-8.102-15.939"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#F6D2A2" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M108.579,519.975c-14.229,2.202-22.238,15.039-34.1,21.558c-11.178,6.665-15.454-2.134-16.461-3.92
c-1.752-0.799-1.605,0.744-4.309-1.979c-10.362-16.354,10.797-28.308,21.815-36.432C90.87,496.1,100.487,509.404,108.579,519.975z"
/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M58.019,537.612c0.542-6.233,5.484-10.407,7.838-15.677"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.513,91.667c-7.955-4.208-13.791-9.923-8.925-19.124
c4.505-8.518,12.874-7.593,20.83-3.385L49.513,91.667z"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M337.716,83.667c7.955-4.208,13.791-9.923,8.925-19.124
c-4.505-8.518-12.874-7.593-20.83-3.385L337.716,83.667z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#F6D2A2" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M392.475,298.493c-0.764,15.751-16.499,8.463-23.626,3.539c-6.765-4.675-8.743-0.789-9.337-10.015
c-0.389-6.064-1.088-12.128-0.744-18.216c10.23-0.927,21.357,1.509,29.744,7.602C392.831,284.542,400.932,294.561,392.475,298.493"
/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#C6B198" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M392.475,298.493c-2.29-0.852-4.717-1.457-6.271-3.528"/>
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#6AD7E5" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M195.512,13.124c60.365,0,116.953,8.633,146.452,66.629c26.478,65.006,17.062,135.104,21.1,203.806
c3.468,58.992,11.157,127.145-16.21,181.812c-28.79,57.514-100.73,71.982-160,69.863c-46.555-1.666-102.794-16.854-129.069-59.389
c-30.826-49.9-16.232-124.098-13.993-179.622c2.652-65.771-17.815-131.742,3.792-196.101
C69.999,33.359,130.451,18.271,195.512,13.124"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" stroke="#000000" stroke-width="2.9081" stroke-linecap="round" d="
M206.169,94.16c10.838,63.003,113.822,46.345,99.03-17.197C291.935,19.983,202.567,35.755,206.169,94.16"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" stroke="#000000" stroke-width="2.8214" stroke-linecap="round" d="
M83.103,104.35c14.047,54.85,101.864,40.807,98.554-14.213C177.691,24.242,69.673,36.957,83.103,104.35"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M218.594,169.762c0.046,8.191,1.861,17.387,0.312,26.101c-2.091,3.952-6.193,4.37-9.729,5.967c-4.89-0.767-9.002-3.978-10.963-8.552
c-1.255-9.946,0.468-19.576,0.785-29.526L218.594,169.762z"/>
<g>
<ellipse fill-rule="evenodd" clip-rule="evenodd" cx="107.324" cy="95.404" rx="14.829" ry="16.062"/>
<ellipse fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" cx="114.069" cy="99.029" rx="3.496" ry="4.082"/>
</g>
<g>
<ellipse fill-rule="evenodd" clip-rule="evenodd" cx="231.571" cy="91.404" rx="14.582" ry="16.062"/>
<ellipse fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" cx="238.204" cy="95.029" rx="3.438" ry="4.082"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
M176.217,168.87c-6.47,15.68,3.608,47.035,21.163,23.908c-1.255-9.946,0.468-19.576,0.785-29.526L176.217,168.87z"/>
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#F6D2A2" stroke="#231F20" stroke-width="3" stroke-linecap="round" d="
M178.431,138.673c-12.059,1.028-21.916,15.366-15.646,26.709c8.303,15.024,26.836-1.329,38.379,0.203
c13.285,0.272,24.17,14.047,34.84,2.49c11.867-12.854-5.109-25.373-18.377-30.97L178.431,138.673z"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M176.913,138.045c-0.893-20.891,38.938-23.503,43.642-6.016
C225.247,149.475,178.874,153.527,176.913,138.045C175.348,125.682,176.913,138.045,176.913,138.045z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0"?><svg width="629" height="999" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<path id="svg_1" fill="#ffffff" d="m627,993l1,-988l-627,0l0,986l626,2z"/>
<ellipse id="svg_2" fill="#000000" ry="12" rx="189" cy="898" cx="320"/>
<ellipse id="svg_3" fill="#000000" ry="411" rx="12" cy="494" cx="543"/>
<ellipse id="svg_4" fill="#000000" ry="11" rx="191" cy="94" cx="320"/>
<ellipse id="svg_5" fill="#000000" ry="412" rx="12" cy="496" cx="97"/>
<ellipse id="svg_6" fill="#000000" ry="156" rx="11" cy="702" cx="155"/>
<ellipse id="svg_7" fill="#000000" ry="12" rx="132" cy="841" cx="316"/>
<ellipse id="svg_8" fill="#000000" ry="152" rx="12" cy="706" cx="478"/>
<ellipse id="svg_9" fill="#000000" ry="11" rx="131" cy="565" cx="318"/>
<ellipse id="svg_10" fill="#000000" ry="154" rx="11" cy="297" cx="155"/>
<ellipse id="svg_11" fill="#000000" ry="11" rx="126" cy="435" cx="316"/>
<path id="svg_12" fill="#000000" d="m487,437l1,-279l-1,-5l-2,-4l-4,-2l-5,-1l-4,1l-4,2l-2,4l-1,4l-1,280l1,5l2,4l4,2l4,1l5,-1l4,-2l2,-4l1,-5z"/>
<ellipse id="svg_13" fill="#000000" ry="11" rx="129" cy="157" cx="315"/>
<circle id="svg_14" fill="#fff" r="8" cy="493" cx="478"/>
<circle id="svg_15" fill="#000000" r="31" cy="493" cx="478"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+52
View File
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html class="no-js" lang="en" ng-app="bab">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>bab</title>
<!-- If you are using CSS version, only link these 2 files, you may add app.css to use for your overrides if you like. -->
<link rel="stylesheet" href="bower_components/foundation/css/foundation.css">
<link rel="stylesheet" href="bower_components/foundation/css/normalize.css">
<link rel="stylesheet" href="bower_components/fontawesome/css/font-awesome.css">
<script src="bower_components/angular/angular.js"></script>
</head>
<body>
<div class="row">
<div class="large-12 columns">
<h3><img src="images/logo.svg" width="50px"> Bab</h3>
</div>
</div>
<div class="row" ng-controller="topBarCtrl">
<div class="large-12 columns">
<dl class="sub-nav">
<dd ng-class="{active: path == '/'}"><a href="#/">Web Apps</a></dd>
<dd ng-class="{active: path == '/about'}"><a href="#/about">About</a></dd>
</dl>
</div>
</div>
<div ng-view></div>
<script src="bower_components/underscore/underscore.js"></script>
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/foundation/js/foundation.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="js/babApp.js"></script>
<script src="js/controllers/homeCtrl.js"></script>
<script src="js/controllers/loginCtrl.js"></script>
<script src="js/controllers/aboutCtrl.js"></script>
<script src="js/controllers/topBarCtrl.js"></script>
<script src="js/directives/service.js"></script>
<script>
$(document).foundation();
</script>
</body>
</html>
+11
View File
@@ -0,0 +1,11 @@
{
"devDependencies": {
"grunt": "^0.4.4",
"grunt-bower-task": "^0.3.4",
"grunt-contrib-connect": "^0.7.1",
"grunt-contrib-coffee": "^0.10.1",
"grunt-contrib-watch": "^0.6.1",
"grunt-concurrent": "^0.5.0",
"grunt-contrib-clean": "^0.5.0"
}
}
+25
View File
@@ -0,0 +1,25 @@
<div class="row">
<div class="columns large-12">
<p>
Thanks for using <it>Bab</it>.
</p>
<p>
The source code of the application is available on
<a href="https://bitbucket.org/damyot/bab">bitbucket</a>.
</p>
</div>
</div>
<div class="row" style="margin-top: 100px;">
<div class="large-4 large-centered columns" style="text-align: center;">
<img src="images/gopher.svg" width="100px">
</div>
</div>
<div class="row" >
<div class="large-4 large-centered columns" style="text-align: center;">
<p>This program has been done with <a href="http://golang.org">Go</a>!</p>
</div>
</div>
+10
View File
@@ -0,0 +1,10 @@
<div class="row">
<div class="large-12 columns">
<ul class="small-block-grid-2 medium-block-grid-3 large-block-grid-4">
<li ng-repeat="service in services">
<bab-service service=service></bab-service>
</li>
</ul>
</div>
</div>
+27
View File
@@ -0,0 +1,27 @@
<div class="row">
<div class="columns large-6 large-offset-6">
<form>
<fieldset>
<div class="row">
<div class="large-12 columns">
<label>email
<input type="text">
</label>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<label>password
<input type="password">
</label>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<button class="button">login</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
+106
View File
@@ -0,0 +1,106 @@
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"io/ioutil"
"launchpad.net/goyaml"
"log"
"net/http"
"path"
)
const helloworld string = `
____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
||s ||||e ||||r ||||v ||||i ||||n ||||g ||||: ||||8 ||||0 ||||0 ||||0 ||
||__||||__||||__||||__||||__||||__||||__||||__||||__||||__||||__||||__||
|/__\||/__\||/__\||/__\||/__\||/__\||/__\||/__\||/__\||/__\||/__\||/__\|
`
type WebAppServers []*WebAppServer
func (this WebAppServers) Handle(w http.ResponseWriter, request *http.Request) {
for _, was := range this {
if was.Subdomain == mux.Vars(request)["subdomain"] {
was.Handle(w, request)
return
}
}
fmt.Fprint(w, "could not find a web application for ")
}
func (this WebAppServers) Localize(domain string) WebAppServers {
fmt.Println(">>", domain)
ret := make(WebAppServers, len(this))
for i, was := range this {
ret[i] = was.Localize(domain)
}
return ret
}
var webAppServers WebAppServers
var port int = 8000
func init() {
var err error
webAppServers, err = loadWebAppServers()
if err != nil {
panic(err)
}
}
func loadWebAppServers() (WebAppServers, error) {
data, err := ioutil.ReadFile("webapps.yml")
if err != nil {
return nil, err
}
return loadWebAppServersFromYamlFile(data)
}
func loadWebAppServersFromYamlFile(yamlFile []byte) (WebAppServers, error) {
ret := make(WebAppServers, 0, 10)
err := goyaml.Unmarshal(yamlFile, &ret)
return ret, err
}
func serveStatic(router *mux.Router) {
handler := func(w http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
filepath := "/" + vars["path"]
w.Header().Set("Cache-Control", "public, max-age=43200")
http.ServeFile(w, request, path.Join("client/", filepath))
}
router.HandleFunc("/{path:.*}", handler)
}
func ServeWebApps(router *mux.Router) {
router.HandleFunc("/{path:.*}", webAppServers.Handle)
}
func WebappHandler(w http.ResponseWriter, request *http.Request) {
w.Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(w)
encoder.Encode(webAppServers.Localize(request.Host))
}
func createMuxRouter() http.Handler {
r := mux.NewRouter()
ServeWebApps(r.Host(`{subdomain:\w+}.{domain:\w+}.{topleveldomain:[a-z]+}`).Subrouter())
ServeWebApps(r.Host(`{subdomain:\w+}.localhost`).Subrouter())
ServeWebApps(r.Host(`{subdomain:\w+}.\d{1-3}.\d{1-3}.\d{1-3}.\d{1-3}`).Subrouter())
r.HandleFunc("/webapps", WebappHandler)
serveStatic(r.PathPrefix("/").Subrouter())
return r
}
func main() {
fmt.Print(helloworld)
address := fmt.Sprintf("0.0.0.0:%v", port)
if err := http.ListenAndServe(address, createMuxRouter()); err != nil {
log.Fatal(err)
}
}
+28
View File
@@ -0,0 +1,28 @@
package main
import (
"testing"
)
func TestLoadWebAppServersFromYamlFile(t *testing.T) {
yml := []byte(`
---
-
name: mongs
url: http://localhost:3333
subdomain: mongs
image: images/mongo.png
-
name: ipython
url: http://localhost:8888
subdomain: ipython
image: images/ipython.png
`)
if was, err := loadWebAppServersFromYamlFile(yml); err != nil {
t.Error(err)
} else if len(was) != 2 {
t.Fail()
}
}
+3
View File
@@ -0,0 +1,3 @@
# Bab
Bab is a gateway to your web applications. Run
+15
View File
@@ -0,0 +1,15 @@
---
# This yaml file where your need to define your services. Look at the *http bin*
# example for fields one needs to give to define a service
#
# Before wishing to use *bab*, one needs to setup correctly its DNS server to points
# the subdomains to the correct ips. For localhost case, we recommend changing the
# /etc/hosts file to have a file similar to the one bellow
# 127.0.0.1 localhost httpbin.localhost
-
name: http bin # service's name as it will be shown to the user
url: http://httpbin.org # service's url
subdomain: httpbin # subdomain where the service will be reachable
image: images/bin.png # service's imagae path relative to the client directory
+95
View File
@@ -0,0 +1,95 @@
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"regexp"
"strings"
)
var _ = fmt.Print
type WebAppServer struct {
Subdomain string `yaml:"subdomain"`
WebAppURL string `yaml:"url"`
ImageUrl string `yaml:"image"`
Name string `yaml:"name"`
Domain string `yaml:"default_domain,omitempty"`
}
func (this *WebAppServer) Localize(domain string) *WebAppServer {
return &WebAppServer{this.Subdomain, this.WebAppURL, this.ImageUrl, this.Name, domain}
}
type jsonWebAppServer struct {
Name string `json:"name"`
Url string `json:"url"`
Image string `json:"image"`
}
func (this *WebAppServer) copyHeader(from, to http.Header) {
for key, val := range from {
to.Set(key, strings.Join(val, ";"))
}
}
func (this *WebAppServer) GetWebAppBaseUrl() string {
return fmt.Sprintf("http://%s.%s", this.Subdomain, this.Domain)
}
func (this *WebAppServer) MarshalJSON() ([]byte, error) {
ret := &jsonWebAppServer{this.Name,
this.GetWebAppBaseUrl(),
this.ImageUrl}
return json.Marshal(ret)
}
func (this *WebAppServer) HandleGet(w http.ResponseWriter, request *http.Request) {
URL := this.WebAppURL + request.URL.Path
if request.URL.RawQuery != "" {
URL += "?" + request.URL.RawQuery
}
req, err := http.NewRequest(request.Method, URL, request.Body)
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, "bab error :(", err.Error())
return
}
this.copyHeader(request.Header, req.Header)
resp, err := new(http.Client).Do(req)
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, "bab error :(\n", err.Error())
return
}
this.copyHeader(resp.Header, w.Header())
w.WriteHeader(resp.StatusCode)
defer resp.Body.Close()
io.Copy(w, resp.Body)
}
func (this *WebAppServer) Handle(w http.ResponseWriter, request *http.Request) {
switch request.Method {
case "GET":
this.HandleGet(w, request)
case "POST":
this.HandleGet(w, request)
case "PUT":
this.HandleGet(w, request)
default:
w.WriteHeader(500)
fmt.Fprint(w, "method "+request.Method+" is not yet available")
}
}
func (this *WebAppServer) CanHandle(host string) bool {
r := regexp.MustCompile(`[:\.]`)
domain := r.Split(host, -1)
if len(domain) < 3 {
return false
}
return domain[len(domain)-3] == this.Subdomain
}
+213
View File
@@ -0,0 +1,213 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
type TestServer struct {
Server *httptest.Server
Get func(w http.ResponseWriter, request *http.Request)
Post func(w http.ResponseWriter, request *http.Request)
T *testing.T
}
func (this *TestServer) ServeHTTP(w http.ResponseWriter, request *http.Request) {
if request.Method == "GET" {
this.Get(w, request)
} else if request.Method == "POST" {
this.Post(w, request)
} else {
this.T.Error("cannot execute ", request.Method, " method")
}
}
func (this *TestServer) HelloWorld(w http.ResponseWriter, request *http.Request) {
fmt.Fprint(w, "hello world\n")
}
func (this *TestServer) ReturnPath(w http.ResponseWriter, request *http.Request) {
fmt.Fprint(w, request.URL.Path)
}
func (this *TestServer) ReturnBogusHeader(w http.ResponseWriter, request *http.Request) {
fmt.Fprint(w, request.Header.Get("Bogus"))
}
func (this *TestServer) ReturnBody(w http.ResponseWriter, request *http.Request) {
io.Copy(w, request.Body)
}
func (this *TestServer) SetBogusHeader(w http.ResponseWriter, request *http.Request) {
w.Header().Set("Bogus", "has been set on the server")
fmt.Fprint(w, request.Header.Get("Bogus"))
}
func (this *TestServer) ReturnParamValue(w http.ResponseWriter, request *http.Request) {
if err := request.ParseForm(); err != nil {
this.T.Error(err)
return
}
fmt.Fprint(w, request.Form.Get("search"))
}
func GetTestServer(t *testing.T) *TestServer {
ret := new(TestServer)
ret.T = t
server := httptest.NewServer(ret)
ret.Server = server
return ret
}
func TestMarshalJSON(t *testing.T) {
wapp := &WebAppServer{"big", "http://bigtits.com", "img.png", "some name", "tits.com:8000"}
b, err := json.Marshal(wapp)
if err != nil {
t.Error(err)
}
if s := string(b); !strings.Contains(s, `"http://big.tits.com:8000"`) {
t.Fail()
}
}
func TestCanHandle(t *testing.T) {
was := &WebAppServer{Subdomain: "foo"}
exps := map[string]bool{"foo.bigtits.com": true,
"foo.localhost:8000": true,
"bar.bigtits.com": false,
"bigtits.com": false}
for host, exp := range exps {
if was.CanHandle(host) != exp {
t.Error("error handeling ", host)
}
}
}
func TestHandleGetHelloWorld(t *testing.T) {
ts := GetTestServer(t)
ts.Get = ts.HelloWorld
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
w := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://foo.bigtits.com/natasha", nil)
if err != nil {
t.Error(err)
}
was.HandleGet(w, req)
if body := string(w.Body.Bytes()); body != "hello world\n" {
t.Error(body)
}
}
func TestHandleGetPath(t *testing.T) {
ts := GetTestServer(t)
ts.Get = ts.ReturnPath
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
w := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://foo.bigtits.com/natasha", nil)
if err != nil {
t.Error(err)
}
was.HandleGet(w, req)
if body := string(w.Body.Bytes()); body != "/natasha" {
t.Error(body)
}
}
func TestHandleGetBogusHeader(t *testing.T) {
ts := GetTestServer(t)
ts.Get = ts.ReturnBogusHeader
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
w := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://foo.bigtits.com/natasha", nil)
if err != nil {
t.Error(err)
}
req.Header.Set("Bogus", "something in the header!")
was.HandleGet(w, req)
if body := string(w.Body.Bytes()); body != "something in the header!" {
t.Error(body)
}
}
func TestHandleGetSetBogusHeader(t *testing.T) {
ts := GetTestServer(t)
ts.Get = ts.SetBogusHeader
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
w := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://foo.bigtits.com/natasha", nil)
if err != nil {
t.Error(err)
}
was.HandleGet(w, req)
if header := w.Header().Get("Bogus"); header != "has been set on the server" {
t.Error(header)
}
}
func TestHandleGetReturnParamValue(t *testing.T) {
ts := GetTestServer(t)
ts.Get = ts.ReturnParamValue
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
w := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://foo.bigtits.com/natasha?search=bigtits", nil)
if err != nil {
t.Error(err)
}
was.HandleGet(w, req)
if body := string(w.Body.Bytes()); body != "bigtits" {
t.Error(body)
}
}
func TestHandlePostWithBody(t *testing.T) {
ts := GetTestServer(t)
ts.Post = ts.ReturnBody
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
w := httptest.NewRecorder()
req, err := http.NewRequest("POST", "http://foo.bigtits.com/natasha", bytes.NewBuffer([]byte(`hello world in the body`)))
if err != nil {
t.Error(err)
}
was.Handle(w, req)
if body := string(w.Body.Bytes()); body != "hello world in the body" {
t.Error("wrong body :", body)
}
}
func TestHandlePostBogusHeader(t *testing.T) {
ts := GetTestServer(t)
ts.Post = ts.SetBogusHeader
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
w := httptest.NewRecorder()
req, err := http.NewRequest("POST", "http://foo.bigtits.com/natasha", nil)
if err != nil {
t.Error(err)
}
was.HandleGet(w, req)
if header := w.Header().Get("Bogus"); header != "has been set on the server" {
t.Error(header)
}
}
func TestCanHandleNoService(t *testing.T) {
ts := GetTestServer(t)
was := &WebAppServer{Subdomain: "foo", WebAppURL: ts.Server.URL}
ts.Server.Close()
w := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://foo.bigtits.com/natasha?search=bigtits", nil)
if err != nil {
t.Error(err)
}
was.HandleGet(w, req)
if w.Code != 500 {
t.Error("status should be 500, service not found")
}
}