func TestGCMConnector_Check(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() testutil.EnableDebugForMethod() assert := assert.New(t) routerMock := NewMockRouter(ctrl) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { assert.Equal("/gcm/broadcast", string(route.Path)) assert.Equal("gcm_connector", route.UserID) assert.Equal("gcm_connector", route.ApplicationID) }) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) assert.Nil(err) err = gcm.Start() assert.Nil(err) done := make(chan bool, 1) mockSender := testutil.CreateGcmSender(testutil.CreateRoundTripperWithJsonResponse(http.StatusOK, testutil.CorrectGcmResponseMessageJSON, done)) gcm.Sender = mockSender err = gcm.Check() fmt.Println(err) done2 := make(chan bool, 1) mockSender2 := testutil.CreateGcmSender(testutil.CreateRoundTripperWithJsonResponse(http.StatusUnauthorized, "", done2)) gcm.Sender = mockSender2 err = gcm.Check() fmt.Println(err) }
func TestPostMessage(t *testing.T) { defer initCtrl(t)() a := assert.New(t) // given: a rest api with a message sink routerMock := NewMockPubSubSource(ctrl) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { a.Equal("/notifications", string(route.Path)) a.Equal("marvin", route.UserId) a.Equal("gcmId123", route.ApplicationId) }) kvStore := store.NewMemoryKVStore() gcm := NewGCMConnector("/gcm/", "testApi") gcm.SetRouter(routerMock) gcm.SetKVStore(kvStore) url, _ := url.Parse("http://localhost/gcm/marvin/gcmId123/subscribe/notifications") // and a http context req := &http.Request{URL: url} w := httptest.NewRecorder() params := httprouter.Params{ httprouter.Param{Key: "userid", Value: "marvin"}, httprouter.Param{Key: "gcmid", Value: "gcmId123"}, httprouter.Param{Key: "topic", Value: "/notifications"}, } // when: I POST a message gcm.Subscribe(w, req, params) // the the result a.Equal("registered: /notifications\n", string(w.Body.Bytes())) }
func TestServeHTTPSuccess(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) // given: a rest api with a message sink routerMock := NewMockRouter(ctrl) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { a.Equal("/notifications", string(route.Path)) a.Equal("marvin", route.UserID) a.Equal("gcmId123", route.ApplicationID) }) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) url, _ := url.Parse("http://localhost/gcm/marvin/gcmId123/subscribe/notifications") // and a http context req := &http.Request{URL: url, Method: "POST"} w := httptest.NewRecorder() // when: I POST a message gcm.ServeHTTP(w, req) // then a.Equal("registered: /notifications\n", string(w.Body.Bytes())) }
func TestGCMConnector_GetErrorMessageFromGcm(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() // defer testutil.EnableDebugForMethod()() a := assert.New(t) routerMock := NewMockRouter(ctrl) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { a.Equal("/gcm/broadcast", string(route.Path)) a.Equal("gcm_connector", route.UserID) a.Equal("gcm_connector", route.ApplicationID) }) // expect the route unsubscribed from removeSubscription routerMock.EXPECT().Unsubscribe(gomock.Any()).Do(func(route *server.Route) { a.Equal("/path", string(route.Path)) a.Equal("id", route.ApplicationID) }) // expect the route subscribe with the new canonicalId from replaceSubscriptionWithCanonicalID routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { a.Equal("/path", string(route.Path)) a.Equal("marvin", route.UserID) a.Equal("gcmCanonicalID", route.ApplicationID) }) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) err = gcm.Start() a.Nil(err) done := make(chan bool, 1) mockSender := testutil.CreateGcmSender( testutil.CreateRoundTripperWithJsonResponse(http.StatusOK, testutil.ErrorResponseMessageJSON, done)) gcm.Sender = mockSender // put a dummy gcm message with minimum information msg := &server.MessageForRoute{ Message: &protocol.Message{ ID: uint64(4), Body: []byte("{id:id}"), Time: 1405544146, Path: "/gcm/marvin/gcm124/subscribe/stuff"}, Route: &server.Route{ ApplicationID: "id", Path: "/path", UserID: "marvin"}} gcm.routerC <- msg // expect that the Http Server gives us a malformed message <-done //wait before closing the gcm connector time.Sleep(50 * time.Millisecond) err = gcm.Stop() a.NoError(err) }
func TestGcmConnector_StartWithMessageSending(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) routerMock := NewMockRouter(ctrl) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { a.Equal("/gcm/broadcast", string(route.Path)) a.Equal("gcm_connector", route.UserID) a.Equal("gcm_connector", route.ApplicationID) }) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) err = gcm.Start() a.Nil(err) done := make(chan bool, 1) mockSender := testutil.CreateGcmSender( testutil.CreateRoundTripperWithJsonResponse(http.StatusOK, testutil.CorrectGcmResponseMessageJSON, done)) gcm.Sender = mockSender // put a broadcast message with no recipients and expect to be dropped by broadcastMsgWithNoRecipients := &server.MessageForRoute{ Message: &protocol.Message{ ID: uint64(4), Body: []byte("{id:id}"), Time: 1405544146, Path: "/gcm/broadcast"}} gcm.routerC <- broadcastMsgWithNoRecipients time.Sleep(50 * time.Millisecond) // expect that the HTTP Dummy Server to not handle any requests // put a dummy gcm message with minimum information msgWithNoRecipients := &server.MessageForRoute{ Message: &protocol.Message{ ID: uint64(4), Body: []byte("{id:id}"), Time: 1405544146, Path: "/gcm/marvin/gcm124/subscribe/stuff"}, Route: &server.Route{ApplicationID: "id"}} gcm.routerC <- msgWithNoRecipients // expect that the Http Server to give us a malformed message <-done //wait a little to Stop the GcmConnector time.Sleep(50 * time.Millisecond) err = gcm.Stop() a.NoError(err) }
func aMockedService() (*Service, store.KVStore, store.MessageStore, *MockMessageSink, *MockPubSubSource) { kvStore := store.NewMemoryKVStore() messageStore := store.NewDummyMessageStore() messageSink := NewMockMessageSink(ctrl) pubSubSource := NewMockPubSubSource(ctrl) return NewService("localhost:0", kvStore, messageStore, messageSink, pubSubSource, NewAllowAllAccessManager(true)), kvStore, messageStore, messageSink, pubSubSource }
func TestGCMConnector_GetPrefix(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) routerMock := NewMockRouter(ctrl) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) a.Equal(gcm.GetPrefix(), "/gcm/") }
func TestGCMConnector_BroadcastMessage(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) routerMock := NewMockRouter(ctrl) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { a.Equal("/notifications", string(route.Path)) a.Equal("marvin", route.UserID) a.Equal("gcmId123", route.ApplicationID) }) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) url, _ := url.Parse("http://localhost/gcm/marvin/gcmId123/subscribe/notifications") // and a http context req := &http.Request{URL: url, Method: "POST"} w := httptest.NewRecorder() // when: I POST a message gcm.ServeHTTP(w, req) // then a.Equal("registered: /notifications\n", string(w.Body.Bytes())) done := make(chan bool, 1) mockSender := testutil.CreateGcmSender( testutil.CreateRoundTripperWithJsonResponse(http.StatusOK, testutil.CorrectGcmResponseMessageJSON, done)) gcm.Sender = mockSender // put a broadcast message with no recipients and expect to be dropped by broadcastMessage := &server.MessageForRoute{ Message: &protocol.Message{ ID: uint64(4), Body: []byte("{id:id}"), Time: 1405544146, Path: "/gcm/broadcast"}} gcm.broadcastMessage(broadcastMessage) // wait for the message to be processed by http server <-done //wait before closing the gcm connector time.Sleep(50 * time.Millisecond) err = gcm.Stop() a.Nil(err) }
func TestGcmOnlyStartedIfEnabled(t *testing.T) { _, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) routerMock, _, _ := initRouterMock() routerMock.EXPECT().KVStore().Return(store.NewMemoryKVStore(), nil) *config.GCM.Enabled = true *config.GCM.APIKey = "xyz" a.True(containsGcmModule(CreateModules(routerMock))) *config.GCM.Enabled = false a.False(containsGcmModule(CreateModules(routerMock))) }
func TestSaveAndLoadSubscriptions(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) // given: some test routes testRoutes := map[string]bool{ "marvin:/foo:1234": true, "zappod:/bar:1212": true, "athur:/erde:42": true, } routerMock := NewMockRouter(ctrl) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { // delete the route from the map, if we got it in the test delete(testRoutes, fmt.Sprintf("%v:%v:%v", route.UserID, route.Path, route.ApplicationID)) }).AnyTimes() gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) // when: we save the routes for k := range testRoutes { splitKey := strings.SplitN(k, ":", 3) userID := splitKey[0] topic := splitKey[1] gcmID := splitKey[2] gcm.saveSubscription(userID, topic, gcmID) } // and reload the routes gcm.loadSubscriptions() time.Sleep(50 * time.Millisecond) // then: all expected subscriptions were called a.Equal(0, len(testRoutes)) }
func TestSaveAndLoadSubscriptions(t *testing.T) { defer initCtrl(t)() defer enableDebugForMethod()() a := assert.New(t) // given: some test routes testRoutes := map[string]bool{ "marvin:/foo:1234": true, "zappod:/bar:1212": true, "athur:/erde:42": true, } routerMock := NewMockPubSubSource(ctrl) routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(route *server.Route) { // delte the route from the map, if we got it in the test delete(testRoutes, fmt.Sprintf("%v:%v:%v", route.UserId, route.Path, route.ApplicationId)) }).AnyTimes() kvStore := store.NewMemoryKVStore() gcm := NewGCMConnector("/gcm/", "testApi") gcm.SetRouter(routerMock) gcm.SetKVStore(kvStore) // when: we save the routes for k, _ := range testRoutes { splitedKey := strings.SplitN(k, ":", 3) userid := splitedKey[0] topic := splitedKey[1] gcmid := splitedKey[2] gcm.saveSubscription(userid, topic, gcmid) } // and reload the routes gcm.loadSubscriptions() time.Sleep(time.Millisecond * 100) // than: all expected subscriptions were called a.Equal(0, len(testRoutes)) }
func TestGCMConnector_Stop(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) routerMock := NewMockRouter(ctrl) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) err = gcm.Stop() a.Nil(err) a.Equal(len(gcm.stopC), 0, "The Stop Channel should be empty") select { case _, opened := <-gcm.stopC: a.False(opened, "The Stop Channel should be closed") default: a.Fail("Reading from the Stop Channel should not block") } }
func TestGCMConnector_parseParams(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) routerMock := NewMockRouter(ctrl) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) testCases := []struct { urlPath, userID, gcmID, topic, err string }{ {"/gcm/marvin/gcmId123/subscribe/notifications", "marvin", "gcmId123", "/notifications", ""}, {"/gcm2/marvin/gcmId123/subscribe/notifications", "", "", "", "gcm: GCM request is not starting with gcm prefix"}, {"/gcm/marvin/gcmId123/subscrib2e/notifications", "", "", "", "gcm: GCM request third param is not subscribe"}, {"/gcm/marvin/gcmId123subscribenotifications", "", "", "", "gcm: GCM request has wrong number of params"}, {"/gcm/marvin/gcmId123/subscribe/notifications/alert/", "marvin", "gcmId123", "/notifications/alert", ""}, } for i, c := range testCases { userID, gcmID, topic, err := gcm.parseParams(c.urlPath) //if error message is present check only the error if c.err != "" { a.NotNil(err) a.EqualError(err, c.err, fmt.Sprintf("Failed on testcase no=%d", i)) } else { a.Equal(userID, c.userID, fmt.Sprintf("Failed on testcase no=%d", i)) a.Equal(gcmID, c.gcmID, fmt.Sprintf("Failed on testcase no=%d", i)) a.Equal(topic, c.topic, fmt.Sprintf("Failed on testcase no=%d", i)) a.Nil(err, fmt.Sprintf("Failed on testcase no=%d", i)) } } err = gcm.Stop() a.Nil(err) }
func TestServeHTTPWithErrorCases(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) // given: a rest api with a message sink routerMock := NewMockRouter(ctrl) kvStore := store.NewMemoryKVStore() routerMock.EXPECT().KVStore().Return(kvStore, nil) gcm, err := NewGCMConnector(routerMock, "/gcm/", "testApi", 1) a.Nil(err) url, _ := url.Parse("http://localhost/gcm/marvin/gcmId123/subscribe/notifications") // and a http context req := &http.Request{URL: url, Method: "GET"} w := httptest.NewRecorder() // do a GET instead of POST gcm.ServeHTTP(w, req) // check the result a.Equal("Permission Denied\n", string(w.Body.Bytes())) a.Equal(w.Code, http.StatusMethodNotAllowed) // send a new request with wrong parameters encoding req.Method = "POST" req.URL, _ = url.Parse("http://localhost/gcm/marvin/gcmId123/subscribe3/notifications") w2 := httptest.NewRecorder() gcm.ServeHTTP(w2, req) a.Equal("Invalid Parameters in request\n", string(w2.Body.Bytes())) a.Equal(w2.Code, http.StatusBadRequest) }
type Args struct { Listen string `arg:"-l,help: [Host:]Port the address to listen on (:8080)" env:"GUBLE_LISTEN"` LogInfo bool `arg:"--log-info,help: Log on INFO level (false)" env:"GUBLE_LOG_INFO"` LogDebug bool `arg:"--log-debug,help: Log on DEBUG level (false)" env:"GUBLE_LOG_DEBUG"` StoragePath string `arg:"--storage-path,help: The path for storing messages and key value data if 'file' is enabled (/var/lib/guble)" env:"GUBLE_STORAGE_PATH"` KVBackend string `arg:"--kv-backend,help: The storage backend for the key value store to use: file|memory (file)" env:"GUBLE_KV_BACKEND"` MSBackend string `arg:"--ms-backend,help: The message storage backend : file|memory (file)" env:"GUBLE_MS_BACKEND"` GcmEnable bool `arg:"--gcm-enable: Enable the Google Cloud Messaging Connector (false)" env:"GUBLE_GCM_ENABLE"` GcmApiKey string `arg:"--gcm-api-key: The Google API Key for Google Cloud Messaging" env:"GUBLE_GCM_API_KEY"` } var CreateKVStoreBackend = func(args Args) store.KVStore { switch args.KVBackend { case "memory": return store.NewMemoryKVStore() case "file": db := store.NewSqliteKVStore(path.Join(args.StoragePath, "kv-store.db"), true) if err := db.Open(); err != nil { panic(err) } return db default: panic(fmt.Errorf("unknown key value backend: %q", args.KVBackend)) } } var CreateMessageStoreBackend = func(args Args) store.MessageStore { switch args.MSBackend { case "none", "": return store.NewDummyMessageStore()
"storagePath": *config.StoragePath, "err": err, }).Error("Use --storage-path=<path> to override the default location, or create the directory with RW rights.") } return err } f.Close() os.Remove(testfile) } return nil } var CreateKVStore = func() store.KVStore { switch *config.KVS { case "memory": return store.NewMemoryKVStore() case "file": db := store.NewSqliteKVStore(path.Join(*config.StoragePath, "kv-store.db"), true) if err := db.Open(); err != nil { logger.WithField("err", err).Panic("Could not open database connection") } return db default: panic(fmt.Errorf("Unknown key-value backend: %q", *config.KVS)) } } var CreateMessageStore = func() store.MessageStore { switch *config.MS { case "none", "": return store.NewDummyMessageStore(store.NewMemoryKVStore())