Exporting Tosca from UI

Change-Id: Ie7e58ac5bd51a56d028daa1c1e2577e7723a8297
diff --git a/views/ngXosViews/serviceGrid/spec/sample.test.js b/views/ngXosViews/serviceGrid/spec/sample.test.js
deleted file mode 100644
index c026149..0000000
--- a/views/ngXosViews/serviceGrid/spec/sample.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-
-describe('The User List', () => {
-  
-  var scope, element, isolatedScope, httpBackend;
-
-  beforeEach(module('xos.serviceGrid'));
-  beforeEach(module('templates'));
-
-  beforeEach(inject(function($httpBackend, $compile, $rootScope){
-    
-    httpBackend = $httpBackend;
-    // Setting up mock request
-    $httpBackend.expectGET('/api/core/users/?no_hyperlinks=1').respond([
-      {
-        email: 'teo@onlab.us',
-        firstname: 'Matteo',
-        lastname: 'Scandolo' 
-      }
-    ]);
-  
-    scope = $rootScope.$new();
-    element = angular.element('<users-list></users-list>');
-    $compile(element)(scope);
-    scope.$digest();
-    isolatedScope = element.isolateScope().vm;
-  }));
-
-  xit('should load 1 users', () => {
-    httpBackend.flush();
-    expect(isolatedScope.users.length).toBe(1);
-    expect(isolatedScope.users[0].email).toEqual('teo@onlab.us');
-    expect(isolatedScope.users[0].firstname).toEqual('Matteo');
-    expect(isolatedScope.users[0].lastname).toEqual('Scandolo');
-  });
-
-});
\ No newline at end of file
diff --git a/views/ngXosViews/serviceGrid/spec/services_encoder.test.js b/views/ngXosViews/serviceGrid/spec/services_encoder.test.js
new file mode 100644
index 0000000..3107b7f
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/spec/services_encoder.test.js
@@ -0,0 +1,223 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 6/22/16.
+ */
+
+(function () {
+  'use strict';
+  describe('The Services Encoder Service', () => {
+
+    var service, rootScope, ArchiveManagerSpy, toscaBase;
+
+    const toscaBaseDefault = {
+      topology_template: {
+        node_templates: {}
+      }
+    };
+
+    beforeEach(module('xos.serviceGrid'));
+    beforeEach(module('templates'));
+
+    beforeEach(inject(($rootScope, ArchiveManager, ServiceEncoder) => {
+      rootScope = $rootScope;
+      toscaBase = angular.copy(toscaBaseDefault);
+
+      ArchiveManagerSpy = ArchiveManager;
+      spyOn(ArchiveManagerSpy, 'createArchive');
+      spyOn(ArchiveManagerSpy, 'addFile');
+      service = ServiceEncoder;
+    }));
+
+    describe('the formatServiceProperties method', () => {
+
+      it('should return only the existing properties', (done) => {
+        service.formatServiceProperties({name: 'test', kind: 'vCPE'}, toscaBase)
+        .then(res => {
+          expect(res).toEqual({
+            topology_template:{
+              node_templates: {
+                'service#test': {
+                  type: 'tosca.nodes.VSGService',
+                  properties: {kind: 'vCPE'}
+                }
+              }
+            }
+          });
+          done();
+        });
+        rootScope.$apply();
+      });
+
+      it('should return all properties', (done) => {
+        service.formatServiceProperties({
+            name: 'test',
+            kind: 'vCPE',
+            view_url: 'view_url',
+            icon_url: 'icon_url',
+            private_key_fn: 'private_key_fn'
+          }, toscaBase)
+          .then(res => {
+            expect(res).toEqual({
+              topology_template:{
+                node_templates: {
+                  'service#test': {
+                    type: 'tosca.nodes.VSGService',
+                    properties: {
+                      kind: 'vCPE',
+                      view_url: 'view_url',
+                      icon_url: 'icon_url',
+                      private_key_fn: 'private_key_fn'
+                    }
+                  }
+                }
+              }
+            });
+            done();
+          });
+        rootScope.$apply();
+      });
+
+      describe('when a public key is provided', () => {
+        it('should add public_key and artifacts properties', (done) => {
+
+          let expected = {
+            topology_template:{
+              node_templates: {
+                'service#test': {
+                  type: 'tosca.nodes.VSGService',
+                  properties: {
+                    kind: 'vCPE',
+                    public_key: '{ get_artifact: [ SELF, pubkey, LOCAL_FILE] }'
+                  },
+                  artifacts: {
+                    pubkey: '/opt/xos/tosca/test/test_rsa.pub'
+                  }
+                }
+              }
+            }
+          };
+
+          service.formatServiceProperties({
+              kind: 'vCPE',
+              public_key: 'pkey',
+              name: 'test'
+            }, toscaBase)
+            .then(res => {
+              expect(res).toEqual(expected);
+              done();
+            });
+          rootScope.$apply();
+        });
+
+        it('should add public_key file to the archive', (done) => {
+          service.formatServiceProperties({
+              kind: 'vCPE',
+              public_key: 'pkey',
+              name: 'test'
+            }, toscaBase)
+            .then(res => {
+              expect(ArchiveManagerSpy.addFile).toHaveBeenCalledWith('test_rsa.pub', 'pkey');
+              done();
+            });
+          rootScope.$apply();
+        });
+      });
+    });
+
+    describe('the getServiceRequirements method', () => {
+      let TenantSpy, ServiceSpy, tenantQueryPromise;
+      beforeEach(inject(function(Tenants, Services, $q){
+
+        tenantQueryPromise= $q.defer();
+
+        TenantSpy = Tenants;
+        spyOn(TenantSpy, 'query').and.callFake(function(){
+          return {$promise: tenantQueryPromise.promise};
+        });
+
+        ServiceSpy = Services;
+        spyOn(ServiceSpy, 'get').and.callFake(function(p){
+          let d = $q.defer();
+          d.resolve({name: `deps_${p.id}`});
+          return {$promise: d.promise};
+        });
+      }));
+
+      it('should call the tenants service with correct params', () => {
+        service.getServiceRequirements({id: 1});
+        expect(TenantSpy.query).toHaveBeenCalledWith({subscriber_service: 1});
+      });
+
+      it('should not add requirements if the current service has no dependency', (done) => {
+        service.getServiceRequirements({id: 1}, {})
+          .then(res => {
+            expect(res).toEqual({});
+            done();
+          });
+        tenantQueryPromise.resolve();
+        rootScope.$apply();
+      });
+
+      it('should return a list of required service', () => {
+        service.getServiceRequirements({id: 1, name: 'test'}, {topology_template: {node_templates: {'service#test': {}}}})
+          .then(res => {
+            expect(res.topology_template.node_templates['service#test'].requirements).toEqual([
+              {
+                deps_3_tenant: {
+                  node: 'service#deps_3',
+                  relationship: 'tosca.relationships.TenantOfService'
+                }
+              },
+              {
+                deps_4_tenant: {
+                  node: 'service#deps_4',
+                  relationship: 'tosca.relationships.TenantOfService'
+                }
+              }
+            ]);
+          });
+        tenantQueryPromise.resolve([
+          {
+            subscriber_service: 1,
+            provider_service: 3
+          },
+          {
+            subscriber_service: 1,
+            provider_service: 4
+          }
+        ]);
+        rootScope.$apply();
+      });
+
+      it('should return a list of unique required service', () => {
+        service.getServiceRequirements({id: 1, name: 'test'}, {topology_template: {node_templates: {'service#test': {}}}})
+          .then(res => {
+            expect(res.topology_template.node_templates['service#test'].requirements).toEqual([
+              {
+                deps_3_tenant: {
+                  node: 'service#deps_3',
+                  relationship: 'tosca.relationships.TenantOfService'
+                }
+              }
+            ]);
+          });
+        tenantQueryPromise.resolve([
+          {
+            subscriber_service: 1,
+            provider_service: 3
+          },
+          {
+            subscriber_service: 1,
+            provider_service: 3
+          }
+        ]);
+        rootScope.$apply();
+      });
+    });
+  });
+
+})();
+
diff --git a/views/ngXosViews/serviceGrid/spec/site_encoder.test.js b/views/ngXosViews/serviceGrid/spec/site_encoder.test.js
new file mode 100644
index 0000000..fdc6d50
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/spec/site_encoder.test.js
@@ -0,0 +1,62 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 6/22/16.
+ */
+
+(function () {
+  'use strict';
+  describe('The Site Encoder service', () => {
+    let service, toscaBase, siteGetPromise, SiteSpy, rootScope;
+
+    const toscaBaseDefault = {
+      topology_template: {
+        node_templates: {}
+      }
+    };
+
+    const siteResponse = {
+      name: 'MySite'
+    };
+
+    const expected = [{
+      topology_template: {
+        node_templates: {
+          'MySite': {
+            type: 'tosca.nodes.Site',
+          }
+        }
+      }
+    }, siteResponse];
+
+    beforeEach(module('xos.serviceGrid'));
+    beforeEach(module('templates'));
+
+    beforeEach(inject((SiteEncoder, Sites, $q, $rootScope) => {
+      toscaBase = angular.copy(toscaBaseDefault);
+      service = SiteEncoder;
+      rootScope = $rootScope;
+
+      siteGetPromise= $q.defer();
+      SiteSpy = Sites;
+      spyOn(SiteSpy, 'get').and.callFake(function(){
+        return {$promise: siteGetPromise.promise};
+      });
+    }));
+
+    describe('given a Site Id', () => {
+      it('should return the correct JSON structure', (done) => {
+        service.buildTosca({id: 1}, toscaBase)
+          .then(res => {
+            expect(res).toEqual(expected);
+            done();
+          });
+        siteGetPromise.resolve(siteResponse);
+        rootScope.$apply();
+      });
+    });
+  });
+})();
+
diff --git a/views/ngXosViews/serviceGrid/spec/slices_encoder.test.js b/views/ngXosViews/serviceGrid/spec/slices_encoder.test.js
new file mode 100644
index 0000000..f32bc9a
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/spec/slices_encoder.test.js
@@ -0,0 +1,103 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 6/22/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The Slices Encoder service', () => {
+
+    let service, toscaBase, sliceQueryPromise, SliceSpy, rootScope;
+
+    const toscaBaseDefault = {
+      topology_template: {
+        node_templates: {}
+      }
+    };
+
+    const slicesArray = [
+      {
+        name: 'Slice1',
+        description: 'Description1',
+        network: 'noauto'
+      },
+      {
+        name: 'Slice2',
+        description: 'Description2',
+        network: 'noauto'
+      }
+    ];
+
+    const expected = {
+      topology_template: {
+        node_templates: {
+          Slice1: {
+            description: 'Description1',
+            type: 'tosca.nodes.Slice',
+            properties: {
+              network: 'noauto'
+            },
+            requirements: [
+              {management: {node: 'management', relationship: 'tosca.relationships.ConnectsToNetwork'}},
+              {test_service: {node: 'service#test', relationship: 'tosca.relationships.MemberOfService'}}
+            ]
+          },
+          Slice2: {
+            description: 'Description2',
+            type: 'tosca.nodes.Slice',
+            properties: {
+              network: 'noauto'
+            },
+            requirements: [
+              {management: {node: 'management', relationship: 'tosca.relationships.ConnectsToNetwork'}},
+              {test_service: {node: 'service#test', relationship: 'tosca.relationships.MemberOfService'}}
+            ]
+          }
+        }
+      }
+    };
+
+    beforeEach(module('xos.serviceGrid'));
+    beforeEach(module('templates'));
+
+    beforeEach(inject((SlicesEncoder, Slices, $q, $rootScope) => {
+      toscaBase = angular.copy(toscaBaseDefault);
+      service = SlicesEncoder;
+      rootScope = $rootScope;
+
+      sliceQueryPromise= $q.defer();
+      SliceSpy = Slices;
+      spyOn(SliceSpy, 'query').and.callFake(function(){
+        return {$promise: sliceQueryPromise.promise};
+      });
+    }));
+    
+    describe('given a Slices array ', () => {
+      it('should return the correct JSON structure', (done) => {
+        service.buildTosca(slicesArray, toscaBase, 'test')
+        .then(res => {
+          expect(res).toEqual(expected);
+          done();
+        });
+        rootScope.$apply();
+      });
+    });
+
+    describe('given a service', () => {
+      it('should return the JSON structure for all related slices', (done) => {
+        service.getServiceSlices({id : 1, name: 'test'}, toscaBase)
+        .then(res => {
+          expect(res).toEqual(expected);
+          done();
+        });
+        sliceQueryPromise.resolve(slicesArray);
+        rootScope.$apply();
+      });
+    });
+  });
+})();
+
diff --git a/views/ngXosViews/serviceGrid/spec/tosca_encoder.test.js b/views/ngXosViews/serviceGrid/spec/tosca_encoder.test.js
new file mode 100644
index 0000000..d968419
--- /dev/null
+++ b/views/ngXosViews/serviceGrid/spec/tosca_encoder.test.js
@@ -0,0 +1,234 @@
+(function () {
+  'use strict';
+  describe('The Tosca Encoder Service', () => {
+
+    var service, httpBackend, rootScope, ArchiveManagerSpy, toscaBase;
+
+    const serviceData = {
+      id: 1,
+      name: 'vsg',
+      kind: 'vCPE'
+    };
+
+    const toscaBaseDefault = {
+      topology_template: {
+        node_templates: {}
+      }
+    };
+
+    beforeEach(module('xos.serviceGrid'));
+    beforeEach(module('templates'));
+
+    beforeEach(inject(function($httpBackend, $rootScope, ToscaEncoder, ArchiveManager){
+
+      httpBackend = $httpBackend;
+      rootScope = $rootScope;
+      toscaBase = angular.copy(toscaBaseDefault);
+      service = ToscaEncoder;
+      ArchiveManagerSpy = ArchiveManager;
+      spyOn(ArchiveManagerSpy, 'createArchive');
+      spyOn(ArchiveManagerSpy, 'addFile');
+      spyOn(ArchiveManagerSpy, 'download');
+    }));
+
+    describe('the serviceToTosca method', () => {
+
+      const fakePropertiesDefault = {
+        tosca_definitions_version: 'tosca_simple_yaml_1_0',
+        description: 'Just enough Tosca to get the vSG slice running on the CORD POD',
+        imports: [
+          'custom_types/xos.yaml'
+        ],
+        topology_template:{
+          node_templates: {
+            'service#vsg': {
+              type: 'tosca.nodes.VSGService',
+              properties: {
+                view_url: 'viewUrl',
+                icon_url: 'iconUrl',
+                kind: 'vCPE'
+              }
+            }
+          }
+        }
+      };
+
+      const fakeRequirements = {
+        tosca_definitions_version: 'tosca_simple_yaml_1_0',
+        description: 'Just enough Tosca to get the vSG slice running on the CORD POD',
+        imports: [
+          'custom_types/xos.yaml'
+        ],
+        topology_template:{
+          node_templates: {
+            'service#vsg': {
+              type: 'tosca.nodes.VSGService',
+              properties: {
+                view_url: 'viewUrl',
+                icon_url: 'iconUrl',
+                kind: 'vCPE'
+              },
+              requirements: [
+                {
+                  node: 'service#vrouter',
+                  relationship: 'tosca.relationships.TenantOfService'
+                },
+                {
+                  node: 'service#volt',
+                  relationship: 'tosca.relationships.TenantOfService'
+                }
+              ]
+            }
+          }
+        }
+      };
+
+      const expectedWithoutRequirements = `tosca_definitions_version: tosca_simple_yaml_1_0
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+imports:
+  - custom_types/xos.yaml
+topology_template:
+  node_templates:
+    service#vsg:
+      type: tosca.nodes.VSGService
+      properties:
+        view_url: viewUrl
+        icon_url: iconUrl
+        kind: vCPE
+`;
+
+      const expectedWithRequirements = `tosca_definitions_version: tosca_simple_yaml_1_0
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+imports:
+  - custom_types/xos.yaml
+topology_template:
+  node_templates:
+    service#vsg:
+      type: tosca.nodes.VSGService
+      properties:
+        view_url: viewUrl
+        icon_url: iconUrl
+        kind: vCPE
+      requirements:
+        - node: service#vrouter
+          relationship: tosca.relationships.TenantOfService
+        - node: service#volt
+          relationship: tosca.relationships.TenantOfService
+`;
+
+      const expectedWithSlices = `tosca_definitions_version: tosca_simple_yaml_1_0
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+imports:
+  - custom_types/xos.yaml
+topology_template:
+  node_templates:
+    service#vsg:
+      type: tosca.nodes.VSGService
+      properties:
+        view_url: viewUrl
+        icon_url: iconUrl
+        kind: vCPE
+    service_slice:
+      description: A service slice
+      type: tosca.nodes.Slice
+      properties:
+        network: noauto
+`;
+
+      let formatPromise, requirementPromise, slicesPromise, fakeProperties, serviceEncoderSpy, slicesEncoderSpy;
+
+      beforeEach(inject(($q, ServiceEncoder, SlicesEncoder) => {
+
+        serviceEncoderSpy = ServiceEncoder;
+        slicesEncoderSpy = SlicesEncoder;
+
+        // clone the base property for mock
+        fakeProperties = angular.copy(fakePropertiesDefault);
+
+        // create the promises
+        // this will be resolved in the single IT block,
+        // to allow different resolutions
+        formatPromise = $q.defer();
+        requirementPromise = $q.defer();
+        slicesPromise = $q.defer();
+
+        // mock functions and return promises
+        spyOn(serviceEncoderSpy, 'formatServiceProperties').and.callFake(function(){
+          return formatPromise.promise;
+        });
+        spyOn(serviceEncoderSpy, 'getServiceRequirements').and.callFake(function(){
+          return requirementPromise.promise;
+        });
+        spyOn(slicesEncoderSpy, 'getServiceSlices').and.callFake(function(){
+          return slicesPromise.promise;
+        });
+      }));
+
+      it('should create a new archive', () => {
+        service.serviceToTosca(serviceData);
+        expect(ArchiveManagerSpy.createArchive).toHaveBeenCalled();
+      });
+
+      it('should add the service file to the archive', (done) => {
+        service.serviceToTosca(serviceData)
+        .then(() => {
+          expect(ArchiveManagerSpy.addFile).toHaveBeenCalledWith('vsg_service.yaml', expectedWithoutRequirements);
+          expect(ArchiveManagerSpy.download).toHaveBeenCalledWith('vsg');
+          done();
+        });
+        formatPromise.resolve(fakeProperties);
+        requirementPromise.resolve(fakeProperties);
+        slicesPromise.resolve(fakeProperties);
+        rootScope.$apply();
+      });
+
+      // IS IT REALLY USEFULL TO TEST THE CONVERTION TO YAML?
+      xit('should create a tosca spec with no requirements', (done) => {
+        service.serviceToTosca(serviceData)
+          .then(res => {
+            expect(res).toEqual(expectedWithoutRequirements);
+            done();
+          });
+        formatPromise.resolve(fakeProperties);
+        requirementPromise.resolve(fakeProperties);
+        slicesPromise.resolve(fakeProperties);
+        rootScope.$apply();
+      });
+
+      xit('should create a tosca spec with requirements', (done) => {
+        service.serviceToTosca(serviceData)
+          .then(res => {
+            expect(res).toEqual(expectedWithRequirements);
+            done();
+          });
+        formatPromise.resolve(fakeProperties);
+        requirementPromise.resolve(fakeRequirements);
+        slicesPromise.resolve(fakeProperties);
+        rootScope.$apply();
+      });
+
+      xit('should create a tosca spec with additional slices', (done) => {
+
+        // this is dirty, we are changing an object and shouldn't be done in tests
+        angular.extend(
+          fakeProperties.topology_template.node_templates, {service_slice: {
+            description: 'A service slice',
+            type: 'tosca.nodes.Slice',
+            properties: {
+              network: 'noauto'
+            }
+          }});
+
+        service.serviceToTosca(serviceData)
+          .then(res => {
+            expect(res).toEqual(expectedWithSlices);
+            done();
+          });
+        formatPromise.resolve(fakeProperties);
+        requirementPromise.resolve(fakeProperties);
+        slicesPromise.resolve(fakeProperties);
+        rootScope.$apply();
+      });
+    });
+  });
+}());
\ No newline at end of file